24
.gitattributes
vendored
Normal file
24
.gitattributes
vendored
Normal 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
16
.gitmodules
vendored
@@ -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
441
API.md
@@ -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));
|
||||
}
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
195
CMakeLists.txt
195
CMakeLists.txt
@@ -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
|
||||
)
|
||||
|
||||
674
LICENSE.GPL-3
674
LICENSE.GPL-3
@@ -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
149
LICENSE.txt
Normal 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 License’s 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 License’s 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.
|
||||
31
Makefile
31
Makefile
@@ -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
383
README.md
@@ -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
BIN
README.pdf
Normal file
Binary file not shown.
201
dist.bat
201
dist.bat
@@ -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
294
dist.sh
@@ -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
57
examples/README.md
Normal 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)
|
||||
```
|
||||
@@ -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
|
||||
Binary file not shown.
@@ -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>
|
||||
@@ -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>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
260
examples/cpp/adhoc.cpp
Normal file
260
examples/cpp/adhoc.cpp
Normal 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
300
examples/cpp/client.cpp
Normal 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;
|
||||
}
|
||||
435
examples/cpp/comprehensive.cpp
Normal file
435
examples/cpp/comprehensive.cpp
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
303
examples/cpp/nonblockingclient.cpp
Normal file
303
examples/cpp/nonblockingclient.cpp
Normal 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;
|
||||
}
|
||||
363
examples/cpp/nonblockingserver.cpp
Normal file
363
examples/cpp/nonblockingserver.cpp
Normal 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
309
examples/cpp/server.cpp
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
25
examples/java/README.md
Normal 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
|
||||
```
|
||||
@@ -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
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
2
examples/node/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/.zerotier
|
||||
/libzt
|
||||
35
examples/node/README.md
Normal file
35
examples/node/README.md
Normal 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)
|
||||
|
||||
8
examples/node/auto-top.gypi
Normal file
8
examples/node/auto-top.gypi
Normal 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
11
examples/node/auto.gypi
Normal 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"
|
||||
]
|
||||
}
|
||||
6
examples/node/autogypi.json
Normal file
6
examples/node/autogypi.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"nbind"
|
||||
],
|
||||
"includes": []
|
||||
}
|
||||
730
examples/node/binding.cc
Normal file
730
examples/node/binding.cc
Normal 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 *)∈
|
||||
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 *)∈
|
||||
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
29
examples/node/binding.gyp
Normal 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
778
examples/node/libzt.js
Normal 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
788
examples/node/package-lock.json
generated
Normal 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=="
|
||||
}
|
||||
}
|
||||
}
|
||||
23
examples/node/package.json
Normal file
23
examples/node/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
242
examples/node/stream_commons.js
Normal file
242
examples/node/stream_commons.js
Normal 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
25
examples/node/test.js
Normal 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()
|
||||
});
|
||||
240
examples/objective-c/adhoc.m
Normal file
240
examples/objective-c/adhoc.m
Normal 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
2
examples/swift/Makefile
Normal 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
353
examples/swift/main.swift
Normal 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()
|
||||
Submodule ext/ZeroTierOne updated: 21f4f16e63...28df0c2e38
@@ -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];
|
||||
2
ext/lwip
2
ext/lwip
Submodule ext/lwip updated: 159e31b689...32708c0a8b
Submodule ext/lwip-contrib updated: 35b011d4cf...4fd612c9c7
@@ -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*
|
||||
@@ -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
4
include/README.md
Normal 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.
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
1238
include/ZeroTier.h
1238
include/ZeroTier.h
File diff suppressed because it is too large
Load Diff
@@ -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
1721
include/ZeroTierSockets.h
Normal file
File diff suppressed because it is too large
Load Diff
15
ports/Homebrew/README.md
Normal file
15
ports/Homebrew/README.md
Normal 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
58
ports/Homebrew/libzt.rb
Normal 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
|
||||
@@ -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 {
|
||||
|
||||
255
ports/csharp/csharp_callback.cs
Normal file
255
ports/csharp/csharp_callback.cs
Normal 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);
|
||||
@@ -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
30
ports/zt.i
Normal 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"
|
||||
1151
src/Controls.cpp
1151
src/Controls.cpp
File diff suppressed because it is too large
Load Diff
116
src/Controls.hpp
116
src/Controls.hpp
@@ -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
|
||||
@@ -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
248
src/Events.cpp
Normal 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
111
src/Events.hpp
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
627
src/Sockets.cpp
627
src/Sockets.cpp
File diff suppressed because it is too large
Load Diff
@@ -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,ðhdr,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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 //
|
||||
|
||||
@@ -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,ðhdr,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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
280
test/example.cpp
280
test/example.cpp
@@ -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;
|
||||
}
|
||||
3411
test/selftest.cpp
3411
test/selftest.cpp
File diff suppressed because it is too large
Load Diff
@@ -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
43
version.rc.in
Normal 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
|
||||
Reference in New Issue
Block a user