Merge pull request #1 from zerotier/master

Merge upstream
This commit is contained in:
Podcast Studio Development
2020-11-29 17:39:53 -06:00
committed by GitHub
94 changed files with 10702 additions and 11059 deletions

24
.gitattributes vendored Normal file
View File

@@ -0,0 +1,24 @@
examples export-ignore
ports export-ignore
test export-ignore
ext/lwip-contrib/apps export-ignore
ext/lwip-contrib/addons export-ignore
ext/lwip-contrib/Coverity export-ignore
ext/lwip-contrib/examples export-ignore
ext/lwip-contrib/*.mk export-ignore
ext/lwip-contrib/*.cmake export-ignore
ext/lwip/test export-ignore
ext/lwip/doc export-ignore
ext/ZeroTierOne/artwork export-ignore
ext/ZeroTierOne/attic export-ignore
ext/ZeroTierOne/debian export-ignore
ext/ZeroTierOne/doc export-ignore
ext/ZeroTierOne/docker export-ignore
ext/ZeroTierOne/java export-ignore
ext/ZeroTierOne/macui export-ignore
ext/ZeroTierOne/rule-compiler export-ignore
.gitattributes export-ignore
.gitignore export-ignore

16
.gitmodules vendored
View File

@@ -1,13 +1,9 @@
[submodule "zto"]
path = zto
url = https://github.com/zerotier/ZeroTierOne.git
branch = dev
[submodule "ext/lwip"]
path = ext/lwip
url = https://git.savannah.nongnu.org/git/lwip.git
[submodule "ext/lwip-contrib"]
path = ext/lwip-contrib
url = https://git.savannah.nongnu.org/git/lwip/lwip-contrib.git
[submodule "ext/ZeroTierOne"]
path = ext/ZeroTierOne
url = https://github.com/zerotier/ZeroTierOne.git
[submodule "ext/lwip"]
path = ext/lwip
url = https://github.com/joseph-henry/lwip.git
[submodule "ext/lwip-contrib"]
path = ext/lwip-contrib
url = https://github.com/joseph-henry/lwip-contrib.git

441
API.md
View File

@@ -1,441 +0,0 @@
<p align="center">
<img src="https://raw.githubusercontent.com/zerotier/ZeroTierOne/master/artwork/ZeroTierIcon.png" width="128" height="128" />
<br>
ZeroTier SDK
</p>
The ZeroTier SDK is composed of two libraries: `libztcore` which is the platform-agnostic network hypervisor, and `libzt` which is the network hypervisor paired with a userspace network stack. `libzt` is a superset of `libztcore` and is distinguished by the fact that it exposes a standard [socket API](https://en.wikipedia.org/wiki/Berkeley_sockets) and simple network control API. The full source for these products can be found at [github.com/zerotier/libzt](https://github.com/zerotier/libzt) for the SDK and [github.com/zerotier/ZeroTierOne](https://github.com/zerotier/ZeroTierOne) for the desktop client. With these libraries the network stack and virtual link are exclusive to your app and traffic is fully encrypted via the [Salsa20](https://en.wikipedia.org/wiki/Salsa20) cipher. For a more in-depth discussion on the technical side of ZeroTier, check out our [Manual](https://www.zerotier.com/manual.shtml?pk_campaign=github_libzt)
The ZeroTier source code is open source and is licensed under the GNU GPL v3 (not LGPL). If you'd like to embed it in a closed-source commercial product or appliance, please e-mail contact@zerotier.com to discuss commercial licensing. Otherwise it can be used for free.
<div style="page-break-after: always;"></div>
# Getting started
Before we dive into the technicals, the first thing to understand is that there are two API families to choose from and each is intended for a very different purpose:
`libzt` Intended for convenience and simplicity, derives from [Berkley Sockets](https://en.wikipedia.org/wiki/Berkeley_sockets).
- socket API: `zts_socket(), zts_connect(), zts_bind(), ...`
- control API: `zts_start(), zts_join(), zts_leave(), ....`
`libztcore` Intended for raw performance. If your goal is simply moving frames as quickly as possible and you're willing to put in some extra work, is what you're looking. The API is described in `include/ZeroTierOne.h`. For an example of how this API is used, see the living documentation that is `src/Service.cpp`.
- core API: `ZT_VirtualNetworkFrameFunction(), ZT_WirePacketSendFunction(), ...`
*NOTE: The remainder of this document will focus on the usage of the socket and control C API exposed in `include/ZeroTier.h` for `libzt`. For more information on the `libztcore` API see `include/ZeroTierOne.h`. We also provide bindings, frameworks, and packages for other languages and platforms in the `ports` directory and example applications using them in the `examples` directory.*
<div style="page-break-after: always;"></div>
# Starting the service
The next few sections explain how to use the control API. These functions are non-blocking and will return an error code specified in `include/ZeroTierConstants.h` and will result in the generation of callback events. It is your responsibility to handle these events.
To start the service, simply call:
`zts_start(char *path, void (*userCallbackFunc)(struct zts_callback_msg*), int port)`
At this stage, if a cryptographic identity for this node does not already exist, it will generate a new one and store it on disk, the node's address (commonly referred to as `nodeId`) will be derived from this identity and will be presented to you upon receiving the `ZTS_EVENT_NODE_ONLINE` shown below.
*NOTE: The first argument `path` is a path where you will allow ZeroTier to store its automatically-generated cryptographic identity files (`identity.public` and `identity.secret`), these files are your keys to communicating on the network. Keep them safe and keep them unique. If any two nodes are online using the same identities you will have a bad time. The second argument `userCallbackFunc` is a function that you specify to handle all generated events for the life of your program (see below):*
```
void myZeroTierEventCallback(struct zts_callback_msg *msg)
{
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE, nodeId=%llx\n", msg->node->address);
// You can join networks now!
}
// ...
}
```
After calling `zts_start()` you will receive one or more of the following events:
```
ZTS_EVENT_NODE_OFFLINE
ZTS_EVENT_NODE_ONLINE
ZTS_EVENT_NODE_DOWN
ZTS_EVENT_NODE_IDENTITY_COLLISION
ZTS_EVENT_NODE_UNRECOVERABLE_ERROR
ZTS_EVENT_NODE_NORMAL_TERMINATION
```
After receiving `ZTS_EVENT_NODE_ONLINE` you will be allowed to join or leave networks.
At the end of your program or when no more network activity is anticipated, the user application can shut down the service with `zts_stop()`. However, it is safe to leave the service running in the background indefinitely as it doesn't consume much memory or CPU while at idle. `zts_stop()` is a non-blocking call and will itself issue a series of events indicating that various aspects of the ZeroTier service have successfully shut down.
It is worth noting that while `zts_stop()` will stop the service, but the user-space network stack will continue operating in a headless hibernation mode. This is intended behavior due to the fact that the network stack we've chosen doesn't currently support the notion of shutdown since it was initially designed for embedded applications that are simply switched off. If you do need a way to shut everything down and free all resources you can call `zts_free()`, but please note that calling this function will prevent all subsequent `zts_start()` calls from succeeding and will require a full application restart if you want to run the service again. The events `ZTS_EVENT_NODE_ONLINE` and `ZTS_EVENT_NODE_OFFLINE` can be seen periodically throughout the lifetime of your application depending on the reliability of your underlying network link, these events are lagging indicators and are typically only triggered every thirty (30) seconds.
Lastly, the function `zts_restart()` is provided as a way to restart the ZeroTier service along with all of its virtual interfaces. The network stack will remain online and undisturbed during this call. Note that this call will temporarily block until the service has fully shut down, then will return and you may then watch for the appropriate startup callbacks mentioned above.
<div style="page-break-after: always;"></div>
# Joining a network
Joining a ZeroTier virtual network is as easy as calling `zts_join(uint64_t networkId)`. Similarly there is a `zts_leave(uint64_t networkId)`. Note that `zts_start()` must be called and a `ZTS_EVENT_NODE_ONLINE` event must be received before these calls will succeed. After calling `zts_join()` any one of the following events may be generated:
```
ZTS_EVENT_NETWORK_NOT_FOUND
ZTS_EVENT_NETWORK_CLIENT_TOO_OLD
ZTS_EVENT_NETWORK_REQUESTING_CONFIG
ZTS_EVENT_NETWORK_OK
ZTS_EVENT_NETWORK_ACCESS_DENIED
ZTS_EVENT_NETWORK_READY_IP4
ZTS_EVENT_NETWORK_READY_IP6
ZTS_EVENT_NETWORK_DOWN
```
`ZTS_EVENT_NETWORK_READY_IP4` and `ZTS_EVENT_NETWORK_READY_IP6` are combinations of a few different events. They signal that the network was found, joined successfully, an IP address was assigned and the network stack's interface is ready to process traffic of the indicated type. After this point you should be able to communicate with peers on the network.
<div style="page-break-after: always;"></div>
# Communicating with peers
After successfully starting the service and joining a network, communicating with other nodes (peers) on that network is as easy as it would ordinarily be without ZeroTier. However, one thing to be aware of is the difference between relay and P2P modes. In the event that a direct connection cannot be established between your nodes, ZeroTier offers a free relaying service, this means that your nodes are reachable almost instantaneously but at a temporary performance cost. One should wait to send large amounts of traffic until a `ZTS_EVENT_PEER_P2P` is received for the node that you're interested in talking to. This event usually only takes a few seconds to appear after data has initially been sent. Similarly if after some time ZeroTier determines that a previously known path to one of your nodes is no longer available you will see a `ZTS_EVENT_PEER_RELAY` event.
One can use `zts_get_peer_status(uint64_t peerId)` to query the current reachability state of another node. This function will actually **return** the previously mentioned event values, plus an additional one called `ZTS_EVENT_PEER_UNREACHABLE` if no known direct path exists between the calling node and the remote node.
<div style="page-break-after: always;"></div>
# Handling events
As mentioned in previous sections, the control API works by use of non-blocking calls and the generation of a few dozen different event types. Depending on the type of event there may be additional contextual information attached to the `zts_callback_msg` object that you can use. This contextual information will be housed in one of the following structures which are defined in `include/ZeroTier.h`:
```
struct zts_callback_msg
{
int eventCode;
struct zts_node_details *node;
struct zts_network_details *network;
struct zts_netif_details *netif;
struct zts_virtual_network_route *route;
struct zts_physical_path *path;
struct zts_peer_details *peer;
struct zts_addr_details *addr;
};
```
Here's an example of a callback function:
```
void myZeroTierEventCallback(struct zts_callback_msg *msg)
{
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE, node=%llx\n", msg->node->address);
// You can join networks now!
}
}
```
In this callback function you can perform additional non-blocking API calls or other work. While not returning control to the service isn't forbidden (the event messages are generated by a separate thread) it is recommended that you return control as soon as possible as not returning will prevent the user application from receiving additional callback event messages which may be time-sensitive.
<div style="page-break-after: always;"></div>
A typical ordering of messages may look like the following:
```
ZTS_EVENT_NETIF_UP --- network=a09acf023be465c1, mac=73b7abcfc207, mtu=10000
ZTS_EVENT_ADDR_NEW_IP4 --- addr=11.7.7.184 (on network=a09acf023be465c1)
ZTS_EVENT_ADDR_NEW_IP6 --- addr=fda0:9acf:233:e4b0:7099:9309:4c9b:c3c7 (on network=a09acf023be465c1)
ZTS_EVENT_NODE_ONLINE, node=c4c7ba3cf
ZTS_EVENT_NETWORK_READY_IP4 --- network=a09acf023be465c1
ZTS_EVENT_NETWORK_READY_IP6 --- network=a09acf023be465c1
ZTS_EVENT_PEER_P2P --- node=74d0f5e89d
ZTS_EVENT_PEER_P2P --- node=9d219039f3
ZTS_EVENT_PEER_P2P --- node=a09acf0233
```
## Node Events
These events pertain to the state of the current node. This message type will arrive with a `zts_node_details` object accessible via `msg->node`. Additionally, one can query the status of the node with `zts_get_node_status()`, this will **return** the status as an integer value only.
```
ZTS_EVENT_NODE_OFFLINE
ZTS_EVENT_NODE_ONLINE
ZTS_EVENT_NODE_DOWN
ZTS_EVENT_NODE_IDENTITY_COLLISION
ZTS_EVENT_NODE_UNRECOVERABLE_ERROR
ZTS_EVENT_NODE_NORMAL_TERMINATION
```
## Network Events
These events pertain to the state of the indicated network. This event type will arrive with a `zts_network_details` object accessible via `msg->network`. If for example you want to know the number of assigned routes for your network you can use `msg->network->num_routes`. Similarly for the MTU, use `msg->network->mtu`. Additionally, one can query the status of the network with `zts_get_network_status(uint64_t networkId)`, this will **return** the status as an integer value only.
```
ZTS_EVENT_NETWORK_NOT_FOUND
ZTS_EVENT_NETWORK_CLIENT_TOO_OLD
ZTS_EVENT_NETWORK_REQUESTING_CONFIG
ZTS_EVENT_NETWORK_OK
ZTS_EVENT_NETWORK_ACCESS_DENIED
ZTS_EVENT_NETWORK_READY_IP4
ZTS_EVENT_NETWORK_READY_IP6
ZTS_EVENT_NETWORK_DOWN
```
## Peer Events
These events are triggered when the reachability status of a peer has changed, this can happen at any time. This event type will arrive with a `zts_peer_details` object for additional context. Additionally, one can query the status of the network with `zts_get_peer_status(uint64_t peerId)`, this will **return** the status as an integer value only.
```
ZTS_EVENT_PEER_P2P
ZTS_EVENT_PEER_RELAY
ZTS_EVENT_PEER_UNREACHABLE
```
## Path Events
These events are triggered when a direct path to a peer has been discovered or is now considered too old to be used. You will see these in conjunction with peer events. This event type will arrive with a `zts_physical_path` object for additional context.
```
ZTS_EVENT_PATH_DISCOVERED
ZTS_EVENT_PATH_ALIVE
ZTS_EVENT_PATH_DEAD
```
## Route Events
This event type will arrive with a `zts_virtual_network_route` object for additional context.
```
ZTS_EVENT_ROUTE_ADDED
ZTS_EVENT_ROUTE_REMOVED
```
## Address Events
These events are triggered when new addresses are assigned to the node on a particular virtual network. This event type will arrive with a `zts_addr_details` object for additional context.
```
ZTS_EVENT_ADDR_ADDED_IP4
ZTS_EVENT_ADDR_REMOVED_IP4
ZTS_EVENT_ADDR_ADDED_IP6
ZTS_EVENT_ADDR_REMOVED_IP6
```
## Network Stack Events (debugging)
These events aren't very important to the application developer but are important for debugging. These signal whether the userspace networking stack was brought up successfully. You can ignore these in most cases. This event type will arrive with no additional contextual information.
```
ZTS_EVENT_STACK_UP
ZTS_EVENT_STACK_DOWN
```
## Netif Events (debugging)
These events aren't very important to the application developer but are important for debugging. These signal whether the userspace networking stack was brought up successfully. You can ignore these in most cases. This event type will arrive with a `zts_netif_details` object for additional context.
```
ZTS_EVENT_NETIF_UP
ZTS_EVENT_NETIF_DOWN
ZTS_EVENT_NETIF_REMOVED
ZTS_EVENT_NETIF_LINK_UP
ZTS_EVENT_NETIF_LINK_DOWN
```
<div style="page-break-after: always;"></div>
# Errors
Just as there are two APIs (socket and control), there are two sets of error codes. The control API (`zts_start()`, `zts_join()`, etc) errors defined in `include/ZeroTierConstants.h` are:
- `ZTS_ERR_OK`: Everything is ok
- `ZTS_ERR_INVALID_ARG`: An argument provided by the user application is invalid (e.g. out of range, NULL, etc)
- `ZTS_ERR_SERVICE`: The service isn't initialized or is for some reason currently unavailable. Try again.
- `ZTS_ERR_INVALID_OP`: For some reason this API operation is not permitted or doesn't make sense at this time.
- `ZTS_ERR_NO_RESULT`: The call succeeded, but no object or relevant result was available
- `ZTS_ERR_GENERAL`: General internal failure (memory allocation, null reference, etc)
The socket API error codes are defined in `doc/errno.h`
*NOTE: For Android/Java (or similar) which use JNI, the socket API's error codes are negative values*
*NOTE: For protocol-level errors (such as dropped packets) or internal network stack errors, see the section `Statistics`*
<div style="page-break-after: always;"></div>
# Thread model
The control API for `libzt` is thread safe and can be called at any time from any thread. There is a single internal lock guarding access to this API. The socket API is similar in this regard. Callback events are generated by a separate thread and are independent from the rest of the API's internal locking mechanism. Not returning from a callback event won't impact the rest of the API but it will prevent your application from receiving future events so it is in your application's best interest to perform as little work as possible in the callback function and promptly return control back to ZeroTier.
*Note: Internally, `libzt` will spawn a number of threads for various purposes: a thread for the core service, a thread for the network stack, a low priority thread to process callback events, and a thread for each network joined. The vast majority of work is performed by the core service and stack threads.*
<div style="page-break-after: always;"></div>
# Statistics
Protocol and service statistics are available in debug builds of `libzt`. These statistics are detailed fully in the section of `include/ZeroTier.h` that is guarded by `LWIP_STATS`. The protocol constants are defined in `include/ZeroTierConstants.h`. An example usage is as follows:
C++ example:
```
struct zts_stats_proto stats;
// Get count of received pings
if (zts_get_protocol_stats(ZTS_STATS_PROTOCOL_ICMP, &stats) == ZTS_ERR_OK) {
printf("icmp.recv=%d\n", stats.recv);
}
// Get count of dropped TCP packets
if (zts_get_protocol_stats(ZTS_STATS_PROTOCOL_TCP, &stats) == ZTS_ERR_OK) {
printf("tcp.drop=%d\n", stats.drop);
}
```
Java Example:
```
import com.zerotier.libzt.ZeroTierProtoStats;
...
// Get received pings
ZeroTierProtoStats stats = new ZeroTierProtoStats();
ZeroTier.get_protocol_stats(ZeroTier.STATS_PROTOCOL_ICMP, stats);
System.out.println("icmp.recv="+stats.recv);
```
<div style="page-break-after: always;"></div>
# Network Controller Mode
The library form of ZeroTier can act as a network controller and in `libzt` this is controlled via the `zts_controller_*` API calls specified in `include/ZeroTier.h`. Currently controller mode is not available in the `iOS` and `macOS` framework builds.
<div style="page-break-after: always;"></div>
# C Example
```
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ZeroTier.h"
bool node_ready = false;
bool network_ready = false;
void myZeroTierEventCallback(struct zts_callback_msg *msg)
{
switch (msg->eventCode)
{
case ZTS_EVENT_NODE_ONLINE:
printf("ZTS_EVENT_NODE_ONLINE, nodeId=%llx\n", msg->node->address);
node_ready = true;
break;
case ZTS_EVENT_NODE_OFFLINE:
printf("ZTS_EVENT_NODE_OFFLINE\n");
node_ready = false;
break;
case ZTS_EVENT_NETWORK_READY_IP4:
printf("ZTS_EVENT_NETWORK_READY_IP4, networkId=%llx\n", msg->network->nwid);
network_ready = true;
break;
case ZTS_EVENT_PEER_P2P:
printf("ZTS_EVENT_PEER_P2P, nodeId=%llx\n", msg->peer->address);
break;
case ZTS_EVENT_PEER_RELAY:
printf("ZTS_EVENT_PEER_RELAY, nodeId=%llx\n", msg->peer->address);
break;
default:
break;
}
}
int main()
{
char *str = "welcome to the machine";
char *remoteIp = "11.7.7.223";
int remotePort = 8082;
int fd, err = 0;
struct zts_sockaddr_in addr;
addr.sin_family = ZTS_AF_INET;
addr.sin_addr.s_addr = inet_addr(remoteIp);
addr.sin_port = htons(remotePort);
// Set up ZeroTier service and wait for callbacks
int port = 9994;
int nwid = 0x0123456789abcdef;
zts_start("test/path", &myZeroTierEventCallback, port);
printf("Waiting for node to come online...\n");
while (!node_ready) { sleep(1); }
zts_join(nwid);
printf("Joined virtual network. Requesting configuration...\n");
while (!network_ready) { sleep(1); }
// Socket API example
if ((fd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating socket\n");
}
if ((err = zts_connect(fd, (const struct sockaddr *)&addr, sizeof(addr))) < 0) {
printf("error connecting to remote host\n");
}
if ((err = zts_write(fd, str, strlen(str))) < 0) {
printf("error writing to socket\n");
}
zts_close(fd);
zts_stop();
return 0;
}
```
<div style="page-break-after: always;"></div>
# Java Example
Starting ZeroTier:
```
MyZeroTierEventListener listener = new MyZeroTierEventListener();
ZeroTier.start(getApplicationContext().getFilesDir() + "/zerotier", listener, myPort);
// Wait for EVENT_NODE_ONLINE
while (listener.isOnline == false) {
try {
Thread.sleep(interval);
} catch (Exception e) { }
}
ZeroTier.join(myNetworkId);
// Wait for EVENT_NETWORK_READY_IP4/6
while (listener.isNetworkReady == false) {
try {
Thread.sleep(interval);
} catch (Exception e) { }
}
// Now you can use the socket API!
```
An example event listener:
```
package com.example.exampleandroidapp;
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierEventListener;
import com.zerotier.libzt.ZeroTierPeerDetails;
public class MyZeroTierEventListener implements ZeroTierEventListener
{
public void onZeroTierEvent(long id, int eventCode)
{
if (eventCode == ZeroTier.EVENT_NODE_ONLINE) {
System.out.println("EVENT_NODE_ONLINE: nodeId=" + Long.toHexString(ZeroTier.get_node_id()));
isOnline = true;
}
if (eventCode == ZeroTier.EVENT_NODE_OFFLINE) {
System.out.println("EVENT_NODE_OFFLINE");
}
if (eventCode == ZeroTier.EVENT_NETWORK_READY_IP4) {
System.out.println("ZTS_EVENT_NETWORK_READY_IP4: nwid=" + Long.toHexString(id));
if (id == myNetworkId) {
isNetworkReady = true;
}
}
if (eventCode == ZeroTier.EVENT_PEER_P2P) {
System.out.println("EVENT_PEER_P2P: id=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_PEER_RELAY) {
System.out.println("EVENT_PEER_RELAY: id=" + Long.toHexString(id));
}
// ...
}
}
```

View File

@@ -29,10 +29,6 @@ endif ()
if (${CMAKE_GENERATOR} STREQUAL "Xcode")
set (IN_XCODE TRUE)
set(XCODE_EMIT_EFFECTIVE_PLATFORM_NAME ON)
#set_target_properties (${STATIC_LIB_NAME}
# PROPERTIES XCODE_ATTRIBUTE_MY_BUILD_ONLY_ACTIVE_ARCH YES)
#set_target_properties (${STATIC_LIB_NAME}
# PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "${MY_BUILD_ONLY_ACTIVE_ARCH})
endif ()
if (BUILDING_WIN32 OR BUILDING_WIN64 OR MSVC)
set (BUILDING_WIN TRUE)
@@ -51,7 +47,7 @@ endif ()
if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "debug")
set (DEBUG_BUILD ON)
set (CMAKE_VERBOSE_MAKEFILE ON)
set (CMAKE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin)
set (CMAKE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin)
set (LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib)
endif()
if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "release")
@@ -98,8 +94,6 @@ set (SILENCE "${SILENCE} -Wno-sign-compare")
set (SILENCE "${SILENCE} -Wno-unused-variable")
set (SILENCE "${SILENCE} -Wno-missing-field-initializers")
set (SILENCE "${SILENCE} -Wno-unused-parameter")
#set (SILENCE "${SILENCE} -Wno-nullability-completeness")
#set (SILENCE "${SILENCE} -Wno-expansion-to-defined")
set (ZT_FLAGS "${ZT_FLAGS} -DZT_USE_MINIUPNPC=1")
set (ZT_FLAGS "${ZT_FLAGS} -DZT_SOFTWARE_UPDATE_DEFAULT=0")
@@ -109,8 +103,8 @@ set (ZT_FLAGS "${ZT_FLAGS} -DZT_SDK=1")
if (DEBUG_BUILD)
set (LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_DBG_TYPES_ON=128")
set (LWIP_FLAGS "${LWIP_FLAGS} -DSOCKETS_DEBUG=128")
set (LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_STATS_LARGE=1")
set (LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_STATS=1")
#set (LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_STATS_LARGE=1")
#set (LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_STATS=1")
set (LWIP_FLAGS "${LWIP_FLAGS} -DLINK_STATS=1")
set (LWIP_FLAGS "${LWIP_FLAGS} -DETHARP_STATS=1")
set (LWIP_FLAGS "${LWIP_FLAGS} -DIPFRAG_STATS=1")
@@ -171,6 +165,29 @@ if (BUILDING_LINUX AND NOT BUILDING_ANDROID)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lpthread")
endif ()
# WINDOWS-specific MSVC flags and libraries
if (BUILDING_WIN)
# 32-bit
if(NOT BUILDING_WIN64)
set (WINLIBDIR, "C:/Program Files (x86)/Windows Kits/10/Lib/10.0.16299.0/um/x86")
endif ()
# 64-bit
if(BUILDING_WIN64)
set (WINLIBDIR, "C:/Program Files (x86)/Windows Kits/10/Lib/10.0.16299.0/um/x64")
endif ()
#find_library (ws2_32_LIBRARY_PATH NAMES WS2_32 HINTS ${WINLIBDIR})
#find_library (shlwapi_LIBRARY_PATH NAMES ShLwApi HINTS ${WINLIBDIR})
set (ws2_32_LIBRARY_PATH "${WINLIBDIR}/WS2_32.Lib")
set (shlwapi_LIBRARY_PATH "${WINLIBDIR}/ShLwApi.Lib")
set (iphlpapi_LIBRARY_PATH "${WINLIBDIR}/iphlpapi.Lib")
message (STATUS ${WINLIBDIR})
message (STATUS "WS2_32=${ws2_32_LIBRARY_PATH}")
message (STATUS "ShLwApi=${shlwapi_LIBRARY_PATH}")
message (STATUS "liphlpapi=${iphlpapi_LIBRARY_PATH}")
add_definitions (-DZT_SDK=1)
add_definitions (-DADD_EXPORTS=1)
endif ()
# -----------------------------------------------------------------------------
# | JNI |
# -----------------------------------------------------------------------------
@@ -219,7 +236,7 @@ if (SDK_JNI OR BUILDING_ANDROID)
endif () # SDK_JNI
# -----------------------------------------------------------------------------
# | SOURCE FILE GLOBS |
# | SOURCES |
# -----------------------------------------------------------------------------
set (PROJ_DIR ${PROJECT_SOURCE_DIR})
@@ -230,27 +247,28 @@ set (LIBZT_SRC_DIR "${PROJ_DIR}/src")
file (GLOB ztcoreSrcGlob
${ZTO_SRC_DIR}/node/*.cpp
${ZTO_SRC_DIR}/osdep/OSUtils.cpp
${ZTO_SRC_DIR}/osdep/PortMapper.cpp
${ZTO_SRC_DIR}/osdep/PortMapper.cpp
${ZTO_SRC_DIR}/osdep/ManagedRoute.cpp)
file (GLOB libnatpmpSrcGlob
${ZTO_SRC_DIR}/ext/libnatpmp/natpmp.c
${ZTO_SRC_DIR}/ext/libnatpmp/wingettimeofday.c
${ZTO_SRC_DIR}/ext/libnatpmp/getgateway.c)
file (GLOB libminiupnpcSrcGlob
${ZTO_SRC_DIR}/ext/miniupnpc/connecthostport.c
${ZTO_SRC_DIR}/ext/miniupnpc/igd_desc_parse.c
${ZTO_SRC_DIR}/ext/miniupnpc/minisoap.c
${ZTO_SRC_DIR}/ext/miniupnpc/minissdpc.c
${ZTO_SRC_DIR}/ext/miniupnpc/miniupnpc.c
${ZTO_SRC_DIR}/ext/miniupnpc/miniwget.c
${ZTO_SRC_DIR}/ext/miniupnpc/minixml.c
${ZTO_SRC_DIR}/ext/miniupnpc/portlistingparse.c
${ZTO_SRC_DIR}/ext/miniupnpc/receivedata.c
${ZTO_SRC_DIR}/ext/miniupnpc/upnpcommands.c
${ZTO_SRC_DIR}/ext/miniupnpc/upnpdev.c
${ZTO_SRC_DIR}/ext/miniupnpc/upnperrors.c
${ZTO_SRC_DIR}/ext/miniupnpc/upnpreplyparse.c)
${ZTO_SRC_DIR}/ext/miniupnpc/connecthostport.c
${ZTO_SRC_DIR}/ext/miniupnpc/igd_desc_parse.c
${ZTO_SRC_DIR}/ext/miniupnpc/minisoap.c
${ZTO_SRC_DIR}/ext/miniupnpc/minissdpc.c
${ZTO_SRC_DIR}/ext/miniupnpc/miniupnpc.c
${ZTO_SRC_DIR}/ext/miniupnpc/miniwget.c
${ZTO_SRC_DIR}/ext/miniupnpc/minixml.c
${ZTO_SRC_DIR}/ext/miniupnpc/portlistingparse.c
${ZTO_SRC_DIR}/ext/miniupnpc/receivedata.c
${ZTO_SRC_DIR}/ext/miniupnpc/upnpcommands.c
${ZTO_SRC_DIR}/ext/miniupnpc/upnpdev.c
${ZTO_SRC_DIR}/ext/miniupnpc/upnperrors.c
${ZTO_SRC_DIR}/ext/miniupnpc/upnpreplyparse.c)
file (GLOB libztSrcGlob ${LIBZT_SRC_DIR}/*.cpp)
@@ -272,8 +290,7 @@ file (GLOB lwipSrcGlob
list(REMOVE_ITEM lwipSrcGlob ${LWIP_SRC_DIR}/netif/slipif.c)
# header globs for xcode frameworks
file (GLOB frameworkPrivateHeaderGlob include/ZeroTier.h include/ZeroTierConstants.h)
file (GLOB frameworkPublicHeaderGlob include/Xcode-Bridging-Header.h)
file (GLOB frameworkPublicHeaderGlob include/ZeroTierSockets.h)
file (GLOB frameworkHeaderGlob ${frameworkPublicHeaderGlob} ${frameworkPrivateHeaderGlob})
# -----------------------------------------------------------------------------
@@ -340,7 +357,7 @@ endif ()
# libnatpmp_obj
add_library (libnatpmp_obj OBJECT ${libnatpmpSrcGlob})
set_target_properties (libnatpmp_obj PROPERTIES COMPILE_FLAGS "")
set_target_properties (libnatpmp_obj PROPERTIES COMPILE_FLAGS "-DNATPMP_EXPORTS")
# miniupnpc_obj
add_library (miniupnpc_obj OBJECT ${libminiupnpcSrcGlob})
@@ -373,6 +390,7 @@ set_target_properties (zto_pic PROPERTIES
# libnatpmp_pic
add_library (natpmp_pic ${libnatpmpSrcGlob})
set_target_properties (natpmp_pic PROPERTIES
COMPILE_FLAGS "-DNATPMP_EXPORTS"
POSITION_INDEPENDENT_CODE ON)
# miniupnpc_pic
@@ -404,44 +422,40 @@ set_target_properties (zt_pic PROPERTIES
# libztcore.a
add_library (ztcore STATIC $<TARGET_OBJECTS:zto_obj>)
set_target_properties (ztcore PROPERTIES
OUTPUT_NAME ztcore
LIBRARY_OUTPUT_DIRECTORY ${INTERMEDIATE_LIBRARY_OUTPUT_PATH})
# libnatpmp.a
add_library (natpmp STATIC $<TARGET_OBJECTS:libnatpmp_obj>)
set_target_properties (natpmp PROPERTIES
OUTPUT_NAME natpmp
LIBRARY_OUTPUT_DIRECTORY ${INTERMEDIATE_LIBRARY_OUTPUT_PATH})
# libminiupnpc.a
add_library (miniupnpc STATIC $<TARGET_OBJECTS:miniupnpc_obj>)
set_target_properties (miniupnpc PROPERTIES
OUTPUT_NAME miniupnpc
LIBRARY_OUTPUT_DIRECTORY ${INTERMEDIATE_LIBRARY_OUTPUT_PATH})
# liblwip.a
add_library (lwip STATIC $<TARGET_OBJECTS:lwip_obj>)
set_target_properties (lwip PROPERTIES
OUTPUT_NAME lwip
LIBRARY_OUTPUT_DIRECTORY ${INTERMEDIATE_LIBRARY_OUTPUT_PATH})
OUTPUT_NAME ztcore
LIBRARY_OUTPUT_DIRECTORY ${INTERMEDIATE_LIBRARY_OUTPUT_PATH})
# libzt.a
add_library (${STATIC_LIB_NAME} STATIC $<TARGET_OBJECTS:libzt_obj>
$<TARGET_OBJECTS:zto_obj>
$<TARGET_OBJECTS:libnatpmp_obj>
$<TARGET_OBJECTS:miniupnpc_obj>
$<TARGET_OBJECTS:lwip_obj> ${libztSrcGlob})
add_library (${STATIC_LIB_NAME} STATIC $<TARGET_OBJECTS:zt_pic>
$<TARGET_OBJECTS:zto_pic>
$<TARGET_OBJECTS:natpmp_pic>
$<TARGET_OBJECTS:miniupnpc_pic>
$<TARGET_OBJECTS:lwip_pic> ${libztSrcGlob})
set_target_properties (${STATIC_LIB_NAME} PROPERTIES
OUTPUT_NAME zt
LIBRARY_OUTPUT_DIRECTORY ${INTERMEDIATE_LIBRARY_OUTPUT_PATH})
OUTPUT_NAME zt
POSITION_INDEPENDENT_CODE ON
LIBRARY_OUTPUT_DIRECTORY ${INTERMEDIATE_LIBRARY_OUTPUT_PATH})
set_target_properties (${STATIC_LIB_NAME} PROPERTIES COMPILE_FLAGS "${ZT_FLAGS}")
if (BUILDING_WIN)
target_link_libraries (
${STATIC_LIB_NAME}
${ws2_32_LIBRARY_PATH}
${shlwapi_LIBRARY_PATH}
${iphlpapi_LIBRARY_PATH})
endif ()
# libzt.so/dylib/dll
add_library (${DYNAMIC_LIB_NAME} SHARED ${libztSrcGlob})
target_link_libraries (${DYNAMIC_LIB_NAME} zt_pic lwip_pic zto_pic natpmp_pic miniupnpc_pic)
set_target_properties (${DYNAMIC_LIB_NAME} PROPERTIES COMPILE_FLAGS "${ZT_FLAGS}")
set_target_properties (${DYNAMIC_LIB_NAME} PROPERTIES OUTPUT_NAME ${DYNAMIC_LIB_OUTPUT_NAME}
WINDOWS_EXPORT_ALL_SYMBOLS true)
WINDOWS_EXPORT_ALL_SYMBOLS true)
target_link_libraries (
${DYNAMIC_LIB_NAME}
${ws2_32_LIBRARY_PATH}
${shlwapi_LIBRARY_PATH}
${iphlpapi_LIBRARY_PATH} zt_pic lwip_pic zto_pic natpmp_pic miniupnpc_pic)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
if (BUILDING_ANDROID)
@@ -450,7 +464,8 @@ endif ()
# xcode framework
if (IN_XCODE)
include_directories (${frameworkHeaderGlob})
include_directories (${frameworkHeaderGlob})
add_library(${XCODE_FRAMEWORK_NAME} STATIC
$<TARGET_OBJECTS:libzt_obj>
@@ -461,12 +476,17 @@ if (IN_XCODE)
${libztSrcGlob}
${frameworkHeaderGlob})
set_target_properties(${XCODE_FRAMEWORK_NAME} PROPERTIES ENABLE_BITCODE "YES")
set_target_properties(${XCODE_FRAMEWORK_NAME} PROPERTIES BITCODE_GENERATION_MODE bitcode)
target_compile_options( ${XCODE_FRAMEWORK_NAME} PUBLIC -fembed-bitcode )
target_link_libraries( ${XCODE_FRAMEWORK_NAME} PUBLIC -fembed-bitcode )
set_target_properties(${XCODE_FRAMEWORK_NAME} PROPERTIES
FRAMEWORK TRUE
FRAMEWORK_VERSION A
DEFINES_MODULE TRUE
MACOSX_FRAMEWORK_IDENTIFIER com.cmake.${XCODE_FRAMEWORK_NAME}
MODULE_MAP "~/op/zt/libzt/libzt_experimental/ports/module.modulemap"
MODULE_MAP "${PROJ_DIR}/ports/module.modulemap"
PUBLIC_HEADER "${frameworkHeaderGlob}"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer"
)
@@ -477,46 +497,35 @@ endif ()
# -----------------------------------------------------------------------------
if (SHOULD_BUILD_TESTS)
# Minimal functional example
#add_executable (example ${PROJ_DIR}/test/example.cpp)
#target_link_libraries(example ${STATIC_LIB_NAME})
# API test
#add_executable (apitest ${PROJ_DIR}/test/apitest.cpp)
#target_link_libraries(apitest ${STATIC_LIB_NAME})
# Selftest
#add_executable (selftest ${PROJ_DIR}/test/selftest.cpp)
#target_link_libraries(selftest ${STATIC_LIB_NAME})
#set_target_properties (selftest PROPERTIES COMPILE_FLAGS "-D__SELFTEST__")
# client/server performance test
#add_executable (client ${PROJ_DIR}/test/client.cpp)
#target_link_libraries(client ${STATIC_LIB_NAME})
#add_executable (server ${PROJ_DIR}/test/server.cpp)
#target_link_libraries(server ${STATIC_LIB_NAME})
# Simple Example
#add_executable (simple ${PROJ_DIR}/test/simple.cpp)
#target_link_libraries(simple ${STATIC_LIB_NAME})
add_executable (earthtest ${PROJ_DIR}/examples/cpp/earthtest.cpp)
target_link_libraries(earthtest ${STATIC_LIB_NAME})
add_executable (adhoc ${PROJ_DIR}/examples/cpp/adhoc.cpp)
target_link_libraries(adhoc ${STATIC_LIB_NAME})
add_executable (comprehensive ${PROJ_DIR}/examples/cpp/comprehensive.cpp)
target_link_libraries(comprehensive ${STATIC_LIB_NAME})
add_executable (client ${PROJ_DIR}/examples/cpp/client.cpp)
target_link_libraries(client ${STATIC_LIB_NAME})
add_executable (server ${PROJ_DIR}/examples/cpp/server.cpp)
target_link_libraries(server ${STATIC_LIB_NAME})
add_executable (nonblockingclient ${PROJ_DIR}/examples/cpp/nonblockingclient.cpp)
target_link_libraries(nonblockingclient ${STATIC_LIB_NAME})
add_executable (nonblockingserver ${PROJ_DIR}/examples/cpp/nonblockingserver.cpp)
target_link_libraries(nonblockingserver ${STATIC_LIB_NAME})
endif ()
# -----------------------------------------------------------------------------
# | INSTALL |
# -----------------------------------------------------------------------------
set(PUBLIC_ZT_HEADERS
${PROJECT_SOURCE_DIR}/include/ZeroTier.h
${PROJECT_SOURCE_DIR}/include/ZeroTierConstants.h)
set (PUBLIC_ZT_HEADERS ${PROJECT_SOURCE_DIR}/include/ZeroTierSockets.h)
set(PUBLIC_ZTCORE_HEADERS
${PROJECT_SOURCE_DIR}/ext/ZeroTierOne/include/ZeroTierOne.h)
set(include_dest "include")
set(main_lib_dest "lib")
set(lib_dest "${main_lib_dest}/${CMAKE_BUILD_TYPE}")
install(TARGETS ${STATIC_LIB_NAME} EXPORT ${STATIC_LIB_NAME} DESTINATION "${lib_dest}")
install(TARGETS ${DYNAMIC_LIB_NAME} EXPORT ${DYNAMIC_LIB_NAME} DESTINATION "${lib_dest}")
install(FILES ${PUBLIC_ZT_HEADERS} DESTINATION "${include_dest}")
install(FILES ${PUBLIC_ZTCORE_HEADERS} DESTINATION "${include_dest}")
install(EXPORT ${STATIC_LIB_NAME} DESTINATION "${lib_dest}")
set_target_properties(${STATIC_LIB_NAME} PROPERTIES PUBLIC_HEADER "${PUBLIC_ZT_HEADERS}")
install (TARGETS ${STATIC_LIB_NAME}
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
PUBLIC_HEADER DESTINATION include
)
install (TARGETS ${DYNAMIC_LIB_NAME}
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

View File

@@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

149
LICENSE.txt Normal file
View File

@@ -0,0 +1,149 @@
-----------------------------------------------------------------------------
Business Source License 1.1
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
"Business Source License" is a trademark of MariaDB Corporation Ab.
-----------------------------------------------------------------------------
Parameters
Licensor: ZeroTier, Inc.
Licensed Work: ZeroTier Network Virtualization Engine 1.4.4
The Licensed Work is (c)2019 ZeroTier, Inc.
Additional Use Grant: You may make use of the Licensed Work, provided you
do not use it in any of the following ways:
* Sell hosted ZeroTier services as a "SaaS" Product
(1) Operate or sell access to ZeroTier root servers,
network controllers, or authorization key or certificate
generation components of the Licensed Work as a
for-profit service, regardless of whether the use of
these components is sold alone or is bundled with other
services. Note that this does not apply to the use of
ZeroTier behind the scenes to operate a service not
related to ZeroTier network administration.
* Create Non-Open-Source Commercial Derviative Works
(2) Link or directly include the Licensed Work in a
commercial or for-profit application or other product
not distributed under an Open Source Initiative (OSI)
compliant license. See: https://opensource.org/licenses
(3) Remove the name, logo, copyright, or other branding
material from the Licensed Work to create a "rebranded"
or "white labeled" version to distribute as part of
any commercial or for-profit product or service.
* Certain Government Uses
(4) Use or deploy the Licensed Work in a government
setting in support of any active government function
or operation with the exception of the following:
physical or mental health care, family and social
services, social welfare, senior care, child care, and
the care of persons with disabilities.
Change Date: 2023-01-01
Change License: Apache License version 2.0 as published by the Apache
Software Foundation
https://www.apache.org/licenses/
Alternative Licensing
If you would like to use the Licensed Work in any way that conflicts with
the stipulations of the Additional Use Grant, contact ZeroTier, Inc. to
obtain an alternative commercial license.
Visit us on the web at: https://www.zerotier.com/
Notice
The Business Source License (this document, or the "License") is not an Open
Source license. However, the Licensed Work will eventually be made available
under an Open Source License, as stated in this License.
For more information on the use of the Business Source License for ZeroTier
products, please visit our pricing page which contains license details and
and license FAQ: https://zerotier.com/pricing
For more information on the use of the Business Source License generally,
please visit the Adopting and Developing Business Source License FAQ at
https://mariadb.com/bsl-faq-adopting.
-----------------------------------------------------------------------------
Business Source License 1.1
Terms
The Licensor hereby grants you the right to copy, modify, create derivative
works, redistribute, and make non-production use of the Licensed Work. The
Licensor may make an Additional Use Grant, above, permitting limited
production use.
Effective on the Change Date, or the fourth anniversary of the first publicly
available distribution of a specific version of the Licensed Work under this
License, whichever comes first, the Licensor hereby grants you rights under
the terms of the Change License, and the rights granted in the paragraph
above terminate.
If your use of the Licensed Work does not comply with the requirements
currently in effect as described in this License, you must purchase a
commercial license from the Licensor, its affiliated entities, or authorized
resellers, or you must refrain from using the Licensed Work.
All copies of the original and modified Licensed Work, and derivative works
of the Licensed Work, are subject to this License. This License applies
separately for each version of the Licensed Work and the Change Date may vary
for each version of the Licensed Work released by Licensor.
You must conspicuously display this License on each original or modified copy
of the Licensed Work. If you receive the Licensed Work in original or
modified form from a third party, the terms and conditions set forth in this
License apply to your use of that work.
Any use of the Licensed Work in violation of this License will automatically
terminate your rights under this License for the current and all other
versions of the Licensed Work.
This License does not grant you any right in any trademark or logo of
Licensor or its affiliates (provided that you may use a trademark or logo of
Licensor as expressly required by this License).
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
TITLE.
-----------------------------------------------------------------------------
MariaDB hereby grants you permission to use this Licenses text to license
your works, and to refer to it using the trademark "Business Source License",
as long as you comply with the Covenants of Licensor below.
Covenants of Licensor
In consideration of the right to use this Licenses text and the "Business
Source License" name and trademark, Licensor covenants to MariaDB, and to all
other recipients of the licensed work to be provided by Licensor:
1. To specify as the Change License the GPL Version 2.0 or any later version,
or a license that is compatible with GPL Version 2.0 or a later version,
where "compatible" means that software provided under the Change License can
be included in a program with software provided under GPL Version 2.0 or a
later version. Licensor may specify additional Change Licenses without
limitation.
2. To either: (a) specify an additional grant of rights to use that does not
impose any additional restriction on the right granted in this License, as
the Additional Use Grant; or (b) insert the text "None".
3. To specify a Change Date.
4. Not to modify this License in any other way.

View File

@@ -5,9 +5,9 @@ else
DIST_BUILD_SCRIPT := ./dist.sh
endif
EXECUTABLES = cmake
build_reqs := $(foreach exec,$(EXECUTABLES),\
$(if $(shell which $(exec)),some string,$(error "No $(exec) in PATH")))
#EXECUTABLES = cmake
#build_reqs := $(foreach exec,$(EXECUTABLES),\
# $(if $(shell which $(exec)),some string,$(error "No $(exec) in PATH")))
.PHONY: list
list:
@@ -17,18 +17,19 @@ list:
# Pull all submodules
update:
git submodule update --init
git submodule status
@git submodule update --init
@git submodule status
# Patch submodules (issue update first)
patch:
-git -C ext/lwip apply ../lwip.patch
-git -C ext/lwip-contrib apply ../lwip-contrib.patch
-git -C ext/ZeroTierOne apply ../ZeroTierOne.patch
#-cd ext/lwip; git apply ../lwip.patch;
#-cd ext/lwip-contrib; git apply ../lwip-contrib.patch;
#-cd ext/ZeroTierOne; git apply ../ZeroTierOne.patch;
# Target-specific clean
clean_ios:
-rm -rf ports/xcode_ios-arm64
-rm -rf ports/xcode_ios
-rm -rf ports/xcode_ios_simulator
clean_macos:
-rm -rf ports/xcode_macos
clean_android:
@@ -97,7 +98,13 @@ all: host host_jar macos ios android
wrap:
$(DIST_BUILD_SCRIPT) wrap
# [For distribution process only] Marge and package everything into a tarball
dist:
# Binary distribution
bdist:
$(DIST_BUILD_SCRIPT) merge
$(DIST_BUILD_SCRIPT) dist
$(DIST_BUILD_SCRIPT) bdist
# Source distribution
sdist: update patch
$(DIST_BUILD_SCRIPT) sdist
dist: bdist sdist

383
README.md
View File

@@ -1,64 +1,383 @@
# ZeroTier SDK (libzt, libztcore)
Library edition of [ZeroTier](https://github.com/zerotier/ZeroTierOne)
# ZeroTier SDK
Connect physical devices, virtual devices, and application instances as if everything is on a single LAN.
***
<a href="https://www.zerotier.com/"><img src="https://raw.githubusercontent.com/zerotier/ZeroTierOne/master/artwork/ZeroTierIcon.png" width="128" height="128" align="left" hspace="20" vspace="9"></a>
The ZeroTier SDK brings your network into user-space. We've paired our network hypervisor core with a network stack ([lwIP](https://savannah.nongnu.org/projects/lwip/)) to provide your application with an exclusive and private virtual network interface. All traffic on this interface is end-to-end encrypted between each peer and we provide an easy-to-use socket interface derived from [Berkeley Sockets](https://en.wikipedia.org/wiki/Berkeley_sockets). Since we aren't using the kernel's network stack that means, no drivers, no root, and no host configuration requirements. For a more in-depth discussion on the technical side of ZeroTier, check out our [Manual](https://www.zerotier.com/manual.shtml). For troubleshooting advice see our [Knowledgebase](https://zerotier.atlassian.net/wiki/spaces/SD/overview). If you need further assistance, create an account at [my.zerotier.com](https://my.zerotier.com) and join our community of users and professionals.
The ZeroTier SDK is composed of two libraries: `libztcore` which is the platform-agnostic network hypervisor, and `libzt` which is the network hypervisor paired with a userspace network stack. `libzt` is a superset of `libztcore` and is distinguished by the fact that it exposes a standard socket API and simple network control API. With these libraries the stack and virtual link are exclusive to your app and traffic is fully encrypted via the [Salsa20](https://en.wikipedia.org/wiki/Salsa20) cipher. For a more in-depth discussion on the technical side of ZeroTier, check out our [Manual](https://www.zerotier.com/manual.shtml)
Downloads: [download.zerotier.com/dist/sdk](https://download.zerotier.com/dist/sdk)
***
<div style="page-break-after: always;"></div>
<br>
## Building from source
For a complete example, see [test/simple.cpp](test/simple.cpp) or [test/example.cpp](test/example.cpp). With no error checking, a paraphrased example is as follows:
To build both `release` and `debug` libraries for only your host's architecture use `make host`. Or optionally `make host_release` for release only. To build everything including things like iOS frameworks, Android packages, etc, use `make all`. Possible build targets can be seen by using `make list`. Resultant libraries will be placed in `./lib`, test and example programs will be placed in `./bin`:
```
#include "ZeroTier.h"
make update; make patch; make host
# OR
brew install cmake
make clean; make update && make patch && make host_release CC=clang CXX=clang++
```
Typical build output:
```
lib
├── release
| └── linux-x86_64
| ├── libzt.a
| └── libzt.so
└── debug
└── ...
bin
└── release
└── linux-x86_64
├── client
└── server
```
Example linking step:
```
clang++ -o yourApp yourApp.cpp -L./lib/release/linux-x86_64/ -lzt; ./yourApp
```
<div style="page-break-after: always;"></div>
## Starting ZeroTier
The next few sections explain how to use the network control interface portion of the API. These functions are non-blocking and will return an error code specified in the [Error Handling](#error-handling) section and will result in the generation of callback events detailed in the [Event Handling](#event-handling) section. It is your responsibility to handle these events. To start the service, simply call:
`zts_start(char *path, void (*userCallbackFunc)(struct zts_callback_msg*), int port)`
At this stage, if a cryptographic identity for this node does not already exist on your local storage medium, it will generate a new one and store it, the node's address (commonly referred to as `nodeId`) will be derived from this identity and will be presented to you upon receiving the `ZTS_EVENT_NODE_ONLINE` shown below. The first argument `path` is a path where you will direct ZeroTier to store its automatically-generated cryptographic identity files (`identity.public` and `identity.secret`), these files are your keys to communicating on the network. Keep them safe and keep them unique. If any two nodes are online using the same identities you will have a bad time. The second argument `userCallbackFunc` is a function that you specify to handle all generated events for the life of your program, see below:
```
#include "ZeroTierSockets.h"
...
bool networkReady = false;
void myZeroTierEventCallback(struct zts_callback_msg *msg)
{
switch (msg->eventCode)
{
//
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE, nodeId=%llx\n", msg->node->address);
networkReady = true;
}
...
}
int main()
{
zts_start("yourConfig/key/path", &myZeroTierEventCallback, 9994);
zts_join(0x0123456789abcdef);
zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0);
zts_connect(fd, (const struct sockaddr *)&addr, sizeof(addr));
zts_write(fd, "welcome to the machine", 22);
zts_close(fd);
zts_stop();
zts_start("configPath", &myZeroTierEventCallback, 9994);
uint64_t nwid = 0x0123456789abcdef;
while (!networkReady) { sleep(1); }
zts_join(nwid);
int fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0);
...
return 0;
}
```
For more complete examples see `./examples/`
<div style="page-break-after: always;"></div>
After calling `zts_start()` you will receive one or more events specified in the [Node Events](#node-events) section. After receiving `ZTS_EVENT_NODE_ONLINE` you will be allowed to join or leave networks. You must authorize the node ID provided by the this callback event to join your network. This can be done manually or via our [Web API](https://my.zerotier.com/help/api). Note however that if you are using an Ad-hoc network, it has no controller and therefore requires no authorization.
At the end of your program or when no more network activity is anticipated, the user application can shut down the service with `zts_stop()`. However, it is safe to leave the service running in the background indefinitely as it doesn't consume much memory or CPU while at idle. `zts_stop()` is a non-blocking call and will itself issue a series of events indicating that various aspects of the ZeroTier service have successfully shut down.
It is worth noting that while `zts_stop()` will stop the service, the user-space network stack will continue operating in a headless hibernation mode. This is intended behavior due to the fact that the network stack we've chosen doesn't currently support the notion of shutdown since it was initially designed for embedded applications that are simply switched off. If you do need a way to shut everything down and free all resources you can call `zts_free()`, but please note that calling this function will prevent all subsequent `zts_start()` calls from succeeding and will require a full application restart if you want to run the service again. The events `ZTS_EVENT_NODE_ONLINE` and `ZTS_EVENT_NODE_OFFLINE` can be seen periodically throughout the lifetime of your application depending on the reliability of your underlying network link, these events are lagging indicators and are typically only triggered every thirty (30) seconds.
Lastly, the function `zts_restart()` is provided as a way to restart the ZeroTier service along with all of its virtual interfaces. The network stack will remain online and undisturbed during this call. Note that this call will temporarily block until the service has fully shut down, then will return and you may then watch for the appropriate startup callbacks mentioned above.
<div style="page-break-after: always;"></div>
## Joining a network
Joining a ZeroTier virtual network is as easy as calling `zts_join(uint64_t networkId)`. Similarly there is a `zts_leave(uint64_t networkId)`. Note that `zts_start()` must be called and a `ZTS_EVENT_NODE_ONLINE` event must have been received before these calls will succeed. After calling `zts_join()` any one of the events detailed in the [Network Events](#network-events) section may be generated.
<div style="page-break-after: always;"></div>
## Connecting and communicating with peers
Creating a standard socket connection generally works the same as it would using an ordinary socket interface, however with ZeroTier there is a subtle difference in how connections are established which may cause confusion. Since ZeroTier employs transport-triggered link provisioning a direct connection between peers will not exist until contact has been attempted by at least one peer. During this time before a direct link is available traffic will be handled via our free relay service. The provisioning of this direct link usually only takes a couple of seconds but it is important to understand that if you attempt something like s `zts_connect(...)` call during this time it may fail due to packet loss. Therefore it is advised to repeatedly call `zts_connect(...)` until it succeeds and to wait to send additional traffic until `ZTS_EVENT_PEER_DIRECT` has been received for the peer you are attempting to communicate with. All of the above is optional, but it will improve your experience.
`tl;dr: Try a few times and wait a few seconds`
As a mitigation for the above behavior, ZeroTier will by default cache details about how to contact a peer in the `peers.d` subdirectory of the config path you passed to `zts_start(...)`. In scenarios where paths do not often change, this can almost completely eliminate the issue and will make connections nearly instantaneous. If however you do not wish to cache these details you can disable it via `zts_set_peer_caching(false)`.
<div style="page-break-after: always;"></div>
## Event handling
As mentioned in previous sections, the control API works by use of non-blocking calls and the generation of a few dozen different event types. Depending on the type of event there may be additional contextual information attached to the `zts_callback_msg` object that you can use. This contextual information will be housed in one of the following structures which are defined in `include/ZeroTierSockets.h`:
```
struct zts_callback_msg
{
int eventCode;
struct zts_node_details *node;
struct zts_network_details *network;
struct zts_netif_details *netif;
struct zts_virtual_network_route *route;
struct zts_peer_details *peer;
struct zts_addr_details *addr;
};
```
Here's an example of a callback function:
```
void myZeroTierEventCallback(struct zts_callback_msg *msg)
{
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE, node=%llx\n", msg->node->address);
// You can join networks now!
}
}
```
In this callback function you can perform additional non-blocking API calls or other work. While not returning control to the service isn't forbidden (the event messages are generated by a separate thread) it is recommended that you return control as soon as possible as not returning will prevent the user application from receiving additional callback event messages which may be time-sensitive.
<div style="page-break-after: always;"></div>
A typical ordering of messages may look like the following:
```
...
ZTS_EVENT_NODE_ONLINE // Your node is ready to be used.
ZTS_EVENT_ADDR_ADDED_IP4 // Your node received an IP address assignment on a given network.
ZTS_EVENT_NETWORK_UPDATE // Something about a network changed.
ZTS_EVENT_NETWORK_READY_IP4 // Your node has joined a network, has an address, and can send/receive traffic.
ZTS_EVENT_PEER_RELAY // A peer was discovered but no direct path exists (yet.)
...
ZTS_EVENT_PEER_DIRECT // One or more direct paths to a peer were discovered.
```
The complete API specification can be found here: [API.md](API.md)
## Node Events
***
## Build
Build scripts use a combination of make, and cmake. To retrieve sources for all submodules, patch them, and build all targets (debug and release) for your host machine, issue the following:
Accessible via `msg->node` as a `zts_node_details` object, this message type will contain information about the status of your node. *Possible values of `msg->eventCode`:*
```
make update
make patch
make all
ZTS_EVENT_NODE_OFFLINE // Your node is offline.
ZTS_EVENT_NODE_ONLINE // Your node is online and ready to communicate!
ZTS_EVENT_NODE_DOWN // The node is down (for any reason.)
ZTS_EVENT_NODE_IDENTITY_COLLISION // There is another node with the same identity causing a conflict.
ZTS_EVENT_NODE_UNRECOVERABLE_ERROR // Something went wrong internally.
ZTS_EVENT_NODE_NORMAL_TERMINATION // Your node has terminated.
```
All build targets can be seen by using `make list`.
*Example contents of `msg->node`:*
Resultant libraries will be placed in `lib`, test and example programs will be placed in `bin`.
```
id : f746d550dd
version : 1.4.6
primaryPort : 9995
secondaryPort : 0
```
***
## Network Events
## Commercial License
Accessible via `msg->network` as a `zts_network_details` object, this message type will contain information about the status of a particular network your node has joined. *Possible values of `msg->eventCode`:*
If you want a commercial license to use the ZeroTier SDK in your product contact us directly via `contact@zerotier.com`
```
ZTS_EVENT_NETWORK_NOT_FOUND // The network does not exist. The provided networkID may be incorrect.
ZTS_EVENT_NETWORK_CLIENT_TOO_OLD // This client is too old.
ZTS_EVENT_NETWORK_REQ_CONFIG // Waiting for network config, this might take a few seconds.
ZTS_EVENT_NETWORK_OK // Node successfully joined.
ZTS_EVENT_NETWORK_ACCESS_DENIED // The network is private. Your node requires authorization.
ZTS_EVENT_NETWORK_READY_IP4 // Your node successfully received an IPv4 address.
ZTS_EVENT_NETWORK_READY_IP6 // Your node successfully received an IPv6 address.
ZTS_EVENT_NETWORK_DOWN // For some reason the network is no longer available.
ZTS_EVENT_NETWORK_UPDATE // The network's config has changed: mtu, name, managed route, etc.
```
*Example contents of `msg->network`:*
```
nwid : 8bd712bf36bdae5f
mac : ae53fa031fcf
name : cranky_hayes
type : 0
mtu : 2800
dhcp : 0
bridge : 0
broadcastEnabled : 1
portError : 0
netconfRevision : 34
routeCount : 1
multicastSubscriptionCount : 1
- mac=ffffffffffff, adi=ac1b2561
addresses:
- FC5D:69B6:E0F7:46D5:50DD::1
- 172.27.37.97
routes:
- target : 172.27.0.0
- via : 0.0.0.0
- flags : 0
- metric : 0
```
<div style="page-break-after: always;"></div>
## Peer Events
Accessible via `msg->peer` as a `zts_peer_details` object, this message type will contain information about a peer that was discovered by your node. These events are triggered when the reachability status of a peer has changed. *Possible values of `msg->eventCode`:*
```
ZTS_EVENT_PEER_DIRECT // At least one direct path to this peer is known.
ZTS_EVENT_PEER_RELAY // No direct path to this peer is known. It will be relayed, (high packet loss and jitter.)
ZTS_EVENT_PEER_UNREACHABLE // Peer is not reachable by any means.
ZTS_EVENT_PEER_PATH_DISCOVERED // A new direct path to this peer has been discovered.
ZTS_EVENT_PEER_PATH_DEAD // A direct path to this peer has expired.
```
*Example contents of `msg->peer`:*
```
peer : a747d5502d
role : 0
latency : 4
version : 1.4.6
pathCount : 2
- 172.27.37.97
- F75D:69B6:E0C7:47D5:51DB::1
```
## Address Events
Accessible via `msg->addr` as a `zts_addr_details` object, this message type will contain information about addresses assign to your node on a particular network. The information contained in these events is also available via `ZTS_EVENT_NETWORK_UPDATE` events. *Possible values of `msg->eventCode`:*
```
ZTS_EVENT_ADDR_ADDED_IP4 // A new IPv4 address was assigned to your node on the indicated network.
ZTS_EVENT_ADDR_REMOVED_IP4 // An IPv4 address assignment to your node was removed on the indicated network.
ZTS_EVENT_ADDR_ADDED_IP6 // A new IPv6 address was assigned to your node on the indicated network.
ZTS_EVENT_ADDR_REMOVED_IP6 // An IPv6 address assignment to your node was removed on the indicated network.
```
*Example contents of `msg->addr`:*
```
nwid : a747d5502d
addr : 172.27.37.97
```
<div style="page-break-after: always;"></div>
## Error handling
Calling a `zts_*` function will result in one of the following return codes. Only when `ZTS_ERR` is returned will `zts_errno` be set. Its values closely mirror those used in standard socket interfaces and are defined in `include/ZeroTierSockets.h`.
```
ZTS_ERR_OK // No error
ZTS_ERR_SOCKET // Socket error (see zts_errno for more information)
ZTS_ERR_SERVICE // General ZeroTier internal error. Maybe you called something out of order?
ZTS_ERR_ARG // An argument provided is invalid.
ZTS_ERR_NO_RESULT // Call succeeded but no result was available. Not necessarily an error.
ZTS_ERR_GENERAL // General internal failure. Consider filing a bug report.
```
*NOTE: For Android/Java (or similar) which use JNI, the socket API's error codes are negative values encoded in the return values of function calls*
*NOTE: For protocol-level errors (such as dropped packets) or internal network stack errors, see the section `Statistics`*
<div style="page-break-after: always;"></div>
## Common pitfalls
- If you have started a node but have not received a `ZTS_EVENT_NODE_ONLINE`:
- You may need to view our [Router Config Tips](https://zerotier.atlassian.net/wiki/spaces/SD/pages/6815768/Router+Configuration+Tips) knowledgebase article. Sometimes this is due to firewall/NAT settings.
- If you have received a `ZTS_EVENT_NODE_ONLINE` event and attempted to join a network but do not see your node ID in the network panel on [my.zerotier.com](my.zerotier.com) after some time:
- You may have typed in your network ID incorrectly.
- Used an improper integer representation for your network ID (e.g. `int` instead of `uint64_t`).
- If you are unable to reliably connect to peers:
- You should first read the section on [Connecting and communicating with peers](#connecting-and-communicating-with-peers).
- If the previous step doesn't help move onto our knowledgebase article [Router Config Tips](https://zerotier.atlassian.net/wiki/spaces/SD/pages/6815768/Router+Configuration+Tips). Sometimes this can be a transport-triggered link issue, and sometimes it can be a firewall/NAT issue.
- API calls seem to fail in nonsensical ways and you're tearing your hair out:
- Be sure to read and understand the [API compatibility with host OS](#api-compatibility-with-host-os) section.
- See the [Debugging](#debugging) section for more advice.
<div style="page-break-after: always;"></div>
## API compatibility with host OS
Since libzt re-implements a socket interface likely very similar to your host OS's own interface it may be tempting to mix and match host OS structures and functions with those of libzt. This may work on occasion, but you are tempting fate. Here are a few important guidelines:
If you are calling a `zts_*` function, use the appropriate `ZTS_*` constants:
```
zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
```
If you are calling a `zts_*` function, use the appropriate `zts_*` structure:
```
struct zts_sockaddr_in in4; <------ Note the zts_ prefix
...
zts_bind(fd, (struct sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
```
If you are calling a host OS function, use your host OS's constants (and structures!):
```
inet_ntop(AF_INET6, &(in6->sin6_addr), ...); (CORRECT)
inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ...); (INCORRECT)
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ...); (CORRECT)
```
If you are calling a host OS function but passing a `zts_*` structure, this can work sometimes but you should take care to pass the correct host OS constants:
```
struct zts_sockaddr_in6 in6;
...
inet_ntop(AF_INET6, &(in6->sin6_addr), dstStr, INET6_ADDRSTRLEN);
```
<div style="page-break-after: always;"></div>
## Thread model (advanced)
Both the **socket** and **control** interfaces are thread-safe but are implemented differently. The socket interface is implemented using a relatively performant core locking mechanism in lwIP. This can be disabled if you know what you're doing. The control interface is implemented by a single coarse-grained lock. This lock is not a performance bottleneck since it only applies to functions that manipulate the ZeroTier service and are called seldomly. Callback events are generated by a separate thread and are independent from the rest of the API's internal locking mechanism. Not returning from a callback event won't impact the rest of the API but it will prevent your application from receiving future events so it is in your application's best interest to perform as little work as possible in the callback function and promptly return control back to ZeroTier.
*Note: Internally, `libzt` will spawn a number of threads for various purposes: a thread for the core service, a thread for the network stack, a low priority thread to process callback events, and a thread for each network joined. The vast majority of work is performed by the core service and stack threads.*
<div style="page-break-after: always;"></div>
## Debugging
If you're experiencing odd behavior or something that looks like a bug I would suggest first reading and understanding the following sections:
* [Common pitfalls](#common-pitfalls)
* [API compatibility with host OS](#api-compatibility-with-host-os)
* [Thread model](#thread-model)
If the information in those sections hasn't helped, there are a couple of ways to get debug traces out of various parts of the library.
1) Build the library in debug mode with `make host_debug`. This will prevent the stripping of debug symbols from the library and will enable basic output traces from libzt.
2) If you believe your problem is in the network stack you can manually enable debug traces for individual modules in `src/lwipopts.h`. Toggle the `*_DEBUG` types from `LWIP_DBG_OFF` to `LWIP_DBG_ON`. And then rebuild. This will come with a significant performance cost.
3) Enabling network stack statistics. This is useful if you want to monitor the stack's receipt and handling of traffic as well as internal things like memory allocations and cache hits. Protocol and service statistics are available in debug builds of `libzt`. These statistics are detailed fully in the section of `include/ZeroTierSockets.h` that is guarded by `LWIP_STATS`.
```
struct zts_stats_proto stats;
if (zts_get_protocol_stats(ZTS_STATS_PROTOCOL_ICMP, &stats) == ZTS_ERR_OK) {
printf("icmp.recv=%d\n", stats.recv); // Count of received pings
}
if (zts_get_protocol_stats(ZTS_STATS_PROTOCOL_TCP, &stats) == ZTS_ERR_OK) {
printf("tcp.drop=%d\n", stats.drop); // Count of dropped TCP packets
}
```
4) There are a series of additional events which can signal whether the network stack or its virtual network interfaces have been set up properly. See `ZTS_EVENT_STACK_*` and `ZTS_EVENT_NETIF_*`.
<div style="page-break-after: always;"></div>
## Licensing
ZeroTier is licensed under the BSL version 1.1. See [LICENSE.txt](./LICENSE.txt) and the ZeroTier pricing page for details. ZeroTier is free to use internally in businesses and academic institutions and for non-commercial purposes. Certain types of commercial use such as building closed-source apps and devices based on ZeroTier or offering ZeroTier network controllers and network management as a SaaS service require a commercial license.
A small amount of third party code is also included in ZeroTier and is not subject to our BSL license. See [AUTHORS.md](ext/ZeroTierOne/AUTHORS.md) for a list of third party code, where it is included, and the licenses that apply to it. All of the third party code in ZeroTier is liberally licensed (MIT, BSD, Apache, public domain, etc.). If you want a commercial license to use the ZeroTier SDK in your product contact us directly via [contact@zerotier.com](mailto:contact@zerotier.com)

BIN
README.pdf Normal file

Binary file not shown.

201
dist.bat
View File

@@ -1,88 +1,115 @@
REM Build all target configurations and copy results into "prebuilt"
set PrebuiltDebugWin32Dir=staging\debug\win32
set PrebuiltDebugWin64Dir=staging\debug\win64
set PrebuiltReleaseWin32Dir=staging\release\win32
set PrebuiltReleaseWin64Dir=staging\release\win64
mkdir %PrebuiltDebugWin32Dir%
mkdir %PrebuiltDebugWin64Dir%
mkdir %PrebuiltReleaseWin32Dir%
mkdir %PrebuiltReleaseWin64Dir%
set DebugWinBuildDir=bin\lib\Debug
set ReleaseWinBuildDir=bin\lib\Release
mkdir WinBuild32 & pushd WinBuild32
cmake -G "Visual Studio 15 2017" ../
popd
mkdir WinBuild64 & pushd WinBuild64
cmake -G "Visual Studio 15 2017 Win64" ../
popd
cmake --build WinBuild32 --config Release
cmake --build WinBuild32 --config Debug
copy %DebugWinBuildDir%\zt-static.lib %PrebuiltDebugWin32Dir%\zt.lib
copy %DebugWinBuildDir%\zt-shared.dll %PrebuiltDebugWin32Dir%\zt.dll
copy %ReleaseWinBuildDir%\zt-static.lib %PrebuiltReleaseWin32Dir%\zt.lib
copy %ReleaseWinBuildDir%\zt-shared.dll %PrebuiltReleaseWin32Dir%\zt.dll
cmake --build WinBuild64 --config Release
cmake --build WinBuild64 --config Debug
copy %DebugWinBuildDir%\zt-static.lib %PrebuiltDebugWin64Dir%\zt.lib
copy %DebugWinBuildDir%\zt-shared.dll %PrebuiltDebugWin64Dir%\zt.dll
copy %ReleaseWinBuildDir%\zt-static.lib %PrebuiltReleaseWin64Dir%\zt.lib
copy %ReleaseWinBuildDir%\zt-shared.dll %PrebuiltReleaseWin64Dir%\zt.dll
rd /S /Q bin
# Build with JNI
mkdir WinBuild32 & pushd WinBuild32
cmake -D JNI:BOOL=ON -G "Visual Studio 15 2017" ../
popd
mkdir WinBuild64 & pushd WinBuild64
cmake -D JNI:BOOL=ON -G "Visual Studio 15 2017 Win64" ../
popd
cmake --build WinBuild32 --config Release
cmake --build WinBuild32 --config Debug
REM Build JAR file
REM release variant
cd packages\java
del com/zerotier/libzt/*.class
move ..\..\%ReleaseWinBuildDir%\zt-shared.dll zt.dll
javac com/zerotier/libzt/*.java
jar cf zt.jar zt.dll com/zerotier/libzt/*.class
move zt.jar ..\..\%PrebuiltReleaseWin32Dir%
REM debug variant
del com/zerotier/libzt/*.class
move ..\..\%DebugWinBuildDir%\zt-shared.dll zt.dll
javac com/zerotier/libzt/*.java
jar cf zt.jar zt.dll com/zerotier/libzt/*.class
move zt.jar ..\..\%PrebuiltDebugWin32Dir%
popd
popd
cmake --build WinBuild64 --config Release
cmake --build WinBuild64 --config Debug
REM Build JAR file
REM release variant
cd packages\java
del com/zerotier/libzt/*.class
move ..\..\%ReleaseWinBuildDir%\zt-shared.dll zt.dll
javac com/zerotier/libzt/*.java
jar cf zt.jar zt.dll com/zerotier/libzt/*.class
move zt.jar ..\..\%PrebuiltReleaseWin64Dir%
REM debug variant
del com/zerotier/libzt/*.class
move ..\..\%DebugWinBuildDir%\zt-shared.dll zt.dll
javac com/zerotier/libzt/*.java
jar cf zt.jar zt.dll com/zerotier/libzt/*.class
move zt.jar ..\..\%PrebuiltDebugWin64Dir%
popd
REM build temp directories
set Win32ReleaseBuildDir=tmp\release\win32
set Win64ReleaseBuildDir=tmp\release\win64
set Win32DebugBuildDir=tmp\debug\win32
set Win64DebugBuildDir=tmp\debug\win64
mkdir %Win32ReleaseBuildDir%
mkdir %Win64ReleaseBuildDir%
mkdir %Win32DebugBuildDir%
mkdir %Win64DebugBuildDir%
REM final output directories
set WinReleaseOutputDir=lib\release
set WinDebugOutputDir=lib\debug
mkdir %WinReleaseOutputDir%\win-x86
mkdir %WinReleaseOutputDir%\win-x86_64
mkdir %WinDebugOutputDir%\win-x86
mkdir %WinDebugOutputDir%\win-x86_64
mkdir %WinReleaseOutputDir%
mkdir %WinDebugOutputDir%
pushd %Win32ReleaseBuildDir%
cmake -G "Visual Studio 16 2019" ../../../
cmake --build . --config Release
popd
copy %Win32ReleaseBuildDir%\Release\zt.lib %WinReleaseOutputDir%\win-x86\libzt32.lib
copy %Win32ReleaseBuildDir%\Release\zt-shared.dll %WinReleaseOutputDir%\win-x86\libzt32.dll
pushd %Win32DebugBuildDir%
cmake -G "Visual Studio 16 2019" ../../../
cmake --build . --config Debug
popd
copy %Win32DebugBuildDir%\Debug\zt.lib %WinDebugOutputDir%\win-x86\libzt32d.lib
copy %Win32DebugBuildDir%\Debug\zt-shared.dll %WinDebugOutputDir%\win-x86\libzt32d.dll
pushd %Win64ReleaseBuildDir%
cmake -G "Visual Studio 16 2019" -A x64 ../../../
cmake --build . --config Release
popd
copy %Win64ReleaseBuildDir%\Release\zt.lib %WinReleaseOutputDir%\win-x86_64\libzt64.lib
copy %Win64ReleaseBuildDir%\Release\zt-shared.dll %WinReleaseOutputDir%\win-x86_64\libzt64.dll
pushd %Win64DebugBuildDir%
cmake -G "Visual Studio 16 2019" -A x64 ../../../
cmake --build . --config Debug
popd
copy %Win64DebugBuildDir%\Debug\zt.lib %WinDebugOutputDir%\win-x86_64\libzt64d.lib
copy %Win64DebugBuildDir%\Debug\zt-shared.dll %WinDebugOutputDir%\win-x86_64\libzt64d.dll
REM Copy example binaries
mkdir bin\debug\win-x86\
copy %Win32DebugBuildDir%\Debug\*.exe bin\debug\win-x86\
mkdir bin\debug\win-x86_64\
copy %Win64DebugBuildDir%\Debug\*.exe bin\debug\win-x86_64\
mkdir bin\release\win-x86\
copy %Win32ReleaseBuildDir%\Release\*.exe bin\release\win-x86\
mkdir bin\release\win-x86_64\
copy %Win64ReleaseBuildDir%\Release\*.exe bin\release\win-x86_64\
exit 0
rd /S /Q bin
# Build with JNI
mkdir WinBuild32 & pushd WinBuild32
cmake -D JNI:BOOL=ON -G "Visual Studio 16 2019" ../
popd
mkdir WinBuild64 & pushd WinBuild64
cmake -D JNI:BOOL=ON -G "Visual Studio 16 2019" -A x64 ../
popd
cmake --build WinBuild32 --config Release
cmake --build WinBuild32 --config Debug
REM Build JAR file
REM release variant
cd packages\java
del com/zerotier/libzt/*.class
move ..\..\%ReleaseWinBuildDir%\zt-shared.dll zt.dll
javac com/zerotier/libzt/*.java
jar cf zt.jar zt.dll com/zerotier/libzt/*.class
move zt.jar ..\..\%PrebuiltReleaseWin32Dir%
REM debug variant
del com/zerotier/libzt/*.class
move ..\..\%DebugWinBuildDir%\zt-shared.dll zt.dll
javac com/zerotier/libzt/*.java
jar cf zt.jar zt.dll com/zerotier/libzt/*.class
move zt.jar ..\..\%PrebuiltDebugWin32Dir%
popd
popd
cmake --build WinBuild64 --config Release
cmake --build WinBuild64 --config Debug
REM Build JAR file
REM release variant
cd packages\java
del com/zerotier/libzt/*.class
move ..\..\%ReleaseWinBuildDir%\zt-shared.dll zt.dll
javac com/zerotier/libzt/*.java
jar cf zt.jar zt.dll com/zerotier/libzt/*.class
move zt.jar ..\..\%PrebuiltReleaseWin64Dir%
REM debug variant
del com/zerotier/libzt/*.class
move ..\..\%DebugWinBuildDir%\zt-shared.dll zt.dll
javac com/zerotier/libzt/*.java
jar cf zt.jar zt.dll com/zerotier/libzt/*.class
move zt.jar ..\..\%PrebuiltDebugWin64Dir%
popd
popd

294
dist.sh
View File

@@ -1,7 +1,7 @@
#!/bin/bash
# This script works in conjunction with the Makefile and CMakeLists.txt. It is
# intented to be called from the Makefile, it generates projects and builds
# intended to be called from the Makefile, it generates projects and builds
# targets as specified in CMakeLists.txt. In addition, this script is
# responsible for packaging all of the resultant builds, licenses, and
# documentation as well as controlling the installation and remote execution of
@@ -11,6 +11,7 @@
#
# (1) On packaging platform, build most targets (including android and ios):
# (1a) make all
# (1b) make wrap
# (2) On other supported platforms, build remaining supported targets
# and copy them into a directory structure that is expected by a later stage:
# (2a) make all
@@ -19,7 +20,7 @@
# of packaging platform. For instance:
#
# libzt
# ├── API.md
# ├── README.md
# ├── products
# ├── linux-x86_64_products
# ├── linux-armv7l_products
@@ -29,17 +30,73 @@
# └── ...
#
# (4) Merge all builds into single `products` directory and package:
# (4a) make clean
# (4a) make dist
CMAKE=cmake
BUILD_CONCURRENCY=
#"-j 2"
OSNAME=$(uname | tr '[A-Z]' '[a-z]')
BUILD_TMP=$(pwd)/tmp
ANDROID_PROJ_DIR=$(pwd)/ports/android
XCODE_IOS_ARM64_PROJ_DIR=$(pwd)/ports/xcode_ios-arm64
#XCODE_IOS_ARMV7_PROJ_DIR=$(pwd)/ports/xcode_ios-armv7
XCODE_IOS_PROJ_DIR=$(pwd)/ports/xcode_ios
XCODE_IOS_SIMULATOR_PROJ_DIR=$(pwd)/ports/xcode_ios_simulator
XCODE_MACOS_PROJ_DIR=$(pwd)/ports/xcode_macos
# Generates wrapper source files for various target languages
generate_swig_wrappers()
{
SRC=../src
cd ports/;
# C#
mkdir -p ${SRC}/csharp
swig -csharp -c++ zt.i
# Prepend our callback garb to libzt.cs, copy new source files into src/csharp
cat csharp/csharp_callback.cs libzt.cs > libzt_concat.cs
rm libzt.cs
mv libzt_concat.cs libzt.cs
mv -f *.cs zt_wrap.cxx ${SRC}/csharp/
# Javascript
# Build for all three engines. Why not?
ENGINE=jsc
mkdir -p ${SRC}/js/${ENGINE}
swig -javascript -${ENGINE} -c++ zt.i
mv zt_wrap.cxx ${SRC}/js/${ENGINE}
ENGINE=v8
mkdir -p ${SRC}/js/${ENGINE}
swig -javascript -${ENGINE} -c++ zt.i
mv zt_wrap.cxx ${SRC}/js/${ENGINE}
ENGINE=node
mkdir -p ${SRC}/js/${ENGINE}
swig -javascript -${ENGINE} -c++ zt.i
mv -f zt_wrap.cxx ${SRC}/js/${ENGINE}
# Python
mkdir -p ${SRC}/python
swig -python -c++ zt.i
mv -f zt_wrap.cxx *.py ${SRC}/python
# Lua
mkdir -p ${SRC}/lua
swig -lua -c++ zt.i
mv -f zt_wrap.cxx ${SRC}/lua
# Go 64
mkdir -p ${SRC}/go64
swig -intgosize 64 -go -c++ zt.i
mv -f zt_wrap.cxx *.go *.c ${SRC}/go64
# Go 32
mkdir -p ${SRC}/go32
swig -intgosize 32 -go -c++ zt.i
mv -f zt_wrap.cxx *.go *.c ${SRC}/go32
cd -
}
# Generates projects if needed
generate_projects()
{
@@ -49,28 +106,29 @@ generate_projects()
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
if [[ $OSNAME = *"darwin"* ]]; then
# iOS (SDK 11+, 64-bit only, arm64)
if [ ! -d "$XCODE_IOS_ARM64_PROJ_DIR" ]; then
mkdir -p $XCODE_IOS_ARM64_PROJ_DIR
cd $XCODE_IOS_ARM64_PROJ_DIR
cmake -G Xcode ../../ -DIOS_FRAMEWORK=1 -DIOS_ARM64=1
if [ ! -d "$XCODE_IOS_PROJ_DIR" ]; then
mkdir -p $XCODE_IOS_PROJ_DIR
cd $XCODE_IOS_PROJ_DIR
$CMAKE -G Xcode ../../ -DIOS_FRAMEWORK=1 -DIOS_ARM64=1
# Manually replace arch strings in project file
sed -i '' 's/x86_64/$(CURRENT_ARCH)/g' zt.xcodeproj/project.pbxproj
cd -
fi
# iOS (SDK <11, 32-bit only, armv7, armv7s)
#if [ ! -d "$XCODE_IOS_ARMV7_PROJ_DIR" ]; then
# mkdir -p $XCODE_IOS_ARMV7_PROJ_DIR
# cd $XCODE_IOS_ARMV7_PROJ_DIR
# cmake -G Xcode ../../ -DIOS_FRAMEWORK=1 -DIOS_ARMV7=1
if [ ! -d "$XCODE_IOS_SIMULATOR_PROJ_DIR" ]; then
mkdir -p $XCODE_IOS_SIMULATOR_PROJ_DIR
cd $XCODE_IOS_SIMULATOR_PROJ_DIR
$CMAKE -G Xcode ../../ -DIOS_FRAMEWORK=1
# Manually replace arch strings in project file
# sed -i '' 's/x86_64/$(CURRENT_ARCH)/g' zt.xcodeproj/project.pbxproj
# cd -
#fi
#sed -i '' 's/x86_64/$(CURRENT_ARCH)/g' zt.xcodeproj/project.pbxproj
cd -
fi
# macOS
if [ ! -d "$XCODE_MACOS_PROJ_DIR" ]; then
mkdir -p $XCODE_MACOS_PROJ_DIR
cd $XCODE_MACOS_PROJ_DIR
cmake -G Xcode ../../ -DMACOS_FRAMEWORK=1
$CMAKE -G Xcode ../../ -DMACOS_FRAMEWORK=1
cd -
fi
fi
@@ -86,27 +144,29 @@ ios()
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
UPPERCASE_CONFIG="$(tr '[:lower:]' '[:upper:]' <<< ${1:0:1})${1:1}"
# 64-bit
cd $XCODE_IOS_ARM64_PROJ_DIR
cd $XCODE_IOS_PROJ_DIR
# Framework
xcodebuild -arch arm64 -target zt -configuration "$UPPERCASE_CONFIG" -sdk "iphoneos"
cd -
OUTPUT_DIR=$(pwd)/lib/$1/ios-arm64
mkdir -p $OUTPUT_DIR
rm -rf $OUTPUT_DIR/zt.framework # Remove prior to move to prevent error
mv $XCODE_IOS_ARM64_PROJ_DIR/$UPPERCASE_CONFIG-iphoneos/* $OUTPUT_DIR
IOS_OUTPUT_DIR=$(pwd)/lib/$1/ios
mkdir -p $IOS_OUTPUT_DIR
rm -rf $IOS_OUTPUT_DIR/zt.framework # Remove prior to move to prevent error
mv $XCODE_IOS_PROJ_DIR/$UPPERCASE_CONFIG-iphoneos/* $IOS_OUTPUT_DIR
# 32-bit
#cd $XCODE_IOS_ARMV7_PROJ_DIR
cd $XCODE_IOS_SIMULATOR_PROJ_DIR
# Framework
#xcodebuild -target zt -configuration "$UPPERCASE_CONFIG" -sdk "iphoneos10.0"
# Manually replace arch strings in project file
#sed -i '' 's/x86_64/$(CURRENT_ARCH)/g' zt.xcodeproj/project.pbxproj
#cd -
#OUTPUT_DIR=$(pwd)/lib/$1/ios-armv7
#mkdir -p $OUTPUT_DIR
#rm -rf $OUTPUT_DIR/*
#mv $XCODE_IOS_ARMV7_PROJ_DIR/$UPPERCASE_CONFIG-iphoneos/* $OUTPUT_DIR
xcodebuild -target zt -configuration "$UPPERCASE_CONFIG" -sdk "iphonesimulator"
cd -
SIMULATOR_OUTPUT_DIR=$(pwd)/lib/$1/ios-simulator
mkdir -p $SIMULATOR_OUTPUT_DIR
rm -rf $SIMULATOR_OUTPUT_DIR/zt.framework # Remove prior to move to prevent error
mv $XCODE_IOS_SIMULATOR_PROJ_DIR/$UPPERCASE_CONFIG-iphonesimulator/* $SIMULATOR_OUTPUT_DIR
# Combine the two archs
lipo -create $IOS_OUTPUT_DIR/zt.framework/zt $SIMULATOR_OUTPUT_DIR/zt.framework/zt -output $IOS_OUTPUT_DIR/zt.framework/zt
# Clean up
rm -rf $SIMULATOR_OUTPUT_DIR
}
# Build framework for current host (macOS only)
@@ -152,8 +212,8 @@ host_jar()
# Build dynamic library
BUILD_DIR=$(pwd)/tmp/${NORMALIZED_OSNAME}-$(uname -m)-jni-$1
UPPERCASE_CONFIG="$(tr '[:lower:]' '[:upper:]' <<< ${1:0:1})${1:1}"
cmake -H. -B$BUILD_DIR -DCMAKE_BUILD_TYPE=$UPPERCASE_CONFIG -DSDK_JNI=ON "-DSDK_JNI=1"
cmake --build $BUILD_DIR $BUILD_CONCURRENCY
$CMAKE -H. -B$BUILD_DIR -DCMAKE_BUILD_TYPE=$UPPERCASE_CONFIG -DSDK_JNI=ON "-DSDK_JNI=1"
$CMAKE --build $BUILD_DIR $BUILD_CONCURRENCY
# Copy dynamic library from previous build step
# And, remove any lib that may exist prior. We don't want accidental successes
cd $(pwd)/ports/java
@@ -172,7 +232,7 @@ host_jar()
# Build sample app classes
# Remove old dynamic library if it exists
rm -rf $(pwd)/examples/java/$DYNAMIC_LIB_NAME
javac -cp ".:"$LIB_OUTPUT_DIR/zt.jar $(pwd)/examples/java/src/main/java/*.java
javac -cp ".:"$LIB_OUTPUT_DIR/zt.jar $(pwd)/examples/java/src/com/zerotier/libzt/javasimpleexample/*.java
# To run:
# jar xf $LIB_OUTPUT_DIR/zt.jar libzt.dylib
# cp libzt.dylib examples/java/
@@ -202,8 +262,8 @@ host()
mkdir -p $LIB_OUTPUT_DIR
rm -rf $LIB_OUTPUT_DIR/libzt.a $LIB_OUTPUT_DIR/$DYNAMIC_LIB_NAME $LIB_OUTPUT_DIR/libztcore.a
# Build
cmake -H. -B$BUILD_DIR -DCMAKE_BUILD_TYPE=$1
cmake --build $BUILD_DIR $BUILD_CONCURRENCY
$CMAKE -H. -B$BUILD_DIR -DCMAKE_BUILD_TYPE=$1
$CMAKE --build $BUILD_DIR $BUILD_CONCURRENCY
# Move and clean up
mv $BUILD_DIR/bin/* $BIN_OUTPUT_DIR
mv $BUILD_DIR/lib/* $LIB_OUTPUT_DIR
@@ -233,9 +293,8 @@ android()
if [[ ! $OSNAME = *"darwin"* ]]; then
exit 0
fi
ARCH="armeabi-v7a"
# CMake build files
BUILD_DIR=$(pwd)/tmp/android-$ARCH-$1
BUILD_DIR=$(pwd)/tmp/android-$1
mkdir -p $BUILD_DIR
# If clean requested, remove temp build dir
if [[ $1 = *"clean"* ]]; then
@@ -243,7 +302,7 @@ android()
exit 0
fi
# Where to place results
LIB_OUTPUT_DIR=$(pwd)/lib/$1/android-$ARCH
LIB_OUTPUT_DIR=$(pwd)/lib/$1/android
mkdir -p $LIB_OUTPUT_DIR
# Build
UPPERCASE_CONFIG="$(tr '[:lower:]' '[:upper:]' <<< ${1:0:1})${1:1}"
@@ -277,7 +336,7 @@ clean()
rm -rf tmp lib bin products
rm -f *.o *.s *.exp *.lib *.core core
# Generally search for and remove object files, libraries, etc
find . -type f \( -name '*.dylib' -o -name '*.so' -o -name \
find . -path './*_products' -prune -type f \( -name '*.dylib' -o -name '*.so' -o -name \
'*.a' -o -name '*.o' -o -name '*.o.d' -o -name \
'*.out' -o -name '*.log' -o -name '*.dSYM' -o -name '*.class' \) -delete
# Remove any sources copied to project directories
@@ -289,7 +348,8 @@ clean()
prep_android_example()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
cp -f lib/$1/android-armeabi-v7a/libzt-$1.aar \
mkdir -p examples/android/ExampleAndroidApp/app/libs/
cp -f lib/$1/android/libzt-$1.aar \
examples/android/ExampleAndroidApp/app/libs/libzt.aar
}
# Clean Android project
@@ -394,11 +454,11 @@ display()
# Merge all remotely-built targets. This is used before dist()
merge()
{
#if [ -d "darwin-x86_64_products" ]; then
# rsync -a darwin-x86_64_products/ products/
#else
# echo "Warning: darwin-x86_64_products is missing"
#fi
if [ -d "darwin-x86_64_products" ]; then
rsync -a darwin-x86_64_products/ products/
else
echo "Warning: darwin-x86_64_products is missing"
fi
# x86_64 64-bit linux
REMOTE_PRODUCTS_DIR=linux-x86_64_products
if [ -d "$REMOTE_PRODUCTS_DIR" ]; then
@@ -445,8 +505,21 @@ wrap()
tar --exclude=$PROD_FILENAME -zcvf $PROD_FILENAME -C $ARCH_WRAP_DIR .
}
# Copies binaries, documentation, licenses, etc into a products
# dir and then tarballs everything together
# Renames and copies licenses for libzt and each of its dependencies
package_licenses()
{
CURR_DIR=$1
DEST_DIR=$2
mkdir -p $DEST_DIR
cp $CURR_DIR/ext/lwip/COPYING $DEST_DIR/LWIP-LICENSE.BSD
cp $CURR_DIR/ext/concurrentqueue/LICENSE.md $DEST_DIR/CONCURRENTQUEUE-LICENSE.BSD
cp $CURR_DIR/LICENSE.txt $DEST_DIR/ZEROTIER-LICENSE.BSL-1.1
cp $CURR_DIR/include/net/ROUTE_H-LICENSE.APSL $DEST_DIR/ROUTE_H-LICENSE.APSL
cp $CURR_DIR/include/net/ROUTE_H-LICENSE $DEST_DIR/ROUTE_H-LICENSE
}
# Copies binaries, documentation, licenses, source, etc into a products
# directory and then tarballs everything together
package_everything()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
@@ -454,35 +527,24 @@ package_everything()
PROD_NAME=$LIBZT_VERSION-$(date '+%Y%m%d_%H-%M')-$1
PROD_DIR=$(pwd)/products/$PROD_NAME/
# Make products directory
LICENSE_DIR=$PROD_DIR/licenses
mkdir -p $LICENSE_DIR
# Licenses
cp $(pwd)/ext/lwip/COPYING $LICENSE_DIR/LWIP-LICENSE.BSD
cp $(pwd)/ext/concurrentqueue/LICENSE.md $LICENSE_DIR/CONCURRENTQUEUE-LICENSE.BSD
cp $(pwd)/LICENSE.GPL-3 $LICENSE_DIR/ZEROTIER-LICENSE.GPL-3
cp $(pwd)/include/net/ROUTE_H-LICENSE.APSL $LICENSE_DIR/ROUTE_H-LICENSE.APSL
cp $(pwd)/include/net/ROUTE_H-LICENSE $LICENSE_DIR/ROUTE_H-LICENSE
# Documentation
mkdir -p $PROD_DIR/doc
# Copy the errno header from lwIP for customer reference
cp ext/lwip/src/include/lwip/errno.h $PROD_DIR/doc
cp $(pwd)/API.pdf $PROD_DIR/API.pdf
package_licenses $(pwd) $PROD_DIR/licenses
# Examples
mkdir -p $PROD_DIR/examples
cp examples/cpp/* $PROD_DIR/examples
# Source
mkdir -p $PROD_DIR/src
cp src/*.cpp src/*.hpp src/*.c src/*.h $PROD_DIR/src
cp $(pwd)/README.pdf $PROD_DIR/README.pdf
# Header(s)
mkdir -p $PROD_DIR/include
cp $(pwd)/include/*.h $PROD_DIR/include
cp $(pwd)/ext/ZeroTierOne/include/ZeroTierOne.h $PROD_DIR/include
# Libraries
mkdir -p $PROD_DIR/lib
cp -r $(pwd)/lib/$1/* $PROD_DIR/lib
cp -r $(pwd)/products/$1/* $PROD_DIR/lib
rm -rf $(pwd)/products/$1
# Clean
find $PROD_DIR -type f \( -name '*.DS_Store' -o -name 'thumbs.db' \) -delete
# Emit a README file
echo 'See API.md for more information on how to use the SDK
- ZeroTier Manual: https://www.zerotier.com/manual.shtml
- libzt Manual: https://www.zerotier.com/manual.shtml#5
- libzt Repo: https://github.com/zerotier/libzt
- ZeroTierOne Repo: https://github.com/zerotier/ZeroTierOne
- Downloads: https://www.zerotier.com/download.shtml' > $PROD_DIR/README
# Record the version (and each submodule's version)
echo "$(git describe)" > $PROD_DIR/VERSION
echo -e "$(git submodule status | awk '{$1=$1};1')" >> $PROD_DIR/VERSION
@@ -502,13 +564,13 @@ package_everything()
tree $PROD_DIR
cat $PROD_DIR/VERSION
# Final check. Display warnings if anything is missing
FILES="README
VERSION
API.pdf
doc/errno.h
FILES="VERSION
README.md
README.pdf
reference/errno.h
licenses/LWIP-LICENSE.BSD
licenses/CONCURRENTQUEUE-LICENSE.BSD
licenses/ZEROTIER-LICENSE.GPL-3
licenses/ZEROTIER-LICENSE.BSL-1.1
licenses/ROUTE_H-LICENSE.APSL
licenses/ROUTE_H-LICENSE
licenses/LWIP-LICENSE.BSD"
@@ -520,14 +582,92 @@ package_everything()
done
}
# Generates a source-only tarball
sdist()
{
VERSION=$(git describe --abbrev=0)
TARBALL_DIR="libzt-${VERSION}"
TARBALL_NAME=libzt-${VERSION}-source.tar.gz
PROD_DIR=$(pwd)/products/
mkdir -p $PROD_DIR
#
mkdir ${TARBALL_DIR}
# primary sources
cp -rf src ${TARBALL_DIR}/src
cp -rf include ${TARBALL_DIR}/include
# important build scripts
cp Makefile ${TARBALL_DIR}
cp CMakeLists.txt ${TARBALL_DIR}
cp *.md ${TARBALL_DIR}
cp *.sh ${TARBALL_DIR}
cp *.bat ${TARBALL_DIR}
# submodules/dependencies
# lwIP
mkdir ${TARBALL_DIR}/ext
mkdir -p ${TARBALL_DIR}/ext/lwip/src
cp -rf ext/lwip/src/api ${TARBALL_DIR}/ext/lwip/src
cp -rf ext/lwip/src/core ${TARBALL_DIR}/ext/lwip/src
cp -rf ext/lwip/src/include ${TARBALL_DIR}/ext/lwip/src
cp -rf ext/lwip/src/netif ${TARBALL_DIR}/ext/lwip/src
# lwIP ports
mkdir -p ${TARBALL_DIR}/ext/lwip-contrib/ports
cp -rf ext/lwip-contrib/ports/unix ${TARBALL_DIR}/ext/lwip-contrib/ports
cp -rf ext/lwip-contrib/ports/win32 ${TARBALL_DIR}/ext/lwip-contrib/ports
# ZeroTierOne
mkdir ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/*.h ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/controller ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/ext ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/include ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/node ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/osdep ${TARBALL_DIR}/ext/ZeroTierOne
#
# Perform selective removal
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/bin
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/tap-mac
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/librethinkdbxx
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/installfiles
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/curl-*
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/http-parser
#
mkdir ${TARBALL_DIR}/ext/concurrentqueue
cp -rf ext/concurrentqueue/*.h ${TARBALL_DIR}/ext/concurrentqueue
# Licenses
package_licenses $(pwd) $TARBALL_DIR/licenses
# Tarball everything and display the results
tar -cvf ${TARBALL_NAME} ${TARBALL_DIR}
tree ${TARBALL_DIR}
rm -rf ${TARBALL_DIR}
mv ${TARBALL_NAME} ${PROD_DIR}
}
# Package both debug and release
dist()
bdist()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
package_everything "debug"
package_everything "release"
}
# Generate a markdown CHANGELOG from git-log
update_changelog()
{
first_commit=$(git rev-list --max-parents=0 HEAD)
git for-each-ref --sort=-refname --format="## [%(refname:short)] - %(taggerdate:short) &(newline)*** &(newline)- %(subject) %(body)" refs/tags > CHANGELOG.md
gsed -i '''s/\&(newline)/\n/' CHANGELOG.md # replace first instance
gsed -i '''s/\&(newline)/\n/' CHANGELOG.md # replace second instance
echo -e "\n" >> CHANGELOG.md
for curr_tag in $(git tag -l --sort=-v:refname)
do
prev_tag=$(git describe --abbrev=0 ${curr_tag}^)
if [ -z "${prev_tag}" ]
then
prev_tag=${first_commit}
fi
echo "[${curr_tag}]: https://github.com/zerotier/libzt/compare/${prev_tag}..${curr_tag}" >> CHANGELOG.md
done
}
# List all functions in this script (just for convenience)
list()
{

57
examples/README.md Normal file
View File

@@ -0,0 +1,57 @@
Useful things to know
=====
### IDENTITIES and AUTHORIZATION:
Upon the first execution of this code, a new identity will be generated and placed in the location given in the first argument to zts_start(path, ...). If you accidentally duplicate the identity files and use them simultaneously in a different node instance **you will experience undefined behavior** and it is likely that nothing will work.
You must authorize the node ID provided by the `ZTS_EVENT_NODE_ONLINE` callback to join your network, otherwise nothing will happen. This can be done manually or via our web API: https://my.zerotier.com/help/api
An exception to the above rule is if you are using an Ad-hoc network, it has no controller and therefore requires no authorization.
### ESTABLISHING A CONNECTION:
Creating a standard socket connection generally works the same as it would using an ordinary socket interface, however with libzt there is a subtle difference in how connections are established which may cause confusion:
The underlying virtual ZT layer creates what are called "transport-triggered links" between nodes. That is, links are not established until an attempt to communicate with a peer has taken place. The side effect is that the first few packets sent from a libzt instance are usually relayed via our free infrastructure and it isn't until a root server has passed contact information to both peers that a direct connection will be established. Therefore, it is required that multiple connection attempts be undertaken when initially communicating with a peer. After a transport-triggered link is established libzt will inform you via `ZTS_EVENT_PEER_DIRECT` for a specific peer ID. No action is required on your part for this callback event.
*Note: In these initial moments before `ZTS_EVENT_PEER_DIRECT` has been received for a specific peer, traffic may be slow, jittery and there may be high packet loss. This will subside within a couple of seconds.*
### ERROR HANDLING:
libzt's API is actually composed of two categories of functions with slightly different error reporting mechanisms.
- Category 1: Control functions (`zts_start`, `zts_join`, `zts_get_peer_status`, etc). Errors returned by these functions can be any of the following:
```
ZTS_ERR_OK // No error
ZTS_ERR_SOCKET // Socket error, see zts_errno
ZTS_ERR_SERVICE // You probably did something at the wrong time
ZTS_ERR_ARG // Invalid argument
ZTS_ERR_NO_RESULT // No result (not necessarily an error)
ZTS_ERR_GENERAL // Consider filing a bug report
```
- Category 2: Sockets (`zts_socket`, `zts_bind`, `zts_connect`, `zts_listen`, etc). Errors returned by these functions can be the same as the above. With the added possibility of `zts_errno` being set. Much like standard errno this will provide a more specific reason for an error's occurrence. See `ZeroTierSockets.h` for values.
### API COMPATIBILITY WITH HOST OS:
While the ZeroTier socket interface can coexist with your host OS's own interface in the same file with no type and naming conflicts, try not to mix and match host OS/libzt structures, functions, or constants. It may look similar and may even work some of the time but there enough differences that it will cause headaches:
If you are calling a `zts_*` function, use the appropriate `ZTS_*` constants:
```
zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
```
If you are calling a `zts_*` function, use the appropriate `zts_*` structure:
```
struct zts_sockaddr_in in4; <------ Note the zts_* prefix
...
zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
```

View File

@@ -1,31 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2027
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExampleWindowsCppApp", "ExampleWindowsCppApp\ExampleWindowsCppApp.vcxproj", "{D6BC8888-0498-4BDB-AFAF-21090A39082A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D6BC8888-0498-4BDB-AFAF-21090A39082A}.Debug|x64.ActiveCfg = Debug|x64
{D6BC8888-0498-4BDB-AFAF-21090A39082A}.Debug|x64.Build.0 = Debug|x64
{D6BC8888-0498-4BDB-AFAF-21090A39082A}.Debug|x86.ActiveCfg = Debug|Win32
{D6BC8888-0498-4BDB-AFAF-21090A39082A}.Debug|x86.Build.0 = Debug|Win32
{D6BC8888-0498-4BDB-AFAF-21090A39082A}.Release|x64.ActiveCfg = Release|x64
{D6BC8888-0498-4BDB-AFAF-21090A39082A}.Release|x64.Build.0 = Release|x64
{D6BC8888-0498-4BDB-AFAF-21090A39082A}.Release|x86.ActiveCfg = Release|Win32
{D6BC8888-0498-4BDB-AFAF-21090A39082A}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {68E97C56-8BB2-44E4-8536-069924BC9707}
EndGlobalSection
EndGlobal

View File

@@ -1,174 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{D6BC8888-0498-4BDB-AFAF-21090A39082A}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ExampleWindowsCppApp</RootNamespace>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\libzt\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>C:\libzt\bin\lib\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>ws2_32.lib;iphlpapi.lib;Shlwapi.lib;zt-static.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\libzt\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>C:\libzt\bin\lib\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>zt-static.lib;ws2_32.lib;shlwapi.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>C:\libzt\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>zt-static.lib;ws2_32.lib;iphlpapi.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>C:\libzt\examples\cpp\ExampleWindowsCppApp\ExampleWindowsCppApp\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ExampleWindowsCppApp.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ExampleWindowsCppApp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

260
examples/cpp/adhoc.cpp Normal file
View File

@@ -0,0 +1,260 @@
/**
* libzt API example
*
* Pingable node joined to controller-less adhoc network with a 6PLANE addressing scheme
*/
/**
*
* IDENTITIES and AUTHORIZATION:
*
* - Upon the first execution of this code, a new identity will be generated and placed in
* the location given in the first argument to zts_start(path, ...). If you accidentally
* duplicate the identity files and use them simultaneously in a different node instance
* you will experience undefined behavior and it is likely nothing will work.
*
* - You must authorize the node ID provided by the ZTS_EVENT_NODE_ONLINE callback to join
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - Exceptions to the above rule are:
* 1) Joining a public network (such as "earth")
* 2) Joining an Ad-hoc network, (no controller and therefore requires no authorization.)
*
*
* ESTABLISHING A CONNECTION:
*
* - Creating a standard socket connection generally works the same as it would using
* an ordinary socket interface, however with libzt there is a subtle difference in
* how connections are established which may cause confusion:
*
* The underlying virtual ZT layer creates what are called "transport-triggered links"
* between nodes. That is, links are not established until an attempt to communicate
* with a peer has taken place. The side effect is that the first few packets sent from
* a libzt instance are usually relayed via our free infrastructure and it isn't until a
* root server has passed contact information to both peers that a direct connection will be
* established. Therefore, it is required that multiple connection attempts be undertaken
* when initially communicating with a peer. After a transport-triggered link is
* established libzt will inform you via ZTS_EVENT_PEER_DIRECT for a specific peer ID. No
* action is required on your part for this callback event.
*
* Note: In these initial moments before ZTS_EVENT_PEER_DIRECT has been received for a
* specific peer, traffic may be slow, jittery and there may be high packet loss.
* This will subside within a couple of seconds.
*
*
* ERROR HANDLING:
*
* - libzt's API is actually composed of two categories of functions with slightly
* different error reporting mechanisms.
*
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* ZTS_ERR_OK // No error
* ZTS_ERR_SOCKET // Socket error, see zts_errno
* ZTS_ERR_SERVICE // You probably did something at the wrong time
* ZTS_ERR_ARG // Invalid argument
* ZTS_ERR_NO_RESULT // No result (not necessarily an error)
* ZTS_ERR_GENERAL // Consider filing a bug report
*
* Category 2: Sockets (zts_socket, zts_bind, zts_connect, zts_listen, etc).
* Errors returned by these functions can be the same as the above. With
* the added possibility of zts_errno being set. Much like standard
* errno this will provide a more specific reason for an error's occurrence.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - While the ZeroTier socket interface can coexist with your host OS's own interface in
* the same file with no type and naming conflicts, try not to mix and match host
* OS/libzt structures, functions, or constants. It may look similar and may even work
* some of the time but there enough differences that it will cause headaches. Here
* are a few guidelines:
*
* If you are calling a zts_* function, use the appropriate ZTS_* constants:
*
* zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
* zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
*
* If you are calling a zts_* function, use the appropriate zts_* structure:
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "ZeroTierSockets.h"
struct Node
{
Node() : online(false), joinedAtLeastOneNetwork(false), id(0) {}
bool online;
bool joinedAtLeastOneNetwork;
uint64_t id;
// etc
} myNode;
/* Callback handler, you should return control from this function as quickly as you can
to ensure timely receipt of future events. You should not call libzt API functions from
this function unless it's something trivial like zts_inet_ntop() or similar that has
no state-change implications. */
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
myNode.id = msg->node->address;
myNode.online = true;
}
if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) {
printf("ZTS_EVENT_NODE_OFFLINE --- Check your physical Internet connection, router, firewall, etc. What ports are you blocking?\n");
myNode.online = false;
}
// Virtual network events
if (msg->eventCode == ZTS_EVENT_NETWORK_NOT_FOUND) {
printf("ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQ_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQ_CONFIG --- Requesting config for network %llx, please wait a few seconds...\n", msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
printf("ZTS_EVENT_NETWORK_ACCESS_DENIED --- Access to virtual network %llx has been denied. Did you authorize the node yet?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
printf("ZTS_EVENT_NETWORK_READY_IP6 --- Network config received. IPv6 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_DOWN) {
printf("ZTS_EVENT_NETWORK_DOWN --- %llx\n", msg->network->nwid);
}
// Network stack events
if (msg->eventCode == ZTS_EVENT_NETIF_UP) {
printf("ZTS_EVENT_NETIF_UP --- network=%llx, mac=%llx, mtu=%d\n",
msg->netif->nwid,
msg->netif->mac,
msg->netif->mtu);
}
if (msg->eventCode == ZTS_EVENT_NETIF_DOWN) {
printf("ZTS_EVENT_NETIF_DOWN --- network=%llx, mac=%llx\n",
msg->netif->nwid,
msg->netif->mac);
}
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP6 --- Join %llx and ping me at %s\n",
msg->addr->nwid, ipstr);
}
// Peer events
if (msg->peer) {
if (msg->peer->role == ZTS_PEER_ROLE_PLANET) {
/* Safe to ignore, these are our roots. They orchestrate the P2P connection.
You might also see other unknown peers, these are our network controllers. */
return;
}
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- A direct path is known for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
printf("ZTS_EVENT_PEER_RELAY --- No direct path to node=%llx\n", msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DISCOVERED) {
printf("ZTS_EVENT_PEER_PATH_DISCOVERED --- A new direct path was discovered for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DEAD) {
printf("ZTS_EVENT_PEER_PATH_DEAD --- A direct path has died for node=%llx\n",
msg->peer->address);
}
}
}
/*
Ad-hoc Network:
ffSSSSEEEE000000
| | | |
| | | Reserved for future use, must be 0
| | End of port range (hex)
| Start of port range (hex)
Reserved ZeroTier address prefix indicating a controller-less network.
Ad-hoc networks are public (no access control) networks that have no network controller. Instead
their configuration and other credentials are generated locally. Ad-hoc networks permit only IPv6
UDP and TCP unicast traffic (no multicast or broadcast) using 6plane format NDP-emulated IPv6
addresses. In addition an ad-hoc network ID encodes an IP port range. UDP packets and TCP SYN
(connection open) packets are only allowed to destination ports within the encoded range.
For example ff00160016000000 is an ad-hoc network allowing only SSH, while ff0000ffff000000 is an
ad-hoc network allowing any UDP or TCP port.
Keep in mind that these networks are public and anyone in the entire world can join them. Care must
be taken to avoid exposing vulnerable services or sharing unwanted files or other resources.
*/
int main(int argc, char **argv)
{
if (argc != 5) {
printf("\nlibzt example\n");
printf("adhoc <config_file_path> <adhocStartPort> <adhocEndPort> <ztServicePort>\n");
exit(0);
}
int adhocStartPort = atoi(argv[2]); // Start of port range your application will use
int adhocEndPort = atoi(argv[3]); // End of port range your application will use
int ztServicePort = atoi(argv[4]); // Port ZT uses to send encrypted UDP packets to peers (try something like 9994)
uint64_t adhoc_nwid = zts_generate_adhoc_nwid_from_range(adhocStartPort, adhocEndPort);
int err = ZTS_ERR_OK;
// If disabled: (network) details will NOT be written to or read from (networks.d/). It may take slightly longer to start the node
zts_allow_network_caching(1);
// If disabled: (peer) details will NOT be written to or read from (peers.d/). It may take slightly longer to contact a remote peer
zts_allow_peer_caching(1);
// If disabled: Settings will NOT be read from local.conf
zts_allow_local_conf(1);
if((err = zts_start(argv[1], &myZeroTierEventCallback, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (!myNode.online) { zts_delay_ms(50); }
printf("This node's identity is stored in %s\n", argv[1]);
if((err = zts_join(adhoc_nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", adhoc_nwid);
while (!myNode.joinedAtLeastOneNetwork) { zts_delay_ms(50); }
// Idle and just show callback events, stack statistics, etc
printf("Node will now idle...\n");
while (true) { zts_delay_ms(1000); }
// Shut down service and stack threads
zts_stop();
return 0;
}

300
examples/cpp/client.cpp Normal file
View File

@@ -0,0 +1,300 @@
/**
* libzt API example
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "ZeroTierSockets.h"
struct Node
{
Node() : online(false), joinedAtLeastOneNetwork(false), id(0) {}
bool online;
bool joinedAtLeastOneNetwork;
uint64_t id;
// etc
} myNode;
/* Callback handler, you should return control from this function as quickly as you can
to ensure timely receipt of future events. You should not call libzt API functions from
this function unless it's something trivial like zts_inet_ntop() or similar that has
no state-change implications. */
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
myNode.id = msg->node->address;
myNode.online = true;
}
if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) {
printf("ZTS_EVENT_NODE_OFFLINE --- Check your physical Internet connection, router, firewall, etc. What ports are you blocking?\n");
myNode.online = false;
}
if (msg->eventCode == ZTS_EVENT_NODE_NORMAL_TERMINATION) {
printf("ZTS_EVENT_NODE_NORMAL_TERMINATION\n");
}
// Virtual network events
if (msg->eventCode == ZTS_EVENT_NETWORK_NOT_FOUND) {
printf("ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQ_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQ_CONFIG --- Requesting config for network %llx, please wait a few seconds...\n", msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
printf("ZTS_EVENT_NETWORK_ACCESS_DENIED --- Access to virtual network %llx has been denied. Did you authorize the node yet?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP4) {
printf("ZTS_EVENT_NETWORK_READY_IP4 --- Network config received. IPv4 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
printf("ZTS_EVENT_NETWORK_READY_IP6 --- Network config received. IPv6 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_DOWN) {
printf("ZTS_EVENT_NETWORK_DOWN --- %llx\n", msg->network->nwid);
}
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP4 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP6 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP4 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP6 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
// Peer events
if (msg->peer) {
if (msg->peer->role == ZTS_PEER_ROLE_PLANET) {
/* Safe to ignore, these are our roots. They orchestrate the P2P connection.
You might also see other unknown peers, these are our network controllers. */
return;
}
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- A direct path is known for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
printf("ZTS_EVENT_PEER_RELAY --- No direct path to node=%llx\n", msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DISCOVERED) {
printf("ZTS_EVENT_PEER_PATH_DISCOVERED --- A new direct path was discovered for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DEAD) {
printf("ZTS_EVENT_PEER_PATH_DEAD --- A direct path has died for node=%llx\n",
msg->peer->address);
}
}
}
/**
*
* IDENTITIES and AUTHORIZATION:
*
* - Upon the first execution of this code, a new identity will be generated and placed in
* the location given in the first argument to zts_start(path, ...). If you accidentally
* duplicate the identity files and use them simultaneously in a different node instance
* you will experience undefined behavior and it is likely nothing will work.
*
* - You must authorize the node ID provided by the ZTS_EVENT_NODE_ONLINE callback to join
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - Exceptions to the above rule are:
* 1) Joining a public network (such as "earth")
* 2) Joining an Ad-hoc network, (no controller and therefore requires no authorization.)
*
*
* ESTABLISHING A CONNECTION:
*
* - Creating a standard socket connection generally works the same as it would using
* an ordinary socket interface, however with libzt there is a subtle difference in
* how connections are established which may cause confusion:
*
* The underlying virtual ZT layer creates what are called "transport-triggered links"
* between nodes. That is, links are not established until an attempt to communicate
* with a peer has taken place. The side effect is that the first few packets sent from
* a libzt instance are usually relayed via our free infrastructure and it isn't until a
* root server has passed contact information to both peers that a direct connection will be
* established. Therefore, it is required that multiple connection attempts be undertaken
* when initially communicating with a peer. After a transport-triggered link is
* established libzt will inform you via ZTS_EVENT_PEER_DIRECT for a specific peer ID. No
* action is required on your part for this callback event.
*
* Note: In these initial moments before ZTS_EVENT_PEER_DIRECT has been received for a
* specific peer, traffic may be slow, jittery and there may be high packet loss.
* This will subside within a couple of seconds.
*
*
* ERROR HANDLING:
*
* - libzt's API is actually composed of two categories of functions with slightly
* different error reporting mechanisms.
*
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* ZTS_ERR_OK // No error
* ZTS_ERR_SOCKET // Socket error, see zts_errno
* ZTS_ERR_SERVICE // You probably did something at the wrong time
* ZTS_ERR_ARG // Invalid argument
* ZTS_ERR_NO_RESULT // No result (not necessarily an error)
* ZTS_ERR_GENERAL // Consider filing a bug report
*
* Category 2: Sockets (zts_socket, zts_bind, zts_connect, zts_listen, etc).
* Errors returned by these functions can be the same as the above. With
* the added possibility of zts_errno being set. Much like standard
* errno this will provide a more specific reason for an error's occurrence.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - While the ZeroTier socket interface can coexist with your host OS's own interface in
* the same file with no type and naming conflicts, try not to mix and match host
* OS/libzt structures, functions, or constants. It may look similar and may even work
* some of the time but there enough differences that it will cause headaches. Here
* are a few guidelines:
*
* If you are calling a zts_* function, use the appropriate ZTS_* constants:
*
* zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
* zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
*
* If you are calling a zts_* function, use the appropriate zts_* structure:
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
*/
int main(int argc, char **argv)
{
if (argc != 6) {
printf("\nlibzt example client\n");
printf("client <config_file_path> <nwid> <remoteAddr> <remotePort> <ztServicePort>\n");
exit(0);
}
uint64_t nwid = strtoull(argv[2],NULL,16); // Network ID to join
std::string remoteAddr = argv[3]; // Remote application's virtual ZT address
int remotePort = atoi(argv[4]); // Port the application will try to connect to the server on
int ztServicePort = atoi(argv[5]); // Port ZT uses to send encrypted UDP packets to peers (try something like 9994)
struct zts_sockaddr_in in4;
in4.sin_port = zts_htons(remotePort);
#if defined(_WIN32)
in4.sin_addr.S_addr = zts_inet_addr(remoteAddr.c_str());
#else
in4.sin_addr.s_addr = zts_inet_addr(remoteAddr.c_str());
#endif
in4.sin_family = ZTS_AF_INET;
// Bring up ZeroTier service and join network
int err = ZTS_ERR_OK;
// If disabled: (network) details will NOT be written to or read from (networks.d/). It may take slightly longer to start the node
zts_allow_network_caching(1);
// If disabled: (peer) details will NOT be written to or read from (peers.d/). It may take slightly longer to contact a remote peer
zts_allow_peer_caching(1);
// If disabled: Settings will NOT be read from local.conf
zts_allow_local_conf(1);
if((err = zts_start(argv[1], &myZeroTierEventCallback, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (!myNode.online) { zts_delay_ms(50); }
printf("This node's identity is stored in %s\n", argv[1]);
if((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (!myNode.joinedAtLeastOneNetwork) { zts_delay_ms(50); }
// Socket-like API example
char *msgStr = (char*)"Welcome to the machine";
int bytes=0, fd;
char recvBuf[128];
memset(recvBuf, 0, sizeof(recvBuf));
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
printf("Error creating ZeroTier socket (fd=%d, zts_errno=%d). Exiting.\n", fd, zts_errno);
exit(1);
}
// Retries are often required since ZT uses transport-triggered links (explained above)
for (;;) {
printf("Connecting to remote host...\n");
if ((err = zts_connect(fd, (const struct zts_sockaddr *)&in4, sizeof(in4))) < 0) {
printf("Error connecting to remote host (fd=%d, ret=%d, zts_errno=%d). Trying again.\n",
fd, err, zts_errno);
zts_close(fd);
printf("Creating socket...\n");
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
printf("Error creating ZeroTier socket (fd=%d, zts_errno=%d). Exiting.\n", fd, zts_errno);
exit(1);
}
zts_delay_ms(250);
}
else {
printf("Connected.\n");
break;
}
}
printf("Sending message string to server...\n");
if((bytes = zts_write(fd, msgStr, strlen(msgStr))) < 0) {
printf("Error writing to socket (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, bytes, zts_errno);
exit(1);
}
printf("Sent %d bytes: %s\n", bytes, msgStr);
printf("Reading message string from server...\n");
if((bytes = zts_read(fd, recvBuf, sizeof(recvBuf))) < 0) {
printf("Error writing to socket (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, bytes, zts_errno);
exit(1);
}
printf("Read %d bytes: %s\n", bytes, recvBuf);
printf("Closing socket\n");
zts_close(fd);
printf("Shutting down service\n");
zts_stop();
return 0;
}

View File

@@ -0,0 +1,435 @@
/**
* libzt API example
*
* For more straight-to-the-point examples, see the other files in this same directory.
*/
/**
*
* IDENTITIES and AUTHORIZATION:
*
* - Upon the first execution of this code, a new identity will be generated and placed in
* the location given in the first argument to zts_start(path, ...). If you accidentally
* duplicate the identity files and use them simultaneously in a different node instance
* you will experience undefined behavior and it is likely nothing will work.
*
* - You must authorize the node ID provided by the ZTS_EVENT_NODE_ONLINE callback to join
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - Exceptions to the above rule are:
* 1) Joining a public network (such as "earth")
* 2) Joining an Ad-hoc network, (no controller and therefore requires no authorization.)
*
*
* ESTABLISHING A CONNECTION:
*
* - Creating a standard socket connection generally works the same as it would using
* an ordinary socket interface, however with libzt there is a subtle difference in
* how connections are established which may cause confusion:
*
* The underlying virtual ZT layer creates what are called "transport-triggered links"
* between nodes. That is, links are not established until an attempt to communicate
* with a peer has taken place. The side effect is that the first few packets sent from
* a libzt instance are usually relayed via our free infrastructure and it isn't until a
* root server has passed contact information to both peers that a direct connection will be
* established. Therefore, it is required that multiple connection attempts be undertaken
* when initially communicating with a peer. After a transport-triggered link is
* established libzt will inform you via ZTS_EVENT_PEER_DIRECT for a specific peer ID. No
* action is required on your part for this callback event.
*
* Note: In these initial moments before ZTS_EVENT_PEER_DIRECT has been received for a
* specific peer, traffic may be slow, jittery and there may be high packet loss.
* This will subside within a couple of seconds.
*
*
* ERROR HANDLING:
*
* - libzt's API is actually composed of two categories of functions with slightly
* different error reporting mechanisms.
*
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* ZTS_ERR_OK // No error
* ZTS_ERR_SOCKET // Socket error, see zts_errno
* ZTS_ERR_SERVICE // You probably did something at the wrong time
* ZTS_ERR_ARG // Invalid argument
* ZTS_ERR_NO_RESULT // No result (not necessarily an error)
* ZTS_ERR_GENERAL // Consider filing a bug report
*
* Category 2: Sockets (zts_socket, zts_bind, zts_connect, zts_listen, etc).
* Errors returned by these functions can be the same as the above. With
* the added possibility of zts_errno being set. Much like standard
* errno this will provide a more specific reason for an error's occurrence.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - While the ZeroTier socket interface can coexist with your host OS's own interface in
* the same file with no type and naming conflicts, try not to mix and match host
* OS/libzt structures, functions, or constants. It may look similar and may even work
* some of the time but there enough differences that it will cause headaches. Here
* are a few guidelines:
*
* If you are calling a zts_* function, use the appropriate ZTS_* constants:
*
* zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
* zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
*
* If you are calling a zts_* function, use the appropriate zts_* structure:
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "ZeroTierSockets.h"
#ifdef __WINDOWS__
#include "winsock.h"
#endif
struct Node
{
Node() : online(false), joinedAtLeastOneNetwork(false), id(0) {}
bool online;
bool joinedAtLeastOneNetwork;
uint64_t id;
// etc
} myNode;
void printNodeDetails(const char *msgStr, struct zts_node_details *d)
{
printf("\n%s\n", msgStr);
printf("\t- id : %llx\n", d->address);
printf("\t- version : %d.%d.%d\n", d->versionMajor, d->versionMinor, d->versionRev);
printf("\t- primaryPort : %d\n", d->primaryPort);
printf("\t- secondaryPort : %d\n", d->secondaryPort);
}
void printPeerDetails(const char *msgStr, struct zts_peer_details *d)
{
printf("\n%s\n", msgStr);
printf("\t- peer : %llx\n", d->address);
printf("\t- role : %llx\n", d->role);
printf("\t- latency : %d\n", d->latency);
printf("\t- version : %d.%d.%d\n", d->versionMajor, d->versionMinor, d->versionRev);
printf("\t- pathCount : %d\n", d->pathCount);
printf("\t- paths:\n");
// Print all known paths for each peer
for (unsigned int j=0; j<d->pathCount; j++) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
int port = 0;
struct zts_sockaddr *sa = (struct zts_sockaddr *)&(d->paths[j].address);
if (sa->sa_family == ZTS_AF_INET) {
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)sa;
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
port = zts_ntohs(in4->sin_port);
}
if (sa->sa_family == ZTS_AF_INET6) {
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)sa;
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
}
printf("\t - %15s : %6d\n", ipstr, port);
}
printf("\n");
}
void printNetworkDetails(const char *msgStr, struct zts_network_details *d)
{
printf("\n%s\n", msgStr);
printf("\t- nwid : %llx\n", d->nwid);
printf("\t- mac : %lx\n", d->mac);
printf("\t- name : %s\n", d->name);
printf("\t- type : %d\n", d->type);
/* MTU for the virtual network can be set via our web API */
printf("\t- mtu : %d\n", d->mtu);
printf("\t- dhcp : %d\n", d->dhcp);
printf("\t- bridge : %d\n", d->bridge);
printf("\t- broadcastEnabled : %d\n", d->broadcastEnabled);
printf("\t- portError : %d\n", d->portError);
printf("\t- netconfRevision : %d\n", d->netconfRevision);
printf("\t- routeCount : %d\n", d->routeCount);
printf("\t- multicastSubscriptionCount : %d\n", d->multicastSubscriptionCount);
for (int i=0; i<d->multicastSubscriptionCount; i++) {
printf("\t - mac=%llx, adi=%x\n", d->multicastSubscriptions[i].mac, d->multicastSubscriptions[i].adi);
}
printf("\t- addresses:\n");
for (int i=0; i<d->assignedAddressCount; i++) {
if (d->assignedAddresses[i].ss_family == ZTS_AF_INET) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(d->assignedAddresses[i]);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("\t - %s\n",ipstr);
}
if (d->assignedAddresses[i].ss_family == ZTS_AF_INET6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(d->assignedAddresses[i]);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("\t - %s\n",ipstr);
}
}
printf("\t- routes:\n");
for (int i=0; i<d->routeCount; i++) {
if (d->routes[i].target.ss_family == ZTS_AF_INET) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(d->routes[i].target);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("\t - target : %s\n",ipstr);
in4 = (struct zts_sockaddr_in*)&(d->routes[i].via);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("\t - via : %s\n",ipstr);
}
if (d->routes[i].target.ss_family == ZTS_AF_INET6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(d->routes[i].target);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("\t - target : %s\n",ipstr);
in6 = (struct zts_sockaddr_in6*)&(d->routes[i].via);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("\t - via : %s\n",ipstr);
}
printf("\t - flags : %d\n", d->routes[i].flags);
printf("\t - metric : %d\n", d->routes[i].metric);
}
}
void printNetifDetails(const char *msgStr, struct zts_netif_details *d)
{
printf("\n%s\n", msgStr);
printf("\t- nwid : %llx\n", d->nwid);
printf("\t- mac : %llx\n", d->mac);
printf("\t- mtu : %d\n", d->mtu);
}
/* Callback handler, you should return control from this function as quickly as you can
to ensure timely receipt of future events. You should not call libzt API functions from
this function unless it's something trivial like zts_inet_ntop() or similar that has
no state-change implications. */
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
printf("eventCode=%d\n", msg->eventCode);
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printNodeDetails("nZTS_EVENT_NODE_ONLINE", msg->node);
myNode.id = msg->node->address;
myNode.online = true;
}
if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) {
printf("\nZTS_EVENT_NODE_OFFLINE --- Check your Internet connection, router, firewall, etc. What ports are you blocking?\n");
myNode.online = false;
}
if (msg->eventCode == ZTS_EVENT_NODE_NORMAL_TERMINATION) {
printf("\nZTS_EVENT_NODE_NORMAL_TERMINATION -- A call to zts_start() will restart ZeroTier.\n");
myNode.online = false;
}
// Virtual network events
if (msg->eventCode == ZTS_EVENT_NETWORK_NOT_FOUND) {
printf("\nZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQ_CONFIG) {
printf("\nZTS_EVENT_NETWORK_REQ_CONFIG --- Requesting config for network %llx, please wait a few seconds...\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
printf("\nZTS_EVENT_NETWORK_ACCESS_DENIED --- Access to virtual network %llx has been denied. Did you authorize the node yet?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP4) {
printNetworkDetails("ZTS_EVENT_NETWORK_READY_IP4 --- Network config received.", msg->network);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
printNetworkDetails("ZTS_EVENT_NETWORK_READY_IP6 --- Network config received.", msg->network);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_DOWN) {
printf("\nZTS_EVENT_NETWORK_DOWN --- %llx\n", msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_UPDATE) {
printNetworkDetails("ZTS_EVENT_NETWORK_UPDATE --- Network config received.", msg->network);
}
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("\nZTS_EVENT_ADDR_ADDED_IP4 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("\nZTS_EVENT_ADDR_ADDED_IP6 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("\nZTS_EVENT_ADDR_REMOVED_IP4 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("\nZTS_EVENT_ADDR_REMOVED_IP6 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
// Peer events
if (msg->peer) {
if (msg->peer->role == ZTS_PEER_ROLE_PLANET) {
/* Safe to ignore, these are our roots. They orchestrate the P2P connection.
You might also see other unknown peers, these are our network controllers. */
return;
}
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printPeerDetails("ZTS_EVENT_PEER_DIRECT --- A direct path is known.", msg->peer);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
printPeerDetails("ZTS_EVENT_PEER_RELAY --- No direct path known.", msg->peer);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DISCOVERED) {
printPeerDetails("ZTS_EVENT_PEER_PATH_DISCOVERED --- A new direct path was discovered.", msg->peer);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DEAD) {
printPeerDetails("ZTS_EVENT_PEER_PATH_DEAD --- A direct path has died.", msg->peer);
}
}
// Network stack (netif) events (used for debugging, can be ignored)
if (msg->eventCode == ZTS_EVENT_NETIF_UP) {
printNetifDetails("ZTS_EVENT_NETIF_UP --- No action required.", msg->netif);
}
if (msg->eventCode == ZTS_EVENT_NETIF_DOWN) {
printNetifDetails("ZTS_EVENT_NETIF_DOWN --- No action required.", msg->netif);
}
if (msg->eventCode == ZTS_EVENT_NETIF_REMOVED) {
printNetifDetails("ZTS_EVENT_NETIF_REMOVED --- No action required.", msg->netif);
}
if (msg->eventCode == ZTS_EVENT_NETIF_LINK_UP) {
printNetifDetails("ZTS_EVENT_NETIF_LINK_UP --- No action required.", msg->netif);
}
if (msg->eventCode == ZTS_EVENT_NETIF_LINK_DOWN) {
printNetifDetails("ZTS_EVENT_NETIF_LINK_DOWN --- No action required.", msg->netif);
}
// Network stack events (used for debugging, can be ignored)
if (msg->eventCode == ZTS_EVENT_STACK_UP) {
printf("\nZTS_EVENT_STACK_UP --- No action required.\n");
}
if (msg->eventCode == ZTS_EVENT_STACK_DOWN) {
printf("\nZTS_EVENT_STACK_DOWN --- No action required. An app restart is needed to use ZeroTier again.\n");
}
}
void get6PLANEAddressOfPeer(uint64_t peerId, uint64_t nwId)
{
char peerAddrStr[ZTS_INET6_ADDRSTRLEN] = {0};
struct zts_sockaddr_storage sixplane_addr;
zts_get_6plane_addr(&sixplane_addr, nwId, peerId);
struct zts_sockaddr_in6 *p6 = (struct zts_sockaddr_in6*)&sixplane_addr;
zts_inet_ntop(ZTS_AF_INET6, &(p6->sin6_addr), peerAddrStr, ZTS_INET6_ADDRSTRLEN);
printf("6PLANE address of peer is: %s\n", peerAddrStr);
}
struct zts_stats_proto protoSpecificStats;
void display_stack_stats()
{
int err = 0;
// Count received pings
if ((err = zts_get_protocol_stats(ZTS_STATS_PROTOCOL_ICMP, &protoSpecificStats)) != ZTS_ERR_OK) {
printf("zts_get_proto_stats()=%d", err);
return;
}
printf("icmp.recv=%d\n", protoSpecificStats.recv);
// Count dropped TCP packets
if ((err = zts_get_protocol_stats(ZTS_STATS_PROTOCOL_TCP, &protoSpecificStats)) != ZTS_ERR_OK) {
printf("zts_get_proto_stats()=%d", err);
return;
}
printf("tcp.drop=%d\n", protoSpecificStats.drop);
}
int main(int argc, char **argv)
{
if (argc != 4) {
printf("\nlibzt example server\n");
printf("comprehensive <config_file_path> <nwid> <ztServicePort>\n");
exit(0);
}
std::string configPath = std::string(argv[1]);
uint64_t nwid = strtoull(argv[2],NULL,16); // Network ID to join
int ztServicePort = atoi(argv[3]); // Port ZT uses to send encrypted UDP packets to peers (try something like 9994)
// Bring up ZeroTier service and join network
int err = ZTS_ERR_OK;
// If disabled: (network) details will NOT be written to or read from (networks.d/). It may take slightly longer to start the node
zts_allow_network_caching(1);
// If disabled: (peer) details will NOT be written to or read from (peers.d/). It may take slightly longer to contact a remote peer
zts_allow_peer_caching(1);
// If disabled: Settings will NOT be read from local.conf
zts_allow_local_conf(1);
if((err = zts_start(configPath.c_str(), &myZeroTierEventCallback, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (!myNode.online) { zts_delay_ms(50); }
printf("This node's identity is stored in %s\n", argv[1]);
if((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (!myNode.joinedAtLeastOneNetwork) { zts_delay_ms(50); }
// Idle and just show callback events, stack statistics, etc
// Alternatively, this is where you could start making calls to the socket API
/*
while(true) {
display_stack_stats();
zts_delay_ms(1000);
}
*/
int delay = 500000;
printf("This program will delay for %d seconds and then shut down.\n", (delay / 1000));
zts_delay_ms(delay);
//printf("Leaving network %llx\n", nwid);
//zts_leave(nwid);
//zts_delay_ms(3000); /* added for demo purposes so that events show up */
printf("Stopping ZeroTier\n");
zts_stop();
zts_delay_ms(delay); /* added for demo purposes so that events show up */
printf("Stopping network stack\n");
zts_free();
zts_delay_ms(delay); /* added for demo purposes so that events show up */
return 0;
}

View File

@@ -1,39 +1,218 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
/**
* libzt API example
*
* 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.
* Pingable node joined to public ZT network "earth"
*/
/**
*
* 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.
* IDENTITIES and AUTHORIZATION:
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* - Upon the first execution of this code, a new identity will be generated and placed in
* the location given in the first argument to zts_start(path, ...). If you accidentally
* duplicate the identity files and use them simultaneously in a different node instance
* you will experience undefined behavior and it is likely nothing will work.
*
* --
* - You must authorize the node ID provided by the ZTS_EVENT_NODE_ONLINE callback to join
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - Exceptions to the above rule are:
* 1) Joining a public network (such as "earth")
* 2) Joining an Ad-hoc network, (no controller and therefore requires no authorization.)
*
*
* ESTABLISHING A CONNECTION:
*
* - Creating a standard socket connection generally works the same as it would using
* an ordinary socket interface, however with libzt there is a subtle difference in
* how connections are established which may cause confusion:
*
* The underlying virtual ZT layer creates what are called "transport-triggered links"
* between nodes. That is, links are not established until an attempt to communicate
* with a peer has taken place. The side effect is that the first few packets sent from
* a libzt instance are usually relayed via our free infrastructure and it isn't until a
* root server has passed contact information to both peers that a direct connection will be
* established. Therefore, it is required that multiple connection attempts be undertaken
* when initially communicating with a peer. After a transport-triggered link is
* established libzt will inform you via ZTS_EVENT_PEER_DIRECT for a specific peer ID. No
* action is required on your part for this callback event.
*
* Note: In these initial moments before ZTS_EVENT_PEER_DIRECT has been received for a
* specific peer, traffic may be slow, jittery and there may be high packet loss.
* This will subside within a couple of seconds.
*
*
* ERROR HANDLING:
*
* - libzt's API is actually composed of two categories of functions with slightly
* different error reporting mechanisms.
*
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* ZTS_ERR_OK // No error
* ZTS_ERR_SOCKET // Socket error, see zts_errno
* ZTS_ERR_SERVICE // You probably did something at the wrong time
* ZTS_ERR_ARG // Invalid argument
* ZTS_ERR_NO_RESULT // No result (not necessarily an error)
* ZTS_ERR_GENERAL // Consider filing a bug report
*
* Category 2: Sockets (zts_socket, zts_bind, zts_connect, zts_listen, etc).
* Errors returned by these functions can be the same as the above. With
* the added possibility of zts_errno being set. Much like standard
* errno this will provide a more specific reason for an error's occurrence.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - While the ZeroTier socket interface can coexist with your host OS's own interface in
* the same file with no type and naming conflicts, try not to mix and match host
* OS/libzt structures, functions, or constants. It may look similar and may even work
* some of the time but there enough differences that it will cause headaches. Here
* are a few guidelines:
*
* If you are calling a zts_* function, use the appropriate ZTS_* constants:
*
* zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
* zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
*
* If you are calling a zts_* function, use the appropriate zts_* structure:
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include "libzt.h"
#include "ZeroTierSockets.h"
struct Node
{
Node() : online(false), joinedAtLeastOneNetwork(false), id(0) {}
bool online;
bool joinedAtLeastOneNetwork;
uint64_t id;
// etc
} myNode;
/* Callback handler, you should return control from this function as quickly as you can
to ensure timely receipt of future events. You should not call libzt API functions from
this function unless it's something trivial like zts_inet_ntop() or similar that has
no state-change implications. */
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
myNode.id = msg->node->address;
myNode.online = true;
}
if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) {
printf("ZTS_EVENT_NODE_OFFLINE --- Check your physical Internet connection, router, firewall, etc. What ports are you blocking?\n");
myNode.online = false;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQ_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQ_CONFIG --- Requesting config for network %llx, please wait a few seconds...\n", msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
printf("ZTS_EVENT_NETWORK_ACCESS_DENIED --- Access to virtual network %llx has been denied. Did you authorize the node yet?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
printf("ZTS_EVENT_NETWORK_READY_IP6 --- Network config received. IPv6 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_DOWN) {
printf("ZTS_EVENT_NETWORK_DOWN --- %llx\n", msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP4 --- Join %llx and ping me at %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP6 --- Join %llx and ping me at %s\n",
msg->addr->nwid, ipstr);
}
// Peer events
if (msg->peer) {
if (msg->peer->role == ZTS_PEER_ROLE_PLANET) {
/* Safe to ignore, these are our roots. They orchestrate the P2P connection.
You might also see other unknown peers, these are our network controllers. */
return;
}
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- A direct path is known for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
printf("ZTS_EVENT_PEER_RELAY --- No direct path to node=%llx\n", msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DISCOVERED) {
printf("ZTS_EVENT_PEER_PATH_DISCOVERED --- A new direct path was discovered for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DEAD) {
printf("ZTS_EVENT_PEER_PATH_DEAD --- A direct path has died for node=%llx\n",
msg->peer->address);
}
}
}
int main(int argc, char **argv)
{
if (argc != 3) {
printf("\nlibzt example\n");
printf("earthtest <config_file_path> <ztServicePort>\n");
exit(0);
}
int ztServicePort = atoi(argv[2]); // Port ZT uses to send encrypted UDP packets to peers (try something like 9994)
int err = ZTS_ERR_OK;
// If disabled: (network) details will NOT be written to or read from (networks.d/). It may take slightly longer to start the node
zts_allow_network_caching(1);
// If disabled: (peer) details will NOT be written to or read from (peers.d/). It may take slightly longer to contact a remote peer
zts_allow_peer_caching(1);
// If disabled: Settings will NOT be read from local.conf
zts_allow_local_conf(1);
if((err = zts_start(argv[1], &myZeroTierEventCallback, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (!myNode.online) { zts_delay_ms(50); }
printf("This node's identity is stored in %s\n", argv[1]);
uint64_t nwid = 0x8056c2e21c000001;
zts_startjoin(".", nwid);
fprintf(stderr, "%llx", (unsigned long long)zts_get_node_id());
zts_leave(nwid);
if((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", nwid);
while (!myNode.joinedAtLeastOneNetwork) { zts_delay_ms(50); }
// Idle and just show callback events, stack statistics, etc
printf("Node will now idle...\n");
while (true) { zts_delay_ms(1000); }
// Shut down service and stack threads
zts_stop();
return 0;
}
}

View File

@@ -1,96 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include "libzt.h"
char *msg = (char*)"welcome to the machine";
int main(int argc, char **argv)
{
if (argc != 5) {
printf("\nlibzt example client\n");
printf("client [config_file_path] [nwid] [remote_addr] [remote_port]\n");
exit(0);
}
std::string path = argv[1];
std::string nwidstr = argv[2];
std::string remote_addr = argv[3];
int remote_port = atoi(argv[4]);
int r=0, w=0, err=0, sockfd;
char rbuf[32];
memset(rbuf, 0, sizeof rbuf);
struct sockaddr_in in4;
in4.sin_port = htons(remote_port);
in4.sin_addr.s_addr = inet_addr(remote_addr.c_str());
in4.sin_family = AF_INET;
// --- BEGIN EXAMPLE CODE
printf("Waiting for libzt to come online...\n");
uint64_t nwid = strtoull(nwidstr.c_str(),NULL,16);
printf("nwid=%llx\n", (unsigned long long)nwid);
zts_startjoin(path.c_str(), nwid);
uint64_t nodeId = zts_get_node_id();
printf("I am %llx\n", (unsigned long long)nodeId);
if ((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket\n");
}
if ((err = zts_connect(sockfd, (const struct sockaddr *)&in4, sizeof(in4))) < 0) {
printf("error connecting to remote host (%d)\n", err);
}
printf("sending to server...\n");
w = zts_write(sockfd, msg, strlen(msg));
printf("reading from server...\n");
r = zts_read(sockfd, rbuf, strlen(msg));
printf("Sent : %s\n", msg);
printf("Received : %s\n", rbuf);
err = zts_close(sockfd);
return err;
}

View File

@@ -1,109 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#include <unistd.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include "libzt.h"
char *msg = (char*)"welcome to the machine";
int main(int argc, char **argv)
{
if (argc != 5) {
printf("\nlibzt example client\n");
printf("client [config_file_path] [nwid] [remote_addr] [remote_port]\n");
exit(0);
}
std::string path = argv[1];
std::string nwidstr = argv[2];
std::string remote_addr = argv[3];
int remote_port = atoi(argv[4]);
int r=0, w=0, err=0, sockfd;
char rbuf[32];
memset(rbuf, 0, sizeof rbuf);
struct sockaddr_in in4;
in4.sin_port = htons(remote_port);
in4.sin_addr.s_addr = INADDR_ANY;
in4.sin_family = AF_INET;
struct sockaddr_in remote4;
remote4.sin_port = htons(remote_port);
remote4.sin_addr.s_addr = inet_addr(remote_addr.c_str());
remote4.sin_family = AF_INET;
// --- BEGIN EXAMPLE CODE
printf("Waiting for libzt to come online...\n");
uint64_t nwid = strtoull(nwidstr.c_str(),NULL,16);
printf("nwid=%llx\n", (unsigned long long)nwid);
zts_startjoin(path.c_str(), nwid);
uint64_t nodeId = zts_get_node_id();
printf("I am %llx\n", (unsigned long long)nodeId);
if ((sockfd = zts_socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
printf("error creating ZeroTier socket\n");
}
if ((err = zts_bind(sockfd, (struct sockaddr *)&in4, sizeof(struct sockaddr_in)) < 0)) {
printf("error binding to interface (%d)\n", err);
}
int flags = 0;
int len = strlen(msg);
while(true) {
sleep(1);
if ((err = zts_sendto(sockfd, msg, len, flags, (const struct sockaddr *)&remote4, sizeof(remote4))) < 0) {
printf("error sending message to remote host (%d)\n", err);
}
printf("sent=%d\n", err);
}
/*
printf("reading from server...\n");
r = zts_read(sockfd, rbuf, strlen(msg));
printf("Sent : %s\n", msg);
printf("Received : %s\n", rbuf);
*/
err = zts_close(sockfd);
return err;
}

View File

@@ -1,119 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include "libzt.h"
int main(int argc, char **argv)
{
if (argc != 4) {
printf("\nlibzt example server\n");
printf("server [config_file_path] [nwid] [bind_port]\n");
exit(0);
}
std::string path = argv[1];
std::string nwidstr = argv[2];
int bind_port = atoi(argv[3]);
int w=0, r=0, err=0, sockfd, accfd;
char rbuf[1000];
memset(rbuf, 0, sizeof rbuf);
struct sockaddr_in in4, acc_in4;
in4.sin_port = htons(bind_port);
in4.sin_addr.s_addr = INADDR_ANY;
in4.sin_family = AF_INET;
// --- BEGIN EXAMPLE CODE
printf("Waiting for libzt to come online...\n");
uint64_t nwid = strtoull(nwidstr.c_str(),NULL,16);
printf("nwid=%llx\n", (unsigned long long)nwid);
zts_startjoin(path.c_str(), nwid);
uint64_t nodeId = zts_get_node_id();
printf("I am %llx\n", (unsigned long long)nodeId);
if ((sockfd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket\n");
}
if ((err = zts_bind(sockfd, (struct sockaddr *)&in4, sizeof(struct sockaddr_in)) < 0)) {
printf("error binding to interface (%d)\n", err);
}
if ((err = zts_listen(sockfd, 100)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
}
socklen_t client_addrlen = sizeof(sockaddr_in);
if ((accfd = zts_accept(sockfd, (struct sockaddr *)&acc_in4, &client_addrlen)) < 0) {
printf("error accepting connection (%d)\n", err);
}
socklen_t peer_addrlen = sizeof(struct sockaddr_storage);
zts_getpeername(accfd, (struct sockaddr*)&acc_in4, &peer_addrlen);
printf("accepted connection from %s : %d\n", inet_ntoa(acc_in4.sin_addr), ntohs(acc_in4.sin_port));
int tot = 0;
printf("reading from client...\n");
while(true) {
memset(rbuf, 0, sizeof rbuf);
if (tot == 500000)
{
break;
}
r = zts_read(accfd, rbuf, sizeof rbuf);
printf("r=%d\n", r);
printf("Received : %s\n", rbuf);
tot+= r;
printf("tot=%d\n", tot);
}
printf("tot=%d\n", tot);
printf("sending to client...\n");
w = zts_write(accfd, rbuf, strlen(rbuf));
printf("w=%d\n", r);
printf("Received : %s\n", rbuf);
err = zts_close(sockfd);
err = zts_close(accfd);
return err;
}

View File

@@ -1,107 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include "libzt.h"
int main(int argc, char **argv)
{
if (argc != 4) {
printf("\nlibzt example server\n");
printf("server [config_file_path] [nwid] [bind_port]\n");
exit(0);
}
std::string path = argv[1];
std::string nwidstr = argv[2];
int bind_port = atoi(argv[3]);
int w=0, r=0, err=0, sockfd = 0, accfd = 0, flags = 0;
char rbuf[32];
memset(rbuf, 0, sizeof rbuf);
struct sockaddr_in in4, acc_in4;
in4.sin_port = htons(bind_port);
in4.sin_addr.s_addr = INADDR_ANY;
in4.sin_family = AF_INET;
// --- BEGIN EXAMPLE CODE
printf("Waiting for libzt to come online...\n");
uint64_t nwid = strtoull(nwidstr.c_str(),NULL,16);
printf("nwid=%llx\n", (unsigned long long)nwid);
zts_startjoin(path.c_str(), nwid);
uint64_t nodeId = zts_get_node_id();
printf("I am %llx\n", (unsigned long long)nodeId);
if ((sockfd = zts_socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
printf("error creating ZeroTier socket\n");
}
if ((err = zts_bind(sockfd, (struct sockaddr *)&in4, sizeof(struct sockaddr_in)) < 0)) {
printf("error binding to interface (%d)\n", err);
}
/*
socklen_t peer_addrlen = sizeof(struct sockaddr_storage);
zts_getpeername(accfd, (struct sockaddr*)&acc_in4, &peer_addrlen);
DEBUG_INFO("accepted connection from %s : %d", inet_ntoa(acc_in4.sin_addr), ntohs(acc_in4.sin_port));
*/
printf("reading from client...\n");
socklen_t addrlen = sizeof(acc_in4);
memset(&acc_in4, 0, sizeof acc_in4);
while(true) {
memset(&rbuf, 0, sizeof rbuf);
r = zts_recvfrom(accfd, rbuf, sizeof(rbuf), flags, (struct sockaddr *)&acc_in4, &addrlen);
if (r >= 0) {
char *ip = inet_ntoa(acc_in4.sin_addr);
printf("Received : r=%d, %s -- from: %s : %d\n", r, rbuf, ip, ntohs(acc_in4.sin_port));
}
}
/*
printf("sending to client...\n");
w = zts_write(accfd, rbuf, strlen(rbuf));
*/
err = zts_close(sockfd);
return err;
}

View File

@@ -1,114 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include "libzt.h"
char *msg = (char*)"welcome to the machine";
uint64_t generate_adhoc_nwid_from_port(int port)
{
std::string padding;
if(port < 10) {
padding = "000";
} else if(port < 100) {
padding = "00";
} else if(port < 1000) {
padding = "0";
}
// We will join ad-hoc network ffSSSSEEEE000000
// Where SSSS = start port
// EEEE = end port
padding = padding + std::to_string(port); // SSSS
std::string nwidstr = "ff" + padding + padding + "000000"; // ff + SSSS + EEEE + 000000
return strtoull(nwidstr.c_str(), NULL, 16);
}
int main(int argc, char **argv)
{
if (argc != 5) {
printf("\nlibzt example client\n");
printf("client [config_file_path] [nwid] [remote_addr] [remote_port]\n");
exit(0);
}
std::string path = argv[1];
std::string nwidstr = argv[2];
std::string remote_addr = argv[3];
int remote_port = atoi(argv[4]);
int r=0, w=0, err=0, sockfd;
char rbuf[32];
memset(rbuf, 0, sizeof rbuf);
struct sockaddr_in6 in6;
in6.sin6_port = htons(remote_port);
inet_pton(AF_INET6, remote_addr.c_str(), &(in6.sin6_addr));
in6.sin6_family = AF_INET6;
// --- BEGIN EXAMPLE CODE
printf("Waiting for libzt to come online...\n");
uint64_t nwid = generate_adhoc_nwid_from_port(remote_port);
printf("nwid=%llx\n", (unsigned long long)nwid);
zts_startjoin(path.c_str(), nwid);
uint64_t nodeId = zts_get_node_id();
printf("I am %llx\n", (unsigned long long)nodeId);
if ((sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket\n");
}
if ((err = zts_connect(sockfd, (const struct sockaddr *)&in6, sizeof(in6))) < 0) {
printf("error connecting to remote host (%d)\n", err);
}
printf("sending to server...\n");
w = zts_write(sockfd, msg, strlen(msg));
printf("reading from server...\n");
r = zts_read(sockfd, rbuf, strlen(msg));
printf("Sent : %s\n", msg);
printf("Received : %s\n", rbuf);
err = zts_close(sockfd);
return err;
}

View File

@@ -1,127 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include "libzt.h"
uint64_t generate_adhoc_nwid_from_port(int port)
{
std::string padding;
if(port < 10) {
padding = "000";
} else if(port < 100) {
padding = "00";
} else if(port < 1000) {
padding = "0";
}
// We will join ad-hoc network ffSSSSEEEE000000
// Where SSSS = start port
// EEEE = end port
padding = padding + std::to_string(port); // SSSS
std::string nwidstr = "ff" + padding + padding + "000000"; // ff + SSSS + EEEE + 000000
return strtoull(nwidstr.c_str(), NULL, 16);
}
int main(int argc, char **argv)
{
if (argc != 4) {
printf("\nlibzt example server\n");
printf("server [config_file_path] [bind_port]\n");
exit(0);
}
std::string path = argv[1];
int bind_port = atoi(argv[2]);
uint64_t nwid = generate_adhoc_nwid_from_port(bind_port);
int w=0, r=0, err=0, sockfd, accfd;
char rbuf[32];
memset(rbuf, 0, sizeof rbuf);
struct sockaddr_in6 in6, acc_in6;
in6.sin6_port = htons(bind_port);
in6.sin6_family = AF_INET6;
in6.sin6_addr = in6addr_any;
fprintf(stderr, "nwid=%llx\n", (unsigned long long)nwid);
exit(-1);
// --- BEGIN EXAMPLE CODE
printf("Waiting for libzt to come online...\n");
nwid = generate_adhoc_nwid_from_port(bind_port);
printf("nwid=%llx\n", (unsigned long long)nwid);
zts_startjoin(path.c_str(), nwid);
uint64_t nodeId = zts_get_node_id();
printf("I am %llx\n", (unsigned long long)nodeId);
if ((sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket\n");
}
if ((err = zts_bind(sockfd, (struct sockaddr *)&in6, sizeof(struct sockaddr_in6)) < 0)) {
printf("error binding to interface (%d)\n", err);
}
if ((err = zts_listen(sockfd, 100)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
}
socklen_t client_addrlen = sizeof(sockaddr_in6);
if ((accfd = zts_accept(sockfd, (struct sockaddr *)&acc_in6, &client_addrlen)) < 0) {
printf("error accepting connection (%d)\n", err);
}
socklen_t peer_addrlen = sizeof(struct sockaddr_storage);
zts_getpeername(accfd, (struct sockaddr*)&acc_in6, &peer_addrlen);
//printf("accepted connection from %s : %d", inet_ntoa(acc_in6.sin6_addr), ntohs(acc_in6.sin6_port));
printf("reading from client...\n");
r = zts_read(accfd, rbuf, sizeof rbuf);
printf("sending to client...\n");
w = zts_write(accfd, rbuf, strlen(rbuf));
printf("Received : %s\n", rbuf);
err = zts_close(sockfd);
err = zts_close(accfd);
return err;
}

View File

@@ -1,96 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include "libzt.h"
char *msg = (char*)"welcome to the machine";
int main(int argc, char **argv)
{
if (argc != 5) {
printf("\nlibzt example client\n");
printf("client [config_file_path] [nwid] [remote_addr] [remote_port]\n");
exit(0);
}
std::string path = argv[1];
std::string nwidstr = argv[2];
std::string remote_addr = argv[3];
int remote_port = atoi(argv[4]);
int r=0, w=0, err=0, sockfd;
char rbuf[32];
memset(rbuf, 0, sizeof rbuf);
struct sockaddr_in6 in6;
in6.sin6_port = htons(remote_port);
inet_pton(AF_INET6, remote_addr.c_str(), &(in6.sin6_addr));
in6.sin6_family = AF_INET6;
// --- BEGIN EXAMPLE CODE
printf("Waiting for libzt to come online...\n");
uint64_t nwid = strtoull(nwidstr.c_str(),NULL,16);
printf("nwid=%llx\n", (unsigned long long)nwid);
zts_startjoin(path.c_str(), nwid);
uint64_t nodeId = zts_get_node_id();
printf("I am %llx\n", (unsigned long long)nodeId);
if ((sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket\n");
}
if ((err = zts_connect(sockfd, (const struct sockaddr *)&in6, sizeof(in6))) < 0) {
printf("error connecting to remote host (%d)\n", err);
}
printf("sending to server...\n");
w = zts_write(sockfd, msg, strlen(msg));
printf("reading from server...\n");
r = zts_read(sockfd, rbuf, strlen(msg));
printf("Sent : %s\n", msg);
printf("Received : %s\n", rbuf);
err = zts_close(sockfd);
return err;
}

View File

@@ -1,106 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include "libzt.h"
int main(int argc, char **argv)
{
if (argc != 4) {
printf("\nlibzt example server\n");
printf("server [config_file_path] [nwid] [bind_port]\n");
exit(0);
}
std::string path = argv[1];
std::string nwidstr = argv[2];
int bind_port = atoi(argv[3]);
int w=0, r=0, err=0, sockfd, accfd;
char rbuf[32];
memset(rbuf, 0, sizeof rbuf);
struct sockaddr_in6 in6, acc_in6;
in6.sin6_port = htons(bind_port);
in6.sin6_family = AF_INET6;
in6.sin6_addr = in6addr_any;
// --- BEGIN EXAMPLE CODE
printf("Waiting for libzt to come online...\n");
uint64_t nwid = strtoull(nwidstr.c_str(),NULL,16);
printf("nwid=%llx\n", (unsigned long long)nwid);
zts_startjoin(path.c_str(), nwid);
uint64_t nodeId = zts_get_node_id();
printf("I am %llx\n", (unsigned long long)nodeId);
if ((sockfd = zts_socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket\n");
}
if ((err = zts_bind(sockfd, (struct sockaddr *)&in6, sizeof(struct sockaddr_in6)) < 0)) {
printf("error binding to interface (%d)\n", err);
}
if ((err = zts_listen(sockfd, 100)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
}
socklen_t client_addrlen = sizeof(sockaddr_in6);
if ((accfd = zts_accept(sockfd, (struct sockaddr *)&acc_in6, &client_addrlen)) < 0) {
printf("error accepting connection (%d)\n", err);
}
socklen_t peer_addrlen = sizeof(struct sockaddr_storage);
zts_getpeername(accfd, (struct sockaddr*)&acc_in6, &peer_addrlen);
//DEBUG_INFO("accepted connection from %s : %d", inet_ntoa(acc_in6.sin6_addr), ntohs(acc_in6.sin6_port));
printf("reading from client...\n");
r = zts_read(accfd, rbuf, sizeof rbuf);
printf("sending to client...\n");
w = zts_write(accfd, rbuf, strlen(rbuf));
printf("Received : %s\n", rbuf);
err = zts_close(sockfd);
err = zts_close(accfd);
return err;
}

View File

@@ -0,0 +1,303 @@
/**
* libzt API example
*/
/**
*
* IDENTITIES and AUTHORIZATION:
*
* - Upon the first execution of this code, a new identity will be generated and placed in
* the location given in the first argument to zts_start(path, ...). If you accidentally
* duplicate the identity files and use them simultaneously in a different node instance
* you will experience undefined behavior and it is likely nothing will work.
*
* - You must authorize the node ID provided by the ZTS_EVENT_NODE_ONLINE callback to join
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - Exceptions to the above rule are:
* 1) Joining a public network (such as "earth")
* 2) Joining an Ad-hoc network, (no controller and therefore requires no authorization.)
*
*
* ESTABLISHING A CONNECTION:
*
* - Creating a standard socket connection generally works the same as it would using
* an ordinary socket interface, however with libzt there is a subtle difference in
* how connections are established which may cause confusion:
*
* The underlying virtual ZT layer creates what are called "transport-triggered links"
* between nodes. That is, links are not established until an attempt to communicate
* with a peer has taken place. The side effect is that the first few packets sent from
* a libzt instance are usually relayed via our free infrastructure and it isn't until a
* root server has passed contact information to both peers that a direct connection will be
* established. Therefore, it is required that multiple connection attempts be undertaken
* when initially communicating with a peer. After a transport-triggered link is
* established libzt will inform you via ZTS_EVENT_PEER_DIRECT for a specific peer ID. No
* action is required on your part for this callback event.
*
* Note: In these initial moments before ZTS_EVENT_PEER_DIRECT has been received for a
* specific peer, traffic may be slow, jittery and there may be high packet loss.
* This will subside within a couple of seconds.
*
*
* ERROR HANDLING:
*
* - libzt's API is actually composed of two categories of functions with slightly
* different error reporting mechanisms.
*
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* ZTS_ERR_OK // No error
* ZTS_ERR_SOCKET // Socket error, see zts_errno
* ZTS_ERR_SERVICE // You probably did something at the wrong time
* ZTS_ERR_ARG // Invalid argument
* ZTS_ERR_NO_RESULT // No result (not necessarily an error)
* ZTS_ERR_GENERAL // Consider filing a bug report
*
* Category 2: Sockets (zts_socket, zts_bind, zts_connect, zts_listen, etc).
* Errors returned by these functions can be the same as the above. With
* the added possibility of zts_errno being set. Much like standard
* errno this will provide a more specific reason for an error's occurrence.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - While the ZeroTier socket interface can coexist with your host OS's own interface in
* the same file with no type and naming conflicts, try not to mix and match host
* OS/libzt structures, functions, or constants. It may look similar and may even work
* some of the time but there enough differences that it will cause headaches. Here
* are a few guidelines:
*
* If you are calling a zts_* function, use the appropriate ZTS_* constants:
*
* zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
* zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
*
* If you are calling a zts_* function, use the appropriate zts_* structure:
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "ZeroTierSockets.h"
struct Node
{
Node() : online(false), joinedAtLeastOneNetwork(false), id(0) {}
bool online;
bool joinedAtLeastOneNetwork;
uint64_t id;
// etc
} myNode;
/* Callback handler, you should return control from this function as quickly as you can
to ensure timely receipt of future events. You should not call libzt API functions from
this function unless it's something trivial like zts_inet_ntop() or similar that has
no state-change implications. */
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
myNode.id = msg->node->address;
myNode.online = true;
}
if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) {
printf("ZTS_EVENT_NODE_OFFLINE --- Check your physical Internet connection, router, firewall, etc. What ports are you blocking?\n");
myNode.online = false;
}
if (msg->eventCode == ZTS_EVENT_NODE_NORMAL_TERMINATION) {
printf("ZTS_EVENT_NODE_NORMAL_TERMINATION\n");
myNode.online = false;
}
// Virtual network events
if (msg->eventCode == ZTS_EVENT_NETWORK_NOT_FOUND) {
printf("ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQ_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQ_CONFIG --- Requesting config for network %llx, please wait a few seconds...\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
printf("ZTS_EVENT_NETWORK_ACCESS_DENIED --- Access to virtual network %llx has been denied. Did you authorize the node yet?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP4) {
printf("ZTS_EVENT_NETWORK_READY_IP4 --- Network config received. IPv4 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
printf("ZTS_EVENT_NETWORK_READY_IP6 --- Network config received. IPv6 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_DOWN) {
printf("ZTS_EVENT_NETWORK_DOWN --- %llx\n", msg->network->nwid);
}
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP4 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP6 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP4 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP6 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
// Peer events
if (msg->peer) {
if (msg->peer->role == ZTS_PEER_ROLE_PLANET) {
/* Safe to ignore, these are our roots. They orchestrate the P2P connection.
You might also see other unknown peers, these are our network controllers. */
return;
}
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- A direct path is known for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
printf("ZTS_EVENT_PEER_RELAY --- No direct path to node=%llx\n", msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DISCOVERED) {
printf("ZTS_EVENT_PEER_PATH_DISCOVERED --- A new direct path was discovered for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DEAD) {
printf("ZTS_EVENT_PEER_PATH_DEAD --- A direct path has died for node=%llx\n",
msg->peer->address);
}
}
}
int main(int argc, char **argv)
{
if (argc != 6) {
printf("\nlibzt example non-blocking client\n");
printf("nonblockingclient <config_file_path> <nwid> <remoteAddr> <remotePort> <ztServicePort>\n");
exit(0);
}
uint64_t nwid = strtoull(argv[2],NULL,16); // Network ID to join
std::string remoteAddr = argv[3]; // Remote application's virtual ZT address
int remotePort = atoi(argv[4]); // Port the application will try to connect to the server on
int ztServicePort = atoi(argv[5]); // Port ZT uses to send encrypted UDP packets to peers (try something like 9994)
struct zts_sockaddr_in in4;
in4.sin_port = zts_htons(remotePort);
#if defined(_WIN32)
in4.sin_addr.S_addr = zts_inet_addr(remoteAddr.c_str());
#else
in4.sin_addr.s_addr = zts_inet_addr(remoteAddr.c_str());
#endif
in4.sin_family = ZTS_AF_INET;
// Bring up ZeroTier service and join network
int err = ZTS_ERR_OK;
// If disabled: (network) details will NOT be written to or read from (networks.d/). It may take slightly longer to start the node
zts_allow_network_caching(1);
// If disabled: (peer) details will NOT be written to or read from (peers.d/). It may take slightly longer to contact a remote peer
zts_allow_peer_caching(1);
// If disabled: Settings will NOT be read from local.conf
zts_allow_local_conf(1);
if((err = zts_start(argv[1], &myZeroTierEventCallback, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (!myNode.online) { zts_delay_ms(50); }
printf("This node's identity is stored in %s\n", argv[1]);
if((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (!myNode.joinedAtLeastOneNetwork) { zts_delay_ms(50); }
// Socket-like API example
char *msgStr = (char*)"Welcome to the machine";
int bytes=0, fd;
char recvBuf[128];
memset(recvBuf, 0, sizeof(recvBuf));
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
printf("Error creating ZeroTier socket (fd=%d, zts_errno=%d). Exiting.\n", fd, zts_errno);
exit(1);
}
// Retries are often required since ZT uses transport-triggered links (explained above)
for (;;) {
printf("Connecting to remote host...\n");
if ((err = zts_connect(fd, (const struct zts_sockaddr *)&in4, sizeof(in4))) < 0) {
printf("Error connecting to remote host (fd=%d, ret=%d, zts_errno=%d). Trying again.\n",
fd, err, zts_errno);
zts_close(fd);
printf("Creating socket...\n");
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
printf("Error creating ZeroTier socket (fd=%d, zts_errno=%d). Exiting.\n", fd, zts_errno);
exit(1);
}
zts_delay_ms(250);
}
else {
printf("Connected.\n");
break;
}
}
// Wait random intervals to send a message to the server
// The non-blocking aspect of this example is server-side
while(1) {
if((bytes = zts_send(fd, msgStr, strlen(msgStr), 0)) < 0) {
printf("Error writing to socket (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, bytes, zts_errno);
exit(1);
}
printf("zts_send()=%d\n", bytes);
zts_delay_ms((rand() % 100) * 50);
}
printf("Read %d bytes: %s\n", bytes, recvBuf);
printf("Closing socket\n");
zts_close(fd);
printf("Shutting down service\n");
zts_stop();
return 0;
}

View File

@@ -0,0 +1,363 @@
/**
* libzt API example
*/
/**
*
* IDENTITIES and AUTHORIZATION:
*
* - Upon the first execution of this code, a new identity will be generated and placed in
* the location given in the first argument to zts_start(path, ...). If you accidentally
* duplicate the identity files and use them simultaneously in a different node instance
* you will experience undefined behavior and it is likely nothing will work.
*
* - You must authorize the node ID provided by the ZTS_EVENT_NODE_ONLINE callback to join
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - Exceptions to the above rule are:
* 1) Joining a public network (such as "earth")
* 2) Joining an Ad-hoc network, (no controller and therefore requires no authorization.)
*
*
* ESTABLISHING A CONNECTION:
*
* - Creating a standard socket connection generally works the same as it would using
* an ordinary socket interface, however with libzt there is a subtle difference in
* how connections are established which may cause confusion:
*
* The underlying virtual ZT layer creates what are called "transport-triggered links"
* between nodes. That is, links are not established until an attempt to communicate
* with a peer has taken place. The side effect is that the first few packets sent from
* a libzt instance are usually relayed via our free infrastructure and it isn't until a
* root server has passed contact information to both peers that a direct connection will be
* established. Therefore, it is required that multiple connection attempts be undertaken
* when initially communicating with a peer. After a transport-triggered link is
* established libzt will inform you via ZTS_EVENT_PEER_DIRECT for a specific peer ID. No
* action is required on your part for this callback event.
*
* Note: In these initial moments before ZTS_EVENT_PEER_DIRECT has been received for a
* specific peer, traffic may be slow, jittery and there may be high packet loss.
* This will subside within a couple of seconds.
*
*
* ERROR HANDLING:
*
* - libzt's API is actually composed of two categories of functions with slightly
* different error reporting mechanisms.
*
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* ZTS_ERR_OK // No error
* ZTS_ERR_SOCKET // Socket error, see zts_errno
* ZTS_ERR_SERVICE // You probably did something at the wrong time
* ZTS_ERR_ARG // Invalid argument
* ZTS_ERR_NO_RESULT // No result (not necessarily an error)
* ZTS_ERR_GENERAL // Consider filing a bug report
*
* Category 2: Sockets (zts_socket, zts_bind, zts_connect, zts_listen, etc).
* Errors returned by these functions can be the same as the above. With
* the added possibility of zts_errno being set. Much like standard
* errno this will provide a more specific reason for an error's occurrence.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - While the ZeroTier socket interface can coexist with your host OS's own interface in
* the same file with no type and naming conflicts, try not to mix and match host
* OS/libzt structures, functions, or constants. It may look similar and may even work
* some of the time but there enough differences that it will cause headaches. Here
* are a few guidelines:
*
* If you are calling a zts_* function, use the appropriate ZTS_* constants:
*
* zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
* zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
*
* If you are calling a zts_* function, use the appropriate zts_* structure:
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ZeroTierSockets.h"
struct Node
{
Node() : online(false), joinedAtLeastOneNetwork(false), id(0) {}
bool online;
bool joinedAtLeastOneNetwork;
uint64_t id;
// etc
} myNode;
/* Callback handler, you should return control from this function as quickly as you can
to ensure timely receipt of future events. You should not call libzt API functions from
this function unless it's something trivial like zts_inet_ntop() or similar that has
no state-change implications. */
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
myNode.id = msg->node->address;
myNode.online = true;
}
if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) {
printf("ZTS_EVENT_NODE_OFFLINE --- Check your physical Internet connection, router, firewall, etc. What ports are you blocking?\n");
myNode.online = false;
}
if (msg->eventCode == ZTS_EVENT_NODE_NORMAL_TERMINATION) {
printf("ZTS_EVENT_NODE_NORMAL_TERMINATION\n");
myNode.online = false;
}
// Virtual network events
if (msg->eventCode == ZTS_EVENT_NETWORK_NOT_FOUND) {
printf("ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQ_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQ_CONFIG --- Requesting config for network %llx, please wait a few seconds...\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
printf("ZTS_EVENT_NETWORK_ACCESS_DENIED --- Access to virtual network %llx has been denied. Did you authorize the node yet?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP4) {
printf("ZTS_EVENT_NETWORK_READY_IP4 --- Network config received. IPv4 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
printf("ZTS_EVENT_NETWORK_READY_IP6 --- Network config received. IPv6 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_DOWN) {
printf("ZTS_EVENT_NETWORK_DOWN --- %llx\n", msg->network->nwid);
}
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP4 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP6 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP4 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP6 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
// Peer events
if (msg->peer) {
if (msg->peer->role == ZTS_PEER_ROLE_PLANET) {
/* Safe to ignore, these are our roots. They orchestrate the P2P connection.
You might also see other unknown peers, these are our network controllers. */
return;
}
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- A direct path is known for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
printf("ZTS_EVENT_PEER_RELAY --- No direct path to node=%llx\n", msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DISCOVERED) {
printf("ZTS_EVENT_PEER_PATH_DISCOVERED --- A new direct path was discovered for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DEAD) {
printf("ZTS_EVENT_PEER_PATH_DEAD --- A direct path has died for node=%llx\n",
msg->peer->address);
}
}
}
int main(int argc, char **argv)
{
if (argc != 5) {
printf("\nlibzt example non-blocking server\n");
printf("nonblockingserver <config_file_path> <nwid> <serverBindPort> <ztServicePort>\n");
exit(0);
}
uint64_t nwid = strtoull(argv[2],NULL,16); // Network ID to join
int serverBindPort = atoi(argv[3]); // Port the application should bind to
int ztServicePort = atoi(argv[4]); // Port ZT uses to send encrypted UDP packets to peers (try something like 9994)
struct zts_sockaddr_in in4, acc_in4;
in4.sin_port = zts_htons(serverBindPort);
#if defined(_WIN32)
in4.sin_addr.S_addr = ZTS_INADDR_ANY;
#else
in4.sin_addr.s_addr = ZTS_INADDR_ANY;
#endif
in4.sin_family = ZTS_AF_INET;
// Bring up ZeroTier service and join network
int fd, accfd;
int err = ZTS_ERR_OK;
// If disabled: (network) details will NOT be written to or read from (networks.d/). It may take slightly longer to start the node
zts_allow_network_caching(1);
// If disabled: (peer) details will NOT be written to or read from (peers.d/). It may take slightly longer to contact a remote peer
zts_allow_peer_caching(1);
// If disabled: Settings will NOT be read from local.conf
zts_allow_local_conf(1);
if((err = zts_start(argv[1], &myZeroTierEventCallback, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (!myNode.online) { zts_delay_ms(50); }
printf("This node ID is %llx\n", myNode.id);
printf("This node's identity is stored in %s\n", argv[1]);
if((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (!myNode.joinedAtLeastOneNetwork) { zts_delay_ms(50); }
// Socket-like API example
printf("Creating socket...\n");
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
printf("Error creating ZeroTier socket (fd=%d, ret=%d, zts_errno=%d). Exiting.\n",fd, err, zts_errno);
exit(1);
}
printf("Binding...\n");
if ((err = zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)) {
printf("Error binding to interface (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, err, zts_errno);
exit(1);
}
printf("Listening...\n");
int backlog = 100;
if ((err = zts_listen(fd, backlog)) < 0) {
printf("Error placing socket in LISTENING state (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, err, zts_errno);
exit(1);
}
zts_socklen_t client_addrlen = sizeof(zts_sockaddr_in);
if ((accfd = zts_accept(fd, (struct zts_sockaddr *)&acc_in4, &client_addrlen)) < 0) {
printf("Error accepting connection (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, err, zts_errno);
}
zts_socklen_t peer_addrlen = sizeof(struct zts_sockaddr_storage);
zts_getpeername(accfd, (struct zts_sockaddr*)&acc_in4, &peer_addrlen);
char ipstr[ZTS_INET_ADDRSTRLEN];
memset(ipstr, 0, sizeof(ipstr));
zts_inet_ntop(ZTS_AF_INET, &(acc_in4.sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("Accepted connection from %s:%d\n", ipstr, zts_ntohs(acc_in4.sin_port));
int bytes=0;
char recvBuf[128];
memset(recvBuf, 0, sizeof(recvBuf));
//
// Technique 1: ZTS_O_NONBLOCK
//
if (false) {
zts_fcntl(fd, ZTS_F_SETFL, ZTS_O_NONBLOCK);
zts_fcntl(accfd, ZTS_F_SETFL, ZTS_O_NONBLOCK);
while(1) {
bytes = zts_recv(accfd, recvBuf, sizeof(recvBuf), 0);
printf("zts_recv(%d, ...)=%d\n", accfd, bytes);
zts_delay_ms(100);
}
}
//
// Technique 2: zts_select
//
if (false) {
struct zts_timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 50000;
int result = 0;
zts_fd_set active_fd_set, read_fd_set;
ZTS_FD_ZERO(&active_fd_set);
ZTS_FD_SET(accfd, &active_fd_set);
while (1)
{
read_fd_set = active_fd_set;
if ((result = zts_select(ZTS_FD_SETSIZE, &read_fd_set, NULL, NULL, &tv) < 0))
{
//perror ("select");
exit (1);
}
for (int i=0; i<ZTS_FD_SETSIZE; i++) {
if (ZTS_FD_ISSET(i, &read_fd_set))
{
bytes = zts_recv(accfd, recvBuf, sizeof(recvBuf), 0);
printf("zts_recv(%d, ...)=%d\n", i, bytes);
}
//ZTS_FD_CLR(i, &active_fd_set);
}
}
}
//
// Technique 3: zts_poll
//
if (true) {
int numfds = 0;
struct zts_pollfd poll_set[16];
memset(poll_set, '\0', sizeof(poll_set));
poll_set[0].fd = accfd;
poll_set[0].events = ZTS_POLLIN;
numfds++;
int result = 0;
int timeout_ms = 50;
while(1) {
result = zts_poll(poll_set, numfds, timeout_ms);
printf("zts_poll()=%d\n", result);
for(int i = 0; i < numfds; i++)
{
if(poll_set[i].revents & ZTS_POLLIN) {
bytes = zts_recv(poll_set[i].fd, recvBuf, sizeof(recvBuf), 0);
printf("zts_recv(%d, ...)=%d\n", i, bytes);
}
}
}
}
printf("Closing listen socket\n");
err = zts_close(fd);
printf("Shutting down service\n");
zts_stop();
return 0;
}

309
examples/cpp/server.cpp Normal file
View File

@@ -0,0 +1,309 @@
/**
* libzt API example
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "ZeroTierSockets.h"
struct Node
{
Node() : online(false), joinedAtLeastOneNetwork(false), id(0) {}
bool online;
bool joinedAtLeastOneNetwork;
uint64_t id;
// etc
} myNode;
/* Callback handler, you should return control from this function as quickly as you can
to ensure timely receipt of future events. You should not call libzt API functions from
this function unless it's something trivial like zts_inet_ntop() or similar that has
no state-change implications. */
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
myNode.id = msg->node->address;
myNode.online = true;
}
if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) {
printf("ZTS_EVENT_NODE_OFFLINE --- Check your physical Internet connection, router, firewall, etc. What ports are you blocking?\n");
myNode.online = false;
}
if (msg->eventCode == ZTS_EVENT_NODE_NORMAL_TERMINATION) {
printf("ZTS_EVENT_NODE_NORMAL_TERMINATION\n");
}
// Virtual network events
if (msg->eventCode == ZTS_EVENT_NETWORK_NOT_FOUND) {
printf("ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQ_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQ_CONFIG --- Requesting config for network %llx, please wait a few seconds...\n", msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
printf("ZTS_EVENT_NETWORK_ACCESS_DENIED --- Access to virtual network %llx has been denied. Did you authorize the node yet?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP4) {
printf("ZTS_EVENT_NETWORK_READY_IP4 --- Network config received. IPv4 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
printf("ZTS_EVENT_NETWORK_READY_IP6 --- Network config received. IPv6 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_DOWN) {
printf("ZTS_EVENT_NETWORK_DOWN --- %llx\n", msg->network->nwid);
}
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP4 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP6 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP4 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP6 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
// Peer events
if (msg->peer) {
if (msg->peer->role == ZTS_PEER_ROLE_PLANET) {
/* Safe to ignore, these are our roots. They orchestrate the P2P connection.
You might also see other unknown peers, these are our network controllers. */
return;
}
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- A direct path is known for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
printf("ZTS_EVENT_PEER_RELAY --- No direct path to node=%llx\n", msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DISCOVERED) {
printf("ZTS_EVENT_PEER_PATH_DISCOVERED --- A new direct path was discovered for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DEAD) {
printf("ZTS_EVENT_PEER_PATH_DEAD --- A direct path has died for node=%llx\n",
msg->peer->address);
}
}
}
/**
*
* IDENTITIES and AUTHORIZATION:
*
* - Upon the first execution of this code, a new identity will be generated and placed in
* the location given in the first argument to zts_start(path, ...). If you accidentally
* duplicate the identity files and use them simultaneously in a different node instance
* you will experience undefined behavior and it is likely nothing will work.
*
* - You must authorize the node ID provided by the ZTS_EVENT_NODE_ONLINE callback to join
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - Exceptions to the above rule are:
* 1) Joining a public network (such as "earth")
* 2) Joining an Ad-hoc network, (no controller and therefore requires no authorization.)
*
*
* ESTABLISHING A CONNECTION:
*
* - Creating a standard socket connection generally works the same as it would using
* an ordinary socket interface, however with libzt there is a subtle difference in
* how connections are established which may cause confusion:
*
* The underlying virtual ZT layer creates what are called "transport-triggered links"
* between nodes. That is, links are not established until an attempt to communicate
* with a peer has taken place. The side effect is that the first few packets sent from
* a libzt instance are usually relayed via our free infrastructure and it isn't until a
* root server has passed contact information to both peers that a direct connection will be
* established. Therefore, it is required that multiple connection attempts be undertaken
* when initially communicating with a peer. After a transport-triggered link is
* established libzt will inform you via ZTS_EVENT_PEER_DIRECT for a specific peer ID. No
* action is required on your part for this callback event.
*
* Note: In these initial moments before ZTS_EVENT_PEER_DIRECT has been received for a
* specific peer, traffic may be slow, jittery and there may be high packet loss.
* This will subside within a couple of seconds.
*
*
* ERROR HANDLING:
*
* - libzt's API is actually composed of two categories of functions with slightly
* different error reporting mechanisms.
*
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* ZTS_ERR_OK // No error
* ZTS_ERR_SOCKET // Socket error, see zts_errno
* ZTS_ERR_SERVICE // You probably did something at the wrong time
* ZTS_ERR_ARG // Invalid argument
* ZTS_ERR_NO_RESULT // No result (not necessarily an error)
* ZTS_ERR_GENERAL // Consider filing a bug report
*
* Category 2: Sockets (zts_socket, zts_bind, zts_connect, zts_listen, etc).
* Errors returned by these functions can be the same as the above. With
* the added possibility of zts_errno being set. Much like standard
* errno this will provide a more specific reason for an error's occurrence.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - While the ZeroTier socket interface can coexist with your host OS's own interface in
* the same file with no type and naming conflicts, try not to mix and match host
* OS/libzt structures, functions, or constants. It may look similar and may even work
* some of the time but there enough differences that it will cause headaches. Here
* are a few guidelines:
*
* If you are calling a zts_* function, use the appropriate ZTS_* constants:
*
* zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
* zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
*
* If you are calling a zts_* function, use the appropriate zts_* structure:
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
*/
int main(int argc, char **argv)
{
if (argc != 5) {
printf("\nlibzt example server\n");
printf("server <config_file_path> <nwid> <serverBindPort> <ztServicePort>\n");
exit(0);
}
uint64_t nwid = strtoull(argv[2],NULL,16); // Network ID to join
int serverBindPort = atoi(argv[3]); // Port the application should bind to
int ztServicePort = atoi(argv[4]); // Port ZT uses to send encrypted UDP packets to peers (try something like 9994)
struct zts_sockaddr_in in4, acc_in4;
in4.sin_port = zts_htons(serverBindPort);
#if defined(_WIN32)
in4.sin_addr.S_addr = ZTS_INADDR_ANY;
#else
in4.sin_addr.s_addr = ZTS_INADDR_ANY;
#endif
in4.sin_family = ZTS_AF_INET;
// Bring up ZeroTier service and join network
int fd, accfd;
int err = ZTS_ERR_OK;
// If disabled: (network) details will NOT be written to or read from (networks.d/). It may take slightly longer to start the node
zts_allow_network_caching(1);
// If disabled: (peer) details will NOT be written to or read from (peers.d/). It may take slightly longer to contact a remote peer
zts_allow_peer_caching(1);
// If disabled: Settings will NOT be read from local.conf
zts_allow_local_conf(1);
if((err = zts_start(argv[1], &myZeroTierEventCallback, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (!myNode.online) { zts_delay_ms(50); }
printf("This node's identity is stored in %s\n", argv[1]);
if((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (!myNode.joinedAtLeastOneNetwork) { zts_delay_ms(50); }
// Socket-like API example
printf("Creating socket...\n");
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
printf("Error creating ZeroTier socket (fd=%d, ret=%d, zts_errno=%d). Exiting.\n",fd, err, zts_errno);
exit(1);
}
printf("Binding...\n");
if ((err = zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)) {
printf("Error binding to interface (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, err, zts_errno);
exit(1);
}
printf("Listening...\n");
int backlog = 100;
if ((err = zts_listen(fd, backlog)) < 0) {
printf("Error placing socket in LISTENING state (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, err, zts_errno);
exit(1);
}
int bytes=0;
char recvBuf[128];
memset(recvBuf, 0, sizeof(recvBuf));
while (true) {
zts_socklen_t client_addrlen = sizeof(zts_sockaddr_in);
if ((accfd = zts_accept(fd, (struct zts_sockaddr *)&acc_in4, &client_addrlen)) < 0) {
printf("Error accepting connection (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, err, zts_errno);
}
zts_socklen_t peer_addrlen = sizeof(struct zts_sockaddr_storage);
zts_getpeername(accfd, (struct zts_sockaddr*)&acc_in4, &peer_addrlen);
char ipstr[ZTS_INET_ADDRSTRLEN];
memset(ipstr, 0, sizeof(ipstr));
zts_inet_ntop(ZTS_AF_INET, &(acc_in4.sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("Accepted connection from %s:%d\n", ipstr, zts_ntohs(acc_in4.sin_port));
printf("Reading message string from client...\n");
if((bytes = zts_read(accfd, recvBuf, sizeof(recvBuf))) < 0) {
printf("Error writing to socket (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, bytes, zts_errno);
exit(1);
}
printf("Read %d bytes: %s\n", bytes, recvBuf);
printf("Sending message string to client...\n");
if((bytes = zts_write(accfd, recvBuf, bytes)) < 0) {
printf("Error writing to socket (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, bytes, zts_errno);
exit(1);
}
printf("Sent %d bytes: %s\n", bytes, recvBuf);
printf("Closing connection socket\n");
err = zts_close(accfd);
}
printf("Closing listen socket\n");
err = zts_close(fd);
printf("Shutting down service\n");
zts_stop();
return 0;
}

View File

@@ -1,215 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
#if !defined(_MSC_VER)
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <dlfcn.h>
#include "libzt.h"
// function pointers which will have values assigned once the dynamic library is loaded
int (*_zts_set_service_port)(int portno);
int (*_zts_start)(const char *path, bool blocking);
int (*_zts_startjoin)(const char*, uint64_t);
void (*_zts_stop)(void);
int (*_zts_core_running)(void);
int (*_zts_stack_running)(void);
int (*_zts_ready)(void);
int (*_zts_join)(const uint64_t);
int (*_zts_leave)(const uint64_t);
void (*_zts_get_path)(char *homePath, const size_t len);
uint64_t (*_zts_get_node_id)(void);
int (*_zts_has_address)(const uint64_t);
int (*_zts_get_num_assigned_addresses)(const uint64_t nwid);
int (*_zts_get_address_at_index)(const uint64_t nwid, const int index, struct sockaddr_storage *addr);
int (*_zts_get_address)(const uint64_t nwid, struct sockaddr_storage *addr, const int address_family);
void (*_zts_get_6plane_addr)(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId);
void (*_zts_get_rfc4193_addr)(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId);
unsigned long (*_zts_get_peer_count)(void);
int (*_zts_get_peer_address)(char *peer, const uint64_t nodeId);
int (*_zts_socket)(int socket_family, int socket_type, int protocol);
int (*_zts_connect)(int fd, const struct sockaddr *addr, socklen_t addrlen);
int (*_zts_bind)(int fd, const struct sockaddr *addr, socklen_t addrlen);
int (*_zts_listen)(int fd, int backlog);
int (*_zts_accept)(int fd, struct sockaddr *addr, socklen_t *addrlen);
#if defined(__linux__)
int (*_zts_accept4)(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags);
#endif
int (*_zts_setsockopt)(int fd, int level, int optname, const void *optval, socklen_t optlen);
int (*_zts_getsockopt)(int fd, int level, int optname, void *optval, socklen_t *optlen);
int (*_zts_getsockname)(int fd, struct sockaddr *addr, socklen_t *addrlen);
int (*_zts_getpeername)(int fd, struct sockaddr *addr, socklen_t *addrlen);
int (*_zts_gethostname)(char *name, size_t len);
int (*_zts_sethostname)(const char *name, size_t len);
struct hostent *(*_zts_gethostbyname)(const char *name);
int (*_zts_close)(int fd);
int(*_zts_fcntl)(int fd, int cmd, int flags);
int (*_zts_ioctl)(int fd, unsigned long request, void *argp);
ssize_t (*_zts_send)(int fd, const void *buf, size_t len, int flags);
ssize_t (*_zts_sendto)(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen);
ssize_t (*_zts_sendmsg)(int fd, const struct msghdr *msg, int flags);
ssize_t (*_zts_recv)(int fd, void *buf, size_t len, int flags);
ssize_t (*_zts_recvfrom)(int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen);
ssize_t (*_zts_recvmsg)(int fd, struct msghdr *msg,int flags);
int (*_zts_read)(int fd, void *buf, size_t len);
int (*_zts_write)(int fd, const void *buf, size_t len);
int (*_zts_shutdown)(int fd, int how);
int (*_zts_add_dns_nameserver)(struct sockaddr *addr);
int (*_zts_del_dns_nameserver)(struct sockaddr *addr);
void load_library_symbols(char *library_path)
{
void *libHandle = dlopen(library_path, RTLD_LAZY);
if (libHandle == NULL) {
DEBUG_ERROR("unable to load dynamic libs: %s", dlerror());
exit(-1);
}
// Load symbols from library (call these directly)
_zts_set_service_port = (int(*)(int portno))dlsym(libHandle, "zts_set_service_port");
_zts_start = (int(*)(const char *path, bool blocking))dlsym(libHandle, "zts_start");
_zts_startjoin = (int(*)(const char*, uint64_t))dlsym(libHandle, "zts_startjoin");
_zts_stop = (void(*)(void))dlsym(libHandle, "zts_stop");
_zts_core_running = (int(*)(void))dlsym(libHandle, "zts_core_running");
_zts_stack_running = (int(*)(void))dlsym(libHandle, "zts_stack_running");
_zts_ready = (int(*)(void))dlsym(libHandle, "zts_ready");
_zts_join = (int(*)(const uint64_t))dlsym(libHandle, "zts_join");
_zts_leave = (int(*)(const uint64_t))dlsym(libHandle, "zts_leave");
_zts_get_path = (void(*)(char *homePath, const size_t len))dlsym(libHandle, "zts_get_path");
_zts_get_node_id = (uint64_t(*)(void))dlsym(libHandle, "zts_get_node_id");
_zts_has_address = (int(*)(const uint64_t))dlsym(libHandle, "zts_has_address");
_zts_get_num_assigned_addresses = (int(*)(const uint64_t nwid))dlsym(libHandle, "zts_get_num_assigned_addresses");
_zts_get_address_at_index = (int(*)(const uint64_t nwid, const int index, struct sockaddr_storage *addr))dlsym(libHandle, "zts_get_address_at_index");
_zts_get_address = (int(*)(const uint64_t nwid, struct sockaddr_storage *addr, const int address_family))dlsym(libHandle, "zts_get_address");
_zts_get_6plane_addr = (void(*)(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId))dlsym(libHandle, "zts_get_6plane_addr");
_zts_get_rfc4193_addr = (void(*)(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId))dlsym(libHandle, "zts_get_rfc4193_addr");
_zts_get_peer_count = (unsigned long(*)(void))dlsym(libHandle, "zts_get_peer_count");
_zts_get_peer_address = (int(*)(char *peer, const uint64_t nodeId))dlsym(libHandle, "zts_get_peer_address");
_zts_socket = (int(*)(int socket_family, int socket_type, int protocol))dlsym(libHandle, "zts_socket");
_zts_connect = (int(*)(int fd, const struct sockaddr *addr, socklen_t addrlen))dlsym(libHandle, "zts_connect");
_zts_bind = (int(*)(int fd, const struct sockaddr *addr, socklen_t addrlen))dlsym(libHandle, "zts_bind");
_zts_listen = (int(*)(int fd, int backlog))dlsym(libHandle, "zts_listen");
_zts_accept = (int(*)(int fd, struct sockaddr *addr, socklen_t *addrlen))dlsym(libHandle, "zts_accept");
#if defined(__linux__)
_zts_accept4 = (int(*)(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags))dlsym(libHandle, "zts_accept4");
#endif
_zts_setsockopt = (int(*)(int fd, int level, int optname, const void *optval, socklen_t optlen))dlsym(libHandle, "zts_setsockopt");
_zts_getsockopt = (int(*)(int fd, int level, int optname, void *optval, socklen_t *optlen))dlsym(libHandle, "zts_getsockopt");
_zts_getsockname = (int(*)(int fd, struct sockaddr *addr, socklen_t *addrlen))dlsym(libHandle, "zts_getsockname");
_zts_getpeername = (int(*)(int fd, struct sockaddr *addr, socklen_t *addrlen))dlsym(libHandle, "zts_getpeername");
_zts_gethostname = (int(*)(char *name, size_t len))dlsym(libHandle, "zts_gethostname");
_zts_sethostname = (int(*)(const char *name, size_t len))dlsym(libHandle, "zts_sethostname");
_zts_gethostbyname = (struct hostent*(*)(const char *name))dlsym(libHandle, "zts_gethostbyname");
_zts_close = (int(*)(int fd))dlsym(libHandle, "zts_close");
_zts_fcntl = (int(*)(int fd, int cmd, int flags))dlsym(libHandle, "zts_fcntl");
_zts_ioctl = (int(*)(int fd, unsigned long request, void *argp))dlsym(libHandle, "zts_ioctl");
_zts_send = (ssize_t(*)(int fd, const void *buf, size_t len, int flags))dlsym(libHandle, "zts_send");
_zts_sendto = (ssize_t(*)(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen))dlsym(libHandle, "zts_sendto");
_zts_sendmsg = (ssize_t(*)(int fd, const struct msghdr *msg, int flags))dlsym(libHandle, "zts_sendmsg");
_zts_recv = (ssize_t(*)(int fd, void *buf, size_t len, int flags))dlsym(libHandle, "zts_recv");
_zts_recvfrom = (ssize_t(*)(int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen))dlsym(libHandle, "zts_recvfrom");
_zts_recvmsg = (ssize_t(*)(int fd, struct msghdr *msg,int flags))dlsym(libHandle, "zts_recvmsg");
_zts_read = (int(*)(int fd, void *buf, size_t len))dlsym(libHandle, "zts_read");
_zts_write = (int(*)(int fd, const void *buf, size_t len))dlsym(libHandle, "zts_write");
_zts_shutdown = (int(*)(int fd, int how))dlsym(libHandle, "zts_shutdown");
_zts_add_dns_nameserver = (int(*)(struct sockaddr *addr))dlsym(libHandle, "zts_add_dns_nameserver");
}
char *msg = (char*)"welcome to the machine";
int main(int argc, char **argv)
{
if (argc != 5) {
printf("\nlibzt example client\n");
printf("client [config_file_path] [nwid] [remote_addr] [remote_port]\n");
exit(0);
}
#ifdef __linux__
char *library_path = (char*)"./libzt.so";
#endif
#ifdef __APPLE__
char *library_path = (char*)"./libzt.dylib";
#endif
load_library_symbols(library_path);
std::string path = argv[1];
std::string nwidstr = argv[2];
std::string remote_addr = argv[3];
int remote_port = atoi(argv[4]);
int r=0, w=0, err=0, sockfd;
char rbuf[32];
memset(rbuf, 0, sizeof rbuf);
struct sockaddr_in in4;
in4.sin_port = htons(remote_port);
in4.sin_addr.s_addr = inet_addr(remote_addr.c_str());
in4.sin_family = AF_INET;
//
printf("Waiting for libzt to come online...\n");
uint64_t nwid = strtoull(nwidstr.c_str(),NULL,16);
printf("nwid=%llx\n", (unsigned long long)nwid);
_zts_startjoin(path.c_str(), nwid);
uint64_t nodeId = _zts_get_node_id();
printf("I am %llx\n", (unsigned long long)nodeId);
if ((sockfd = _zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket\n");
}
if ((err = _zts_connect(sockfd, (const struct sockaddr *)&in4, sizeof(in4))) < 0) {
printf("error connecting to remote host (%d)\n", err);
}
printf("sending to server...\n");
w = _zts_write(sockfd, msg, strlen(msg));
printf("reading from server...\n");
r = _zts_read(sockfd, rbuf, strlen(msg));
printf("Sent : %s\n", msg);
printf("Received : %s\n", rbuf);
err = _zts_close(sockfd);
return err;
}
#endif // _MSC_VER

View File

@@ -1,222 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
#if !defined(_MSC_VER)
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <dlfcn.h>
#include "libzt.h"
// function pointers which will have values assigned once the dynamic library is loaded
int (*_zts_set_service_port)(int portno);
int (*_zts_start)(const char *path, bool blocking);
int (*_zts_startjoin)(const char*, uint64_t);
void (*_zts_stop)(void);
int (*_zts_core_running)(void);
int (*_zts_stack_running)(void);
int (*_zts_ready)(void);
int (*_zts_join)(const uint64_t);
int (*_zts_leave)(const uint64_t);
void (*_zts_get_path)(char *homePath, const size_t len);
uint64_t (*_zts_get_node_id)(void);
int (*_zts_has_address)(const uint64_t);
int (*_zts_get_num_assigned_addresses)(const uint64_t nwid);
int (*_zts_get_address_at_index)(const uint64_t nwid, const int index, struct sockaddr_storage *addr);
int (*_zts_get_address)(const uint64_t nwid, struct sockaddr_storage *addr, const int address_family);
void (*_zts_get_6plane_addr)(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId);
void (*_zts_get_rfc4193_addr)(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId);
unsigned long (*_zts_get_peer_count)(void);
int (*_zts_get_peer_address)(char *peer, const uint64_t nodeId);
int (*_zts_socket)(int socket_family, int socket_type, int protocol);
int (*_zts_connect)(int fd, const struct sockaddr *addr, socklen_t addrlen);
int (*_zts_bind)(int fd, const struct sockaddr *addr, socklen_t addrlen);
int (*_zts_listen)(int fd, int backlog);
int (*_zts_accept)(int fd, struct sockaddr *addr, socklen_t *addrlen);
#if defined(__linux__)
int (*_zts_accept4)(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags);
#endif
int (*_zts_setsockopt)(int fd, int level, int optname, const void *optval, socklen_t optlen);
int (*_zts_getsockopt)(int fd, int level, int optname, void *optval, socklen_t *optlen);
int (*_zts_getsockname)(int fd, struct sockaddr *addr, socklen_t *addrlen);
int (*_zts_getpeername)(int fd, struct sockaddr *addr, socklen_t *addrlen);
int (*_zts_gethostname)(char *name, size_t len);
int (*_zts_sethostname)(const char *name, size_t len);
struct hostent *(*_zts_gethostbyname)(const char *name);
int (*_zts_close)(int fd);
int(*_zts_fcntl)(int fd, int cmd, int flags);
int (*_zts_ioctl)(int fd, unsigned long request, void *argp);
ssize_t (*_zts_send)(int fd, const void *buf, size_t len, int flags);
ssize_t (*_zts_sendto)(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen);
ssize_t (*_zts_sendmsg)(int fd, const struct msghdr *msg, int flags);
ssize_t (*_zts_recv)(int fd, void *buf, size_t len, int flags);
ssize_t (*_zts_recvfrom)(int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen);
ssize_t (*_zts_recvmsg)(int fd, struct msghdr *msg,int flags);
int (*_zts_read)(int fd, void *buf, size_t len);
int (*_zts_write)(int fd, const void *buf, size_t len);
int (*_zts_shutdown)(int fd, int how);
int (*_zts_add_dns_nameserver)(struct sockaddr *addr);
int (*_zts_del_dns_nameserver)(struct sockaddr *addr);
void load_library_symbols(char *library_path)
{
void *libHandle = dlopen(library_path, RTLD_LAZY);
if (libHandle == NULL) {
DEBUG_ERROR("unable to load dynamic libs: %s", dlerror());
exit(-1);
}
// Load symbols from library (call these directly)
_zts_set_service_port = (int(*)(int portno))dlsym(libHandle, "zts_set_service_port");
_zts_start = (int(*)(const char *path, bool blocking))dlsym(libHandle, "zts_start");
_zts_startjoin = (int(*)(const char*, uint64_t))dlsym(libHandle, "zts_startjoin");
_zts_stop = (void(*)(void))dlsym(libHandle, "zts_stop");
_zts_core_running = (int(*)(void))dlsym(libHandle, "zts_core_running");
_zts_stack_running = (int(*)(void))dlsym(libHandle, "zts_stack_running");
_zts_ready = (int(*)(void))dlsym(libHandle, "zts_ready");
_zts_join = (int(*)(const uint64_t))dlsym(libHandle, "zts_join");
_zts_leave = (int(*)(const uint64_t))dlsym(libHandle, "zts_leave");
_zts_get_path = (void(*)(char *homePath, const size_t len))dlsym(libHandle, "zts_get_path");
_zts_get_node_id = (uint64_t(*)(void))dlsym(libHandle, "zts_get_node_id");
_zts_has_address = (int(*)(const uint64_t))dlsym(libHandle, "zts_has_address");
_zts_get_num_assigned_addresses = (int(*)(const uint64_t nwid))dlsym(libHandle, "zts_get_num_assigned_addresses");
_zts_get_address_at_index = (int(*)(const uint64_t nwid, const int index, struct sockaddr_storage *addr))dlsym(libHandle, "zts_get_address_at_index");
_zts_get_address = (int(*)(const uint64_t nwid, struct sockaddr_storage *addr, const int address_family))dlsym(libHandle, "zts_get_address");
_zts_get_6plane_addr = (void(*)(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId))dlsym(libHandle, "zts_get_6plane_addr");
_zts_get_rfc4193_addr = (void(*)(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId))dlsym(libHandle, "zts_get_rfc4193_addr");
_zts_get_peer_count = (unsigned long(*)(void))dlsym(libHandle, "zts_get_peer_count");
_zts_get_peer_address = (int(*)(char *peer, const uint64_t nodeId))dlsym(libHandle, "zts_get_peer_address");
_zts_socket = (int(*)(int socket_family, int socket_type, int protocol))dlsym(libHandle, "zts_socket");
_zts_connect = (int(*)(int fd, const struct sockaddr *addr, socklen_t addrlen))dlsym(libHandle, "zts_connect");
_zts_bind = (int(*)(int fd, const struct sockaddr *addr, socklen_t addrlen))dlsym(libHandle, "zts_bind");
_zts_listen = (int(*)(int fd, int backlog))dlsym(libHandle, "zts_listen");
_zts_accept = (int(*)(int fd, struct sockaddr *addr, socklen_t *addrlen))dlsym(libHandle, "zts_accept");
#if defined(__linux__)
_zts_accept4 = (int(*)(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags))dlsym(libHandle, "zts_accept4");
#endif
_zts_setsockopt = (int(*)(int fd, int level, int optname, const void *optval, socklen_t optlen))dlsym(libHandle, "zts_setsockopt");
_zts_getsockopt = (int(*)(int fd, int level, int optname, void *optval, socklen_t *optlen))dlsym(libHandle, "zts_getsockopt");
_zts_getsockname = (int(*)(int fd, struct sockaddr *addr, socklen_t *addrlen))dlsym(libHandle, "zts_getsockname");
_zts_getpeername = (int(*)(int fd, struct sockaddr *addr, socklen_t *addrlen))dlsym(libHandle, "zts_getpeername");
_zts_gethostname = (int(*)(char *name, size_t len))dlsym(libHandle, "zts_gethostname");
_zts_sethostname = (int(*)(const char *name, size_t len))dlsym(libHandle, "zts_sethostname");
_zts_gethostbyname = (struct hostent*(*)(const char *name))dlsym(libHandle, "zts_gethostbyname");
_zts_close = (int(*)(int fd))dlsym(libHandle, "zts_close");
_zts_fcntl = (int(*)(int fd, int cmd, int flags))dlsym(libHandle, "zts_fcntl");
_zts_ioctl = (int(*)(int fd, unsigned long request, void *argp))dlsym(libHandle, "zts_ioctl");
_zts_send = (ssize_t(*)(int fd, const void *buf, size_t len, int flags))dlsym(libHandle, "zts_send");
_zts_sendto = (ssize_t(*)(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen))dlsym(libHandle, "zts_sendto");
_zts_sendmsg = (ssize_t(*)(int fd, const struct msghdr *msg, int flags))dlsym(libHandle, "zts_sendmsg");
_zts_recv = (ssize_t(*)(int fd, void *buf, size_t len, int flags))dlsym(libHandle, "zts_recv");
_zts_recvfrom = (ssize_t(*)(int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen))dlsym(libHandle, "zts_recvfrom");
_zts_recvmsg = (ssize_t(*)(int fd, struct msghdr *msg,int flags))dlsym(libHandle, "zts_recvmsg");
_zts_read = (int(*)(int fd, void *buf, size_t len))dlsym(libHandle, "zts_read");
_zts_write = (int(*)(int fd, const void *buf, size_t len))dlsym(libHandle, "zts_write");
_zts_shutdown = (int(*)(int fd, int how))dlsym(libHandle, "zts_shutdown");
_zts_add_dns_nameserver = (int(*)(struct sockaddr *addr))dlsym(libHandle, "zts_add_dns_nameserver");
}
int main(int argc, char **argv)
{
if (argc != 4) {
printf("\nlibzt example server\n");
printf("server [config_file_path] [nwid] [bind_port]\n");
exit(0);
}
#ifdef __linux__
char *library_path = (char*)"./libzt.so";
#endif
#ifdef __APPLE__
char *library_path = (char*)"./libzt.dylib";
#endif
load_library_symbols(library_path);
std::string path = argv[1];
std::string nwidstr = argv[2];
int bind_port = atoi(argv[3]);
int w=0, r=0, err=0, sockfd, accfd;
char rbuf[32];
memset(rbuf, 0, sizeof rbuf);
struct sockaddr_in in4, acc_in4;
in4.sin_port = htons(bind_port);
in4.sin_addr.s_addr = INADDR_ANY;
in4.sin_family = AF_INET;
//
printf("Waiting for libzt to come online...\n");
uint64_t nwid = strtoull(nwidstr.c_str(),NULL,16);
printf("nwid=%llx\n", (unsigned long long)nwid);
_zts_startjoin(path.c_str(), nwid);
uint64_t nodeId = _zts_get_node_id();
printf("I am %llx\n", (unsigned long long)nodeId);
if ((sockfd = _zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating ZeroTier socket\n");
}
if ((err = _zts_bind(sockfd, (struct sockaddr *)&in4, sizeof(struct sockaddr_in)) < 0)) {
printf("error binding to interface (%d)\n", err);
}
if ((err = _zts_listen(sockfd, 100)) < 0) {
printf("error placing socket in LISTENING state (%d)\n", err);
}
socklen_t client_addrlen = sizeof(sockaddr_in);
if ((accfd = _zts_accept(sockfd, (struct sockaddr *)&acc_in4, &client_addrlen)) < 0) {
printf("error accepting connection (%d)\n", err);
}
socklen_t peer_addrlen = sizeof(struct sockaddr_storage);
_zts_getpeername(accfd, (struct sockaddr*)&acc_in4, &peer_addrlen);
DEBUG_INFO("accepted connection from %s : %d\n", inet_ntoa(acc_in4.sin_addr), ntohs(acc_in4.sin_port));
printf("reading from client...\n");
r = _zts_read(accfd, rbuf, sizeof rbuf);
printf("sending to client...\n");
w = _zts_write(accfd, rbuf, strlen(rbuf));
printf("Received : %s\n", rbuf);
err = _zts_close(sockfd);
err = _zts_close(accfd);
return err;
}
#endif // _MSC_VER

25
examples/java/README.md Normal file
View File

@@ -0,0 +1,25 @@
### How to compile/use this example:
1. Follow "Building from source" section from README.md in the root of this git repository
(the linking step/example from that section does not apply to this example)
2. Create the java library .jar file:
```
make host_jar_release
```
for other `host_jar` variants see Makefile in the root of this git repository
2. Copy the output .jar to this directory:
```
cp lib/lib/release/linux-x86_64/zt.jar examples/java/simpleExample/
```
3. Now you can compile this example:
```
cd src
javac -cp ../zt.jar ./com/zerotier/libzt/javasimpleexample/*.java
```

View File

@@ -24,43 +24,41 @@
* of your own application.
*/
package com.zerotier.libzt.javasimpleexample;
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierEventListener;
public class ExampleApp
{
static void sleep(int ms)
{
try { Thread.sleep(ms); }
catch (InterruptedException e) { e.printStackTrace(); }
}
public class Main {
public static void main(String[] args)
{
// Set up event listener and start service
MyZeroTierEventListener listener = new MyZeroTierEventListener();
int servicePort = 9994;
ZeroTier.start("test/path", listener, servicePort);
// Wait for EVENT_NODE_ONLINE
System.out.println("waiting for node to come online...");
while (listener.isOnline == false) { sleep(50); }
System.out.println("joinging network");
ZeroTier.join(0x0123456789abcdefL);
// Wait for EVENT_NETWORK_READY_IP4/6
System.out.println("waiting for network config...");
while (listener.isNetworkReady == false) { sleep(50); }
System.out.println("joined");
static void sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// Set up event listener and start service
MyZeroTierEventListener listener = new MyZeroTierEventListener();
int servicePort = 9994;
ZeroTier.start("test/path", listener, servicePort);
// Wait for EVENT_NODE_ONLINE
System.out.println("waiting for node to come online...");
while (listener.isOnline == false) { sleep(50); }
System.out.println("joining network");
ZeroTier.join(0x0123456789abcdefL);
// Wait for EVENT_NETWORK_READY_IP4/6
System.out.println("waiting for network config...");
while (listener.isNetworkReady == false) { sleep(50); }
System.out.println("joined");
/*
Begin using socket API after this point
Use ZeroTier.ZeroTierSocket, ZeroTier.ZeroTierSocketFactory, etc
(or)
ZeroTier.socket(), ZeroTier.connect(), etc
*/
}
}
}

View File

@@ -1,14 +1,14 @@
package com.zerotier.libzt.javasimpleexample;
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierEventListener;
import com.zerotier.libzt.ZeroTierPeerDetails;
public class MyZeroTierEventListener implements ZeroTierEventListener {
public boolean isNetworkReady = false;
public boolean isOnline = false;
public void onZeroTierEvent(long id, int eventCode)
{
public void onZeroTierEvent(long id, int eventCode) {
if (eventCode == ZeroTier.EVENT_NODE_UP) {
System.out.println("EVENT_NODE_UP: nodeId=" + Long.toHexString(id));
}
@@ -40,7 +40,7 @@ public class MyZeroTierEventListener implements ZeroTierEventListener {
if (eventCode == ZeroTier.EVENT_NETWORK_READY_IP4) {
// We have at least one assigned address and we've received a network configuration
System.out.println("ZTS_EVENT_NETWORK_READY_IP4: nwid=" + Long.toHexString(id));
if ( id == 0xa09acf0233e4b070L) {
if (id == 0xa09acf0233e4b070L) {
isNetworkReady = true;
}
}

2
examples/node/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/.zerotier
/libzt

35
examples/node/README.md Normal file
View File

@@ -0,0 +1,35 @@
## Building from source
The npm install script will attempt to statically link to `libzt.a`.
You first need `Cmake` to build the fPIC-version of the `libzt.a` library.
To build both `release` and `debug` libraries for only your host's architecture use `make host`. Or optionally `make host_release` for release only. To build everything including things like iOS frameworks, Android packages, etc, use `make all`. Possible build targets can be seen by using `make list`. Resultant libraries will be placed in `/lib`:
```
brew install cmake
(cd ../.. ; make clean; make update && make patch && make host_release CC=clang CXX=clang++)
npm install
npm start
```
Typical build output:
```
lib
├── release
| └── linux-x86_64
| ├── libzt.a
| └── libzt.so
| └── macos-x86_64
| ├── libzt.a
└── debug
└── ...
```
## Licensing
ZeroTier is licensed under the BSL version 1.1. See [LICENSE.txt](./LICENSE.txt) and the ZeroTier pricing page for details. ZeroTier is free to use internally in businesses and academic institutions and for non-commercial purposes. Certain types of commercial use such as building closed-source apps and devices based on ZeroTier or offering ZeroTier network controllers and network management as a SaaS service require a commercial license.
A small amount of third party code is also included in ZeroTier and is not subject to our BSL license. See [AUTHORS.md](ext/ZeroTierOne/AUTHORS.md) for a list of third party code, where it is included, and the licenses that apply to it. All of the third party code in ZeroTier is liberally licensed (MIT, BSD, Apache, public domain, etc.). If you want a commercial license to use the ZeroTier SDK in your product contact us directly via [contact@zerotier.com](mailto:contact@zerotier.com)

View File

@@ -0,0 +1,8 @@
# Automatically generated file. Edits will be lost.
# Based on: autogypi.json
{
"includes": [
"node_modules/nbind/src/nbind-common.gypi"
]
}

11
examples/node/auto.gypi Normal file
View File

@@ -0,0 +1,11 @@
# Automatically generated file. Edits will be lost.
# Based on: autogypi.json
{
"include_dirs": [
"node_modules/nan"
],
"includes": [
"node_modules/nbind/src/nbind.gypi"
]
}

View File

@@ -0,0 +1,6 @@
{
"dependencies": [
"nbind"
],
"includes": []
}

730
examples/node/binding.cc Normal file
View File

@@ -0,0 +1,730 @@
/**
* libzt binding
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdexcept>
#include <string.h>
#include <string>
#include "ZeroTierSockets.h"
#include "nbind/api.h"
struct Node
{
Node() : online(false), joinedAtLeastOneNetwork(false), id(0) {}
bool online;
bool joinedAtLeastOneNetwork;
uint64_t id;
// etc
bool getOnline() { return online; }
bool getJoinedAtLeastOneNetwork() { return joinedAtLeastOneNetwork; }
uint64_t getId() { return id; }
} myNode;
/* Callback handler, you should return control from this function as quickly as you can
to ensure timely receipt of future events. You should not call libzt API functions from
this function unless it's something trivial like zts_inet_ntop() or similar that has
no state-change implications. */
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
myNode.id = msg->node->address;
myNode.online = true;
}
if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) {
printf("ZTS_EVENT_NODE_OFFLINE --- Check your physical Internet connection, router, firewall, etc. What ports are you blocking?\n");
myNode.online = false;
}
if (msg->eventCode == ZTS_EVENT_NODE_NORMAL_TERMINATION) {
printf("ZTS_EVENT_NODE_NORMAL_TERMINATION\n");
}
// Virtual network events
if (msg->eventCode == ZTS_EVENT_NETWORK_NOT_FOUND) {
printf("ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQ_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQ_CONFIG --- Requesting config for network %llx, please wait a few seconds...\n", msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
printf("ZTS_EVENT_NETWORK_ACCESS_DENIED --- Access to virtual network %llx has been denied. Did you authorize the node yet?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP4) {
printf("ZTS_EVENT_NETWORK_READY_IP4 --- Network config received. IPv4 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
printf("ZTS_EVENT_NETWORK_READY_IP6 --- Network config received. IPv6 traffic can now be sent over network %llx\n",
msg->network->nwid);
myNode.joinedAtLeastOneNetwork = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_DOWN) {
printf("ZTS_EVENT_NETWORK_DOWN --- %llx\n", msg->network->nwid);
}
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP4 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP6 --- This node's virtual address on network %llx is %s\n",
msg->addr->nwid, ipstr);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP4) {
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP4 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP6) {
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP6 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg->addr->nwid);
}
// Peer events
if (msg->peer) {
if (msg->peer->role == ZTS_PEER_ROLE_PLANET) {
/* Safe to ignore, these are our roots. They orchestrate the P2P connection.
You might also see other unknown peers, these are our network controllers. */
return;
}
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- A direct path is known for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
printf("ZTS_EVENT_PEER_RELAY --- No direct path to node=%llx\n", msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DISCOVERED) {
printf("ZTS_EVENT_PEER_PATH_DISCOVERED --- A new direct path was discovered for node=%llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_PATH_DEAD) {
printf("ZTS_EVENT_PEER_PATH_DEAD --- A direct path has died for node=%llx\n",
msg->peer->address);
}
}
}
zts_sockaddr_in sockaddr_in(const char *remoteAddr, const int remotePort)
{
struct zts_sockaddr_in in4;
in4.sin_port = zts_htons(remotePort);
#if defined(_WIN32)
in4.sin_addr.S_addr = zts_inet_addr(remoteAddr);
#else
in4.sin_addr.s_addr = zts_inet_addr(remoteAddr);
#endif
in4.sin_family = ZTS_AF_INET;
return in4;
}
/**
*
* IDENTITIES and AUTHORIZATION:
*
* - Upon the first execution of this code, a new identity will be generated and placed in
* the location given in the first argument to zts_start(path, ...). If you accidentally
* duplicate the identity files and use them simultaneously in a different node instance
* you will experience undefined behavior and it is likely nothing will work.
*
* - You must authorize the node ID provided by the ZTS_EVENT_NODE_ONLINE callback to join
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - Exceptions to the above rule are:
* 1) Joining a public network (such as "earth")
* 2) Joining an Ad-hoc network, (no controller and therefore requires no authorization.)
*
*
* ESTABLISHING A CONNECTION:
*
* - Creating a standard socket connection generally works the same as it would using
* an ordinary socket interface, however with libzt there is a subtle difference in
* how connections are established which may cause confusion:
*
* The underlying virtual ZT layer creates what are called "transport-triggered links"
* between nodes. That is, links are not established until an attempt to communicate
* with a peer has taken place. The side effect is that the first few packets sent from
* a libzt instance are usually relayed via our free infrastructure and it isn't until a
* root server has passed contact information to both peers that a direct connection will be
* established. Therefore, it is required that multiple connection attempts be undertaken
* when initially communicating with a peer. After a transport-triggered link is
* established libzt will inform you via ZTS_EVENT_PEER_DIRECT for a specific peer ID. No
* action is required on your part for this callback event.
*
* Note: In these initial moments before ZTS_EVENT_PEER_DIRECT has been received for a
* specific peer, traffic may be slow, jittery and there may be high packet loss.
* This will subside within a couple of seconds.
*
*
* ERROR HANDLING:
*
* - libzt's API is actually composed of two categories of functions with slightly
* different error reporting mechanisms.
*
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* ZTS_ERR_OK // No error
* ZTS_ERR_SOCKET // Socket error, see zts_errno
* ZTS_ERR_SERVICE // You probably did something at the wrong time
* ZTS_ERR_ARG // Invalid argument
* ZTS_ERR_NO_RESULT // No result (not necessarily an error)
* ZTS_ERR_GENERAL // Consider filing a bug report
*
* Category 2: Sockets (zts_socket, zts_bind, zts_connect, zts_listen, etc).
* Errors returned by these functions can be the same as the above. With
* the added possibility of zts_errno being set. Much like standard
* errno this will provide a more specific reason for an error's occurrence.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - While the ZeroTier socket interface can coexist with your host OS's own interface in
* the same file with no type and naming conflicts, try not to mix and match host
* OS/libzt structures, functions, or constants. It may look similar and may even work
* some of the time but there enough differences that it will cause headaches. Here
* are a few guidelines:
*
* If you are calling a zts_* function, use the appropriate ZTS_* constants:
*
* zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
* zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
*
* If you are calling a zts_* function, use the appropriate zts_* structure:
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
*/
class ZeroTier
{
public:
static Node getMyNode() { return myNode; }
/**
* @brief Starts the ZeroTier service and notifies user application of events via callback
*
* @param configPath path directory where configuration files are stored
* @param servicePort proit which ZeroTier service will listen on
* @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure
*/
static int start(const char *configPath, uint16_t servicePort)
{
// Bring up ZeroTier service
int err = ZTS_ERR_OK;
if((err = zts_start(configPath, &myZeroTierEventCallback, servicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d.\n", err);
return err;
}
printf("Waiting for node to come online...\n");
while (!myNode.online) { zts_delay_ms(50); }
return err;
}
/**
* @brief Stops the ZeroTier service and brings down all virtual network interfaces
*
* @usage While the ZeroTier service will stop, the stack driver (with associated timers)
* will remain active in case future traffic processing is required. To stop all activity
* and free all resources use zts_free() instead.
* @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure.
*/
static int stop()
{
return zts_stop();
}
/**
* @brief Restart the ZeroTier service.
*
* @usage This call will block until the service has been brought offline. Then
* it will return and the user application can then watch for the appropriate
* startup callback events.
* @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure.
*/
static int restart()
{
return zts_restart();
}
/**
* @brief Stop all background services, bring down all interfaces, free all resources. After
* calling this function an application restart will be required before the library can be
* used again.
*
* @usage This should be called at the end of your program or when you do not anticipate
* communicating over ZeroTier
* @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE on failure.
*/
static int free()
{
return zts_free();
}
/**
* @brief Join a network
*
* @param networkId A 16-digit hexadecimal virtual network ID
* @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure.
*/
static int join(const char *networkId)
{
// Join ZeroTier network
uint64_t nwid = strtoull(networkId,NULL,16); // Network ID to join
int err = ZTS_ERR_OK;
if((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d.\n", err);
return err;
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (!myNode.joinedAtLeastOneNetwork) { zts_delay_ms(50); }
return err;
}
static int openStream()
{
return open(ZTS_AF_INET, ZTS_SOCK_STREAM, 0);
}
static int openDgram()
{
return open(ZTS_AF_INET, ZTS_SOCK_DGRAM, 0);
}
static int openRaw(const int protocol)
{
return open(ZTS_AF_INET, ZTS_SOCK_RAW, protocol);
}
static int openStream6()
{
return open(ZTS_AF_INET6, ZTS_SOCK_STREAM, 0);
}
static int openDgram6()
{
return open(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0);
}
static int openRaw6(const int protocol)
{
return open(ZTS_AF_INET6, ZTS_SOCK_RAW, protocol);
}
/**
* @brief Create a socket (sets zts_errno)
*
* @param socket_family Address family (ZTS_AF_INET, ZTS_AF_INET6)
* @param socket_type Type of socket (ZTS_SOCK_STREAM, ZTS_SOCK_DGRAM, ZTS_SOCK_RAW)
* @param protocol Protocols supported on this socket
* @return Numbered file descriptor on success. ZTS_ERR_SERVICE or ZTS_ERR_SOCKET on failure.
*/
static int open(const int socket_family, const int socket_type, const int protocol)
{
int fd;
if ((fd = zts_socket(socket_family, socket_type, protocol)) < 0) {
printf("Error creating ZeroTier socket (fd=%d, zts_errno=%d).\n", fd, zts_errno);
}
return fd;
}
/**
* @brief Close a socket (sets zts_errno)
*
* @param fd Socket file descriptor
* @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE on failure.
*/
static int close(int fd)
{
return zts_close(fd);
}
/**
* @brief Shut down some aspect of a socket (sets zts_errno)
*
* @param fd Socket file descriptor
* @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure.
*/
static int shutdown(int fd)
{
return zts_shutdown(fd, ZTS_SHUT_RDWR);
}
/**
* @brief Bind a socket to a virtual interface (sets zts_errno)
*
* @param fd Socket file descriptor
* @param remoteAddr Remote Address to connect to
* @param remotePort Remote Port to connect to
* @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure.
*/
static int bind(int fd, const char *localAddr, const int localPort)
{
struct zts_sockaddr_in in4 = sockaddr_in(localAddr, localPort);
int err = ZTS_ERR_OK;
if ((err = zts_bind(fd, (const struct zts_sockaddr *)&in4, sizeof(in4))) < 0) {
printf("Error binding to interface (fd=%d, ret=%d, zts_errno=%d).\n",
fd, err, zts_errno);
}
return err;
}
static int bind6(int fd, const char *remoteAddr, const int remotePort)
{
printf("IPv6 NOT IMPLEMENTED.\n");
return ZTS_ERR_ARG;
}
/**
* @brief Connect a socket to a remote host (sets zts_errno)
*
* @param fd Socket file descriptor
* @param remoteAddr Remote Address to connect to
* @param remotePort Remote Port to connect to
* @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure.
*/
static int connect(int fd, const char *remoteAddr, const int remotePort)
{
struct zts_sockaddr_in in4 = sockaddr_in(remoteAddr, remotePort);
// Retries are often required since ZT uses transport-triggered links (explained above)
int err = ZTS_ERR_OK;
if ((err = zts_connect(fd, (const struct zts_sockaddr *)&in4, sizeof(in4))) < 0) {
printf("Error connecting to remote host (fd=%d, ret=%d, zts_errno=%d).\n",
fd, err, zts_errno);
} else {
// Set non-blocking mode
fcntl(fd, ZTS_F_SETFL, ZTS_O_NONBLOCK);
}
return err;
// int err = ZTS_ERR_OK;
// for (;;) {
// printf("Connecting to remote host...\n");
// if ((err = zts_connect(fd, (const struct zts_sockaddr *)&in4, sizeof(in4))) < 0) {
// printf("Error connecting to remote host (fd=%d, ret=%d, zts_errno=%d). Trying again.\n",
// fd, err, zts_errno);
// zts_close(fd);
// // printf("Creating socket...\n");
// if ((fd = zts_socket(socket_family, socket_type, protocol)) < 0) {
// printf("Error creating ZeroTier socket (fd=%d, zts_errno=%d).\n", fd, zts_errno);
// return -1;
// }
// zts_delay_ms(250);
// }
// else {
// printf("Connected.\n");
// break;
// }
// }
}
static int connect6(int fd, const char *remoteAddr, const int remotePort)
{
printf("IPv6 NOT IMPLEMENTED.\n");
return ZTS_ERR_ARG;
}
/**
* @brief Read bytes from socket onto buffer (sets zts_errno)
*
* @param fd Socket file descriptor
* @param buf Pointer to data buffer
* @return Byte count received on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure.
*/
static ssize_t read(int fd, nbind::Buffer buf)
{
return zts_read(fd, buf.data(), buf.length());
}
/**
* @brief Write bytes from buffer to socket (sets zts_errno)
*
* @param fd Socket file descriptor
* @param buf Pointer to data buffer
* @return Byte count sent on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure.
*/
static ssize_t write(int fd, nbind::Buffer buf)
{
return zts_write(fd, buf.data(), buf.length());
}
/**
* @brief Write data from multiple buffers to socket. (sets zts_errno)
*
* @param fd Socket file descriptor
* @param bufs Array of source buffers
* @return Byte count sent on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure.
*/
static ssize_t writev(int fd, std::vector<nbind::Buffer> bufs)
{
std::size_t size = bufs.size();
zts_iovec iov[size];
for (std::size_t i = 0; i != size; ++i) {
iov[i].iov_base = bufs[i].data();
iov[i].iov_len = bufs[i].length();
}
return zts_writev(fd, iov, bufs.size());
}
/**
* @brief Receive data from remote host (sets zts_errno)
*
* @param fd Socket file descriptor
* @param buf Pointer to data buffer
* @param flags
* @return Byte count received on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure.
*/
static ssize_t recv(int fd, nbind::Buffer buf, int flags)
{
return zts_recv(fd, buf.data(), buf.length(), flags);
}
/**
* @brief Send data to remote host (sets zts_errno)
*
* @param fd Socket file descriptor
* @param buf data buffer
* @param flags
* @return Byte count sent on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure.
*/
static ssize_t send(int fd, nbind::Buffer buf, int flags)
{
return zts_send(fd, buf.data(), buf.length(), flags);
}
static int setBlocking(int fd, bool isBlocking)
{
int flags = fcntl(fd, ZTS_F_GETFL, 0);
if (isBlocking) {
flags &= ~ZTS_O_NONBLOCK;
} else {
flags &= ZTS_O_NONBLOCK;
}
return fcntl(fd, ZTS_F_SETFL, flags);
}
static int setNoDelay(int fd, bool isNdelay)
{
int flags = fcntl(fd, ZTS_F_GETFL, 0);
if (isNdelay) {
flags &= ~ZTS_O_NDELAY;
} else {
flags &= ZTS_O_NDELAY;
}
return fcntl(fd, ZTS_F_SETFL, flags);
}
static int setKeepalive(int fd, int yes)
{
return setsockopt(fd, ZTS_SOL_SOCKET, ZTS_SO_KEEPALIVE, &yes, sizeof(yes));
}
static int setKeepidle(int fd, int idle)
{
return setsockopt(fd, ZTS_IPPROTO_TCP, ZTS_TCP_KEEPIDLE, &idle, sizeof(idle));
}
/**
* @brief Issue file control commands on a socket
*
* @param fd File descriptor
* @param cmd
* @param flags
* @return
*/
static int fcntl(int fd, int cmd, int flags)
{
return zts_fcntl(fd, cmd, flags);
}
/**
* @brief Set socket options (sets zts_errno)
*
* @param fd Socket file descriptor
* @param level Protocol level to which option name should apply
* @param optname Option name to set
* @param optval Source of option value to set
* @param optlen Length of option value
* @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure.
*/
static int setsockopt(int fd, int level, int optname, const void *optval, zts_socklen_t optlen)
{
return zts_setsockopt(fd, level, optname, optval, optlen);
}
/**
* @brief Get socket options (sets zts_errno)
*
* @param fd Socket file descriptor
* @param level Protocol level to which option name should apply
* @param optname Option name to get
* @param optval Where option value will be stored
* @param optlen Length of value
* @return ZTS_ERR_OK on success. ZTS_ERR_SOCKET, ZTS_ERR_SERVICE, ZTS_ERR_ARG on failure.
*/
static int getsockopt(int fd, int level, int optname, void *optval, zts_socklen_t *optlen)
{
return zts_getsockopt(fd, level, optname, optval, optlen);
}
/**
* @brief Get socket name (sets zts_errno)
*
* @param fd Socket file descriptor
* @param addr Name associated with this socket
* @param addrlen Length of name
* @return Sockaddress structure
*/
static zts_sockaddr_in getsockname(int fd)
{
struct zts_sockaddr_in in4;
zts_socklen_t addrlen;
zts_getsockname(fd, (struct zts_sockaddr *)&in4, &addrlen);
return in4;
}
static zts_sockaddr_in6 getsockname6(int fd)
{
struct zts_sockaddr_in6 in6;
zts_socklen_t addrlen;
zts_getsockname(fd, (struct zts_sockaddr *)&in6, &addrlen);
return in6;
}
/**
* @brief Get the peer name for the remote end of a connected socket
*
* @param fd Socket file descriptor
* @param addr Name associated with remote end of this socket
* @param addrlen Length of name
* @return Sockaddress structure
*/
static zts_sockaddr_in getpeername(int fd)
{
struct zts_sockaddr_in in4;
zts_socklen_t addrlen;
zts_getpeername(fd, (struct zts_sockaddr *)&in4, &addrlen);
return in4;
}
static zts_sockaddr_in6 getpeername6(int fd)
{
struct zts_sockaddr_in6 in6;
zts_socklen_t addrlen;
zts_getpeername(fd, (struct zts_sockaddr *)&in6, &addrlen);
return in6;
}
/**
* Convert IPv4 and IPv6 address structures to human-readable text form.
*
* @param af Address family (ZTS_AF_INET, ZTS_AF_INET6)
* @param src Pointer to source address structure
* @param dst Pointer to destination character array
* @param size Size of the destination buffer
* @return On success, returns a non-null pointer to the destination character array
*/
static const char * inet_ntop(const zts_sockaddr in)
{
if (in.sa_family == ZTS_AF_INET) {
const zts_sockaddr_in *in4 = (const zts_sockaddr_in *)&in;
char ipstr[ZTS_INET_ADDRSTRLEN];
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
return ipstr;
} else if (in.sa_family == ZTS_AF_INET6) {
const zts_sockaddr_in6 *in6 = (const zts_sockaddr_in6 *)&in;
char ipstr[ZTS_INET6_ADDRSTRLEN];
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
return ipstr;
} else {
return "";
}
}
};
#include "nbind/nbind.h"
NBIND_CLASS(Node) {
getter(getOnline);
getter(getJoinedAtLeastOneNetwork);
getter(getId);
}
NBIND_CLASS(ZeroTier) {
method(start);
method(restart);
method(stop);
method(free);
method(join);
method(openStream);
method(openDgram);
method(openRaw);
method(openStream6);
method(openDgram6);
method(openRaw6);
method(open);
method(close);
method(shutdown);
method(bind);
method(bind6);
method(connect);
method(connect6);
method(read);
method(write);
method(writev);
method(recv);
method(send);
method(setBlocking);
method(setNoDelay);
method(setKeepalive);
method(setKeepidle);
method(fcntl);
method(getsockname);
method(getsockname6);
method(getpeername);
method(getpeername6);
method(inet_ntop);
method(getMyNode);
}

29
examples/node/binding.gyp Normal file
View File

@@ -0,0 +1,29 @@
{
"targets": [
{
"include_dirs": [
"libzt/include",
],
"includes": [
"auto.gypi"
],
"sources": [
"binding.cc"
],
"conditions":[
["OS=='linux' and target_arch=='x64'", {
"libraries": [ "<(module_root_dir)/libzt/lib/release/linux-x86_64/libzt.a" ]
}],
["OS=='mac' and target_arch=='x64'", {
"libraries": [ "<(module_root_dir)/libzt/lib/release/macos-x86_64/libzt.a" ]
}],
["OS=='win'", {
}]
]
}
],
"includes": [
"auto-top.gypi"
]
}

778
examples/node/libzt.js Normal file
View File

@@ -0,0 +1,778 @@
'use strict';
const net = require('net');
const stream = require('stream');
const { types: { isUint8Array } } = require('util');
const nbind = require('@mcesystems/nbind')
const ZeroTier = nbind.init().lib.ZeroTier
const {
errnoException,
writevGeneric,
writeGeneric,
onStreamRead,
kAfterAsyncWrite,
kHandle,
kUpdateTimer,
// setStreamTimeout,
kBuffer,
kBufferCb,
kBufferGen
} = require('./stream_commons');
const kLastWriteQueueSize = Symbol('lastWriteQueueSize');
/*
* EXAMPLE of Low-level usage
* Usage: `nc -lv 4444`
*/
function example(nwid, address, port) {
// Start ZeroTier service
ZeroTier.start(".zerotier", 9994);
// Join virtual network
ZeroTier.join(nwid);
// Connect the socket
const _connect = (address, port, callback) => {
// Open the socket
const fd = ZeroTier.openStream();
if (fd < 0) { callback(new Error('Could not open socket, errno: ' + fd)); return; }
// Try connect
const status = ZeroTier.connect(fd, address, port);
console.log(status);
if (status === 0) {
callback(null, fd);
} else {
// Close previous socket
ZeroTier.close(fd);
setTimeout(_connect, 250, address, port, callback);
}
}
// Receive some data
const _read = (fd, callback) => {
const buf = Buffer.alloc(32)
let bytes = -1
do {
bytes = ZeroTier.recv(fd, buf, 0)
if (bytes > 0) { callback(null, buf); }
} while (bytes > 0);
if (!ZeroTier.getMyNode().online || buf.toString('utf8').includes("exit")) {
callback('end');
} else {
setTimeout(_read, 500, fd, callback)
}
}
_connect(address, port, (err, fd) => {
if (err) { console.error(err); return; }
console.debug("Connected.");
// Send some data
ZeroTier.send(fd, Buffer.from("Name?\n", 'utf8'), 0);
// Set blocking read mode
// ZeroTier.setBlocking(fd, true);
const heartbeat = setInterval(() => process.stderr.write('.'), 100);
_read(fd, (stop, buf) => {
if (stop) {
// Close the socket
ZeroTier.close(fd);
// Stop ZeroTier service
ZeroTier.stop();
// Clear the interval
clearInterval(heartbeat);
return;
}
process.stdout.write(buf.toString('utf8'));
});
});
}
// Target API:
//
// let s = net.connect({port: 80, host: 'google.com'}, function() {
// ...
// });
//
// There are various forms:
//
// connect(options, [cb])
// connect(port, [host], [cb])
// connect(path, [cb]);
//
function connect(...args) {
const normalized = net._normalizeArgs(args);
const options = normalized[0];
// debug('createConnection', normalized);
const socket = new Socket(Object.assign({ handle: new ZTCP() }, options));
if (options.timeout) {
socket.setTimeout(options.timeout);
}
return socket.connect(normalized);
}
/*
* https://github.com/nodejs/node/blob/v12.18.3/lib/net.js#L567
*/
function tryReadStart(socket) {
// Not already reading, start the flow
// debug('Socket._handle.readStart');
socket._handle.reading = true;
const err = socket._handle.readStart();
if (err)
socket.destroy(errnoException(err, 'read'));
}
/*
* https://github.com/nodejs/node/blob/v12.18.3/lib/net.js#L1107
*/
// function afterConnect(status, self, req, readable, writable) {
// // const self = handle[owner_symbol];
// // Callback may come after call to destroy
// if (self.destroyed) {
// return;
// }
// // debug('afterConnect');
// // assert(self.connecting);
// self.connecting = false;
// self._sockname = null;
// if (status === 0) {
// self.readable = readable;
// if (!self._writableState.ended)
// self.writable = writable;
// self._unrefTimer();
// self.emit('connect');
// self.emit('ready');
// // Start the first read, or get an immediate EOF.
// // this doesn't actually consume any bytes, because len=0.
// if (readable && !self.isPaused())
// self.read(0);
// } else {
// self.connecting = false;
// let details;
// if (req.localAddress && req.localPort) {
// details = req.localAddress + ':' + req.localPort;
// }
// const ex = new Error(status,
// 'connect',
// req.address,
// req.port,
// details);
// if (details) {
// ex.localAddress = req.localAddress;
// ex.localPort = req.localPort;
// }
// self.destroy(ex);
// }
// }
// function afterShutdown(self, _status) {
// // const self = this.handle[owner_symbol];
// // debug('afterShutdown destroyed=%j', self.destroyed,
// // self._readableState);
// this.callback();
// // Callback may come after call to destroy.
// if (self.destroyed)
// return;
// if (!self.readable || self.readableEnded) {
// // debug('readableState ended, destroying');
// self.destroy();
// }
// }
// function writeGeneric(self, chunk, encoding, callback) {
// const decodeStrings = self._writableState && self._writableState.decodeStrings
// const buf = (!decodeStrings && !Buffer.isBuffer(chunk)) ? Buffer.from(chunk, encoding) : chunk
// let bytes
// const err = ZeroTier.send(self._fd, buf, 0)
// switch (err) {
// case -1:
// callback(new Error("ZeroTier Socket error"))
// break
// case -2:
// callback(new Error("ZeroTier Service error"))
// break
// case -3:
// callback(new Error("ZeroTier Invalid argument"))
// break
// default:
// bytes = err
// callback()
// }
// return {
// async: true,
// bytes: bytes,
// }
// }
// function writevGeneric(self, chunks, callback) {
// const decodeStrings = self._writableState && self._writableState.decodeStrings
// const bufs = chunks.map(({ chunk, encoding }) => (!decodeStrings && !Buffer.isBuffer(chunk)) ? Buffer.from(chunk, encoding) : chunk)
// let bytes
// const err = ZeroTier.writev(self._fd, bufs)
// switch (err) {
// case -1:
// callback(new Error("ZeroTier Socket error"))
// break
// case -2:
// callback(new Error("ZeroTier Service error"))
// break
// case -3:
// callback(new Error("ZeroTier Invalid argument"))
// break
// default:
// bytes = err
// callback()
// }
// return {
// async: true,
// bytes: bytes,
// }
// }
class ZTCP {
bytesRead = 0
bytesWritten = 0
writeQueueSize = 0
_fd = null
_reading = false
readTimer = null
get reading() {
return this._reading;
}
set reading(val) {
return this._reading = val;
}
readStart() {
if (!this._buf) {
this._buf = Buffer.alloc(128);
}
let bytes = 0
do {
bytes = ZeroTier.read(this._fd, this._buf)
if (bytes >= 0) {
this.bytesRead += bytes;
bytes = 0;
}
switch (bytes) {
case -2:
throw new Error("ZeroTier Service error")
case -3:
throw new Error("ZeroTier Invalid argument")
default:
if (bytes > 0) {
this.bytesRead += bytes
this._buf = this.onread(this._buf)
}
}
} while (bytes > 0 && this._reading)
if (this._reading) { readTimer = setTimeout(() => this._read(size), 500) }
}
readStop() {
if (readTimer) {
clearTimeout(readTimer);
readTimer = null;
}
this._reading = false
}
writev(req, chunks, allBuffers) {
let bufs = [];
if (allBuffers) {
bufs = chunks;
} else {
const arr = chunks;
for (let i = 0; i < arr.length; i+=2) {
const chunk = arr[i];
const encoding = arr[i+1];
chunks.push(Buffer.from(chunk, encoding));
}
}
let bytes = ZeroTier.writev(this._fd, bufs);
if (bytes >= 0) {
this.bytesWritten += bytes;
bytes = 0;
}
const status = bytes;
// https://github.com/nodejs/node/blob/v12.18.3/lib/internal/stream_base_commons.js#L80
if (req.oncomplete) { req.oncomplete.call(req, status); }
return status;
}
writeBuffer(req, buf) {
let bytes = ZeroTier.write(this._fd, buf);
if (bytes >= 0) {
this.bytesWritten += bytes;
bytes = 0;
}
const status = bytes;
// https://github.com/nodejs/node/blob/v12.18.3/lib/internal/stream_base_commons.js#L80
if (req.oncomplete) { req.oncomplete.call(req, status); }
return status;
}
writeLatin1String(req, data) {
return this.writeBuffer(req, Buffer.from(data, 'latin1'));
}
writeUtf8String(req, data) {
return this.writeBuffer(req, Buffer.from(data, 'utf8'));
}
writeAsciiString(req, data) {
return this.writeBuffer(req, Buffer.from(data, 'ascii'));
}
writeUcs2String(req, data) {
return this.writeBuffer(req, Buffer.from(data, 'ucs2'));
}
getAsyncId() {
return -1;
}
useUserBuffer(buf) {
this._buf = buf;
}
setBlocking(newValue) {
return ZeroTier.setBlocking(this._fd, newValue);
}
setNoDelay(newValue) {
return ZeroTier.setNoDelay(this._fd, newValue);
}
setKeepalive(enable, initialDelay) {
ZeroTier.setKeepidle(initialDelay);
return ZeroTier.setKeepalive(this._fd, +enable);
}
bind(localAddress, localPort) {
return ZeroTier.bind(this._fd, localAddress, localPort);
}
bind6(localAddress, localPort, _flags) {
return ZeroTier.bind6(this._fd, localAddress, localPort);
}
open(fd) {
if (fd) {
this._fd = fd;
return 0;
} else {
const err = ZeroTier.openStream();
if (err < 0) {
return err;
} else {
this._fd = err;
return 0;
}
}
}
close(callback) {
const err = ZeroTier.close(this._fd);
this._fd = null;
if (callback) { callback(err); }
}
shutdown(req) {
const status = ZeroTier.shutdown(this._fd);
// https://github.com/nodejs/node/blob/v12.18.3/test/parallel/test-tcp-wrap-connect.js
if (req.oncomplete) { req.oncomplete.call(req, status, this); }
return status;
}
connect(req, address, port) {
let status = ZeroTier.connect(this._fd, address, port);
// Retries are often required since ZT uses transport-triggered links
if (status !== 0) {
let count = 0;
while (count < 10) {
// Close previous socket
this.close();
status = this.open();
if (status !== 0) {
// Break if reopen-socket fails
break;
}
// Reconnect
status = ZeroTier.connect(this._fd, address, port);
if (status === 0) { break; }
count++;
}
}
// https://github.com/nodejs/node/blob/v12.18.3/test/parallel/test-tcp-wrap-connect.js
if (req && req.oncomplete) { req.oncomplete.call(status, this, req, true, true); }
return status;
}
connect6(req, address, port) {
let status = ZeroTier.connect6(this._fd, address, port);
// Retries are often required since ZT uses transport-triggered links
if (status !== 0) {
let count = 0;
while (count < 10) {
// Close previous socket
this.close();
status = this.open();
if (status !== 0) {
// Break if reopen-socket fails
break;
}
// Reconnect
status = ZeroTier.connect6(this._fd, address, port);
if (status === 0) { break; }
count++;
}
}
// https://github.com/nodejs/node/blob/v12.18.3/test/parallel/test-tcp-wrap-connect.js
if (req.oncomplete) { req.oncomplete.call(status, this, req, true, true); }
return status;
}
getpeername(out) {
const in4 = ZeroTier.getpeername(this._fd);
out.address = ZeroTier.inet_ntop(in4);
out.family = in4.sin_family;
out.port = in4.sin_port;
return 0
}
getsockname(out) {
const in4 = ZeroTier.getsockname(this._fd);
out.address = ZeroTier.inet_ntop(in4);
out.family = in4.sin_family;
out.port = in4.sin_port;
return 0;
}
listen(port) {
// TODO
// this.onconnection
}
fchmod(mode) {
// TODO
return 0;
}
}
class Socket extends net.Socket {
[kLastWriteQueueSize] = 0;
[kBuffer] = null;
[kBufferCb] = null;
[kBufferGen] = null;
[kHandle] = null;
get _handle() { return this[kHandle]; }
set _handle(v) { return this[kHandle] = v; }
/*
* https://github.com/nodejs/node/blob/v12.18.3/lib/net.js#L929
*/
// connect(...args) {
// let normalized;
// // If passed an array, it's treated as an array of arguments that have
// // already been normalized (so we don't normalize more than once). This has
// // been solved before in https://github.com/nodejs/node/pull/12342, but was
// // reverted as it had unintended side effects.
// if (Array.isArray(args[0])) {
// normalized = args[0];
// } else {
// normalized = net._normalizeArgs(args);
// }
// const options = normalized[0];
// const cb = normalized[1];
// if (this.write !== net.Socket.prototype.write)
// this.write = net.Socket.prototype.write;
// if (this.destroyed) {
// this._handle = null;
// this._peername = null;
// this._sockname = null;
// }
// if (!this._handle) {
// this._handle = new ZTCP();
// initSocketHandle(this);
// }
// if (cb !== null) {
// this.once('connect', cb);
// }
// this._unrefTimer();
// this.connecting = true;
// this.writable = true;
// const { host, port } = options;
// // If host is an IP, skip performing a lookup
// const addressType = net.isIP(host);
// if (addressType) {
// this._fd = ZeroTier.connectStream(host, port);
// afterConnect(0, this, {}, true, true);
// } else {
// throw new Error("DNS LOOKUP NOT IMPLEMENTED");
// }
// return this;
// }
/*
* https://github.com/nodejs/node/blob/v12.18.3/lib/net.js#L596
*/
pause() {
if (this[kBuffer] && !this.connecting && this._handle &&
this._handle.reading) {
this._handle.reading = false;
if (!this.destroyed) {
const err = this._handle.readStop();
if (err)
this.destroy(errnoException(err, 'read'));
}
}
return stream.Duplex.prototype.pause.call(this);
}
/*
* https://github.com/nodejs/node/blob/v12.18.3/lib/net.js#L610
*/
resume() {
if (this[kBuffer] && !this.connecting && this._handle &&
!this._handle.reading) {
tryReadStart(this);
}
return stream.Duplex.prototype.resume.call(this);
}
/*
* https://github.com/nodejs/node/blob/v12.18.3/lib/net.js#L619
*/
read(n) {
if (this[kBuffer] && !this.connecting && this._handle &&
!this._handle.reading) {
tryReadStart(this);
}
return stream.Duplex.prototype.read.call(this, n);
}
/*
* https://nodejs.org/docs/latest-v12.x/api/stream.html#stream_readable_read_size_1
*/
_read(n) {
// debug('_read');
if (this.connecting || !this._handle) {
// debug('_read wait for connection');
this.once('connect', () => this._read(n));
} else if (!this._handle.reading) {
tryReadStart(this);
}
// if (!this.readChunk || this.readChunk.length < n) {
// this.readChunk = Buffer.alloc(n)
// }
// let bytes = -1
// let moreData = true
// do {
// bytes = ZeroTier.recv(this._fd, this.readChunk, 0)
// switch (bytes) {
// case -2:
// throw new Error("ZeroTier Service error")
// case -3:
// throw new Error("ZeroTier Invalid argument")
// default:
// if (bytes > 0) {
// // this.bytesRead += bytes
// moreData = this.push(this.readChunk)
// }
// }
// } while (bytes > 0 && moreData)
// if (moreData) { setTimeout(() => this._read(n), 500) }
}
/*
* https://nodejs.org/docs/latest-v12.x/api/stream.html#stream_writable_writev_chunks_callback
*/
_writev(chunks, cb) {
this._writeGeneric(true, chunks, '', cb);
}
/*
* https://nodejs.org/docs/latest-v12.x/api/stream.html#stream_writable_write_chunk_encoding_callback_1
*/
_write(data, encoding, cb) {
this._writeGeneric(false, data, encoding, cb);
}
/*
* https://nodejs.org/docs/latest-v12.x/api/stream.html#stream_writable_final_callback
*/
// _final(cb) {
// // If still connecting - defer handling `_final` until 'connect' will happen
// if (this.pending) {
// // debug('_final: not yet connected');
// return this.once('connect', () => this._final(cb));
// }
// if (!this._handle)
// return cb();
// // debug('_final: not ended, call shutdown()');
// // const req = new ShutdownWrap();
// const req = {};
// req.oncomplete = afterShutdown;
// req.handle = this._handle;
// req.callback = cb;
// // const err = this._handle.shutdown(req);
// const err = ZeroTier.shutdown(this._fd);
// return afterShutdown.call(req, this, 0);
// }
/*
* https://github.com/nodejs/node/blob/v12.18.3/lib/net.js#L760
*/
_writeGeneric(writev, data, encoding, cb) {
// If we are still connecting, then buffer this for later.
// The Writable logic will buffer up any more writes while
// waiting for this one to be done.
if (this.connecting) {
this._pendingData = data;
this._pendingEncoding = encoding;
this.once('connect', function connect() {
this._writeGeneric(writev, data, encoding, cb);
});
return;
}
this._pendingData = null;
this._pendingEncoding = '';
if (!this._handle) {
cb(new Error('ERR_SOCKET_CLOSED'));
return false;
}
this._unrefTimer();
let req;
if (writev)
req = writevGeneric(this, data, cb);
else
req = writeGeneric(this, data, encoding, cb);
if (req.async)
this[kLastWriteQueueSize] = req.bytes;
}
/*
* https://github.com/nodejs/node/blob/v12.18.3/lib/net.js#L552
*/
get bufferSize() {
if (this._handle) {
return this[kLastWriteQueueSize] + this.writableLength;
}
}
/*
* https://github.com/nodejs/node/blob/v12.18.3/lib/net.js#L756
*/
[kAfterAsyncWrite]() {
this[kLastWriteQueueSize] = 0;
}
/*
* https://github.com/nodejs/node/blob/v12.18.3/lib/net.js#L468
*/
_onTimeout() {
const handle = this._handle;
const lastWriteQueueSize = this[kLastWriteQueueSize];
if (lastWriteQueueSize > 0 && handle) {
// `lastWriteQueueSize !== writeQueueSize` means there is
// an active write in progress, so we suppress the timeout.
const { writeQueueSize } = handle;
if (lastWriteQueueSize !== writeQueueSize) {
this[kLastWriteQueueSize] = writeQueueSize;
this._unrefTimer();
return;
}
}
// debug('_onTimeout');
this.emit('timeout');
}
get [kUpdateTimer]() {
return this._unrefTimer;
}
}
module.exports = {
start: ZeroTier.start,
join: ZeroTier.join,
restart: ZeroTier.restart,
stop: ZeroTier.stop,
free: ZeroTier.free,
example,
connect,
createConnection: connect,
Socket,
Stream: Socket, // Legacy naming
TCP: ZTCP,
};

788
examples/node/package-lock.json generated Normal file
View File

@@ -0,0 +1,788 @@
{
"name": "libzt",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@mcesystems/nbind": {
"version": "0.3.18",
"resolved": "https://registry.npmjs.org/@mcesystems/nbind/-/nbind-0.3.18.tgz",
"integrity": "sha512-gZFv881rT/nTNNl92K97DqbFVECiniEHg4ABle7WFKklQSCge7ILY58otnKvCgoqrrS/9Mv//mTf+2k3MPSGXA==",
"requires": {
"emscripten-library-decorator": "~0.2.2",
"mkdirp": "~0.5.1",
"nan": "^2.9.2"
}
},
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"ajv": {
"version": "6.12.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz",
"integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==",
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
},
"are-we-there-yet": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"requires": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
}
},
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"requires": {
"safer-buffer": "~2.1.0"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"autogypi": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/autogypi/-/autogypi-0.2.2.tgz",
"integrity": "sha1-JYurX3hXdVsJvqxqZB/qEw/0Yi0=",
"requires": {
"bluebird": "^3.4.0",
"commander": "~2.9.0",
"resolve": "~1.1.7"
}
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
},
"aws4": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz",
"integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA=="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"requires": {
"tweetnacl": "^0.14.3"
}
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
"chownr": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
},
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"commander": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
"integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
"requires": {
"graceful-readlink": ">= 1.0.0"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"requires": {
"assert-plus": "^1.0.0"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"requires": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
}
},
"emscripten-library-decorator": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/emscripten-library-decorator/-/emscripten-library-decorator-0.2.2.tgz",
"integrity": "sha1-0DXwI+KoTGgwXMhCze6jjmdoPEA="
},
"env-paths": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz",
"integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA=="
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
},
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"fs-minipass": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
"requires": {
"minipass": "^3.0.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"requires": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.0",
"object-assign": "^4.1.0",
"signal-exit": "^3.0.0",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wide-align": "^1.1.0"
}
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"requires": {
"assert-plus": "^1.0.0"
}
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
},
"graceful-readlink": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU="
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
},
"har-validator": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"requires": {
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
}
},
"has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"requires": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"requires": {
"number-is-nan": "^1.0.0"
}
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"verror": "1.10.0"
}
},
"mime-db": {
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
},
"mime-types": {
"version": "2.1.27",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
"requires": {
"mime-db": "1.44.0"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"minipass": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
"integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
"requires": {
"yallist": "^4.0.0"
}
},
"minizlib": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.0.tgz",
"integrity": "sha512-EzTZN/fjSvifSX0SlqUERCN39o6T40AMarPbv0MrarSFtIITCBh7bi+dU8nxGFHuqs9jdIAeoYoKuQAAASsPPA==",
"requires": {
"minipass": "^3.0.0",
"yallist": "^4.0.0"
}
},
"mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"requires": {
"minimist": "^1.2.5"
}
},
"nan": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
"integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw=="
},
"nbind": {
"version": "github:charto/nbind#fe3abe05462d1b7559e0933e7f83802e8f05af27",
"from": "github:charto/nbind",
"requires": {
"emscripten-library-decorator": "~0.2.2",
"mkdirp": "~0.5.1",
"nan": "^2.9.2"
}
},
"node-gyp": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.0.0.tgz",
"integrity": "sha512-ZW34qA3CJSPKDz2SJBHKRvyNQN0yWO5EGKKksJc+jElu9VA468gwJTyTArC1iOXU7rN3Wtfg/CMt/dBAOFIjvg==",
"requires": {
"env-paths": "^2.2.0",
"glob": "^7.1.4",
"graceful-fs": "^4.2.3",
"nopt": "^4.0.3",
"npmlog": "^4.1.2",
"request": "^2.88.2",
"rimraf": "^2.6.3",
"semver": "^7.3.2",
"tar": "^6.0.1",
"which": "^2.0.2"
}
},
"nopt": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
"integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
"requires": {
"abbrev": "1",
"osenv": "^0.1.4"
}
},
"npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
"gauge": "~2.7.3",
"set-blocking": "~2.0.0"
}
},
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
},
"osenv": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"requires": {
"os-homedir": "^1.0.0",
"os-tmpdir": "^1.0.0"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"request": {
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.3",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
}
},
"resolve": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
"integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs="
},
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"requires": {
"glob": "^7.1.3"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"semver": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
},
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
},
"sshpk": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
"requires": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
"bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
"ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
"jsbn": "~0.1.0",
"safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.0"
}
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
}
},
"tar": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.0.2.tgz",
"integrity": "sha512-Glo3jkRtPcvpDlAs/0+hozav78yoXKFr+c4wgw62NNMO3oo4AaJdCo21Uu7lcwr55h39W2XD1LMERc64wtbItg==",
"requires": {
"chownr": "^2.0.0",
"fs-minipass": "^2.0.0",
"minipass": "^3.0.0",
"minizlib": "^2.1.0",
"mkdirp": "^1.0.3",
"yallist": "^4.0.0"
},
"dependencies": {
"mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
}
}
},
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"requires": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
}
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
},
"uri-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
"requires": {
"punycode": "^2.1.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"requires": {
"isexe": "^2.0.0"
}
},
"wide-align": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"requires": {
"string-width": "^1.0.2 || 2"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
}

View File

@@ -0,0 +1,23 @@
{
"name": "libzt",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node test.js",
"preinstall": "mkdir -p libzt; cd libzt; ln -sf ../../../include; ln -sf ../../../lib",
"autogypi": "autogypi",
"node-gyp": "node-gyp",
"ndts": "ndts",
"install": "autogypi && node-gyp configure build"
},
"author": "",
"license": "MIT",
"dependencies": {
"@mcesystems/nbind": "^0.3.18",
"autogypi": "^0.2.2",
"nbind": "github:charto/nbind",
"node-gyp": "^7.0.0"
}
}

View File

@@ -0,0 +1,242 @@
'use strict';
const kMaybeDestroy = Symbol('kMaybeDestroy');
const kUpdateTimer = Symbol('kUpdateTimer');
const kAfterAsyncWrite = Symbol('kAfterAsyncWrite');
const kHandle = Symbol('kHandle');
const kSession = Symbol('kSession');
// const debug = require('internal/util/debuglog').debuglog('stream');
const kBuffer = Symbol('kBuffer');
const kBufferGen = Symbol('kBufferGen');
const kBufferCb = Symbol('kBufferCb');
let excludedStackFn;
function errnoException(err, syscall, original) {
// TODO(joyeecheung): We have to use the type-checked
// getSystemErrorName(err) to guard against invalid arguments from users.
// This can be replaced with [ code ] = errmap.get(err) when this method
// is no longer exposed to user land.
if (util === undefined) util = require('util');
const code = util.getSystemErrorName(err);
const message = original ?
`${syscall} ${code} ${original}` : `${syscall} ${code}`;
// eslint-disable-next-line no-restricted-syntax
const ex = new Error(message);
// TODO(joyeecheung): errno is supposed to err, like in uvException
ex.code = ex.errno = code;
ex.syscall = syscall;
// eslint-disable-next-line no-restricted-syntax
Error.captureStackTrace(ex, excludedStackFn || errnoException);
return ex;
}
function handleWriteReq(req, data, encoding) {
const { handle } = req;
switch (encoding) {
case 'buffer':
{
const ret = handle.writeBuffer(req, data);
// if (streamBaseState[kLastWriteWasAsync])
// req.buffer = data;
return ret;
}
case 'latin1':
case 'binary':
return handle.writeLatin1String(req, data);
case 'utf8':
case 'utf-8':
return handle.writeUtf8String(req, data);
case 'ascii':
return handle.writeAsciiString(req, data);
case 'ucs2':
case 'ucs-2':
case 'utf16le':
case 'utf-16le':
return handle.writeUcs2String(req, data);
default:
{
const buffer = Buffer.from(data, encoding);
const ret = handle.writeBuffer(req, buffer);
// if (streamBaseState[kLastWriteWasAsync])
// req.buffer = buffer;
return ret;
}
}
}
function onWriteComplete(status) {
debug('onWriteComplete', status, this.error);
const stream = this.handle[owner_symbol];
if (stream.destroyed) {
if (typeof this.callback === 'function')
this.callback(null);
return;
}
if (status < 0) {
const ex = errnoException(status, 'write', this.error);
stream.destroy(ex, this.callback);
return;
}
stream[kUpdateTimer]();
stream[kAfterAsyncWrite](this);
if (typeof this.callback === 'function')
this.callback(null);
}
function createWriteWrap(handle) {
// const req = new WriteWrap();
const req = {};
req.handle = handle;
req.oncomplete = onWriteComplete;
req.async = false;
req.bytes = 0;
req.buffer = null;
return req;
}
function writevGeneric(self, data, cb) {
const req = createWriteWrap(self[kHandle]);
const allBuffers = data.allBuffers;
let chunks;
if (allBuffers) {
chunks = data;
for (let i = 0; i < data.length; i++)
data[i] = data[i].chunk;
} else {
chunks = new Array(data.length << 1);
for (let i = 0; i < data.length; i++) {
const entry = data[i];
chunks[i * 2] = entry.chunk;
chunks[i * 2 + 1] = entry.encoding;
}
}
const err = req.handle.writev(req, chunks, allBuffers);
// Retain chunks
if (err === 0) req._chunks = chunks;
afterWriteDispatched(self, req, err, cb);
return req;
}
function writeGeneric(self, data, encoding, cb) {
const req = createWriteWrap(self[kHandle]);
const err = handleWriteReq(req, data, encoding);
afterWriteDispatched(self, req, err, cb);
return req;
}
function afterWriteDispatched(self, req, err, cb) {
// req.bytes = streamBaseState[kBytesWritten];
// req.async = !!streamBaseState[kLastWriteWasAsync];
if (err !== 0)
return self.destroy(errnoException(err, 'write', req.error), cb);
if (!req.async) {
cb();
} else {
req.callback = cb;
}
}
function onStreamRead(arrayBuffer, offset, nread) {
// const nread = streamBaseState[kReadBytesOrError];
const handle = this;
const stream = this[owner_symbol];
stream[kUpdateTimer]();
if (nread > 0 && !stream.destroyed) {
let ret;
let result;
const userBuf = stream[kBuffer];
if (userBuf) {
result = (stream[kBufferCb](nread, userBuf) !== false);
const bufGen = stream[kBufferGen];
if (bufGen !== null) {
const nextBuf = bufGen();
if (isUint8Array(nextBuf))
stream[kBuffer] = ret = nextBuf;
}
} else {
// const offset = streamBaseState[kArrayBufferOffset];
const buf = Buffer.from(arrayBuffer, offset, nread);
result = stream.push(buf);
}
if (!result) {
handle.reading = false;
if (!stream.destroyed) {
const err = handle.readStop();
if (err)
stream.destroy(errnoException(err, 'read'));
}
}
return ret;
}
if (nread === 0) {
return;
}
// if (nread !== UV_EOF) {
// return stream.destroy(errnoException(nread, 'read'));
// }
// Defer this until we actually emit end
if (stream._readableState.endEmitted) {
if (stream[kMaybeDestroy])
stream[kMaybeDestroy]();
} else {
if (stream[kMaybeDestroy])
stream.on('end', stream[kMaybeDestroy]);
// TODO(ronag): Without this `readStop`, `onStreamRead`
// will be called once more (i.e. after Readable.ended)
// on Windows causing a ECONNRESET, failing the
// test-https-truncate test.
if (handle.readStop) {
const err = handle.readStop();
if (err)
return stream.destroy(errnoException(err, 'read'));
}
// Push a null to signal the end of data.
// Do it before `maybeDestroy` for correct order of events:
// `end` -> `close`
stream.push(null);
stream.read(0);
}
}
module.exports = {
errnoException,
createWriteWrap,
writevGeneric,
writeGeneric,
onStreamRead,
kAfterAsyncWrite,
kMaybeDestroy,
kUpdateTimer,
kHandle,
kSession,
// setStreamTimeout,
kBuffer,
kBufferCb,
kBufferGen
};

25
examples/node/test.js Normal file
View File

@@ -0,0 +1,25 @@
'use strict'
const libzt = require('./libzt')
// libzt.example("8056c2e21c000001", "29.49.7.203", 4444)
libzt.start(".zerotier", 9994)
libzt.join("8056c2e21c000001")
// Usage: `nc -lv 4444`
let client = libzt.createConnection({ port: 4444, host: '29.49.7.203' }, () => {
console.log('connected to server!');
});
client.on('ready', () => {
client.write("Name?\n", 'utf8');
});
client.on('data', (data) => {
console.log(data.toString('utf8').trimEnd());
if (data.toString('utf8').includes("exit")) { client.end(); }
});
client.on('end', () => {
console.log('disconnected from server');
libzt.stop()
});

View File

@@ -0,0 +1,240 @@
/**
* libzt API example
*
* Specify location of zt.framework and link to standard C++ library:
*
* clang -lc++ -framework Foundation -F . -framework zt adhoc.m -o adhoc;
*
* Pingable node joined to controller-less adhoc network with a 6PLANE addressing scheme
*/
#import <Foundation/Foundation.h>
#import <zt/ZeroTierSockets.h>
#include <arpa/inet.h>
/**
*
* IDENTITIES and AUTHORIZATION:
*
* - Upon the first execution of this code, a new identity will be generated and placed in
* the location given in the first argument to zts_start(path, ...). If you accidentally
* duplicate the identity files and use them simultaneously in a different node instance
* you will experience undefined behavior and it is likely nothing will work.
*
* - You must authorize the node ID provided by the ZTS_EVENT_NODE_ONLINE callback to join
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - An exception to the above rule is if you are using an Ad-hoc network, it has no
* controller and therefore requires no authorization.
*
*
* ESTABLISHING A CONNECTION:
*
* - Creating a standard socket connection generally works the same as it would using
* an ordinary socket interface, however with libzt there is a subtle difference in
* how connections are established which may cause confusion:
*
* The underlying virtual ZT layer creates what are called "transport-triggered links"
* between nodes. That is, links are not established until an attempt to communicate
* with a peer has taken place. The side effect is that the first few packets sent from
* a libzt instance are usually relayed via our free infrastructure and it isn't until a
* root server has passed contact information to both peers that a direct connection will be
* established. Therefore, it is required that multiple connection attempts be undertaken
* when initially communicating with a peer. After a transport-triggered link is
* established libzt will inform you via ZTS_EVENT_PEER_DIRECT for a specific peer ID. No
* action is required on your part for this callback event.
*
* Note: In these initial moments before ZTS_EVENT_PEER_DIRECT has been received for a
* specific peer, traffic may be slow, jittery and there may be high packet loss.
* This will subside within a couple of seconds.
*
*
* ERROR HANDLING:
*
* - libzt's API is actually composed of two categories of functions with slightly
* different error reporting mechanisms.
*
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* ZTS_ERR_OK // No error
* ZTS_ERR_SOCKET // Socket error, see zts_errno
* ZTS_ERR_SERVICE // You probably did something at the wrong time
* ZTS_ERR_ARG // Invalid argument
* ZTS_ERR_NO_RESULT // No result (not necessarily an error)
* ZTS_ERR_GENERAL // Consider filing a bug report
*
* Category 2: Sockets (zts_socket, zts_bind, zts_connect, zts_listen, etc).
* Errors returned by these functions can be the same as the above. With
* the added possibility of zts_errno being set. Much like standard
* errno this will provide a more specific reason for an error's occurrence.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - While the ZeroTier socket interface can coexist with your host OS's own interface in
* the same file with no type and naming conflicts, try not to mix and match host
* OS/libzt structures, functions, or constants. It may look similar and may even work
* some of the time but there enough differences that it will cause headaches. Here
* are a few guidelines:
*
* If you are calling a zts_* function, use the appropriate ZTS_* constants:
*
* zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
* zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
*
* If you are calling a zts_* function, use the appropriate zts_* structure:
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
*/
void delay_ms(long ms) { usleep(ms*1000); }
bool nodeReady = false;
bool networkReady = false;
// Example callbacks
void myZeroTierEventCallback(struct zts_callback_msg *msg)
{
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
NSLog(@"ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
nodeReady = true;
}
if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) {
NSLog(@"ZTS_EVENT_NODE_OFFLINE --- Check your physical Internet connection, router, firewall, etc. What ports are you blocking?\n");
nodeReady = false;
}
// Virtual network events
if (msg->eventCode == ZTS_EVENT_NETWORK_NOT_FOUND) {
NSLog(@"ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQ_CONFIG) {
NSLog(@"ZTS_EVENT_NETWORK_REQ_CONFIG --- Requesting config for network %llx, please wait a few seconds...\n", msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
NSLog(@"ZTS_EVENT_NETWORK_ACCESS_DENIED --- Access to virtual network %llx has been denied. Did you authorize the node yet?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
NSLog(@"ZTS_EVENT_NETWORK_READY_IP6 --- Network config received. IPv6 traffic can now be sent over network %llx\n",
msg->network->nwid);
networkReady = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_DOWN) {
NSLog(@"ZTS_EVENT_NETWORK_DOWN --- %llx\n", msg->network->nwid);
}
// Network stack events
if (msg->eventCode == ZTS_EVENT_NETIF_UP) {
NSLog(@"ZTS_EVENT_NETIF_UP --- network=%llx, mac=%llx, mtu=%d\n",
msg->netif->nwid,
msg->netif->mac,
msg->netif->mtu);
networkReady = true;
}
if (msg->eventCode == ZTS_EVENT_NETIF_DOWN) {
NSLog(@"ZTS_EVENT_NETIF_DOWN --- network=%llx, mac=%llx\n",
msg->netif->nwid,
msg->netif->mac);
networkReady = true;
}
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
NSLog(@"ZTS_EVENT_ADDR_NEW_IP6 --- Join %llx and ping me at %s\n",
msg->addr->nwid, ipstr);
}
// Peer events
// If you don't recognize the peer ID, don't panic, this is most likely one of our root servers
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
NSLog(@"ZTS_EVENT_PEER_DIRECT --- There is now a direct path to peer %llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
NSLog(@"ZTS_EVENT_PEER_RELAY --- No direct path to peer %llx\n",
msg->peer->address);
}
}
/*
Ad-hoc Network:
ffSSSSEEEE000000
| | | |
| | | Reserved for future use, must be 0
| | End of port range (hex)
| Start of port range (hex)
Reserved ZeroTier address prefix indicating a controller-less network.
Ad-hoc networks are public (no access control) networks that have no network controller. Instead
their configuration and other credentials are generated locally. Ad-hoc networks permit only IPv6
UDP and TCP unicast traffic (no multicast or broadcast) using 6plane format NDP-emulated IPv6
addresses. In addition an ad-hoc network ID encodes an IP port range. UDP packets and TCP SYN
(connection open) packets are only allowed to destination ports within the encoded range.
For example ff00160016000000 is an ad-hoc network allowing only SSH, while ff0000ffff000000 is an
ad-hoc network allowing any UDP or TCP port.
Keep in mind that these networks are public and anyone in the entire world can join them. Care must
be taken to avoid exposing vulnerable services or sharing unwanted files or other resources.
*/
int main(int argc, char **argv)
{
if (argc != 5) {
NSLog(@"\nlibzt example\n");
NSLog(@"adhoc <config_file_path> <adhocStartPort> <adhocEndPort> <ztServicePort>\n");
exit(0);
}
int adhocStartPort = atoi(argv[2]); // Start of port range your application will use
int adhocEndPort = atoi(argv[3]); // End of port range your application will use
int ztServicePort = atoi(argv[4]); // Port ZT uses to send encrypted UDP packets to peers (try something like 9994)
uint64_t adhoc_nwid = zts_generate_adhoc_nwid_from_range(adhocStartPort, adhocEndPort);
int err = ZTS_ERR_OK;
// If disabled: (network) details will NOT be written to or read from (networks.d/). It may take slightly longer to start the node
zts_allow_network_caching(1);
// If disabled: (peer) details will NOT be written to or read from (peers.d/). It may take slightly longer to contact a remote peer
zts_allow_peer_caching(1);
// If disabled: Settings will NOT be read from local.conf
zts_allow_local_conf(1);
if((err = zts_start(argv[1], &myZeroTierEventCallback, ztServicePort)) != ZTS_ERR_OK) {
NSLog(@"Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
NSLog(@"Waiting for node to come online...\n");
while (!nodeReady) { delay_ms(50); }
NSLog(@"This node's identity is stored in %s\n", argv[1]);
if((err = zts_join(adhoc_nwid)) != ZTS_ERR_OK) {
NSLog(@"Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
NSLog(@"Joining network %llx\n", adhoc_nwid);
while (!networkReady) { delay_ms(50); }
// Idle and just show callback events, stack statistics, etc
NSLog(@"Node will now idle...\n");
while (true) { delay_ms(1000); }
// Shut down service and stack threads
zts_stop();
return 0;
}

2
examples/swift/Makefile Normal file
View File

@@ -0,0 +1,2 @@
all:
swiftc -g -lc++ -import-objc-header ../../include/ZeroTierSockets.h ../../lib/debug/macos-x86_64/zt.framework/zt main.swift -o main

353
examples/swift/main.swift Normal file
View File

@@ -0,0 +1,353 @@
/**
* I'll order you a pizza if you can rewrite this in modern idomatic Swift
*/
import Swift
import Foundation
/**
*
* IDENTITIES and AUTHORIZATION:
*
* - Upon the first execution of this code, a new identity will be generated and placed in
* the location given in the first argument to zts_start(path, ...). If you accidentally
* duplicate the identity files and use them simultaneously in a different node instance
* you will experience undefined behavior and it is likely nothing will work.
*
* - You must authorize the node ID provided by the ZTS_EVENT_NODE_ONLINE callback to join
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - An exception to the above rule is if you are using an Ad-hoc network, it has no
* controller and therefore requires no authorization.
*
*
* ESTABLISHING A CONNECTION:
*
* - Creating a standard socket connection generally works the same as it would using
* an ordinary socket interface, however with libzt there is a subtle difference in
* how connections are established which may cause confusion:
*
* The underlying virtual ZT layer creates what are called "transport-triggered links"
* between nodes. That is, links are not established until an attempt to communicate
* with a peer has taken place. The side effect is that the first few packets sent from
* a libzt instance are usually relayed via our free infrastructure and it isn't until a
* root server has passed contact information to both peers that a direct connection will be
* established. Therefore, it is required that multiple connection attempts be undertaken
* when initially communicating with a peer. After a transport-triggered link is
* established libzt will inform you via ZTS_EVENT_PEER_DIRECT for a specific peer ID. No
* action is required on your part for this callback event.
*
* Note: In these initial moments before ZTS_EVENT_PEER_DIRECT has been received for a
* specific peer, traffic may be slow, jittery and there may be high packet loss.
* This will subside within a couple of seconds.
*
*
* ERROR HANDLING:
*
* - libzt's API is actually composed of two categories of functions with slightly
* different error reporting mechanisms.
*
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* ZTS_ERR_OK // No error
* ZTS_ERR_SOCKET // Socket error, see zts_errno
* ZTS_ERR_SERVICE // You probably did something at the wrong time
* ZTS_ERR_ARG // Invalid argument
* ZTS_ERR_NO_RESULT // No result (not necessarily an error)
* ZTS_ERR_GENERAL // Consider filing a bug report
*
* Category 2: Sockets (zts_socket, zts_bind, zts_connect, zts_listen, etc).
* Errors returned by these functions can be the same as the above. With
* the added possibility of zts_errno being set. Much like standard
* errno this will provide a more specific reason for an error's occurrence.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - While the ZeroTier socket interface can coexist with your host OS's own interface in
* the same file with no type and naming conflicts, try not to mix and match host
* OS/libzt structures, functions, or constants. It may look similar and may even work
* some of the time but there enough differences that it will cause headaches. Here
* are a few guidelines:
*
* If you are calling a zts_* function, use the appropriate ZTS_* constants:
*
* zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
* zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
*
* If you are calling a zts_* function, use the appropriate zts_* structure:
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
*/
let printNodeDetails : @convention(c) (UnsafeMutableRawPointer?) -> Void =
{
(msgPtr) -> Void in
let msg = msgPtr?.bindMemory(to: zts_callback_msg.self, capacity: 1)
let d = msg?.pointee.node;
print(String(format: "\t- id : %llx", d!.pointee.address));
print(String(format: "\t- version : %d.%d.%d", d!.pointee.versionMajor, d!.pointee.versionMinor, d!.pointee.versionRev));
print(String(format: "\t- primaryPort : %d", d!.pointee.primaryPort));
print(String(format: "\t- secondaryPort : %d", d!.pointee.secondaryPort));
}
/*
func convertTupleToArray<Tuple, Value>(from tuple: Tuple) -> [Value] {
let tupleMirror = Mirror(reflecting: tuple)
func convert(child: Mirror.Child) -> Value? {
let valueMirror = Mirror(reflecting: child.value)
return child.value as? Value
}
return tupleMirror.children.flatMap(convert)
}
*/
let printNetworkDetails : @convention(c) (UnsafeMutableRawPointer?) -> Void =
{
(msgPtr) -> Void in
let msg = msgPtr?.bindMemory(to: zts_callback_msg.self, capacity: 1)
let d = msg?.pointee.network;
let name = ""; // String(d!.pointee.name);
print(String(format: "\t- nwid : %llx", d!.pointee.nwid));
print(String(format: "\t- mac : %lx", d!.pointee.mac));
print(String(format: "\t- name : %s", name));
print(String(format: "\t- type : %d", Int(d!.pointee.type.rawValue)));
/* MTU for the virtual network can be set via our web API */
print(String(format: "\t- mtu : %d", d!.pointee.mtu));
print(String(format: "\t- dhcp : %d", d!.pointee.dhcp));
print(String(format: "\t- bridge : %d", d!.pointee.bridge));
print(String(format: "\t- broadcastEnabled : %d", d!.pointee.broadcastEnabled));
print(String(format: "\t- portError : %d", d!.pointee.portError));
print(String(format: "\t- netconfRevision : %d", d!.pointee.netconfRevision));
print(String(format: "\t- routeCount : %d", d!.pointee.routeCount));
print(String(format: "\t- multicastSubscriptionCount : %d", d!.pointee.multicastSubscriptionCount));
/*
var addresses: [zts_sockaddr_storage] = convertTupleToArray(from: d!.pointee.assignedAddresses)
print("\t- addresses:\n");
for i in 0...d!.pointee.assignedAddressCount {
if (addresses[Int(i)].ss_family == ZTS_AF_INET) {
// Allocate a byte array that can hold the largest possible IPv4 human-readable string
var ipCharByteArray = Array<Int8>(repeating: 0, count: Int(ZTS_INET_ADDRSTRLEN))
// Cast unsafe pointer from zts_sockaddr_storage to zts_sockaddr_in
var addr:zts_sockaddr_in = withUnsafePointer(to: &(addresses[Int(i)])) {
$0.withMemoryRebound(to: zts_sockaddr_in.self, capacity: 1) {
$0.pointee
}
}
// Pass unsafe pointer (addr) to a ntop to convert into human-readable byte array
zts_inet_ntop(ZTS_AF_INET, &(addr.sin_addr), &ipCharByteArray, UInt32(ZTS_INET_ADDRSTRLEN))
//print(ipCharByteArray) // [49, 55, 50, 46, 50, 55, 46, 49, 49, 54, 46, 49, 54, 55, 0, 0]
// Somehow convery Int8 byte array to Swift String ???
//let ipString = String(bytes: ipStr, encoding: .utf8)
//print(ipString)
// Pass unsafe pointer (addr) to a ntop to convert into human-readable byte array
// convert to UInt8 byte array
let uintArray = ipCharByteArray.map { UInt8(bitPattern: $0) }
if let string = String(bytes: uintArray, encoding: .utf8) {
print("\t\t-", string)
}
}
if (addresses[Int(i)].ss_family == ZTS_AF_INET6) {
// ...
}
}
*/
/*
print("\t- routes:\n");
for i in 0...d!.pointee.routeCount {
// ...
}
*/
}
let printPeerDetails : @convention(c) (UnsafeMutableRawPointer?) -> Void =
{
(msgPtr) -> Void in
let msg = msgPtr?.bindMemory(to: zts_callback_msg.self, capacity: 1)
let d = msg?.pointee.peer;
print(String(format: "\t- peer : %llx", d!.pointee.address));
print(String(format: "\t- role : %d", Int(d!.pointee.role.rawValue)));
print(String(format: "\t- latency : %llx", d!.pointee.latency));
print(String(format: "\t- pathCount : %llx", d!.pointee.pathCount));
print(String(format: "\t- version : %d.%d.%d", d!.pointee.versionMajor, d!.pointee.versionMinor, d!.pointee.versionRev));
print(String(format: "\t- paths:\n"));
/*
for i in 0...d!.pointee.pathCount {
// ...
}
*/
}
let printNetifDetails : @convention(c) (UnsafeMutableRawPointer?) -> Void =
{
(msgPtr) -> Void in
let msg = msgPtr?.bindMemory(to: zts_callback_msg.self, capacity: 1)
let d = msg?.pointee.netif;
print(String(format: "\t- nwid : %llx", d!.pointee.nwid));
print(String(format: "\t- mac : %llx", d!.pointee.mac));
print(String(format: "\t- mtu : %d", d!.pointee.mtu));
}
var nodeReady:Bool = false
var networkReady:Bool = false
let myZeroTierEventCallback : @convention(c) (UnsafeMutableRawPointer?) -> Void =
{
(msgPtr) -> Void in
let msg = msgPtr?.bindMemory(to: zts_callback_msg.self, capacity: 1)
let eventCode = msg!.pointee.eventCode
let network = msg?.pointee.network;
let peer = msg?.pointee.peer;
switch Int32(eventCode)
{
case ZTS_EVENT_NODE_UP:
print("ZTS_EVENT_NODE_UP (you can ignore this)\n")
case ZTS_EVENT_NODE_ONLINE:
print("ZTS_EVENT_NODE_ONLINE\n")
printNodeDetails(msg)
nodeReady = true;
case ZTS_EVENT_NODE_OFFLINE:
print("ZTS_EVENT_NODE_OFFLINE\n")
nodeReady = false;
case ZTS_EVENT_NODE_NORMAL_TERMINATION:
print("ZTS_EVENT_NODE_NORMAL_TERMINATION\n")
case ZTS_EVENT_NETWORK_NOT_FOUND:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_NOT_FOUND (%llx)", networkId))
case ZTS_EVENT_NETWORK_REQ_CONFIG:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_REQ_CONFIG (%llx)", networkId))
case ZTS_EVENT_NETWORK_ACCESS_DENIED:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_ACCESS_DENIED (%llx)", networkId))
case ZTS_EVENT_NETWORK_READY_IP4:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_READY_IP4 (%llx)", networkId))
networkReady = true;
case ZTS_EVENT_NETWORK_READY_IP6:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_READY_IP6 (%llx)", networkId))
networkReady = true;
case ZTS_EVENT_NETWORK_DOWN:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_DOWN (%llx)", networkId))
case ZTS_EVENT_NETWORK_UPDATE:
print("ZTS_EVENT_NETWORK_UPDATE\n")
printNetworkDetails(msg)
case ZTS_EVENT_ADDR_ADDED_IP4:
print("ZTS_EVENT_ADDR_ADDED_IP4\n")
case ZTS_EVENT_ADDR_ADDED_IP6:
print("ZTS_EVENT_ADDR_ADDED_IP6\n")
case ZTS_EVENT_ADDR_REMOVED_IP4:
print("ZTS_EVENT_ADDR_REMOVED_IP4\n")
case ZTS_EVENT_ADDR_REMOVED_IP6:
print("ZTS_EVENT_ADDR_REMOVED_IP6\n")
case ZTS_EVENT_PEER_DIRECT:
let peerId:UInt64 = peer!.pointee.address
print(String(format: "ZTS_EVENT_PEER_DIRECT (%llx)", peerId))
printPeerDetails(msg)
case ZTS_EVENT_PEER_RELAY:
let peerId:UInt64 = peer!.pointee.address
print(String(format: "ZTS_EVENT_PEER_RELAY (%llx)", peerId))
printPeerDetails(msg)
case ZTS_EVENT_PEER_PATH_DISCOVERED:
let peerId:UInt64 = peer!.pointee.address
print(String(format: "ZTS_EVENT_PEER_PATH_DISCOVERED (%llx)", peerId))
printPeerDetails(msg)
case ZTS_EVENT_PEER_PATH_DEAD:
let peerId:UInt64 = peer!.pointee.address
print(String(format: "ZTS_EVENT_PEER_PATH_DEAD (%llx)", peerId))
printPeerDetails(msg)
case ZTS_EVENT_NETIF_UP:
print("ZTS_EVENT_NETIF_UP\n")
case ZTS_EVENT_NETIF_DOWN:
print("ZTS_EVENT_NETIF_DOWN\n")
case ZTS_EVENT_NETIF_REMOVED:
print("ZTS_EVENT_NETIF_REMOVED\n")
case ZTS_EVENT_NETIF_LINK_UP:
print("ZTS_EVENT_NETIF_LINK_UP\n")
case ZTS_EVENT_NETIF_LINK_DOWN:
print("ZTS_EVENT_NETIF_LINK_DOWN\n")
case ZTS_EVENT_STACK_UP:
print("ZTS_EVENT_STACK_UP\n")
case ZTS_EVENT_STACK_DOWN:
print("ZTS_EVENT_STACK_DOWN\n")
default:
print("UNKNOWN_EVENT: ", eventCode)
}
}
func main()
{
print("waiting for node to come online...")
zts_start("config_path", myZeroTierEventCallback, 0)
while(!nodeReady) {
sleep(1)
}
print("Joining network")
let nwId : UInt64 = 0x0123456789abcdef; // Specify your network ID here
zts_join(nwId);
// create address structure
let addr_str = "0.0.0.0"
let port = 8080
var in4 = zts_sockaddr_in(sin_len: UInt8(MemoryLayout<zts_sockaddr_in>.size),
sin_family: UInt8(ZTS_AF_INET),
sin_port: UInt16(port).bigEndian,
sin_addr: zts_in_addr(s_addr: 0),
sin_zero: (0,0,0,0,0,0,0,0))
zts_inet_pton(ZTS_AF_INET, addr_str, &(in4.sin_addr));
print("fd=", zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0));
// ...
while(true) {
sleep(1);
}
}
main()

View File

@@ -1,123 +0,0 @@
diff --git a/node/Node.cpp b/node/Node.cpp
index 30c722b2..f0503e1c 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -317,7 +317,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
// Update online status, post status change as event
const bool oldOnline = _online;
- _online = (((now - lastReceivedFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amUpstream()));
+ _online = (((now - lastReceivedFromUpstream) < (ZT_PEER_ACTIVITY_TIMEOUT / 16))||(RR->topology->amUpstream()));
if (oldOnline != _online)
postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
} catch ( ... ) {
diff --git a/node/RingBuffer.hpp b/node/RingBuffer.hpp
index dab81b9e..0d90152b 100644
--- a/node/RingBuffer.hpp
+++ b/node/RingBuffer.hpp
@@ -72,6 +72,11 @@ public:
memset(buf, 0, sizeof(T) * size);
}
+ ~RingBuffer()
+ {
+ delete [] buf;
+ }
+
/**
* @return A pointer to the underlying buffer
*/
diff --git a/node/Switch.cpp b/node/Switch.cpp
index 74c22d33..3e4f53b4 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -425,16 +425,16 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
from.appendTo(outp);
outp.append((uint16_t)etherType);
outp.append(data,len);
- if (!network->config().disableCompression())
- outp.compress();
+ //if (!network->config().disableCompression())
+ // outp.compress();
aqm_enqueue(tPtr,network,outp,true,qosBucket);
} else {
Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME);
outp.append(network->id());
outp.append((uint16_t)etherType);
outp.append(data,len);
- if (!network->config().disableCompression())
- outp.compress();
+ //if (!network->config().disableCompression())
+ // outp.compress();
aqm_enqueue(tPtr,network,outp,true,qosBucket);
}
@@ -532,7 +532,7 @@ void Switch::aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &
TXQueueEntry *txEntry = new TXQueueEntry(dest,RR->node->now(),packet,encrypt);
ManagedQueue *selectedQueue = nullptr;
- for (int i=0; i<ZT_QOS_NUM_BUCKETS; i++) {
+ for (size_t i=0; i<ZT_QOS_NUM_BUCKETS; i++) {
if (i < nqcb->oldQueues.size()) { // search old queues first (I think this is best since old would imply most recent usage of the queue)
if (nqcb->oldQueues[i]->id == qosBucket) {
selectedQueue = nqcb->oldQueues[i];
@@ -568,7 +568,7 @@ void Switch::aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &
{
// DEBUG_INFO("too many enqueued packets (%d), finding packet to drop", nqcb->_currEnqueuedPackets);
int maxQueueLength = 0;
- for (int i=0; i<ZT_QOS_NUM_BUCKETS; i++) {
+ for (size_t i=0; i<ZT_QOS_NUM_BUCKETS; i++) {
if (i < nqcb->oldQueues.size()) {
if (nqcb->oldQueues[i]->byteLength > maxQueueLength) {
maxQueueLength = nqcb->oldQueues[i]->byteLength;
diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp
index 676f6335..2834fd22 100644
--- a/osdep/OSUtils.cpp
+++ b/osdep/OSUtils.cpp
@@ -452,6 +452,7 @@ std::string OSUtils::platformDefaultHomePath()
#endif // __UNIX_LIKE__ or not...
}
+#ifndef OMIT_JSON_SUPPORT
// Inline these massive JSON operations in one place only to reduce binary footprint and compile time
nlohmann::json OSUtils::jsonParse(const std::string &buf) { return nlohmann::json::parse(buf.c_str()); }
std::string OSUtils::jsonDump(const nlohmann::json &j,int indentation) { return j.dump(indentation); }
@@ -543,6 +544,8 @@ std::string OSUtils::jsonBinFromHex(const nlohmann::json &jv)
return std::string();
}
+#endif // OMIT_JSON_SUPPORT
+
// Used to convert HTTP header names to ASCII lower case
const unsigned char OSUtils::TOLOWER_TABLE[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff };
diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp
index 2c4283b0..afdb1bf1 100644
--- a/osdep/OSUtils.hpp
+++ b/osdep/OSUtils.hpp
@@ -55,7 +55,9 @@
#endif
#endif
+#ifndef OMIT_JSON_SUPPORT
#include "../ext/json/json.hpp"
+#endif
namespace ZeroTier {
@@ -284,6 +286,7 @@ public:
*/
static std::string platformDefaultHomePath();
+#ifndef OMIT_JSON_SUPPORT
static nlohmann::json jsonParse(const std::string &buf);
static std::string jsonDump(const nlohmann::json &j,int indentation = 1);
static uint64_t jsonInt(const nlohmann::json &jv,const uint64_t dfl);
@@ -291,6 +294,7 @@ public:
static bool jsonBool(const nlohmann::json &jv,const bool dfl);
static std::string jsonString(const nlohmann::json &jv,const char *dfl);
static std::string jsonBinFromHex(const nlohmann::json &jv);
+#endif // OMIT_JSON_SUPPORT
private:
static const unsigned char TOLOWER_TABLE[256];

View File

@@ -1,32 +0,0 @@
diff --git a/ports/unix/port/include/arch/cc.h b/ports/unix/port/include/arch/cc.h
index 80b37d8..ed219f3 100644
--- a/ports/unix/port/include/arch/cc.h
+++ b/ports/unix/port/include/arch/cc.h
@@ -32,6 +32,8 @@
#ifndef LWIP_ARCH_CC_H
#define LWIP_ARCH_CC_H
+#include "Debug.hpp" // libzt
+
/* see https://sourceforge.net/p/predef/wiki/OperatingSystems/ */
#if defined __ANDROID__
#define LWIP_UNIX_ANDROID
@@ -65,7 +67,7 @@
#endif
#if defined(LWIP_UNIX_ANDROID) && defined(FD_SET)
-typedef __kernel_fd_set fd_set;
+//typedef __kernel_fd_set fd_set;
#endif
#if defined(LWIP_UNIX_MACH)
@@ -76,6 +78,9 @@ typedef __kernel_fd_set fd_set;
#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS
#endif
+// Comment out the following line to use lwIP's default diagnostic printing routine
+#define LWIP_PLATFORM_DIAG(x) do {DEBUG_INFO x;} while(0)
+
struct sio_status_s;
typedef struct sio_status_s sio_status_t;
#define sio_fd_t sio_status_t*

View File

@@ -1,18 +0,0 @@
diff --git a/src/include/lwip/errno.h b/src/include/lwip/errno.h
index 48d6b539..9f59afc8 100644
--- a/src/include/lwip/errno.h
+++ b/src/include/lwip/errno.h
@@ -174,7 +174,12 @@ extern "C" {
#define EMEDIUMTYPE 124 /* Wrong medium type */
#ifndef errno
-extern int errno;
+//extern int errno;
+#if defined(__linux__) && !defined(__ANDROID__)
+ #include <errno.h>
+#else
+ extern int errno;
+#endif
#endif
#else /* LWIP_PROVIDE_ERRNO */

4
include/README.md Normal file
View File

@@ -0,0 +1,4 @@
ZeroTier Socket API
======
This is the externally facing plain C API. It provides a platform-agnostic ZeroTier-based socket interface.

View File

@@ -1,82 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
/**
* @file
*
* ZeroTier socket API
*/
#ifndef LIBZT_BRIDGING_HEADER_H
#define LIBZT_BRIDGING_HEADER_H
#include <sys/socket.h>
#include "ZeroTier.h"
//////////////////////////////////////////////////////////////////////////////
// Service Controls //
//////////////////////////////////////////////////////////////////////////////
int zts_start(const char *path, void *callbackFunc, int port);
void zts_stop();
int zts_join(uint64_t nwid);
int zts_leave(uint64_t nwid);
uint64_t zts_get_node_id();
uint64_t zts_get_node_status();
int get_peer_status(uint64_t peerId);
//////////////////////////////////////////////////////////////////////////////
// Socket API //
//////////////////////////////////////////////////////////////////////////////
int zts_socket(int socket_family, int socket_type, int protocol);
int zts_connect(int fd, const struct sockaddr *addr, socklen_t addrlen);
int zts_bind(int fd, const struct sockaddr *addr, socklen_t addrlen);
int zts_listen(int fd, int backlog);
int zts_accept(int fd, struct sockaddr *addr, socklen_t *addrlen);
int zts_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen);
int zts_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen);
int zts_read(int fd, void *buf, size_t len);
int zts_write(int fd, const void *buf, size_t len);
ssize_t zts_send(int fd, const void *buf, size_t len, int flags);
ssize_t zts_sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen);
ssize_t zts_sendmsg(int fd, const struct msghdr *msg, int flags);
ssize_t zts_recv(int fd, void *buf, size_t len, int flags);
ssize_t zts_recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen);
ssize_t zts_recvmsg(int fd, struct msghdr *msg,int flags);
int zts_shutdown(int fd, int how);
int zts_close(int fd);
int zts_getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen);
int zts_getpeername(int fd, struct sockaddr *addr, socklen_t *addrlen);
int zts_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
int zts_fcntl(int fd, int cmd, int flags);
int zts_ioctl(int fd, unsigned long request, void *argp);
#endif // _H

File diff suppressed because it is too large Load Diff

View File

@@ -1,251 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
/**
* @file
*
* Common constants used throughout the SDK
*/
#ifndef ZEROTIER_CONSTANTS_H
#define ZEROTIER_CONSTANTS_H
//////////////////////////////////////////////////////////////////////////////
// Control API error codes //
//////////////////////////////////////////////////////////////////////////////
// Everything is ok
#define ZTS_ERR_OK 0
// A argument provided by the user application is invalid (e.g. out of range, NULL, etc)
#define ZTS_ERR_INVALID_ARG -1
// The service isn't initialized or is for some reason currently unavailable. Try again.
#define ZTS_ERR_SERVICE -2
// For some reason this API operation is not permitted or doesn't make sense at this time.
#define ZTS_ERR_INVALID_OP -3
// The call succeeded, but no object or relevant result was available
#define ZTS_ERR_NO_RESULT -4
// General internal failure
#define ZTS_ERR_GENERAL -5
/**
* The system port upon which ZT traffic is sent and received
*/
#define ZTS_DEFAULT_PORT 9994
//////////////////////////////////////////////////////////////////////////////
// Control API event codes //
//////////////////////////////////////////////////////////////////////////////
#define ZTS_EVENT_NONE -1
#define ZTS_EVENT_NODE_UP 0
// Standard node events
#define ZTS_EVENT_NODE_OFFLINE 1
#define ZTS_EVENT_NODE_ONLINE 2
#define ZTS_EVENT_NODE_DOWN 3
#define ZTS_EVENT_NODE_IDENTITY_COLLISION 4
#define ZTS_EVENT_NODE_UNRECOVERABLE_ERROR 16
#define ZTS_EVENT_NODE_NORMAL_TERMINATION 17
// Network events
#define ZTS_EVENT_NETWORK_NOT_FOUND 32
#define ZTS_EVENT_NETWORK_CLIENT_TOO_OLD 33
#define ZTS_EVENT_NETWORK_REQUESTING_CONFIG 34
#define ZTS_EVENT_NETWORK_OK 35
#define ZTS_EVENT_NETWORK_ACCESS_DENIED 36
#define ZTS_EVENT_NETWORK_READY_IP4 37
#define ZTS_EVENT_NETWORK_READY_IP6 38
#define ZTS_EVENT_NETWORK_READY_IP4_IP6 39
#define ZTS_EVENT_NETWORK_DOWN 40
// Network Stack events
#define ZTS_EVENT_STACK_UP 48
#define ZTS_EVENT_STACK_DOWN 49
// lwIP netif events
#define ZTS_EVENT_NETIF_UP 64
#define ZTS_EVENT_NETIF_DOWN 65
#define ZTS_EVENT_NETIF_REMOVED 66
#define ZTS_EVENT_NETIF_LINK_UP 67
#define ZTS_EVENT_NETIF_LINK_DOWN 68
// Peer events
#define ZTS_EVENT_PEER_P2P 96
#define ZTS_EVENT_PEER_RELAY 97
#define ZTS_EVENT_PEER_UNREACHABLE 98
// Path events
#define ZTS_EVENT_PATH_DISCOVERED 112
#define ZTS_EVENT_PATH_ALIVE 113
#define ZTS_EVENT_PATH_DEAD 114
// Route events
#define ZTS_EVENT_ROUTE_ADDED 128
#define ZTS_EVENT_ROUTE_REMOVED 129
// Address events
#define ZTS_EVENT_ADDR_ADDED_IP4 144
#define ZTS_EVENT_ADDR_REMOVED_IP4 145
#define ZTS_EVENT_ADDR_ADDED_IP6 146
#define ZTS_EVENT_ADDR_REMOVED_IP6 147
// Macros for legacy behaviour
#define NODE_EVENT_TYPE(code) code >= ZTS_EVENT_NODE_UP && code <= ZTS_EVENT_NODE_NORMAL_TERMINATION
#define NETWORK_EVENT_TYPE(code) code >= ZTS_EVENT_NETWORK_NOT_FOUND && code <= ZTS_EVENT_NETWORK_DOWN
#define STACK_EVENT_TYPE(code) code >= ZTS_EVENT_STACK_UP && code <= ZTS_EVENT_STACK_DOWN
#define NETIF_EVENT_TYPE(code) code >= ZTS_EVENT_NETIF_UP && code <= ZTS_EVENT_NETIF_LINK_DOWN
#define PEER_EVENT_TYPE(code) code >= ZTS_EVENT_PEER_P2P && code <= ZTS_EVENT_PEER_UNREACHABLE
#define PATH_EVENT_TYPE(code) code >= ZTS_EVENT_PATH_DISCOVERED && code <= ZTS_EVENT_PATH_DEAD
#define ROUTE_EVENT_TYPE(code) code >= ZTS_EVENT_ROUTE_ADDED && code <= ZTS_EVENT_ROUTE_REMOVED
#define ADDR_EVENT_TYPE(code) code >= ZTS_EVENT_ADDR_ADDED_IP4 && code <= ZTS_EVENT_ADDR_REMOVED_IP6
//////////////////////////////////////////////////////////////////////////////
// Common definitions and structures for interacting with the ZT socket API //
// This is a subset of lwip/sockets.h, lwip/arch.h, and lwip/inet.h //
// //
// These re-definitions exist here so that the user application's usage //
// of the API is internally consistent with the underlying network stack. //
// They have an attached prefix so that they can co-exist with the native //
// platform's own definitions and structures. //
//////////////////////////////////////////////////////////////////////////////
// Socket protocol types
#define ZTS_SOCK_STREAM 0x0001
#define ZTS_SOCK_DGRAM 0x0002
#define ZTS_SOCK_RAW 0x0003
// Socket family types
#define ZTS_AF_UNSPEC 0x0000
#define ZTS_AF_INET 0x0002
#define ZTS_AF_INET6 0x000a
#define ZTS_PF_INET ZTS_AF_INET
#define ZTS_PF_INET6 ZTS_AF_INET6
#define ZTS_PF_UNSPEC ZTS_AF_UNSPEC
// Protocol command types
#define ZTS_IPPROTO_IP 0x0000
#define ZTS_IPPROTO_ICMP 0x0001
#define ZTS_IPPROTO_TCP 0x0006
#define ZTS_IPPROTO_UDP 0x0011
#define ZTS_IPPROTO_IPV6 0x0029
#define ZTS_IPPROTO_ICMPV6 0x003a
#define ZTS_IPPROTO_UDPLITE 0x0088
#define ZTS_IPPROTO_RAW 0x00ff
// send() and recv() flags
#define ZTS_MSG_PEEK 0x0001
#define ZTS_MSG_WAITALL 0x0002 // NOT YET SUPPORTED
#define ZTS_MSG_OOB 0x0004 // NOT YET SUPPORTED
#define ZTS_MSG_DONTWAIT 0x0008
#define ZTS_MSG_MORE 0x0010
// fnctl() commands
#define ZTS_F_GETFL 0x0003
#define ZTS_F_SETFL 0x0004
// fnctl() flags
#define ZTS_O_NONBLOCK 0x0001
#define ZTS_O_NDELAY 0x0001
// Shutdown commands
#define ZTS_SHUT_RD 0x0000
#define ZTS_SHUT_WR 0x0001
#define ZTS_SHUT_RDWR 0x0002
// Socket level option number
#define ZTS_SOL_SOCKET 0x0fff
// Socket options
#define ZTS_SO_DEBUG 0x0001 // NOT YET SUPPORTED
#define ZTS_SO_ACCEPTCONN 0x0002
#define ZTS_SO_REUSEADDR 0x0004
#define ZTS_SO_KEEPALIVE 0x0008
#define ZTS_SO_DONTROUTE 0x0010 // NOT YET SUPPORTED
#define ZTS_SO_BROADCAST 0x0020
#define ZTS_SO_USELOOPBACK 0x0040 // NOT YET SUPPORTED
#define ZTS_SO_LINGER 0x0080
#define ZTS_SO_DONTLINGER ((int)(~ZTS_SO_LINGER))
#define ZTS_SO_OOBINLINE 0x0100 // NOT YET SUPPORTED
#define ZTS_SO_REUSEPORT 0x0200 // NOT YET SUPPORTED
#define ZTS_SO_SNDBUF 0x1001 // NOT YET SUPPORTED
#define ZTS_SO_RCVBUF 0x1002
#define ZTS_SO_SNDLOWAT 0x1003 // NOT YET SUPPORTED
#define ZTS_SO_RCVLOWAT 0x1004 // NOT YET SUPPORTED
#define ZTS_SO_SNDTIMEO 0x1005
#define ZTS_SO_RCVTIMEO 0x1006
#define ZTS_SO_ERROR 0x1007
#define ZTS_SO_TYPE 0x1008
#define ZTS_SO_CONTIMEO 0x1009
#define ZTS_SO_NO_CHECK 0x100a
// IPPROTO_IP options
#define ZTS_IP_TOS 0x0001
#define ZTS_IP_TTL 0x0002
// IPPROTO_TCP options
#define ZTS_TCP_NODELAY 0x0001
#define ZTS_TCP_KEEPALIVE 0x0002
#define ZTS_TCP_KEEPIDLE 0x0003
#define ZTS_TCP_KEEPINTVL 0x0004
#define ZTS_TCP_KEEPCNT 0x0005
// IPPROTO_IPV6 options
#define ZTS_IPV6_CHECKSUM 0x0007 // RFC3542
#define ZTS_IPV6_V6ONLY 0x001b // RFC3493
// Macro's for defining ioctl() command values
#define ZTS_IOCPARM_MASK 0x7fU
#define ZTS_IOC_VOID 0x20000000UL
#define ZTS_IOC_OUT 0x40000000UL
#define ZTS_IOC_IN 0x80000000UL
#define ZTS_IOC_INOUT (ZTS_IOC_IN | ZTS_IOC_OUT)
#define ZTS_IO(x,y) (ZTS_IOC_VOID | ((x)<<8)|(y))
#define ZTS_IOR(x,y,t) (ZTS_IOC_OUT | (((long)sizeof(t) & ZTS_IOCPARM_MASK)<<16) | ((x)<<8) | (y))
#define ZTS_IOW(x,y,t) (ZTS_IOC_IN | (((long)sizeof(t) & ZTS_IOCPARM_MASK)<<16) | ((x)<<8) | (y))
// ioctl() commands
#define ZTS_FIONREAD ZTS_IOR('f', 127, unsigned long)
#define ZTS_FIONBIO ZTS_IOW('f', 126, unsigned long)
/* FD_SET used for lwip_select */
#ifndef ZTS_FD_SET
#undef ZTS_FD_SETSIZE
// Make FD_SETSIZE match NUM_SOCKETS in socket.c
#define ZTS_FD_SETSIZE MEMP_NUM_NETCONN
#define ZTS_FDSETSAFESET(n, code) do { \
if (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0)) { \
code; }} while(0)
#define ZTS_FDSETSAFEGET(n, code) (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0) ?\
(code) : 0)
#define ZTS_FD_SET(n, p) ZTS_FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] |= (1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))
#define ZTS_FD_CLR(n, p) ZTS_FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] &= ~(1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))
#define ZTS_FD_ISSET(n,p) ZTS_FDSETSAFEGET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] & (1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))
#define ZTS_FD_ZERO(p) memset((void*)(p), 0, sizeof(*(p)))
#elif LWIP_SOCKET_OFFSET
#error LWIP_SOCKET_OFFSET does not work with external FD_SET!
#elif ZTS_FD_SETSIZE < MEMP_NUM_NETCONN
#error "external ZTS_FD_SETSIZE too small for number of sockets"
#endif // FD_SET
//////////////////////////////////////////////////////////////////////////////
// Statistics //
//////////////////////////////////////////////////////////////////////////////
#define ZTS_STATS_PROTOCOL_LINK 0
#define ZTS_STATS_PROTOCOL_ETHARP 1
#define ZTS_STATS_PROTOCOL_IP 2
#define ZTS_STATS_PROTOCOL_UDP 3
#define ZTS_STATS_PROTOCOL_TCP 4
#define ZTS_STATS_PROTOCOL_ICMP 5
#define ZTS_STATS_PROTOCOL_IP_FRAG 6
#define ZTS_STATS_PROTOCOL_IP6 7
#define ZTS_STATS_PROTOCOL_ICMP6 8
#define ZTS_STATS_PROTOCOL_IP6_FRAG 9
//#if defined(_USING_LWIP_DEFINITIONS_)
#endif // ZEROTIER_CONSTANTS_H

1721
include/ZeroTierSockets.h Normal file

File diff suppressed because it is too large Load Diff

15
ports/Homebrew/README.md Normal file
View File

@@ -0,0 +1,15 @@
Homebrew formula for libzt/libztcore
======
This formula script is only here for archival purposes. To install `libzt` and `libztcore` via Homebrew use:
```
brew tap zerotier/libzt
brew install libzt
```
Once accepted into Homebrew core this will be shortened to:
```
brew install libzt
```

58
ports/Homebrew/libzt.rb Normal file
View File

@@ -0,0 +1,58 @@
class Libzt < Formula
desc "ZeroTier: libzt -- An encrypted P2P networking library for applications"
homepage "https://www.zerotier.com"
version "1.3.0"
stable do
url "https://github.com/zerotier/libzt.git", :branch => "master", :revision => "3d1159882117278fcb5fabb623bd62175b6c7e6c"
end
bottle do
root_url "https://download.zerotier.com/dist/homebrew"
cellar :any
sha256 "e1ac8425fd0ea510c7db734af8d6c41cd3650b12f66a571f9d818c0121422eee" => :mojave
end
devel do
version "1.3.1"
url "https://github.com/zerotier/libzt.git", :branch => "dev"
end
head do
url "https://github.com/zerotier/libzt.git"
end
depends_on "cmake" => :build
depends_on "make" => :build
def install
system "make", "update"
system "cmake", ".", *std_cmake_args
system "cmake", "--build", "."
system "make", "install"
cp "LICENSE.txt", "#{prefix}/LICENSE"
end
def caveats
<<~EOS
Visit https://my.zerotier.com to create virtual networks and authorize devices.
Visit https://www.zerotier.com/manual.shtml to learn more about how ZeroTier works.
Visit https://github.com/zerotier/ZeroTierOne/tree/master/controller to learn how to run your own network controller (advanced).
EOS
end
test do
# Writes a simple test program to test.cpp which calls a library function. The expected output of this
# function is -2. This test verifies the following:
# - The library was installed correctly
# - The library was linked correctly
# - Library code executes successfully and sends the proper error code to the test program
(testpath/"test.cpp").write <<-EOS
#include<cstdlib>\n#include<ZeroTier.h>\nint main(){return zts_socket(0,0,0)!=-2;}
EOS
system ENV.cc, "-v", "test.cpp", "-o", "test", "-L#{lib}/Release", "-lzt"
system "./test"
end
end

View File

@@ -16,7 +16,7 @@ android {
ndk {
// Tells Gradle to build outputs for the following ABIs and package
// them into your APK.
abiFilters 'armeabi-v7a'
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
}
}
buildTypes {

View File

@@ -0,0 +1,255 @@
using System.Runtime.InteropServices;
public struct CallbackMessage
{
public int eventCode;
/* Pointers to structures that contain details about the
subject of the callback */
public System.IntPtr node;
public System.IntPtr network;
public System.IntPtr netif;
public System.IntPtr route;
public System.IntPtr path;
public System.IntPtr peer;
public System.IntPtr addr;
}
[StructLayout(LayoutKind.Sequential)]
public struct SockAddrStorage
{
public byte Length;
public byte Family;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] Data1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public uint[] Data2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public uint[] Data3;
}
[StructLayout(LayoutKind.Sequential)]
public struct SockAddr
{
public ushort Family;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
public byte[] Data;
}
[StructLayout(LayoutKind.Sequential)]
public struct SockAddrIn
{
public byte Length;
public byte Family;
public ushort Port;
public uint Addr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] Zero;
}
public struct NodeDetails
{
/**
* The node ID
*/
public ulong address;
/**
* The current clock value accord to the node
*/
public ulong clock;
/**
* Whether or not this node is online
*/
public bool online;
/**
* Whether port mapping is enabled
*/
public bool portMappingEnabled;
/**
* Whether multipath support is enabled. If true, this node will
* be capable of utilizing multiple physical links simultaneosly
* to create higher quality or more robust aggregate links.
*
* See: https://www.zerotier.com/manual.shtml#2_1_5
*/
public bool multipathEnabled;
/**
* The port used by the service to send and receive
* all encapsulated traffic
*/
public ushort primaryPort;
/**
* Planet ID
*/
public ulong planetWorldId;
public ulong planetWorldTimestamp;
public byte versionMajor;
public byte versionMinor;
public byte versionRev;
};
struct AddrDetails
{
public ulong nwid;
public SockAddrStorage addr;
};
struct NetifDetails
{
/**
* The virtual network that this interface was commissioned for.
*/
public ulong nwid;
/**
* The hardware address assigned to this interface
*/
public ulong mac;
/**
* The MTU for this interface
*/
public int mtu;
};
struct RouteDetails
{
/**
* Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default
*/
public System.IntPtr target;
/**
* Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway)
*/
public System.IntPtr via;
/**
* Route flags
*/
public ushort flags;
/**
* Route metric (not currently used)
*/
public ushort metric;
};
struct NetworkDetails
{
/**
* Network ID
*/
public ulong nwid;
/**
* Maximum Transmission Unit size for this network
*/
public int mtu;
/**
* Number of addresses (actually) assigned to the node on this network
*/
public short num_addresses;
/**
* Array of IPv4 and IPv6 addresses assigned to the node on this network
*/
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 16)]
public System.IntPtr[] addr;
/**
* Number of routes
*/
public uint num_routes;
/**
* Array of IPv4 and IPv6 addresses assigned to the node on this network
*/
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 32)]
public System.IntPtr[] routes;
};
struct PathDetails
{
/**
* Address of endpoint
*/
public System.IntPtr address;
/**
* Time of last send in milliseconds or 0 for never
*/
public ulong lastSend;
/**
* Time of last receive in milliseconds or 0 for never
*/
public ulong lastReceive;
/**
* Is this a trusted path? If so this will be its nonzero ID.
*/
public ulong trustedPathId;
/**
* Is path expired?
*/
int expired;
/**
* Is path preferred?
*/
int preferred;
};
struct PeerDetails
{
/**
* ZeroTier address (40 bits)
*/
public ulong address;
/**
* Remote major version or -1 if not known
*/
int versionMajor;
/**
* Remote minor version or -1 if not known
*/
int versionMinor;
/**
* Remote revision or -1 if not known
*/
int versionRev;
/**
* Last measured latency in milliseconds or -1 if unknown
*/
int latency;
/**
* What trust hierarchy role does this device have?
*/
public int role;
/**
* Number of paths (size of paths[])
*/
public uint pathCount;
/**
* Known network paths to peer
*/
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 16)]
public System.IntPtr[] paths;
};
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate void CSharpCallback(System.IntPtr msg);

View File

@@ -1,5 +1,5 @@
framework module zt {
umbrella header "Xcode-Bridging-Header.h"
umbrella header "ZeroTierSockets.h"
export *
module * { export * }

30
ports/zt.i Normal file
View File

@@ -0,0 +1,30 @@
/* libzt.i */
%begin
%{
#define SWIG_PYTHON_CAST_MODE
%}
%include <stdint.i>
#define PYTHON_BUILD 1
%module libzt
%{
#include "../include/ZeroTier.h"
#include "../include/ZeroTierConstants.h"
%}
%define %cs_callback(TYPE, CSTYPE)
%typemap(ctype) TYPE, TYPE& "void *"
%typemap(in) TYPE %{ $1 = ($1_type)$input; %}
%typemap(in) TYPE& %{ $1 = ($1_type)&$input; %}
%typemap(imtype, out="IntPtr") TYPE, TYPE& "CSTYPE"
%typemap(cstype, out="IntPtr") TYPE, TYPE& "CSTYPE"
%typemap(csin) TYPE, TYPE& "$csinput"
%enddef
%cs_callback(userCallbackFunc, CSharpCallback)
%include "../include/ZeroTier.h"
%include "../include/ZeroTierConstants.h"

File diff suppressed because it is too large Load Diff

View File

@@ -1,116 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
/**
* @file
*
* Header for ZeroTier service controls
*/
#ifndef LIBZT_CONTROLS_HPP
#define LIBZT_CONTROLS_HPP
namespace ZeroTier {
//////////////////////////////////////////////////////////////////////////////
// ZeroTier Internal Service Controls //
//////////////////////////////////////////////////////////////////////////////
/**
* Add a callback event message to the queue. This can be safely called
* from other threads since a lock-free queue is used.
*
* @param eventCode The event ID for this event
* @param msg Pointer to a structure of pointers to other message-relevant
* data structures.
*/
void postEvent(int eventCode, void *arg);
/**
* Add a callback event message to the queue. This can be safely called
* from other threads since a lock-free queue is used. Note: For use in
* situations when no additional information needs to be conveyed to the
* user application.
*
* @param eventCode The event ID for this event
*/
void postEvent(int eventCode);
/**
* Free whatever was allocated to contain the callback message
*
* @param msg Message to be freed
*/
void freeEvent(struct zts_callback_msg *msg);
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Starts a ZeroTier service in the background
*
* @usage For internal use only.
* @param
* @return
*/
#if defined(_WIN32)
DWORD WINAPI _zts_run_service(LPVOID thread_id);
#else
void *_zts_run_service(void *thread_id);
#endif
/**
* @brief [Should not be called from user application] This function must be surrounded by
* ZT service locks. It will determine if it is currently safe and allowed to operate on
* the service.
* @usage Can be called at any time
* @return 1 or 0
*/
int __zts_can_perform_service_operation();
/**
* @brief [Should not be called from user application] Returns whether or not the node is
* online.
* @usage Can be called at any time
* @return 1 or 0
*/
int __zts_node_online();
/**
* @brief [Should not be called from user application] Adjusts the delay multiplier for the
* network stack driver thread.
* @usage Can be called at any time
*/
void _hibernate_if_needed();
#ifdef __cplusplus
}
#endif
} // namespace ZeroTier
#endif // _H

View File

@@ -1,28 +1,15 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (c)2013-2020 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.
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* 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.
* Change Date: 2024-01-01
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* 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.
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
/**
* @file
@@ -149,7 +136,6 @@
#else
#define DEBUG_TRANS(fmt, args...)
#endif
#else // !LIBZT_DEBUG || !__NATIVE_TEST__
#if defined(_WIN32)
#define DEBUG_ERROR(...)

248
src/Events.cpp Normal file
View File

@@ -0,0 +1,248 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
/**
* @file
*
* Callback event processing logic
*/
#include "concurrentqueue.h"
#ifdef SDK_JNI
#include <jni.h>
#endif
#include "Constants.hpp"
#include "Node.hpp"
#include "OSUtils.hpp"
#include "Debug.hpp"
#include "Events.hpp"
#include "ZeroTierSockets.h"
#include "NodeService.hpp"
#define NODE_EVENT_TYPE(code) code >= ZTS_EVENT_NODE_UP && code <= ZTS_EVENT_NODE_NORMAL_TERMINATION
#define NETWORK_EVENT_TYPE(code) code >= ZTS_EVENT_NETWORK_NOT_FOUND && code <= ZTS_EVENT_NETWORK_UPDATE
#define STACK_EVENT_TYPE(code) code >= ZTS_EVENT_STACK_UP && code <= ZTS_EVENT_STACK_DOWN
#define NETIF_EVENT_TYPE(code) code >= ZTS_EVENT_NETIF_UP && code <= ZTS_EVENT_NETIF_LINK_DOWN
#define PEER_EVENT_TYPE(code) code >= ZTS_EVENT_PEER_DIRECT && code <= ZTS_EVENT_PEER_PATH_DEAD
#define ROUTE_EVENT_TYPE(code) code >= ZTS_EVENT_ROUTE_ADDED && code <= ZTS_EVENT_ROUTE_REMOVED
#define ADDR_EVENT_TYPE(code) code >= ZTS_EVENT_ADDR_ADDED_IP4 && code <= ZTS_EVENT_ADDR_REMOVED_IP6
namespace ZeroTier {
extern NodeService *service;
// Global state variable shared between Socket, Control, Event and NodeService logic.
uint8_t _serviceStateFlags;
// Lock to guard access to callback function pointers.
Mutex _callbackLock;
void (*_userEventCallbackFunc)(void *);
moodycamel::ConcurrentQueue<struct zts_callback_msg*> _callbackMsgQueue;
void _enqueueEvent(int16_t eventCode, void *arg)
{
struct zts_callback_msg *msg = new zts_callback_msg();
msg->eventCode = eventCode;
if (NODE_EVENT_TYPE(eventCode)) {
msg->node = (struct zts_node_details*)arg;
} if (NETWORK_EVENT_TYPE(eventCode)) {
msg->network = (struct zts_network_details*)arg;
} if (STACK_EVENT_TYPE(eventCode)) {
/* nothing to convey to user */
} if (NETIF_EVENT_TYPE(eventCode)) {
msg->netif = (struct zts_netif_details*)arg;
} if (ROUTE_EVENT_TYPE(eventCode)) {
msg->route = (struct zts_virtual_network_route*)arg;
} if (PEER_EVENT_TYPE(eventCode)) {
msg->peer = (struct zts_peer_details*)arg;
} if (ADDR_EVENT_TYPE(eventCode)) {
msg->addr = (struct zts_addr_details*)arg;
}
if (msg && _callbackMsgQueue.size_approx() > 1024) {
// Rate-limit number of events
_freeEvent(msg);
}
else {
_callbackMsgQueue.enqueue(msg);
}
}
void _freeEvent(struct zts_callback_msg *msg)
{
if (!msg) {
return;
}
if (msg->node) { delete msg->node; }
if (msg->network) { delete msg->network; }
if (msg->netif) { delete msg->netif; }
if (msg->route) { delete msg->route; }
if (msg->peer) { delete msg->peer; }
if (msg->addr) { delete msg->addr; }
}
void _passDequeuedEventToUser(struct zts_callback_msg *msg)
{
bool bShouldStopCallbackThread = (msg->eventCode == ZTS_EVENT_STACK_DOWN);
#ifdef SDK_JNI
if(_userCallbackMethodRef) {
JNIEnv *env;
#if defined(__ANDROID__)
jint rs = jvm->AttachCurrentThread(&env, NULL);
#else
jint rs = jvm->AttachCurrentThread((void **)&env, NULL);
#endif
assert (rs == JNI_OK);
uint64_t arg = 0;
uint64_t id = 0;
if (NODE_EVENT_TYPE(msg->eventCode)) {
id = msg->node ? msg->node->address : 0;
}
if (NETWORK_EVENT_TYPE(msg->eventCode)) {
id = msg->network ? msg->network->nwid : 0;
}
if (PEER_EVENT_TYPE(msg->eventCode)) {
id = msg->peer ? msg->peer->address : 0;
}
env->CallVoidMethod(objRef, _userCallbackMethodRef, id, msg->eventCode);
_freeEvent(msg);
}
#else
if (_userEventCallbackFunc) {
_userEventCallbackFunc(msg);
_freeEvent(msg);
}
#endif
if (bShouldStopCallbackThread) {
/* Ensure last possible callback ZTS_EVENT_STACK_DOWN is
delivered before callback thread is finally stopped. */
_clrState(ZTS_STATE_CALLBACKS_RUNNING);
}
}
bool _isCallbackRegistered()
{
_callbackLock.lock();
bool retval = false;
#ifdef SDK_JNI
retval = (jvm && objRef && _userCallbackMethodRef);
#else
retval = _userEventCallbackFunc;
#endif
_callbackLock.unlock();
return retval;
}
void _clearRegisteredCallback()
{
_callbackLock.lock();
#ifdef SDK_JNI
objRef = NULL;
_userCallbackMethodRef = NULL;
#else
_userEventCallbackFunc = NULL;
#endif
_callbackLock.unlock();
}
int _canPerformServiceOperation()
{
return service
&& service->isRunning()
&& service->getNode()
&& service->getNode()->online()
&& !_getState(ZTS_STATE_FREE_CALLED);
}
#define RESET_FLAGS( ) _serviceStateFlags = 0;
#define SET_FLAGS(f) _serviceStateFlags |= f;
#define CLR_FLAGS(f) _serviceStateFlags &= ~f;
#define GET_FLAGS(f) ((_serviceStateFlags & f) > 0)
void _setState(uint8_t newFlags)
{
if ((newFlags ^ _serviceStateFlags) & ZTS_STATE_NET_SERVICE_RUNNING) {
return; // No effect. Not allowed to set this flag manually
}
SET_FLAGS(newFlags);
if ( GET_FLAGS(ZTS_STATE_NODE_RUNNING)
&& GET_FLAGS(ZTS_STATE_STACK_RUNNING)
&& !(GET_FLAGS(ZTS_STATE_FREE_CALLED)))
{
SET_FLAGS(ZTS_STATE_NET_SERVICE_RUNNING);
}
else {
CLR_FLAGS(ZTS_STATE_NET_SERVICE_RUNNING);
}
}
void _clrState(uint8_t newFlags)
{
if (newFlags & ZTS_STATE_NET_SERVICE_RUNNING) {
return; // No effect. Not allowed to set this flag manually
}
CLR_FLAGS(newFlags);
if ( GET_FLAGS(ZTS_STATE_NODE_RUNNING)
&& GET_FLAGS(ZTS_STATE_STACK_RUNNING)
&& !(GET_FLAGS(ZTS_STATE_FREE_CALLED)))
{
SET_FLAGS(ZTS_STATE_NET_SERVICE_RUNNING);
}
else {
CLR_FLAGS(ZTS_STATE_NET_SERVICE_RUNNING);
}
}
bool _getState(uint8_t testFlags)
{
return testFlags & _serviceStateFlags;
}
#if defined(__WINDOWS__)
DWORD WINAPI _runCallbacks(LPVOID thread_id)
#else
void *_runCallbacks(void *thread_id)
#endif
{
#if defined(__APPLE__)
pthread_setname_np(ZTS_EVENT_CALLBACK_THREAD_NAME);
#endif
while (_getState(ZTS_STATE_CALLBACKS_RUNNING) || _callbackMsgQueue.size_approx() > 0)
{
struct zts_callback_msg *msg;
size_t sz = _callbackMsgQueue.size_approx();
for (size_t j = 0; j < sz; j++) {
if (_callbackMsgQueue.try_dequeue(msg)) {
_callbackLock.lock();
_passDequeuedEventToUser(msg);
_callbackLock.unlock();
delete msg;
}
}
zts_delay_ms(ZTS_CALLBACK_PROCESSING_INTERVAL);
}
#if SDK_JNI
JNIEnv *env;
jint rs = jvm->DetachCurrentThread();
pthread_exit(0);
#endif
return NULL;
}
} // namespace ZeroTier

111
src/Events.hpp Normal file
View File

@@ -0,0 +1,111 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
/**
* @file
*
* Header for callback event processing logic
*/
#ifndef ZT_EVENTS_HPP
#define ZT_EVENTS_HPP
#include <string>
#include "Constants.hpp"
#include "ZeroTierSockets.h"
#ifdef __WINDOWS__
#include <BaseTsd.h>
#endif
#ifdef SDK_JNI
#include <jni.h>
#endif
namespace ZeroTier {
#define ZTS_STATE_NODE_RUNNING 0x01
#define ZTS_STATE_STACK_RUNNING 0x02
#define ZTS_STATE_NET_SERVICE_RUNNING 0x04
#define ZTS_STATE_CALLBACKS_RUNNING 0x08
#define ZTS_STATE_FREE_CALLED 0x10
#ifdef SDK_JNI
// References to JNI objects and VM kept for future callbacks
extern JavaVM *jvm;
extern jobject objRef;
extern jmethodID _userCallbackMethodRef;
#endif
/**
* How often callback messages are assembled and/or sent
*/
#define ZTS_CALLBACK_PROCESSING_INTERVAL 25
/**
* Enqueue an event to be sent to the user application
*/
void _enqueueEvent(int16_t eventCode, void *arg);
/**
* Send callback message to user application
*/
void _passDequeuedEventToUser(struct ::zts_callback_msg *msg);
/**
* Free memory occupied by callback structures
*/
void _freeEvent(struct ::zts_callback_msg *msg);
/**
* Return whether a callback method has been set
*/
bool _isCallbackRegistered();
/**
* Clear pointer reference to user-provided callback function
*/
void _clearRegisteredCallback();
/**
* Return whether service operation can be performed at this time
*/
int _canPerformServiceOperation();
/**
* Set internal state flags
*/
void _setState(uint8_t newFlags);
/**
* Clear internal state flags
*/
void _clrState(uint8_t newFlags);
/**
* Get internal state flags
*/
bool _getState(uint8_t testFlags);
#ifdef __WINDOWS__
DWORD WINAPI _runCallbacks(LPVOID thread_id);
#else
/**
* Event callback thread
*/
void *_runCallbacks(void *thread_id);
#endif
} // namespace ZeroTier
#endif // _H

View File

View File

View File

@@ -1,111 +1,70 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (c)2013-2020 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.
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* 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.
* Change Date: 2024-01-01
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
/**
* @file
*
* --
*
* 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.
* ZeroTier Node Service (a distant relative of OneService)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <list>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include "version.h"
#include "ZeroTierOne.h"
#include "../version.h"
#include "Debug.hpp"
#include "Events.hpp"
#include "NodeService.hpp"
#include "ZeroTierSockets.h"
#include "VirtualTap.hpp"
#include "Constants.hpp"
#include "Mutex.hpp"
#include "Node.hpp"
#include "Utils.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include "Identity.hpp"
#include "World.hpp"
#include "Salsa20.hpp"
#include "Poly1305.hpp"
#include "SHA512.hpp"
#include "Phy.hpp"
#include "Thread.hpp"
#include "OSUtils.hpp"
#include "PortMapper.hpp"
#include "Binder.hpp"
#include "ManagedRoute.hpp"
#include "InetAddress.hpp"
#include "BlockingQueue.hpp"
#include "Service.hpp"
#include "Debug.hpp"
#include "concurrentqueue.h"
#include "ZeroTier.h"
#include "lwipDriver.hpp"
#ifdef __WINDOWS__
#if defined(__WINDOWS__)
//WSADATA wsaData;
#include <WinSock2.h>
#include <Windows.h>
#include <ShlObj.h>
#include <netioapi.h>
#include <iphlpapi.h>
//#include <unistd.h>
#define stat _stat
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ifaddrs.h>
#endif
#include "Controls.hpp"
#ifdef SDK_JNI
#include <jni.h>
#endif
// Use the virtual netcon endpoint instead of a tun/tap port driver
#include "VirtualTap.hpp"
namespace ZeroTier { typedef VirtualTap EthernetTap; }
// Interface metric for ZeroTier taps -- this ensures that if we are on WiFi and also
// bridged via ZeroTier to the same LAN traffic will (if the OS is sane) prefer WiFi.
#define ZT_IF_METRIC 5000
// How often to check for new multicast subscriptions on a tap device
#define ZT_TAP_CHECK_MULTICAST_INTERVAL 5000
// How often to check for local interface addresses
#define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 60000
// Custom errno-like reporting variable
int zts_errno;
namespace ZeroTier {
extern void postEvent(uint64_t id, int eventCode);
uint8_t allowNetworkCaching;
uint8_t allowPeerCaching;
uint8_t allowLocalConf;
namespace {
typedef VirtualTap EthernetTap;
static std::string _trimString(const std::string &s)
{
@@ -126,7 +85,7 @@ static std::string _trimString(const std::string &s)
return s.substr(start,end - start);
}
class OneServiceImpl;
class NodeServiceImpl;
static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf);
static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData);
@@ -138,7 +97,7 @@ static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t z
static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result);
static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
struct OneServiceIncomingPacket
struct NodeServiceIncomingPacket
{
uint64_t now;
int64_t sock;
@@ -147,7 +106,7 @@ struct OneServiceIncomingPacket
uint8_t data[ZT_MAX_MTU];
};
class OneServiceImpl : public OneService
class NodeServiceImpl : public NodeService
{
public:
// begin member variables --------------------------------------------------
@@ -157,7 +116,7 @@ public:
const std::string _networksPath;
const std::string _moonsPath;
Phy<OneServiceImpl *> _phy;
Phy<NodeServiceImpl *> _phy;
Node *_node;
bool _updateAutoApply;
unsigned int _multipathMode = 0;
@@ -167,12 +126,12 @@ public:
volatile unsigned int _udpPortPickerCounter;
//
std::map<uint64_t, bool> peerCache;
std::map<uint64_t, int> peerCache;
//
unsigned long _incomingPacketConcurrency;
std::vector<OneServiceIncomingPacket *> _incomingPacketMemoryPool;
BlockingQueue<OneServiceIncomingPacket *> _incomingPacketQueue;
std::vector<NodeServiceIncomingPacket *> _incomingPacketMemoryPool;
BlockingQueue<NodeServiceIncomingPacket *> _incomingPacketQueue;
std::vector<std::thread> _incomingPacketThreads;
Mutex _incomingPacketMemoryPoolLock,_incomingPacketThreadsLock;
@@ -250,7 +209,7 @@ public:
// end member variables ----------------------------------------------------
OneServiceImpl(const char *hp,unsigned int port) :
NodeServiceImpl(const char *hp,unsigned int port) :
_homePath((hp) ? hp : ".")
,_phy(this,false,true)
,_node((Node *)0)
@@ -270,52 +229,9 @@ public:
_ports[0] = 0;
_ports[1] = 0;
_ports[2] = 0;
/* Packet input concurrency is disabled intentially since it
would force the user-space network stack to constantly re-order
frames, resulting in lower RX performance */
/*
_incomingPacketConcurrency = 1;
// std::max((unsigned long)1,std::min((unsigned long)16,(unsigned long)std::thread::hardware_concurrency()));
char *envPool = std::getenv("INCOMING_PACKET_CONCURRENCY");
if (envPool != NULL) {
int tmp = atoi(envPool);
if (tmp > 0) {
_incomingPacketConcurrency = tmp;
}
}
for(long t=0;t<_incomingPacketConcurrency;++t) {
_incomingPacketThreads.push_back(std::thread([this]() {
OneServiceIncomingPacket *pkt = nullptr;
for(;;) {
if (!_incomingPacketQueue.get(pkt))
break;
if (!pkt)
break;
if (!_run)
break;
const ZT_ResultCode rc = _node->processWirePacket(nullptr,pkt->now,pkt->sock,&(pkt->from),pkt->data,pkt->size,&_nextBackgroundTaskDeadline);
{
Mutex::Lock l(_incomingPacketMemoryPoolLock);
_incomingPacketMemoryPool.push_back(pkt);
}
if (ZT_ResultCode_isFatal(rc)) {
char tmp[256];
OSUtils::ztsnprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc);
Mutex::Lock _l(_termReason_m);
_termReason = ONE_UNRECOVERABLE_ERROR;
_fatalErrorMessage = tmp;
this->terminate();
break;
}
}
}));
}*/
}
virtual ~OneServiceImpl()
virtual ~NodeServiceImpl()
{
_incomingPacketQueue.stop();
_incomingPacketThreadsLock.lock();
@@ -436,10 +352,8 @@ public:
}
}
#endif
#if NETWORK_CACHING
// Join existing networks in networks.d
{
if (allowNetworkCaching) {
std::vector<std::string> networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "networks.d").c_str()));
for(std::vector<std::string>::iterator f(networksDotD.begin());f!=networksDotD.end();++f) {
std::size_t dot = f->find_last_of('.');
@@ -447,19 +361,15 @@ public:
_node->join(Utils::hexStrToU64(f->substr(0,dot).c_str()),(void *)0,(void *)0);
}
}
#endif
// Main I/O loop
_nextBackgroundTaskDeadline = 0;
int64_t clockShouldBe = OSUtils::now();
_lastRestart = clockShouldBe;
int64_t lastTapMulticastGroupCheck = 0;
int64_t lastBindRefresh = 0;
int64_t lastUpdateCheck = clockShouldBe;
int64_t lastMultipathModeUpdate = 0;
int64_t lastCleanedPeersDb = 0;
int64_t lastLocalInterfaceAddressCheck = (clockShouldBe - ZT_LOCAL_INTERFACE_CHECK_INTERVAL) + 15000; // do this in 15s to give portmapper time to configure and other things time to settle
int64_t lastLocalConfFileCheck = OSUtils::now();
for(;;) {
_run_m.lock();
if (!_run) {
@@ -694,14 +604,42 @@ public:
newManagedIps.erase(std::unique(newManagedIps.begin(),newManagedIps.end()),newManagedIps.end());
for(std::vector<InetAddress>::iterator ip(n.managedIps.begin());ip!=n.managedIps.end();++ip) {
if (std::find(newManagedIps.begin(),newManagedIps.end(),*ip) == newManagedIps.end()) {
if (!n.tap->removeIp(*ip))
if (!n.tap->removeIp(*ip)) {
fprintf(stderr,"ERROR: unable to remove ip address %s" ZT_EOL_S, ip->toString(ipbuf));
} else {
struct zts_addr_details *ad = new zts_addr_details();
ad->nwid = n.tap->_nwid;
if ((*ip).isV4()) {
struct sockaddr_in *in4 = (struct sockaddr_in*)&(ad->addr);
memcpy(&(in4->sin_addr.s_addr), (*ip).rawIpData(), 4);
_enqueueEvent(ZTS_EVENT_ADDR_REMOVED_IP4, (void*)ad);
}
if ((*ip).isV6()) {
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(ad->addr);
memcpy(&(in6->sin6_addr.s6_addr), (*ip).rawIpData(), 16);
_enqueueEvent(ZTS_EVENT_ADDR_REMOVED_IP6, (void*)ad);
}
}
}
}
for(std::vector<InetAddress>::iterator ip(newManagedIps.begin());ip!=newManagedIps.end();++ip) {
if (std::find(n.managedIps.begin(),n.managedIps.end(),*ip) == n.managedIps.end()) {
if (!n.tap->addIp(*ip))
if (!n.tap->addIp(*ip)) {
fprintf(stderr,"ERROR: unable to add ip address %s" ZT_EOL_S, ip->toString(ipbuf));
} else {
struct zts_addr_details *ad = new zts_addr_details();
ad->nwid = n.tap->_nwid;
if ((*ip).isV4()) {
struct sockaddr_in *in4 = (struct sockaddr_in*)&(ad->addr);
memcpy(&(in4->sin_addr.s_addr), (*ip).rawIpData(), 4);
_enqueueEvent(ZTS_EVENT_ADDR_ADDED_IP4, (void*)ad);
}
if ((*ip).isV6()) {
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(ad->addr);
memcpy(&(in6->sin6_addr.s6_addr), (*ip).rawIpData(), 16);
_enqueueEvent(ZTS_EVENT_ADDR_ADDED_IP6, (void*)ad);
}
}
}
}
n.managedIps.swap(newManagedIps);
@@ -779,6 +717,9 @@ public:
_nets.erase(nwid);
return -999; // tap init failed
}
if (op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE) { // Prevent junk from ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP
_enqueueEvent(ZTS_EVENT_NETWORK_UPDATE, (void*)prepare_network_details_msg(n));
}
break;
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN:
@@ -787,13 +728,13 @@ public:
*nuptr = (void *)0;
delete n.tap;
_nets.erase(nwid);
#if NETWORK_CACHING
if (op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY) {
char nlcpath[256];
OSUtils::ztsnprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_homePath.c_str(),nwid);
OSUtils::rm(nlcpath);
if (allowNetworkCaching) {
if (op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY) {
char nlcpath[256];
OSUtils::ztsnprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_homePath.c_str(),nwid);
OSUtils::rm(nlcpath);
}
}
#endif
} else {
_nets.erase(nwid);
}
@@ -805,17 +746,31 @@ public:
inline void nodeEventCallback(enum ZT_Event event,const void *metaData)
{
// Feed node events into lock-free queue for later dequeuing by the callback thread
if (event <= ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION) {
if (event == ZTS_EVENT_NODE_ONLINE) {
switch(event) {
case ZT_EVENT_UP: {
_enqueueEvent(ZTS_EVENT_NODE_UP, NULL);
} break;
case ZT_EVENT_ONLINE: {
struct zts_node_details *nd = new zts_node_details;
nd->address = _node->address();
postEvent(event, (void*)nd);
}
else {
postEvent(event, (void*)0);
}
}
switch(event) {
nd->versionMajor = ZEROTIER_ONE_VERSION_MAJOR;
nd->versionMinor = ZEROTIER_ONE_VERSION_MINOR;
nd->versionRev = ZEROTIER_ONE_VERSION_REVISION;
nd->primaryPort = _primaryPort;
nd->secondaryPort = _secondaryPort;
nd->tertiaryPort = _tertiaryPort;
_enqueueEvent(ZTS_EVENT_NODE_ONLINE, (void*)nd);
} break;
case ZT_EVENT_OFFLINE: {
struct zts_node_details *nd = new zts_node_details;
nd->address = _node->address();
_enqueueEvent(ZTS_EVENT_NODE_OFFLINE, (void*)nd);
} break;
case ZT_EVENT_DOWN: {
struct zts_node_details *nd = new zts_node_details;
nd->address = _node->address();
_enqueueEvent(ZTS_EVENT_NODE_DOWN, (void*)nd);
} break;
case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION: {
Mutex::Lock _l(_termReason_m);
_termReason = ONE_IDENTITY_COLLISION;
@@ -835,10 +790,65 @@ public:
}
}
inline struct zts_network_details *prepare_network_details_msg(uint64_t nwid)
void native_ss_to_zts_ss(struct zts_sockaddr_storage *ss_out, const struct sockaddr_storage *ss_in)
{
struct zts_network_details *nd = new zts_network_details;
nd->nwid = nwid;
if (ss_in->ss_family == AF_INET) {
struct sockaddr_in *s_in4 = (struct sockaddr_in *)ss_in;
struct zts_sockaddr_in *d_in4 = (struct zts_sockaddr_in *)ss_out;
#ifndef __WINDOWS__
d_in4->sin_len = 0; // s_in4->sin_len;
#endif
d_in4->sin_family = ZTS_AF_INET;
d_in4->sin_port = s_in4->sin_port;
memcpy(&(d_in4->sin_addr), &(s_in4->sin_addr), sizeof(s_in4->sin_addr));
}
if (ss_in->ss_family == AF_INET6) {
struct sockaddr_in6 *s_in6 = (struct sockaddr_in6 *)ss_in;
struct zts_sockaddr_in6 *d_in6 = (struct zts_sockaddr_in6 *)ss_out;
#ifndef __WINDOWS__
d_in6->sin6_len = 0; // s_in6->sin6_len;
#endif
d_in6->sin6_family = ZTS_AF_INET6;
d_in6->sin6_port = s_in6->sin6_port;
d_in6->sin6_flowinfo = s_in6->sin6_flowinfo;
memcpy(&(d_in6->sin6_addr), &(s_in6->sin6_addr), sizeof(s_in6->sin6_addr));
d_in6->sin6_scope_id = s_in6->sin6_scope_id;
}
}
struct zts_network_details *prepare_network_details_msg(const NetworkState &n)
{
struct zts_network_details *nd = new zts_network_details();
nd->nwid = n.config.nwid;
nd->mac = n.config.mac;
memcpy(nd->name, n.config.name, sizeof(n.config.name));
nd->status = (ZTS_VirtualNetworkStatus)n.config.status;
nd->type = (ZTS_VirtualNetworkType)n.config.type;
nd->mtu = n.config.mtu;
nd->dhcp = n.config.dhcp;
nd->bridge = n.config.bridge;
nd->broadcastEnabled = n.config.broadcastEnabled;
nd->portError = n.config.portError;
nd->netconfRevision = n.config.netconfRevision;
// Copy and convert address structures
nd->assignedAddressCount = n.config.assignedAddressCount;
for (int i=0; i<n.config.assignedAddressCount; i++) {
native_ss_to_zts_ss(&(nd->assignedAddresses[i]), &(n.config.assignedAddresses[i]));
}
nd->routeCount = n.config.routeCount;
for (int i=0; i<n.config.routeCount; i++) {
native_ss_to_zts_ss(&(nd->routes[i].target), &(n.config.routes[i].target));
native_ss_to_zts_ss(&(nd->routes[i].via), &(n.config.routes[i].via));
nd->routes[i].flags = n.config.routes[i].flags;
nd->routes[i].metric = n.config.routes[i].metric;
}
nd->multicastSubscriptionCount = n.config.multicastSubscriptionCount;
memcpy(nd->multicastSubscriptions, &(n.config.multicastSubscriptions), sizeof(n.config.multicastSubscriptions));
return nd;
}
@@ -846,7 +856,7 @@ public:
{
// Force the ordering of callback messages, these messages are
// only useful if the node and stack are both up and running
if (!_node->online() || !lwip_is_up()) {
if (!_node->online() || !_lwip_is_up()) {
return;
}
// Generate messages to be dequeued by the callback message thread
@@ -860,34 +870,34 @@ public:
}
switch (mostRecentStatus) {
case ZT_NETWORK_STATUS_NOT_FOUND:
postEvent(ZTS_EVENT_NETWORK_NOT_FOUND, (void*)prepare_network_details_msg(nwid));
_enqueueEvent(ZTS_EVENT_NETWORK_NOT_FOUND, (void*)prepare_network_details_msg(n->second));
break;
case ZT_NETWORK_STATUS_CLIENT_TOO_OLD:
postEvent(ZTS_EVENT_NETWORK_CLIENT_TOO_OLD, (void*)prepare_network_details_msg(nwid));
_enqueueEvent(ZTS_EVENT_NETWORK_CLIENT_TOO_OLD, (void*)prepare_network_details_msg(n->second));
break;
case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION:
postEvent(ZTS_EVENT_NETWORK_REQUESTING_CONFIG, (void*)prepare_network_details_msg(nwid));
_enqueueEvent(ZTS_EVENT_NETWORK_REQ_CONFIG, (void*)prepare_network_details_msg(n->second));
break;
case ZT_NETWORK_STATUS_OK:
if (tap->hasIpv4Addr() && lwip_is_netif_up(tap->netif)) {
postEvent(ZTS_EVENT_NETWORK_READY_IP4, (void*)prepare_network_details_msg(nwid));
if (tap->hasIpv4Addr() && _lwip_is_netif_up(tap->netif4)) {
_enqueueEvent(ZTS_EVENT_NETWORK_READY_IP4, (void*)prepare_network_details_msg(n->second));
}
if (tap->hasIpv6Addr() && lwip_is_netif_up(tap->netif)) {
postEvent(ZTS_EVENT_NETWORK_READY_IP6, (void*)prepare_network_details_msg(nwid));
if (tap->hasIpv6Addr() && _lwip_is_netif_up(tap->netif6)) {
_enqueueEvent(ZTS_EVENT_NETWORK_READY_IP6, (void*)prepare_network_details_msg(n->second));
}
// In addition to the READY messages, send one OK message
postEvent(ZTS_EVENT_NETWORK_OK, (void*)prepare_network_details_msg(nwid));
_enqueueEvent(ZTS_EVENT_NETWORK_OK, (void*)prepare_network_details_msg(n->second));
break;
case ZT_NETWORK_STATUS_ACCESS_DENIED:
postEvent(ZTS_EVENT_NETWORK_ACCESS_DENIED, (void*)prepare_network_details_msg(nwid));
_enqueueEvent(ZTS_EVENT_NETWORK_ACCESS_DENIED, (void*)prepare_network_details_msg(n->second));
break;
default:
break;
}
n->second.tap->_networkStatus = mostRecentStatus;
}
// TODO: Add ZTS_EVENT_PEER_NEW
bool bShouldCopyPeerInfo = false;
int eventCode = 0;
ZT_PeerList *pl = _node->peers();
struct zts_peer_details *pd;
if (pl) {
@@ -895,29 +905,42 @@ public:
if (!peerCache.count(pl->peers[i].address)) {
// New peer, add status
if (pl->peers[i].pathCount > 0) {
pd = new zts_peer_details;
memcpy(pd, &(pl->peers[i]), sizeof(struct zts_peer_details));
postEvent(ZTS_EVENT_PEER_P2P, (void*)pd);
bShouldCopyPeerInfo=true;
eventCode = ZTS_EVENT_PEER_DIRECT;
}
if (pl->peers[i].pathCount == 0) {
pd = new zts_peer_details;
memcpy(pd, &(pl->peers[i]), sizeof(struct zts_peer_details));
postEvent(ZTS_EVENT_PEER_RELAY, (void*)pd);
bShouldCopyPeerInfo=true;
eventCode = ZTS_EVENT_PEER_RELAY, (void*)pd;
}
}
// Previously known peer, update status
else {
if (peerCache[pl->peers[i].address] < pl->peers[i].pathCount) {
bShouldCopyPeerInfo=true;
eventCode = ZTS_EVENT_PEER_PATH_DISCOVERED, (void*)pd;
}
if (peerCache[pl->peers[i].address] > pl->peers[i].pathCount) {
bShouldCopyPeerInfo=true;
eventCode = ZTS_EVENT_PEER_PATH_DEAD, (void*)pd;
}
if (peerCache[pl->peers[i].address] == 0 && pl->peers[i].pathCount > 0) {
pd = new zts_peer_details;
memcpy(pd, &(pl->peers[i]), sizeof(struct zts_peer_details));
postEvent(ZTS_EVENT_PEER_P2P, (void*)pd);
bShouldCopyPeerInfo=true;
eventCode = ZTS_EVENT_PEER_DIRECT, (void*)pd;
}
if (peerCache[pl->peers[i].address] > 0 && pl->peers[i].pathCount == 0) {
pd = new zts_peer_details;
memcpy(pd, &(pl->peers[i]), sizeof(struct zts_peer_details));
postEvent(ZTS_EVENT_PEER_RELAY, (void*)pd);
bShouldCopyPeerInfo=true;
eventCode = ZTS_EVENT_PEER_RELAY, (void*)pd;
}
}
if (bShouldCopyPeerInfo) {
pd = new zts_peer_details();
memcpy(pd, &(pl->peers[i]), sizeof(struct zts_peer_details));
for (unsigned int j=0; j<pl->peers[i].pathCount; j++) {
native_ss_to_zts_ss(&(pd->paths[j].address), &(pl->peers[i].paths[j].address));
}
_enqueueEvent(eventCode, (void*)pd);
bShouldCopyPeerInfo = false;
}
// Update our cache with most recently observed path count
peerCache[pl->peers[i].address] = pl->peers[i].pathCount;
}
@@ -925,12 +948,6 @@ public:
_node->freeQueryResult((void *)pl);
}
inline int networkCount()
{
Mutex::Lock _l(_nets_m);
return _nets.size();
}
inline void join(uint64_t nwid)
{
_node->join(nwid, NULL, NULL);
@@ -941,30 +958,6 @@ public:
_node->leave(nwid, NULL, NULL);
}
inline void leaveAll()
{
Mutex::Lock _l(_nets_m);
for(std::map<uint64_t,NetworkState>::iterator n(_nets.begin());n!=_nets.end();++n) {
_node->leave(n->first, NULL, NULL);
}
}
inline int getPeerStatus(uint64_t id)
{
ZT_PeerList *pl = _node->peers();
int status = ZTS_EVENT_PEER_UNREACHABLE;
if (pl) {
for(unsigned long i=0;i<pl->peerCount;++i) {
if (pl->peers[i].address == id) {
status = pl->peers[i].pathCount > 0 ? ZTS_EVENT_PEER_P2P : ZTS_EVENT_PEER_RELAY;
break;
}
}
}
_node->freeQueryResult((void *)pl);
return status;
}
inline void nodeStatePutFunction(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len)
{
char p[1024];
@@ -984,19 +977,22 @@ public:
case ZT_STATE_OBJECT_PLANET:
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str());
break;
#if NETWORK_CACHING
case ZT_STATE_OBJECT_NETWORK_CONFIG:
OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str());
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]);
secure = true;
if (allowNetworkCaching) {
OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str());
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]);
secure = true;
}
else {
return;
}
break;
#endif
#if PEER_CACHING
case ZT_STATE_OBJECT_PEER:
OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str());
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]);
if (allowPeerCaching) {
OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str());
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]);
}
break;
#endif
default:
return;
}
@@ -1046,16 +1042,19 @@ public:
case ZT_STATE_OBJECT_PLANET:
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str());
break;
#if NETWORK_CACHING
case ZT_STATE_OBJECT_NETWORK_CONFIG:
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]);
if (allowNetworkCaching) {
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]);
}
else {
return -1;
}
break;
#endif
#if PEER_CACHING
case ZT_STATE_OBJECT_PEER:
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "peers.d" ZT_PATH_SEPARATOR_S "%.10llx.peer",_homePath.c_str(),(unsigned long long)id[0]);
if (allowPeerCaching) {
OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "peers.d" ZT_PATH_SEPARATOR_S "%.10llx.peer",_homePath.c_str(),(unsigned long long)id[0]);
}
break;
#endif
default:
return -1;
}
@@ -1261,32 +1260,121 @@ public:
};
static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf)
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeVirtualNetworkConfigFunction(nwid,nuptr,op,nwconf); }
{ return reinterpret_cast<NodeServiceImpl *>(uptr)->nodeVirtualNetworkConfigFunction(nwid,nuptr,op,nwconf); }
static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData)
{ reinterpret_cast<OneServiceImpl *>(uptr)->nodeEventCallback(event,metaData); }
{ reinterpret_cast<NodeServiceImpl *>(uptr)->nodeEventCallback(event,metaData); }
static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len)
{ reinterpret_cast<OneServiceImpl *>(uptr)->nodeStatePutFunction(type,id,data,len); }
{ reinterpret_cast<NodeServiceImpl *>(uptr)->nodeStatePutFunction(type,id,data,len); }
static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen)
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeStateGetFunction(type,id,data,maxlen); }
{ return reinterpret_cast<NodeServiceImpl *>(uptr)->nodeStateGetFunction(type,id,data,maxlen); }
static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl)
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeWirePacketSendFunction(localSocket,addr,data,len,ttl); }
{ return reinterpret_cast<NodeServiceImpl *>(uptr)->nodeWirePacketSendFunction(localSocket,addr,data,len,ttl); }
static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
{ reinterpret_cast<OneServiceImpl *>(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); }
{ reinterpret_cast<NodeServiceImpl *>(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); }
static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr)
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodePathCheckFunction(ztaddr,localSocket,remoteAddr); }
{ return reinterpret_cast<NodeServiceImpl *>(uptr)->nodePathCheckFunction(ztaddr,localSocket,remoteAddr); }
static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result)
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodePathLookupFunction(ztaddr,family,result); }
{ return reinterpret_cast<NodeServiceImpl *>(uptr)->nodePathLookupFunction(ztaddr,family,result); }
static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
{ reinterpret_cast<OneServiceImpl *>(uptr)->tapFrameHandler(nwid,from,to,etherType,vlanId,data,len); }
{ reinterpret_cast<NodeServiceImpl *>(uptr)->tapFrameHandler(nwid,from,to,etherType,vlanId,data,len); }
} // anonymous namespace
std::string OneService::platformDefaultHomePath()
std::string NodeService::platformDefaultHomePath()
{
return OSUtils::platformDefaultHomePath();
}
OneService *OneService::newInstance(const char *hp,unsigned int port) { return new OneServiceImpl(hp,port); }
OneService::~OneService() {}
NodeService *NodeService::newInstance(const char *hp,unsigned int port) { return new NodeServiceImpl(hp,port); }
NodeService::~NodeService() {}
//////////////////////////////////////////////////////////////////////////////
// Service //
//////////////////////////////////////////////////////////////////////////////
NodeService *service;
// Lock to guard access to ZeroTier core service
Mutex serviceLock;
// Starts a ZeroTier NodeService background thread
#if defined(__WINDOWS__)
DWORD WINAPI _runNodeService(LPVOID arg)
#else
void *_runNodeService(void *arg)
#endif
{
#if defined(__APPLE__)
pthread_setname_np(ZTS_SERVICE_THREAD_NAME);
#endif
struct serviceParameters *params = (struct serviceParameters *)arg;
int err;
try {
std::vector<std::string> hpsp(OSUtils::split(params->path.c_str(), ZT_PATH_SEPARATOR_S,"",""));
std::string ptmp;
if (params->path[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 (OSUtils::mkdir(ptmp) == false) {
DEBUG_ERROR("home path does not exist, and could not create");
err = true;
perror("error\n");
}
}
}
for(;;) {
serviceLock.lock();
service = NodeService::newInstance(params->path.c_str(),params->port);
service->_userProvidedPort = params->port;
service->_userProvidedPath = params->path;
serviceLock.unlock();
switch(service->run()) {
case NodeService::ONE_STILL_RUNNING:
case NodeService::ONE_NORMAL_TERMINATION:
_enqueueEvent(ZTS_EVENT_NODE_NORMAL_TERMINATION,NULL);
break;
case NodeService::ONE_UNRECOVERABLE_ERROR:
DEBUG_ERROR("fatal error: %s", service->fatalErrorMessage().c_str());
err = true;
_enqueueEvent(ZTS_EVENT_NODE_UNRECOVERABLE_ERROR,NULL);
break;
case NodeService::ONE_IDENTITY_COLLISION: {
err = true;
delete service;
service = (NodeService *)0;
std::string oldid;
OSUtils::readFile((params->path + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid);
if (oldid.length()) {
OSUtils::writeFile((params->path + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid);
OSUtils::rm((params->path + ZT_PATH_SEPARATOR_S + "identity.secret").c_str());
OSUtils::rm((params->path + ZT_PATH_SEPARATOR_S + "identity.public").c_str());
}
_enqueueEvent(ZTS_EVENT_NODE_IDENTITY_COLLISION,NULL);
} continue; // restart!
}
break; // terminate loop -- normally we don't keep restarting
}
serviceLock.lock();
_clrState(ZTS_STATE_NODE_RUNNING);
delete service;
service = (NodeService *)0;
serviceLock.unlock();
_enqueueEvent(ZTS_EVENT_NODE_DOWN,NULL);
}
catch ( ... ) {
DEBUG_ERROR("unexpected exception starting ZeroTier instance");
}
delete params;
zts_delay_ms(ZTS_CALLBACK_PROCESSING_INTERVAL*2);
#ifndef __WINDOWS__
pthread_exit(0);
#endif
return NULL;
}
} // namespace ZeroTier

View File

@@ -1,56 +1,60 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (c)2013-2020 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.
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* 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.
* Change Date: 2024-01-01
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
/**
* @file
*
* --
*
* 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.
* Header for ZeroTier Node Service (a distant relative of OneService)
*/
#ifndef ZT_ONESERVICE_HPP
#define ZT_ONESERVICE_HPP
#ifndef ZT_NODE_SERVICE_HPP
#define ZT_NODE_SERVICE_HPP
#include <string>
#include <vector>
#ifdef SDK_JNI
#include <jni.h>
#include "Constants.hpp"
#include "Node.hpp"
#include "InetAddress.hpp"
#include "Mutex.hpp"
#include "ZeroTierSockets.h"
#define ZTS_SERVICE_THREAD_NAME "ZTServiceThread"
#define ZTS_EVENT_CALLBACK_THREAD_NAME "ZTEventCallbackThread"
// Interface metric for ZeroTier taps -- this ensures that if we are on WiFi and also
// bridged via ZeroTier to the same LAN traffic will (if the OS is sane) prefer WiFi.
#define ZT_IF_METRIC 5000
// How often to check for new multicast subscriptions on a tap device
#define ZT_TAP_CHECK_MULTICAST_INTERVAL 5000
// How often to check for local interface addresses
#define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 60000
#ifdef __WINDOWS__
#include <Windows.h>
#endif
namespace ZeroTier {
class VirtualTap;
// Use the virtual libzt endpoint instead of a tun/tap port driver
namespace ZeroTier { typedef VirtualTap EthernetTap; }
// Forward declaration so we can avoid dragging everything in
struct InetAddress;
class Node;
/**
* Local service for ZeroTier One as system VPN/NFV provider
*/
class OneService
class NodeService
{
public:
uint16_t _userProvidedPort;
std::string _userProvidedPath;
/**
* Returned by node main if/when it terminates
*/
@@ -122,9 +126,9 @@ public:
* @param hp Home path
* @param port TCP and UDP port for packets and HTTP control (if 0, pick random port)
*/
static OneService *newInstance(const char *hp,unsigned int port);
static NodeService *newInstance(const char *hp,unsigned int port);
virtual ~OneService();
virtual ~NodeService();
/**
* Execute the service main I/O loop until terminated
@@ -165,12 +169,9 @@ public:
*/
virtual void getRoutes(uint64_t nwid, void *routeArray, unsigned int *numRoutes) = 0;
virtual int networkCount() = 0;
virtual void leaveAll() = 0;
virtual void join(uint64_t nwid) = 0;
virtual void leave(uint64_t nwid) = 0;
virtual int getPeerStatus(uint64_t id) = 0;
/**
* Terminate background service (can be called from other threads)
*/
@@ -191,13 +192,28 @@ public:
inline bool isRunning() const { return (this->reasonForTermination() == ONE_STILL_RUNNING); }
protected:
OneService() {}
NodeService() {}
private:
OneService(const OneService &one) {}
inline OneService &operator=(const OneService &one) { return *this; }
NodeService(const NodeService &one) {}
inline NodeService &operator=(const NodeService &one) { return *this; }
};
struct serviceParameters
{
int port;
std::string path;
};
#ifdef __WINDOWS__
DWORD WINAPI _runNodeService(LPVOID arg);
#else
/**
* NodeService thread
*/
void *_runNodeService(void *arg);
#endif
} // namespace ZeroTier
#endif

View File

@@ -1,87 +0,0 @@
#ifndef LIBZT_OPTIONS_H
#define LIBZT_OPTIONS_H
//////////////////////////////////////////////////////////////////////////////
// Callbacks //
//////////////////////////////////////////////////////////////////////////////
/**
* The maximum number of un-processed callback messages
*/
#define ZTS_CALLBACK_MSG_QUEUE_LEN 256
//////////////////////////////////////////////////////////////////////////////
// Timing //
//////////////////////////////////////////////////////////////////////////////
/**
* How often callback messages are assembled and/or sent
*/
#define ZTS_CALLBACK_PROCESSING_INTERVAL 25
/**
* Polling interval (in ms) for fds wrapped in the Phy I/O loop
*/
#define ZTS_TAP_THREAD_POLLING_INTERVAL 50
#define ZTS_HOUSEKEEPING_INTERVAL 50
/**
* By how much thread I/O and callback loop delays are multiplied (unitless)
*/
#define ZTS_HIBERNATION_MULTIPLIER 50
//////////////////////////////////////////////////////////////////////////////
// Threading //
//////////////////////////////////////////////////////////////////////////////
#define SERVICE_THREAD_NICENESS 0 // -10
#define CALLBACK_THREAD_NICENESS 0 // 10
#define LWIP_DRIVER_THREAD_NICENESS 0 // 10
#define TCPIP_THREAD_NICENESS 0 // -10
#define TAP_THREAD_NICENESS 0 // 10
#define ZTS_SERVICE_THREAD_NAME "ZeroTierServiceThread"
#define ZTS_EVENT_CALLBACK_THREAD_NAME "ZeroTierEventCallbackThread"
#define ZTS_LWIP_DRIVER_THREAD_NAME "lwipDriver"
//////////////////////////////////////////////////////////////////////////////
// lwIP behaviour (tcpip driver) //
//////////////////////////////////////////////////////////////////////////////
/**
* How many frames are handled per call from core
*/
#define LWIP_FRAMES_HANDLED_PER_CORE_CALL 16
/**
* How often the lwIP tcpip thread callback checks for incoming frames
*/
#define LWIP_DRIVER_LOOP_INTERVAL 250
/**
* Number of packets that can be queued for ingress into the lwIP core
*/
#define ZTS_LWIP_MAX_RX_QUEUE_LEN 1024
//////////////////////////////////////////////////////////////////////////////
// Service behaviour //
//////////////////////////////////////////////////////////////////////////////
/**
* Whether the service will cache peer details (such as known paths). This will
* make startup and reachability time shorter but is generally only effective
* for networks with a somewhat static topology. In other words this would not be
* recommended for use on mobile devices.
*/
#define PEER_CACHING 0
/**
* Whether the service will cache network details. This will shorten startup
* times. This allows the service to nearly instantly inform the network stack
* of an address to use for this peer so that it can create an interface. This
* is only recommended for networks whose IP assignments do not change often.
*/
#define NETWORK_CACHING 1
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,54 +1,55 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (c)2013-2020 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.
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* 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.
* Change Date: 2024-01-01
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* 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.
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
/**
* @file
*
* Virtual Ethernet tap device
* Virtual ethernet tap device and combined network stack driver
*/
#include "VirtualTap.hpp"
#include "Phy.hpp"
#include "Node.hpp"
//#include "OSUtils.hpp"
#include "Service.hpp"
#include "Constants.hpp"
#include "MAC.hpp"
#include "Mutex.hpp"
#include "lwipDriver.hpp"
#include "ZeroTier.h"
#include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#ifdef _MSC_VER
#include "lwip/netif.h"
#include "lwip/etharp.h"
#include "lwip/sys.h"
#include "lwip/ethip6.h"
#include "lwip/tcpip.h"
#include "netif/ethernet.h"
#ifdef LWIP_STATS
#include "lwip/stats.h"
#endif
#include "VirtualTap.hpp"
#include "ZeroTierSockets.h"
#include "Events.hpp"
#include "Debug.hpp"
#if defined(__WINDOWS__)
#include <time.h>
#include "Synchapi.h"
#endif
#define ZTS_TAP_THREAD_POLLING_INTERVAL 50
#define LWIP_DRIVER_LOOP_INTERVAL 250
namespace ZeroTier {
class VirtualTap;
extern OneService *service;
extern void postEvent(int eventCode, void *arg);
extern void _enqueueEvent(int16_t eventCode, void *arg = NULL);
/**
* A virtual tap device. The ZeroTier core service creates one of these for each
@@ -79,7 +80,9 @@ VirtualTap::VirtualTap(
memset(vtap_full_name, 0, sizeof(vtap_full_name));
snprintf(vtap_full_name, sizeof(vtap_full_name), "libzt%llx", (unsigned long long)_nwid);
_dev = vtap_full_name;
#ifndef __WINDOWS__
::pipe(_shutdownSignalPipe);
#endif
// Start virtual tap thread and stack I/O loops
_thread = Thread::start(this);
}
@@ -88,15 +91,21 @@ VirtualTap::~VirtualTap()
{
struct zts_network_details *nd = new zts_network_details;
nd->nwid = _nwid;
postEvent(ZTS_EVENT_NETWORK_DOWN, (void*)nd);
_run = false;
#ifndef __WINDOWS__
::write(_shutdownSignalPipe[1],"\0",1);
#endif
_phy.whack();
lwip_remove_netif(netif);
netif = NULL;
_lwip_remove_netif(netif4);
netif4 = NULL;
_lwip_remove_netif(netif6);
netif6 = NULL;
_enqueueEvent(ZTS_EVENT_NETWORK_DOWN, (void*)nd);
Thread::join(_thread);
#ifndef __WINDOWS__
::close(_shutdownSignalPipe[0]);
::close(_shutdownSignalPipe[1]);
#endif
}
void VirtualTap::lastConfigUpdate(uint64_t lastConfigUpdateTime)
@@ -138,7 +147,7 @@ bool VirtualTap::hasIpv6Addr()
bool VirtualTap::addIp(const InetAddress &ip)
{
//char ipbuf[128];
char ipbuf[128];
//ip.toString(ipbuf);
//DEBUG_INFO("addr=%s", ipbuf);
@@ -146,9 +155,13 @@ bool VirtualTap::addIp(const InetAddress &ip)
This limitation can be removed if some changes
are made in the netif driver. */
if (ip.isV4() && hasIpv4Addr()) {
ip.toString(ipbuf);
DEBUG_INFO("failed to add IP (%s), only one per type per netif allowed\n", ipbuf);
return false;
}
if (ip.isV6() && hasIpv6Addr()) {
ip.toString(ipbuf);
DEBUG_INFO("failed to add IP (%s), only one per type per netif allowed\n", ipbuf);
return false;
}
@@ -157,22 +170,8 @@ bool VirtualTap::addIp(const InetAddress &ip)
return false;
}
if (std::find(_ips.begin(),_ips.end(),ip) == _ips.end()) {
lwip_init_interface((void*)this, this->_mac, ip);
// TODO: Add ZTS_EVENT_ADDR_NEW ?
_lwip_init_interface((void*)this, ip);
_ips.push_back(ip);
// Send callback message
struct zts_addr_details *ad = new zts_addr_details;
ad->nwid = _nwid;
if (ip.isV4()) {
struct sockaddr_in *in4 = (struct sockaddr_in*)&(ad->addr);
memcpy(&(in4->sin_addr.s_addr), ip.rawIpData(), 4);
postEvent(ZTS_EVENT_ADDR_ADDED_IP4, (void*)ad);
}
if (ip.isV6()) {
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(ad->addr);
memcpy(&(in6->sin6_addr.s6_addr), ip.rawIpData(), 16);
postEvent(ZTS_EVENT_ADDR_ADDED_IP6, (void*)ad);
}
std::sort(_ips.begin(),_ips.end());
}
return true;
@@ -183,20 +182,7 @@ bool VirtualTap::removeIp(const InetAddress &ip)
Mutex::Lock _l(_ips_m);
std::vector<InetAddress>::iterator i(std::find(_ips.begin(),_ips.end(),ip));
if (std::find(_ips.begin(),_ips.end(),ip) != _ips.end()) {
struct zts_addr_details *ad = new zts_addr_details;
ad->nwid = _nwid;
if (ip.isV4()) {
struct sockaddr_in *in4 = (struct sockaddr_in*)&(ad->addr);
memcpy(&(in4->sin_addr.s_addr), ip.rawIpData(), 4);
postEvent(ZTS_EVENT_ADDR_REMOVED_IP4, (void*)ad);
// FIXME: De-register from network stack
}
if (ip.isV6()) {
// FIXME: De-register from network stack
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(ad->addr);
memcpy(&(in6->sin6_addr.s6_addr), ip.rawIpData(), 16);
postEvent(ZTS_EVENT_ADDR_REMOVED_IP6, (void*)ad);
}
_lwip_remove_address_from_netif((void*)this, ip);
_ips.erase(i);
}
return true;
@@ -211,8 +197,8 @@ std::vector<InetAddress> VirtualTap::ips() const
void VirtualTap::put(const MAC &from,const MAC &to,unsigned int etherType,
const void *data,unsigned int len)
{
if (len <= _mtu && _enabled) {
lwip_eth_rx(this, from, to, etherType, data, len);
if (len && _enabled) {
_lwip_eth_rx(this, from, to, etherType, data, len);
}
}
@@ -221,19 +207,6 @@ std::string VirtualTap::deviceName() const
return _dev;
}
std::string VirtualTap::nodeId() const
{
if (service) {
char id[16];
memset(id, 0, sizeof(id));
sprintf(id, "%llx", (unsigned long long)((OneService *)service)->getNode()->address());
return std::string(id);
}
else {
return std::string("----------");
}
}
void VirtualTap::setFriendlyName(const char *friendlyName)
{
DEBUG_INFO("%s", friendlyName);
@@ -291,7 +264,7 @@ void VirtualTap::threadMain()
if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) {
break;
}
#if defined(_WIN32)
#if defined(__WINDOWS__)
Sleep(ZTS_TAP_THREAD_POLLING_INTERVAL);
#else
struct timespec sleepValue = {0};
@@ -301,11 +274,6 @@ void VirtualTap::threadMain()
}
}
void VirtualTap::Housekeeping()
{
//
}
void VirtualTap::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address,
const struct sockaddr *from,void *data,unsigned long len) {}
void VirtualTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) {}
@@ -314,5 +282,433 @@ void VirtualTap::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,v
void VirtualTap::phyOnTcpClose(PhySocket *sock,void **uptr) {}
void VirtualTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
void VirtualTap::phyOnTcpWritable(PhySocket *sock,void **uptr) {}
void VirtualTap::phyOnUnixClose(PhySocket *sock,void **uptr) {}
} // namespace ZeroTier
//////////////////////////////////////////////////////////////////////////////
// Netif driver code for lwIP network stack //
//////////////////////////////////////////////////////////////////////////////
bool _has_exited = false;
// Used to generate enumerated lwIP interface names
int netifCount = 0;
// Lock to guard access to network stack state changes
Mutex stackLock;
// Callback for when the TCPIP thread has been successfully started
static void _tcpip_init_done(void *arg)
{
sys_sem_t *sem;
sem = (sys_sem_t *)arg;
_setState(ZTS_STATE_STACK_RUNNING);
_enqueueEvent(ZTS_EVENT_STACK_UP);
sys_sem_signal(sem);
}
static void _main_lwip_driver_loop(void *arg)
{
#if defined(__linux__)
pthread_setname_np(pthread_self(), ZTS_LWIP_DRIVER_THREAD_NAME);
#endif
#if defined(__APPLE__)
pthread_setname_np(ZTS_LWIP_DRIVER_THREAD_NAME);
#endif
sys_sem_t sem;
LWIP_UNUSED_ARG(arg);
if (sys_sem_new(&sem, 0) != ERR_OK) {
DEBUG_ERROR("failed to create semaphore");
}
tcpip_init(_tcpip_init_done, &sem);
sys_sem_wait(&sem);
// Main loop
while(_getState(ZTS_STATE_STACK_RUNNING)) {
zts_delay_ms(LWIP_DRIVER_LOOP_INTERVAL);
}
_has_exited = true;
_enqueueEvent(ZTS_EVENT_STACK_DOWN);
}
bool _lwip_is_up()
{
Mutex::Lock _l(stackLock);
return _getState(ZTS_STATE_STACK_RUNNING);
}
void _lwip_driver_init()
{
if (_lwip_is_up()) {
return;
}
if (_has_exited) {
return;
}
Mutex::Lock _l(stackLock);
#if defined(__WINDOWS__)
sys_init(); // Required for win32 init of critical sections
#endif
sys_thread_new(ZTS_LWIP_DRIVER_THREAD_NAME, _main_lwip_driver_loop,
NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
}
void _lwip_driver_shutdown()
{
if (_has_exited) {
return;
}
Mutex::Lock _l(stackLock);
// Set flag to stop sending frames into the core
_clrState(ZTS_STATE_STACK_RUNNING);
// Wait until the main lwIP thread has exited
while (!_has_exited) { zts_delay_ms(LWIP_DRIVER_LOOP_INTERVAL); }
}
void _lwip_remove_netif(void *netif)
{
if (!netif) {
return;
}
struct netif *n = (struct netif*)netif;
LOCK_TCPIP_CORE();
netif_remove(n);
netif_set_down(n);
netif_set_link_down(n);
UNLOCK_TCPIP_CORE();
}
err_t _lwip_eth_tx(struct netif *n, struct pbuf *p)
{
if (!n) {
return ERR_IF;
}
struct pbuf *q;
char buf[ZT_MAX_MTU+32];
char *bufptr;
int totalLength = 0;
VirtualTap *tap = (VirtualTap*)n->state;
bufptr = buf;
for (q = p; q != NULL; q = q->next) {
memcpy(bufptr, q->payload, q->len);
bufptr += q->len;
totalLength += q->len;
}
struct eth_hdr *ethhdr;
ethhdr = (struct eth_hdr *)buf;
MAC src_mac;
MAC dest_mac;
src_mac.setTo(ethhdr->src.addr, 6);
dest_mac.setTo(ethhdr->dest.addr, 6);
char *data = buf + sizeof(struct eth_hdr);
int len = totalLength - sizeof(struct eth_hdr);
int proto = Utils::ntoh((uint16_t)ethhdr->type);
tap->_handler(tap->_arg, NULL, tap->_nwid, src_mac, dest_mac, proto, 0, data, len);
if (ZT_MSG_TRANSFER == true) {
char flagbuf[32];
memset(&flagbuf, 0, 32);
char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16];
snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
ethhdr->dest.addr[0], ethhdr->dest.addr[1], ethhdr->dest.addr[2],
ethhdr->dest.addr[3], ethhdr->dest.addr[4], ethhdr->dest.addr[5]);
MAC mac;
mac.setTo(ethhdr->dest.addr, 6);
mac.toAddress(tap->_nwid).toString(nodeBuf);
/*
DEBUG_TRANS("len=%5d dst=%s [%s TX <-- %s] ethertype=0x%04x %s", totalLength, macBuf, nodeBuf, tap->nodeId().c_str(),
Utils::ntoh(ethhdr->type), flagbuf);
*/
}
return ERR_OK;
}
void _lwip_eth_rx(VirtualTap *tap, const MAC &from, const MAC &to, unsigned int etherType,
const void *data, unsigned int len)
{
#ifdef LWIP_STATS
stats_display();
#endif
if (!_getState(ZTS_STATE_STACK_RUNNING)) {
return;
}
struct pbuf *p,*q;
struct eth_hdr ethhdr;
from.copyTo(ethhdr.src.addr, 6);
to.copyTo(ethhdr.dest.addr, 6);
ethhdr.type = Utils::hton((uint16_t)etherType);
if (ZT_MSG_TRANSFER == true) {
char flagbuf[32];
memset(&flagbuf, 0, 32);
char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16];
snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
ethhdr.dest.addr[0], ethhdr.dest.addr[1], ethhdr.dest.addr[2],
ethhdr.dest.addr[3], ethhdr.dest.addr[4], ethhdr.dest.addr[5]);
MAC mac;
mac.setTo(ethhdr.src.addr, 6);
mac.toAddress(tap->_nwid).toString(nodeBuf);
/*
DEBUG_TRANS("len=%5d dst=%s [%s RX --> %s] ethertype=0x%04x %s", len, macBuf, nodeBuf, tap->nodeId().c_str(),
Utils::ntoh(ethhdr.type), flagbuf);
*/
}
p = pbuf_alloc(PBUF_RAW, (uint16_t)len+sizeof(struct eth_hdr), PBUF_RAM);
if (!p) {
DEBUG_ERROR("dropped packet: unable to allocate memory for pbuf");
return;
}
// First pbuf gets ethernet header at start
q = p;
if (q->len < sizeof(ethhdr)) {
pbuf_free(p);
p = NULL;
DEBUG_ERROR("dropped packet: first pbuf smaller than ethernet header");
return;
}
// Copy frame data into pbuf
const char *dataptr = reinterpret_cast<const char *>(data);
memcpy(q->payload,&ethhdr,sizeof(ethhdr));
int remainingPayloadSpace = q->len - sizeof(ethhdr);
memcpy((char*)q->payload + sizeof(ethhdr),dataptr,remainingPayloadSpace);
dataptr += remainingPayloadSpace;
// Remaining pbufs (if any) get rest of data
while ((q = q->next)) {
memcpy(q->payload,dataptr,q->len);
dataptr += q->len;
}
// Feed packet into stack
int err;
if (Utils::ntoh(ethhdr.type) == 0x800 || Utils::ntoh(ethhdr.type) == 0x806) {
if (tap->netif4) {
if ((err = ((struct netif *)tap->netif4)->input(p, (struct netif *)tap->netif4)) != ERR_OK) {
DEBUG_ERROR("packet input error (%d)", err);
pbuf_free(p);
}
}
}
if (Utils::ntoh(ethhdr.type) == 0x86DD) {
if (tap->netif6) {
if ((err = ((struct netif *)tap->netif6)->input(p, (struct netif *)tap->netif6)) != ERR_OK) {
DEBUG_ERROR("packet input error (%d)", err);
pbuf_free(p);
}
}
}
}
bool _lwip_is_netif_up(void *n)
{
if (!n) {
return false;
}
LOCK_TCPIP_CORE();
bool result = netif_is_up((struct netif*)n);
UNLOCK_TCPIP_CORE();
return result;
}
static struct zts_netif_details *_lwip_prepare_netif_status_msg(struct netif *n)
{
if (!n || !n->state) {
return NULL;
}
VirtualTap *tap = (VirtualTap *)n->state;
struct zts_netif_details *details = new zts_netif_details();
details->nwid = tap->_nwid;
memcpy(&(details->mac), n->hwaddr, n->hwaddr_len);
details->mtu = n->mtu;
return details;
}
static void _netif_remove_callback(struct netif *n)
{
// Called from core, no need to lock
if (!n || !n->state) {
return;
}
VirtualTap *tap = (VirtualTap *)n->state;
struct zts_netif_details *details = new zts_netif_details();
details->nwid = tap->_nwid;
details->mac = 0;
details->mtu = 0;
_enqueueEvent(ZTS_EVENT_NETIF_REMOVED, (void*)details);
}
static void _netif_status_callback(struct netif *n)
{
// Called from core, no need to lock
if (!n) {
return;
} if (netif_is_up(n)) {
_enqueueEvent(ZTS_EVENT_NETIF_UP, (void*)_lwip_prepare_netif_status_msg(n));
} else {
_enqueueEvent(ZTS_EVENT_NETIF_DOWN, (void*)_lwip_prepare_netif_status_msg(n));
}
}
static void _netif_link_callback(struct netif *n)
{
// Called from core, no need to lock
if (!n) {
return;
} if (netif_is_link_up(n)) {
_enqueueEvent(ZTS_EVENT_NETIF_LINK_UP, (void*)_lwip_prepare_netif_status_msg(n));
} else {
_enqueueEvent(ZTS_EVENT_NETIF_LINK_DOWN, (void*)_lwip_prepare_netif_status_msg(n));
}
}
static err_t _netif_init4(struct netif *n)
{
if (!n || !n->state) {
return ERR_IF;
}
// Called from core, no need to lock
VirtualTap *tap = (VirtualTap*)(n->state);
n->hwaddr_len = 6;
n->name[0] = '4';
n->name[1] = 'a'+netifCount;
n->linkoutput = _lwip_eth_tx;
n->output = etharp_output;
n->mtu = std::min(LWIP_MTU,(int)tap->_mtu);
n->flags = NETIF_FLAG_BROADCAST
| NETIF_FLAG_ETHARP
| NETIF_FLAG_ETHERNET
| NETIF_FLAG_IGMP
| NETIF_FLAG_MLD6
| NETIF_FLAG_LINK_UP
| NETIF_FLAG_UP;
n->hwaddr_len = sizeof(n->hwaddr);
tap->_mac.copyTo(n->hwaddr, n->hwaddr_len);
return ERR_OK;
}
static err_t _netif_init6(struct netif *n)
{
if (!n || !n->state) {
return ERR_IF;
}
n->hwaddr_len = sizeof(n->hwaddr);
VirtualTap *tap = (VirtualTap*)(n->state);
tap->_mac.copyTo(n->hwaddr, n->hwaddr_len);
// Called from core, no need to lock
n->hwaddr_len = 6;
n->name[0] = '6';
n->name[1] = 'a'+netifCount;
n->linkoutput = _lwip_eth_tx;
n->output_ip6 = ethip6_output;
n->mtu = std::min(LWIP_MTU,(int)tap->_mtu);
n->flags = NETIF_FLAG_BROADCAST
| NETIF_FLAG_ETHARP
| NETIF_FLAG_ETHERNET
| NETIF_FLAG_IGMP
| NETIF_FLAG_MLD6
| NETIF_FLAG_LINK_UP
| NETIF_FLAG_UP;
return ERR_OK;
}
void _lwip_init_interface(void *tapref, const InetAddress &ip)
{
char ipbuf[INET6_ADDRSTRLEN];
char macbuf[ZTS_MAC_ADDRSTRLEN];
VirtualTap *vtap = (VirtualTap*)tapref;
struct netif *n = NULL;
bool isNewNetif = false;
if (ip.isV4()) {
if (vtap->netif4) {
n = (struct netif*)vtap->netif4;
}
else {
n = new struct netif;
isNewNetif = true;
netifCount++;
}
/*
netif_set_status_callback(n, _netif_status_callback);
netif_set_remove_callback(n, _netif_remove_callback);
netif_set_link_callback(n, _netif_link_callback);
*/
char nmbuf[INET6_ADDRSTRLEN];
static ip4_addr_t ip4, netmask, gw;
IP4_ADDR(&gw,127,0,0,1);
ip4.addr = *((u32_t *)ip.rawIpData());
netmask.addr = *((u32_t *)ip.netmask().rawIpData());
LOCK_TCPIP_CORE();
netif_add(n, &ip4, &netmask, &gw, (void*)vtap, _netif_init4, tcpip_input);
vtap->netif4 = (void*)n;
UNLOCK_TCPIP_CORE();
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2],
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]);
//DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, nm=%s, tap=%p]",n,
// macbuf, ip.toString(ipbuf), ip.netmask().toString(nmbuf), vtap);
}
if (ip.isV6()) {
if (vtap->netif6) {
n = (struct netif*)vtap->netif6;
}
else {
n = new struct netif;
isNewNetif = true;
netifCount++;
}/*
netif_set_status_callback(n, _netif_status_callback);
netif_set_remove_callback(n, _netif_remove_callback);
netif_set_link_callback(n, _netif_link_callback);
*/
static ip6_addr_t ip6;
memcpy(&(ip6.addr), ip.rawIpData(), sizeof(ip6.addr));
LOCK_TCPIP_CORE();
if (isNewNetif) {
vtap->netif6 = (void*)n;
netif_add(n, NULL, NULL, NULL, (void*)vtap, _netif_init6, ethernet_input);
n->ip6_autoconfig_enabled = 1;
vtap->_mac.copyTo(n->hwaddr, n->hwaddr_len);
netif_create_ip6_linklocal_address(n, 1);
netif_set_link_up(n);
netif_set_up(n);
netif_set_default(n);
}
netif_add_ip6_address(n,&ip6,NULL);
n->output_ip6 = ethip6_output;
UNLOCK_TCPIP_CORE();
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2],
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]);
//DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, tap=%p]", n,
// macbuf, ip.toString(ipbuf), vtap);
}
}
void _lwip_remove_address_from_netif(void *tapref, const InetAddress &ip)
{
if (!tapref) {
return;
}
VirtualTap *vtap = (VirtualTap*)tapref;
struct netif *n = NULL;
/* When true multi-homing is implemented this will need to
be a bit more sophisticated */
if (ip.isV4()) {
if (vtap->netif4) {
n = (struct netif*)vtap->netif4;
}
}
if (ip.isV6()) {
if (vtap->netif6) {
n = (struct netif*)vtap->netif6;
}
}
if (!n) {
return;
}
_lwip_remove_netif(n);
}
} // namespace ZeroTier

View File

@@ -1,64 +1,43 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (c)2013-2020 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.
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* 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.
* Change Date: 2024-01-01
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* 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.
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
/**
* @file
*
* Virtual Ethernet tap device
* Header for virtual ethernet tap device and combined network stack driver
*/
#ifndef LIBZT_VIRTUALTAP_HPP
#define LIBZT_VIRTUALTAP_HPP
#ifndef ZT_VIRTUAL_TAP_HPP
#define ZT_VIRTUAL_TAP_HPP
#ifndef _MSC_VER
extern int errno;
#endif
#include "lwip/err.h"
#define ZTS_LWIP_DRIVER_THREAD_NAME "ZTNetworkStackThread"
#include "MAC.hpp"
#include "Phy.hpp"
#include "Thread.hpp"
#include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#include "Mutex.hpp"
#include "Options.h"
#if defined(_WIN32)
#include <WinSock2.h>
#include <Windows.h>
#include <IPHlpApi.h>
#include <Ifdef.h>
#endif
namespace ZeroTier {
class Mutex;
class MAC;
class MulticastGroup;
struct InetAddress;
/**
* A virtual tap device. The ZeroTier core service creates one of these for each
* virtual network joined. It will be destroyed upon leave().
* A virtual tap device. The ZeroTier Node Service will create one per
* joined network. It will be destroyed upon leave().
*/
class VirtualTap
{
@@ -97,18 +76,18 @@ public:
bool hasIpv6Addr();
/**
* Adds an address to the userspace stack interface associated with this VirtualTap
* Adds an address to the user-space stack interface associated with this VirtualTap
* - Starts VirtualTap main thread ONLY if successful
*/
bool addIp(const InetAddress &ip);
/**
* Removes an address from the userspace stack interface associated with this VirtualTap
* Removes an address from the user-space stack interface associated with this VirtualTap
*/
bool removeIp(const InetAddress &ip);
/**
* Presents data to the userspace stack
* Presents data to the user-space stack
*/
void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,
unsigned int len);
@@ -118,11 +97,6 @@ public:
*/
std::string deviceName() const;
/**
* Get Node ID (ZT address)
*/
std::string nodeId() const;
/**
* Set friendly name
*/
@@ -145,57 +119,24 @@ public:
void threadMain()
throw();
#if defined(__MINGW32__)
/* The following is merely to make ZeroTier's OneService happy while building on Windows.
we won't use these in libzt */
NET_LUID _deviceLuid;
std::string _deviceInstanceId;
/**
* Returns whether the VirtualTap interface has been initialized
*/
bool isInitialized() const { return _initialized; };
inline const NET_LUID &luid() const { return _deviceLuid; }
inline const std::string &instanceId() const { return _deviceInstanceId; }
#endif
/**
* For moving data onto the ZeroTier virtual wire
*/
void (*_handler)(void *, void *, uint64_t, const MAC &, const MAC &, unsigned int, unsigned int,
const void *, unsigned int);
void phyOnUnixClose(PhySocket *sock, void **uptr);
void phyOnUnixData(PhySocket *sock, void **uptr, void *data, ssize_t len);
void phyOnUnixWritable(PhySocket *sock, void **uptr, bool stack_invoked);
//////////////////////////////////////////////////////////////////////////////
// Lower-level lwIP netif handling and traffic handling readiness //
//////////////////////////////////////////////////////////////////////////////
void *netif = NULL;
void *netif4 = NULL;
void *netif6 = NULL;
/**
* The last time that this virtual tap received a network config update from the core
*/
uint64_t _lastConfigUpdateTime = 0;
/**
* The last time that a callback notification was sent to the user application signalling
* that this interface is ready to process traffic.
*/
uint64_t _lastReadyReportTime = 0;
void lastConfigUpdate(uint64_t lastConfigUpdateTime);
int _networkStatus = 0;
//////////////////////////////////////////////////////////////////////////////
// Vars //
//////////////////////////////////////////////////////////////////////////////
std::vector<std::pair<InetAddress, InetAddress> > routes;
char vtap_full_name[64];
std::vector<InetAddress> ips() const;
@@ -221,17 +162,6 @@ public:
std::vector<MulticastGroup> _multicastGroups;
Mutex _multicastGroups_m;
/*
* Timestamp of last run of housekeeping
* SEE: ZT_HOUSEKEEPING_INTERVAL in ZeroTier.h
*/
uint64_t last_housekeeping_ts = 0;
/**
* Performs miscellaneous background tasks
*/
void Housekeeping();
//////////////////////////////////////////////////////////////////////////////
// Not used in this implementation //
//////////////////////////////////////////////////////////////////////////////
@@ -244,8 +174,130 @@ public:
void phyOnTcpClose(PhySocket *sock,void **uptr);
void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len);
void phyOnTcpWritable(PhySocket *sock,void **uptr);
void phyOnUnixClose(PhySocket *sock,void **uptr);
};
/**
* @brief Return whether a given netif's NETIF_FLAG_UP flag is set
*
* @usage This is a convenience function to encapsulate a macro
*/
bool _lwip_is_netif_up(void *netif);
/**
* @brief Increase the delay multiplier for the main driver loop
*
* @usage This should be called when we know the stack won't be used by any virtual taps
*/
void _lwip_hibernate_driver();
/**
* @brief Decrease the delay multiplier for the main driver loop
*
* @usage This should be called when at least one virtual tap is active
*/
void _lwip_wake_driver();
/**
* Returns whether the lwIP network stack is up and ready to process traffic
*/
bool _lwip_is_up();
/**
* @brief Initialize network stack semaphores, threads, and timers.
*
* @usage This is called during the initial setup of each VirtualTap but is only allowed to execute once
*/
void _lwip_driver_init();
/**
* @brief Shutdown the stack as completely as possible (not officially supported by lwIP)
*
* @usage This is to be called after it is determined that no further network activity will take place.
* The tcpip thread will be stopped, all interfaces will be brought down and all resources will
* be deallocated. A full application restart will be required to bring the stack back online.
*/
void _lwip_driver_shutdown();
/**
* @brief Requests that a netif be brought down and removed.
*/
void _lwip_remove_netif(void *netif);
/**
* @brief Initialize and start the DNS client
*/
void _lwip_dns_init();
/**
* @brief Starts DHCP timers
*/
void _lwip_start_dhcp(void *netif);
/**
* @brief Called when the status of a netif changes:
* - Interface is up/down (ZTS_EVENT_NETIF_UP, ZTS_EVENT_NETIF_DOWN)
* - Address changes while up (ZTS_EVENT_NETIF_NEW_ADDRESS)
*/
#if LWIP_NETIF_STATUS_CALLBACK
static void _netif_status_callback(struct netif *netif);
#endif
/**
* @brief Called when a netif is removed (ZTS_EVENT_NETIF_INTERFACE_REMOVED)
*/
#if LWIP_NETIF_REMOVE_CALLBACK
static void _netif_remove_callback(struct netif *netif);
#endif
/**
* @brief Called when a link is brought up or down (ZTS_EVENT_NETIF_LINK_UP, ZTS_EVENT_NETIF_LINK_DOWN)
*/
#if LWIP_NETIF_LINK_CALLBACK
static void _netif_link_callback(struct netif *netif);
#endif
/**
* @brief Set up an interface in the network stack for the VirtualTap.
*
* @param tapref Reference to VirtualTap that will be responsible for sending and receiving data
* @param ip Virtual IP address for this ZeroTier VirtualTap interface
*/
void _lwip_init_interface(void *tapref, const InetAddress &ip);
/**
* @brief Remove an assigned address from an lwIP netif
*
* @param tapref Reference to VirtualTap
* @param ip Virtual IP address to remove from this interface
*/
void _lwip_remove_address_from_netif(void *tapref, const InetAddress &ip);
/**
* @brief Called from the stack, outbound ethernet frames from the network stack enter the ZeroTier virtual wire here.
*
* @usage This shall only be called from the stack or the stack driver. Not the application thread.
* @param netif Transmits an outgoing Ethernet fram from the network stack onto the ZeroTier virtual wire
* @param p A pointer to the beginning of a chain pf struct pbufs
* @return
*/
err_t _lwip_eth_tx(struct netif *netif, struct pbuf *p);
/**
* @brief Receives incoming Ethernet frames from the ZeroTier virtual wire
*
* @usage This shall be called from the VirtualTap's I/O thread (via VirtualTap::put())
* @param tap Pointer to VirtualTap from which this data comes
* @param from Origin address (virtual ZeroTier hardware address)
* @param to Intended destination address (virtual ZeroTier hardware address)
* @param etherType Protocol type
* @param data Pointer to Ethernet frame
* @param len Length of Ethernet frame
*/
void _lwip_eth_rx(VirtualTap *tap, const MAC &from, const MAC &to, unsigned int etherType,
const void *data, unsigned int len);
} // namespace ZeroTier
#endif // _H

View File

@@ -1,28 +1,15 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (c)2013-2020 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.
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* 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.
* Change Date: 2024-01-01
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* 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.
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
package com.zerotier.libzt;
@@ -36,16 +23,18 @@ public class ZeroTier
// Everything is ok
public static int ZTS_ERR_OK = 0;
// Error
public static int ZTS_ERR = -1;
// A argument provided by the user application is invalid (e.g. out of range, NULL, etc)
public static int ZTS_ERR_INVALID_ARG = -1;
public static int ZTS_ERR_INVALID_ARG = -2;
// The service isn't initialized or is for some reason currently unavailable. Try again.
public static int ZTS_ERR_SERVICE = -2;
public static int ZTS_ERR_SERVICE = -3;
// For some reason this API operation is not permitted or doesn't make sense at this time.
public static int ZTS_ERR_INVALID_OP = -3;
public static int ZTS_ERR_INVALID_OP = -4;
// The call succeeded, but no object or relevant result was available
public static int ZTS_ERR_NO_RESULT = -4;
public static int ZTS_ERR_NO_RESULT = -5;
// General internal failure
public static int ZTS_ERR_GENERAL = -5;
public static int ZTS_ERR_GENERAL = -6;
//////////////////////////////////////////////////////////////////////////////
// Static initialization //

View File

@@ -1,481 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
/**
* @file
*
* lwIP network stack driver
*/
#include <queue>
#include "MAC.hpp"
#include "Mutex.hpp"
#include "netif/ethernet.h"
#include "lwip/netif.h"
#include "lwip/etharp.h"
#include "lwip/tcpip.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/sys.h"
#include "lwip/tcp.h"
#include "lwip/timeouts.h"
#include "lwip/stats.h"
#include "lwip/ethip6.h"
#include "lwip/ip_addr.h"
#include "lwip/nd6.h"
#include "lwip/netifapi.h"
#include "lwip/stats.h"
#include "VirtualTap.hpp"
#include "lwipDriver.hpp"
#include "ZeroTier.h"
#include "Controls.hpp"
extern void postEvent(uint64_t eventCode, void *arg);
extern void postEvent(uint64_t eventCode);
#if defined(_WIN32)
#include <time.h>
#endif
/**
* Length of human-readable MAC address string
*/
#define ZTS_MAC_ADDRSTRLEN 18
#ifndef htonll
#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
#endif
namespace ZeroTier {
bool _has_exited = false;
int hibernationDelayMultiplier = 1;
extern bool _run_lwip_tcpip;
Mutex lwip_driver_m;
void lwip_sleep(long ms)
{
#if defined(_WIN32)
Sleep(ms*hibernationDelayMultiplier);
#else
usleep(ms*1000*hibernationDelayMultiplier);
#endif
}
void lwip_hibernate_driver()
{
hibernationDelayMultiplier = ZTS_HIBERNATION_MULTIPLIER;
}
void lwip_wake_driver()
{
hibernationDelayMultiplier = 1;
}
// Callback for when the TCPIP thread has been successfully started
static void tcpip_init_done(void *arg)
{
sys_sem_t *sem;
sem = (sys_sem_t *)arg;
_run_lwip_tcpip = true;
postEvent(ZTS_EVENT_STACK_UP);
sys_sem_signal(sem);
}
static void main_lwip_driver_loop(void *arg)
{
#if defined(__linux__)
pthread_setname_np(pthread_self(), ZTS_LWIP_DRIVER_THREAD_NAME);
#endif
#if defined(__APPLE__)
pthread_setname_np(ZTS_LWIP_DRIVER_THREAD_NAME);
#endif
sys_sem_t sem;
LWIP_UNUSED_ARG(arg);
if (sys_sem_new(&sem, 0) != ERR_OK) {
DEBUG_ERROR("failed to create semaphore");
}
tcpip_init(tcpip_init_done, &sem);
sys_sem_wait(&sem);
// Main loop
while(_run_lwip_tcpip) {
lwip_sleep(LWIP_DRIVER_LOOP_INTERVAL);
}
_has_exited = true;
postEvent(ZTS_EVENT_STACK_DOWN);
}
bool lwip_is_up()
{
Mutex::Lock _l(lwip_driver_m);
return _run_lwip_tcpip;
}
bool lwip_has_previously_shutdown()
{
Mutex::Lock _l(lwip_driver_m);
return _has_exited;
}
void lwip_driver_init()
{
if (lwip_is_up()) {
return;
}
if (lwip_has_previously_shutdown()) {
return;
}
Mutex::Lock _l(lwip_driver_m);
#if defined(_WIN32)
sys_init(); // Required for win32 init of critical sections
#endif
void *st = sys_thread_new(ZTS_LWIP_DRIVER_THREAD_NAME, main_lwip_driver_loop,
NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
}
void lwip_driver_shutdown()
{
if (lwip_has_previously_shutdown()) {
return;
}
Mutex::Lock _l(lwip_driver_m);
// Set flag to stop sending frames into the core
_run_lwip_tcpip = false;
// Wait until the main lwIP thread has exited
while (!_has_exited) { lwip_sleep(LWIP_DRIVER_LOOP_INTERVAL); }
/*
if (tcpip_shutdown() == ERR_OK) {
sys_timeouts_free();
}
*/
}
void lwip_remove_netif(void *netif)
{
struct netif *n = (struct netif*)netif;
LOCK_TCPIP_CORE();
netif_remove(n);
netif_set_down(n);
netif_set_link_down(n);
UNLOCK_TCPIP_CORE();
}
err_t lwip_eth_tx(struct netif *n, struct pbuf *p)
{
struct pbuf *q;
char buf[ZT_MAX_MTU+32];
char *bufptr;
int totalLength = 0;
VirtualTap *tap = (VirtualTap*)n->state;
bufptr = buf;
for (q = p; q != NULL; q = q->next) {
memcpy(bufptr, q->payload, q->len);
bufptr += q->len;
totalLength += q->len;
}
struct eth_hdr *ethhdr;
ethhdr = (struct eth_hdr *)buf;
MAC src_mac;
MAC dest_mac;
src_mac.setTo(ethhdr->src.addr, 6);
dest_mac.setTo(ethhdr->dest.addr, 6);
char *data = buf + sizeof(struct eth_hdr);
int len = totalLength - sizeof(struct eth_hdr);
int proto = Utils::ntoh((uint16_t)ethhdr->type);
tap->_handler(tap->_arg, NULL, tap->_nwid, src_mac, dest_mac, proto, 0, data, len);
/*
if (ZT_MSG_TRANSFER == true) {
char flagbuf[32];
memset(&flagbuf, 0, 32);
char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16];
snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
ethhdr->dest.addr[0], ethhdr->dest.addr[1], ethhdr->dest.addr[2],
ethhdr->dest.addr[3], ethhdr->dest.addr[4], ethhdr->dest.addr[5]);
MAC mac;
mac.setTo(ethhdr->dest.addr, 6);
mac.toAddress(tap->_nwid).toString(nodeBuf);
DEBUG_TRANS("len=%5d dst=%s [%s TX <-- %s] proto=0x%04x %s", totalLength, macBuf, nodeBuf, tap->nodeId().c_str(),
Utils::ntoh(ethhdr->type), flagbuf);
}
*/
return ERR_OK;
}
void lwip_eth_rx(VirtualTap *tap, const MAC &from, const MAC &to, unsigned int etherType,
const void *data, unsigned int len)
{
#ifdef LWIP_STATS
stats_display();
#endif
if (!_run_lwip_tcpip) {
return;
}
struct pbuf *p,*q;
struct eth_hdr ethhdr;
from.copyTo(ethhdr.src.addr, 6);
to.copyTo(ethhdr.dest.addr, 6);
ethhdr.type = Utils::hton((uint16_t)etherType);
/*
if (ZT_MSG_TRANSFER == true) {
char flagbuf[32];
memset(&flagbuf, 0, 32);
char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16];
snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
ethhdr.dest.addr[0], ethhdr.dest.addr[1], ethhdr.dest.addr[2],
ethhdr.dest.addr[3], ethhdr.dest.addr[4], ethhdr.dest.addr[5]);
MAC mac;
mac.setTo(ethhdr.src.addr, 6);
mac.toAddress(tap->_nwid).toString(nodeBuf);
DEBUG_TRANS("len=%5d dst=%s [%s RX --> %s] proto=0x%04x %s", len, macBuf, nodeBuf, tap->nodeId().c_str(),
Utils::ntoh(ethhdr.type), flagbuf);
}
*/
p = pbuf_alloc(PBUF_RAW, len+sizeof(struct eth_hdr), PBUF_RAM);
if (!p) {
DEBUG_ERROR("dropped packet: unable to allocate memory for pbuf");
return;
}
// First pbuf gets ethernet header at start
q = p;
if (q->len < sizeof(ethhdr)) {
pbuf_free(p);
p = NULL;
DEBUG_ERROR("dropped packet: first pbuf smaller than ethernet header");
return;
}
// Copy frame data into pbuf
const char *dataptr = reinterpret_cast<const char *>(data);
memcpy(q->payload,&ethhdr,sizeof(ethhdr));
int remainingPayloadSpace = q->len - sizeof(ethhdr);
memcpy((char*)q->payload + sizeof(ethhdr),dataptr,remainingPayloadSpace);
dataptr += remainingPayloadSpace;
// Remaining pbufs (if any) get rest of data
while ((q = q->next)) {
memcpy(q->payload,dataptr,q->len);
dataptr += q->len;
}
// Feed packet into stack
int err;
if ((err = ((struct netif *)tap->netif)->input(p, (struct netif *)tap->netif)) != ERR_OK) {
DEBUG_ERROR("packet input error (%d)", err);
pbuf_free(p);
}
}
/*
static void print_netif_info(struct netif *n) {
DEBUG_INFO("n=%p, %c%c, %d, o=%p, o6=%p, mc=%x:%x:%x:%x:%x:%x, hwln=%d, st=%p, flgs=%d\n",
n,
n->name[0],
n->name[1],
n->mtu,
n->output,
n->output_ip6,
n->hwaddr[0],
n->hwaddr[1],
n->hwaddr[2],
n->hwaddr[3],
n->hwaddr[4],
n->hwaddr[5],
n->hwaddr_len,
n->state,
n->flags
);
}
*/
bool lwip_is_netif_up(void *n)
{
LOCK_TCPIP_CORE();
bool result = netif_is_up((struct netif*)n);
UNLOCK_TCPIP_CORE();
return result;
}
/**
* Called when a netif is removed (ZTS_EVENT_NETIF_INTERFACE_REMOVED)
*/
#if LWIP_NETIF_REMOVE_CALLBACK
static void netif_remove_callback(struct netif *n)
{
// Called from core, no need to lock
if (!n->state) {
return;
}
VirtualTap *tap = (VirtualTap *)n->state;
uint64_t mac = 0;
memcpy(&mac, n->hwaddr, n->hwaddr_len);
struct zts_netif_details *ifd = new zts_netif_details;
ifd->nwid = tap->_nwid;
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
ifd->mac = lwip_htonl(ifd->mac) >> 16;
postEvent(ZTS_EVENT_NETIF_REMOVED, (void*)ifd);
}
#endif
/**
* Called when a link is brought up or down (ZTS_EVENT_NETIF_LINK_UP, ZTS_EVENT_NETIF_LINK_DOWN)
*/
#if LWIP_NETIF_LINK_CALLBACK
static void netif_link_callback(struct netif *n)
{
// Called from core, no need to lock
if (!n->state) {
return;
}
VirtualTap *tap = (VirtualTap *)n->state;
uint64_t mac = 0;
memcpy(&mac, n->hwaddr, n->hwaddr_len);
if (n->flags & NETIF_FLAG_LINK_UP) {
struct zts_netif_details *ifd = new zts_netif_details;
ifd->nwid = tap->_nwid;
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
ifd->mac = lwip_htonl(ifd->mac) >> 16;
postEvent(ZTS_EVENT_NETIF_LINK_UP, (void*)ifd);
}
if (n->flags & NETIF_FLAG_LINK_UP) {
struct zts_netif_details *ifd = new zts_netif_details;
ifd->nwid = tap->_nwid;
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
ifd->mac = lwip_htonl(ifd->mac) >> 16;
postEvent(ZTS_EVENT_NETIF_LINK_DOWN, (void*)ifd);
}
}
#endif
void lwip_set_callbacks(struct netif *n)
{
#if LWIP_NETIF_STATUS_CALLBACK
// Not currently used
netif_set_status_callback(n, netif_status_callback);
#endif
#if LWIP_NETIF_REMOVE_CALLBACK
netif_set_remove_callback(n, netif_remove_callback);
#endif
#if LWIP_NETIF_LINK_CALLBACK
netif_set_link_callback(n, netif_link_callback);
#endif
}
static struct zts_netif_details *lwip_prepare_netif_status_msg(struct netif *n)
{
VirtualTap *tap = (VirtualTap*)(n->state);
struct zts_netif_details *ifd = new zts_netif_details;
// nwid
ifd->nwid = tap->_nwid;
// mtu
ifd->mtu = n->mtu;
// MAC
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
ifd->mac = htonll(ifd->mac) >> 16;
return ifd;
}
static err_t netif_init(struct netif *n)
{
// Called from netif code, no need to lock
n->hwaddr_len = 6;
n->name[0] = 'z';
n->name[1] = '4';
n->linkoutput = lwip_eth_tx;
n->output = etharp_output;
n->mtu = LWIP_MTU < ZT_MAX_MTU ? LWIP_MTU : ZT_MAX_MTU;
n->flags = NETIF_FLAG_BROADCAST
| NETIF_FLAG_ETHARP
| NETIF_FLAG_ETHERNET
| NETIF_FLAG_IGMP
| NETIF_FLAG_MLD6
| NETIF_FLAG_LINK_UP
| NETIF_FLAG_UP;
n->hwaddr_len = sizeof(n->hwaddr);
VirtualTap *tap = (VirtualTap*)(n->state);
tap->_mac.copyTo(n->hwaddr, n->hwaddr_len);
return ERR_OK;
}
void lwip_init_interface(void *tapref, const MAC &mac, const InetAddress &ip)
{
char ipbuf[INET6_ADDRSTRLEN];
char macbuf[ZTS_MAC_ADDRSTRLEN];
VirtualTap *vtap = (VirtualTap*)tapref;
struct netif *n = NULL;
if (vtap->netif) {
n = (struct netif*)vtap->netif;
}
else {
n = new struct netif;
}
if (ip.isV4()) {
char nmbuf[INET6_ADDRSTRLEN];
static ip4_addr_t ipaddr, netmask, gw;
IP4_ADDR(&gw,127,0,0,1);
ipaddr.addr = *((u32_t *)ip.rawIpData());
netmask.addr = *((u32_t *)ip.netmask().rawIpData());
LOCK_TCPIP_CORE();
netif_add(n, &ipaddr, &netmask, &gw, tapref, netif_init, tcpip_input);
postEvent(ZTS_EVENT_NETIF_UP, (void*)lwip_prepare_netif_status_msg(n));
UNLOCK_TCPIP_CORE();
/*
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2],
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]);
DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, nm=%s]",n,
macbuf, ip.toString(ipbuf), ip.netmask().toString(nmbuf));
*/
vtap->netif = (void*)n;
}
if (ip.isV6()) {
static ip6_addr_t ipaddr;
memcpy(&(ipaddr.addr), ip.rawIpData(), sizeof(ipaddr.addr));
n->ip6_autoconfig_enabled = 1;
LOCK_TCPIP_CORE();
netif_ip6_addr_set(n, 1, &ipaddr);
netif_create_ip6_linklocal_address(n, 1);
netif_ip6_addr_set_state(n, 0, IP6_ADDR_TENTATIVE);
netif_ip6_addr_set_state(n, 1, IP6_ADDR_TENTATIVE);
n->output_ip6 = ethip6_output;
postEvent(ZTS_EVENT_NETIF_UP, (void*)lwip_prepare_netif_status_msg(n));
UNLOCK_TCPIP_CORE();
/*
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2],
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]);
DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s]", n,
macbuf, ip.toString(ipbuf));
*/
}
}
} // namespace ZeroTier

View File

@@ -1,187 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* 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/>.
*
* --
*
* 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.
*/
/**
* @file
*
* lwIP network stack driver
*/
#ifndef LIBZT_LWIP_DRIVER_HPP
#define LIBZT_LWIP_DRIVER_HPP
#include "Debug.hpp"
#include "lwip/err.h"
namespace ZeroTier {
class MAC;
class Mutex;
class VirtualTap;
struct InetAddress;
/**
* @brief Structure used to associate packets with interfaces.
*/
struct zts_sorted_packet
{
// lwIP pbuf containing packet (originally encapsulated by ZT packet)
struct pbuf *p;
// ZT VirtualTap from which this packet originates
VirtualTap *vtap;
// lwIP netif we should accept this packet on
struct netif *n;
};
/**
* @brief Return whether a given netif's NETIF_FLAG_UP flag is set
*
* @usage This is a convenience function to encapsulate a macro
*/
bool lwip_is_netif_up(void *netif);
/**
* @brief Increase the delay multiplier for the main driver loop
*
* @usage This should be called when we know the stack won't be used by any virtual taps
*/
void lwip_hibernate_driver();
/**
* @brief Decrease the delay multiplier for the main driver loop
*
* @usage This should be called when at least one virtual tap is active
*/
void lwip_wake_driver();
/**
* Returns whether the lwIP network stack is up and ready to process traffic
*/
bool lwip_is_up();
/**
* @brief Initialize network stack semaphores, threads, and timers.
*
* @usage This is called during the initial setup of each VirtualTap but is only allowed to execute once
* @return
*/
void lwip_driver_init();
/**
* @brief Shutdown the stack as completely as possible (not officially supported by lwIP)
*
* @usage This is to be called after it is determined that no further network activity will take place.
* The tcpip thread will be stopped, all interfaces will be brought down and all resources will
* be deallocated. A full application restart will be required to bring the stack back online.
* @return
*/
void lwip_driver_shutdown();
/**
* @brief Requests that a netif be brought down and removed.
*
* @return
*/
void lwip_remove_netif(void *netif);
/**
* @brief Initialize and start the DNS client
*
* @usage Called after lwip_driver_init()
* @return
*/
void lwip_dns_init();
/**
* @brief Starts DHCP timers
*
* @usage lwip_driver_init()
* @return
*/
void lwip_start_dhcp(void *netif);
/**
* @brief Called when the status of a netif changes:
* - Interface is up/down (ZTS_EVENT_NETIF_UP, ZTS_EVENT_NETIF_DOWN)
* - Address changes while up (ZTS_EVENT_NETIF_NEW_ADDRESS)
*/
#if LWIP_NETIF_STATUS_CALLBACK
static void netif_status_callback(struct netif *netif);
#endif
/**
* @brief Called when a netif is removed (ZTS_EVENT_NETIF_INTERFACE_REMOVED)
*/
#if LWIP_NETIF_REMOVE_CALLBACK
static void netif_remove_callback(struct netif *netif);
#endif
/**
* @brief Called when a link is brought up or down (ZTS_EVENT_NETIF_LINK_UP, ZTS_EVENT_NETIF_LINK_DOWN)
*/
#if LWIP_NETIF_LINK_CALLBACK
static void netif_link_callback(struct netif *netif);
#endif
/**
* @brief Set up an interface in the network stack for the VirtualTap.
*
* @param
* @param tapref Reference to VirtualTap that will be responsible for sending and receiving data
* @param mac Virtual hardware address for this ZeroTier VirtualTap interface
* @param ip Virtual IP address for this ZeroTier VirtualTap interface
* @return
*/
void lwip_init_interface(void *tapref, const MAC &mac, const InetAddress &ip);
/**
* @brief Called from the stack, outbound ethernet frames from the network stack enter the ZeroTier virtual wire here.
*
* @usage This shall only be called from the stack or the stack driver. Not the application thread.
* @param netif Transmits an outgoing Ethernet fram from the network stack onto the ZeroTier virtual wire
* @param p A pointer to the beginning of a chain pf struct pbufs
* @return
*/
err_t lwip_eth_tx(struct netif *netif, struct pbuf *p);
/**
* @brief Receives incoming Ethernet frames from the ZeroTier virtual wire
*
* @usage This shall be called from the VirtualTap's I/O thread (via VirtualTap::put())
* @param tap Pointer to VirtualTap from which this data comes
* @param from Origin address (virtual ZeroTier hardware address)
* @param to Intended destination address (virtual ZeroTier hardware address)
* @param etherType Protocol type
* @param data Pointer to Ethernet frame
* @param len Length of Ethernet frame
* @return
*/
void lwip_eth_rx(VirtualTap *tap, const MAC &from, const MAC &to, unsigned int etherType,
const void *data, unsigned int len);
} // namespace ZeroTier
#endif // _H

View File

View File

View File

@@ -55,7 +55,7 @@
#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS 0
#endif
#if __ANDROID__
#define LWIP_PROVIDE_ERRNO 1
//#define LWIP_PROVIDE_ERRNO 0
#define SOCKLEN_T_DEFINED
#elif !defined(_MSC_VER)
#define LWIP_PROVIDE_ERRNO 1
@@ -83,7 +83,7 @@
------------------------------------ Presets -----------------------------------
------------------------------------------------------------------------------*/
#define LWIP_MTU 1500
#define LWIP_MTU 2800
#define LWIP_CHKSUM_ALGORITHM 2
// memory
#define MEMP_NUM_NETCONN 1024

View File

@@ -1,280 +0,0 @@
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ZeroTier.h"
bool node_ready = false;
bool network_ready = false;
// Example callbacks
void myZeroTierEventCallback(struct zts_callback_msg *msg)
{
//
// Node events
//
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE, node=%llx\n", msg->node->address);
node_ready = true;
// ZeroTier service is running and online
}
if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) {
printf("ZTS_EVENT_NODE_OFFLINE\n");
node_ready = false;
// ZeroTier service is running and online
}
if (msg->eventCode == ZTS_EVENT_NODE_NORMAL_TERMINATION) {
printf("ZTS_EVENT_NODE_NORMAL_TERMINATION\n");
// ZeroTier service has stopped
}
//
// Virtual network events
//
if (msg->eventCode == ZTS_EVENT_NETWORK_NOT_FOUND) {
printf("ZTS_EVENT_NETWORK_NOT_FOUND --- network=%llx\n", msg->network->nwid);
// Is your nwid incorrect?
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQUESTING_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQUESTING_CONFIG --- network=%llx\n", msg->network->nwid);
// Node is requesting network config details from controller, please wait
}
if (msg->eventCode == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
printf("ZTS_EVENT_NETWORK_ACCESS_DENIED --- network=%llx\n", msg->network->nwid);
// This node is not authorized to join nwid
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP4) {
printf("ZTS_EVENT_NETWORK_READY_IP4 --- network=%llx\n", msg->network->nwid);
network_ready = true;
// IPv4 traffic can now be processed for nwid
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
printf("ZTS_EVENT_NETWORK_READY_IP6 --- network=%llx\n", msg->network->nwid);
network_ready = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_DOWN) {
printf("ZTS_EVENT_NETWORK_DOWN --- network=%llx\n", msg->network->nwid);
// Can happen if another thread called zts_leave()
}
//
// Network stack events
//
if (msg->eventCode == ZTS_EVENT_NETIF_UP) {
printf("ZTS_EVENT_NETIF_UP --- network=%llx, mac=%llx, mtu=%d\n",
msg->netif->nwid,
msg->netif->mac,
msg->netif->mtu);
network_ready = true;
}
if (msg->eventCode == ZTS_EVENT_NETIF_DOWN) {
printf("ZTS_EVENT_NETIF_DOWN --- network=%llx, mac=%llx\n",
msg->netif->nwid,
msg->netif->mac);
network_ready = true;
}
//
// Address events
//
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP4) {
char ipstr[INET_ADDRSTRLEN];
struct sockaddr_in *in4 = (struct sockaddr_in*)&(msg->addr->addr);
inet_ntop(AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP4 --- addr=%s (on network=%llx)\n",
ipstr, msg->addr->nwid);
}
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[INET6_ADDRSTRLEN];
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(msg->addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_NEW_IP6 --- addr=%s (on network=%llx)\n",
ipstr, msg->addr->nwid);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP4) {
char ipstr[INET_ADDRSTRLEN];
struct sockaddr_in *in4 = (struct sockaddr_in*)&(msg->addr->addr);
inet_ntop(AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP4 --- addr=%s (on network=%llx)\n",
ipstr, msg->addr->nwid);
}
if (msg->eventCode == ZTS_EVENT_ADDR_REMOVED_IP6) {
char ipstr[INET6_ADDRSTRLEN];
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(msg->addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
printf("ZTS_EVENT_ADDR_REMOVED_IP6 --- addr=%s (on network=%llx)\n",
ipstr, msg->addr->nwid);
}
//
// Peer events
//
if (msg->eventCode == ZTS_EVENT_PEER_P2P) {
printf("ZTS_EVENT_PEER_P2P --- node=%llx\n", msg->peer->address);
// A direct path is known for nodeId
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
printf("ZTS_EVENT_PEER_RELAY --- node=%llx\n", msg->peer->address);
// No direct path is known for nodeId
}
}
void printPeerDetails(struct zts_peer_details *pd)
{
printf("\npeer=%llx, latency=%d, version=%d.%d.%d, pathCount=%d\n",
pd->address,
pd->latency,
pd->versionMajor,
pd->versionMinor,
pd->versionRev,
pd->pathCount);
// Print all known paths for each peer
for (int j=0; j<pd->pathCount; j++) {
char ipstr[INET6_ADDRSTRLEN];
int port;
struct sockaddr *sa = (struct sockaddr *)&(pd->paths[j].address);
if (sa->sa_family == AF_INET) {
struct sockaddr_in *in4 = (struct sockaddr_in*)sa;
inet_ntop(AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
port = ntohs(in4->sin_port);
}
if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *in6 = (struct sockaddr_in6*)sa;
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
}
printf("\tpath[%d]=%s, port=%d\n", j, ipstr, port);
}
}
void getSinglePeerDetails(uint64_t peerId)
{
struct zts_peer_details pd;
int err = zts_get_peer(&pd, peerId);
if (err == ZTS_ERR_OK) {
printf("(%d) call succeeded\n", err);
} if (err == ZTS_ERR_INVALID_ARG) {
printf("(%d) invalid argument\n", err);
return;
} if (err == ZTS_ERR_SERVICE) {
printf("(%d) error: service is unavailable\n", err);
return;
} if (err == ZTS_ERR_INVALID_OP) {
printf("(%d) error: invalid API operation\n", err);
return;
} if (err == ZTS_ERR_NO_RESULT) {
printf("(%d) error: object or result not found\n", err);
return;
}
if (err == 0) { // ZTS_ERR_OK
printPeerDetails(&pd);
}
}
// Similar to "zerotier-cli listpeers"
void getAllPeerDetails()
{
struct zts_peer_details pd[128];
/* This number should be large enough to handle the
expected number of peers. This call can also get
expensive for large numbers of peers. Consider using
get_peer(struct zts_peer_details *pds, uint64_t peerId)
instead */
int num = 128;
int err;
if ((err = zts_get_peers(pd, &num)) < 0) {
printf("error (%d)\n", err);
return;
}
if (num) {
printf("num=%d\n", num);
for (int i=0; i<num; i++) {
printPeerDetails(&pd[i]);
}
}
}
struct zts_stats_proto protoSpecificStats;
void display_stack_stats()
{
int err = 0;
// Count received pings
if ((err = zts_get_protocol_stats(ZTS_STATS_PROTOCOL_ICMP, &protoSpecificStats)) != ZTS_ERR_OK) {
printf("zts_get_proto_stats()=%d", err);
return;
}
printf("icmp.recv=%d\n", protoSpecificStats.recv);
// Count dropped TCP packets
if ((err = zts_get_protocol_stats(ZTS_STATS_PROTOCOL_TCP, &protoSpecificStats)) != ZTS_ERR_OK) {
printf("zts_get_proto_stats()=%d", err);
return;
}
printf("tcp.drop=%d\n", protoSpecificStats.drop);
}
int main()
{
char *str = "welcome to the machine";
char *remoteIp = "11.7.7.223";
int remotePort = 8082;
int fd, err = 0;
struct zts_sockaddr_in addr;
addr.sin_family = ZTS_AF_INET;
addr.sin_addr.s_addr = inet_addr(remoteIp);
addr.sin_port = htons(remotePort);
// Set up ZeroTier service
int defaultServicePort = 9994;
int nwid = 0x0123456789abcdef;
zts_start("test/path", &myZeroTierEventCallback, defaultServicePort);
printf("Waiting for node to come online...\n");
// Wait for the node to come online before joining a network
while (!node_ready) { sleep(1); }
zts_join(nwid);
printf("Joined virtual network. Requesting configuration...\n");
//sleep(1);
// Get multiple peer's details
getAllPeerDetails();
// Get a single peer's details
getSinglePeerDetails(0x01b34f67c90);
int status = -1;
// Get status of the node/service
status = zts_get_node_status();
printf("zts_get_node_status()=%d\n", status);
// Get status of a network
status = zts_get_network_status(0x0123456789abcdef);
printf("zts_get_network_status()=%d\n", status);
while (true) {
sleep(1);
status = zts_get_node_status();
printf("zts_get_node_status()=%d\n", status);
display_stack_stats();
}
// Socket API example
printf("zts_errno=%d\n",zts_errno);
if ((fd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating socket\n");
}
printf("fd=%d, zts_errno=%d\n", fd, zts_errno);
if ((err = zts_connect(fd, (const struct sockaddr *)&addr, sizeof(addr))) < 0) {
printf("error connecting to remote host\n");
}
if ((err = zts_write(fd, str, strlen(str))) < 0) {
printf("error writing to socket\n");
}
zts_close(fd);
zts_stop();
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,73 +0,0 @@
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ZeroTier.h"
bool node_ready = false;
bool network_ready = false;
void myZeroTierEventCallback(struct zts_callback_msg *msg)
{
switch (msg->eventCode)
{
case ZTS_EVENT_NODE_ONLINE:
printf("ZTS_EVENT_NODE_ONLINE, node=%llx\n", msg->node->address);
node_ready = true;
break;
case ZTS_EVENT_NODE_OFFLINE:
printf("ZTS_EVENT_NODE_OFFLINE\n");
node_ready = false;
break;
case ZTS_EVENT_NETWORK_READY_IP4:
printf("ZTS_EVENT_NETWORK_READY_IP4 --- network=%llx\n", msg->network->nwid);
network_ready = true;
break;
case ZTS_EVENT_PEER_P2P:
printf("ZTS_EVENT_PEER_P2P --- node=%llx\n", msg->peer->address);
break;
case ZTS_EVENT_PEER_RELAY:
printf("ZTS_EVENT_PEER_RELAY --- node=%llx\n", msg->peer->address);
break;
// ...
default:
break;
}
}
int main()
{
char *str = "welcome to the machine";
char *remoteIp = "11.7.7.223";
int remotePort = 8082;
int fd, err = 0;
struct zts_sockaddr_in addr;
addr.sin_family = ZTS_AF_INET;
addr.sin_addr.s_addr = inet_addr(remoteIp);
addr.sin_port = htons(remotePort);
// Set up ZeroTier service and wai for callbacks
int port = 9994;
int nwid = 0x0123456789abcdef;
zts_start("test/path", &myZeroTierEventCallback, port);
printf("Waiting for node to come online...\n");
while (!node_ready) { sleep(1); }
zts_join(nwid);
printf("Joined virtual network. Requesting configuration...\n");
while (!network_ready) { sleep(1); }
// Socket API example
if ((fd = zts_socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("error creating socket\n");
}
if ((err = zts_connect(fd, (const struct sockaddr *)&addr, sizeof(addr))) < 0) {
printf("error connecting to remote host\n");
}
if ((err = zts_write(fd, str, strlen(str))) < 0) {
printf("error writing to socket\n");
}
zts_close(fd);
zts_stop();
return 0;
}

43
version.rc.in Normal file
View File

@@ -0,0 +1,43 @@
#define VER_FILEVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0
#define VER_FILEVERSION_STR "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@.0\0"
#define VER_PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0
#define VER_PRODUCTVERSION_STR "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@\0"
#define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#define APSTUDIO_READONLY_SYMBOLS
#include "windows.h"
#undef APSTUDIO_READONLY_SYMBOLS
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "ZeroTier, Inc.\0"
VALUE "FileDescription", "ZeroTier SDK\0"
VALUE "InternalName", "zt\0"
VALUE "LegalCopyright", "Copyright (C) 2020 ZeroTier, Inc.\0"
VALUE "OriginalFilename", "libzt.dll\0"
VALUE "PrivateBuild", "0\0"
VALUE "ProductName", "libzt\0"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END