Added Threading and Error section to API.md, minor build script additions
This commit is contained in:
76
API.md
76
API.md
@@ -1,35 +1,43 @@
|
||||
# ZeroTier SDK
|
||||
|
||||
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.
|
||||
<a href="https://www.zerotier.com/?pk_campaign=github_libzt"><img src="https://raw.githubusercontent.com/zerotier/ZeroTierOne/master/artwork/ZeroTierIcon.png" width="128" height="128" align="left" hspace="20"></a>
|
||||
|
||||
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 stack and virtual link is 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)
|
||||
|
||||
<br>
|
||||
|
||||
# Getting started
|
||||
|
||||
The first thing to understand is that there are two API families to choose from and each is intended for very different purposes, they are briefly explained below:
|
||||
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 very different purposes, they are briefly explained below:
|
||||
|
||||
`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, this API exposed in [include/ZeroTierOne.h](include/ZeroTierOne.h) is what you're looking for. For an example of how this API is used, see [src/Service.cpp](src/Service.cpp).
|
||||
`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, this API exposed in `include/ZeroTierOne.h` is what you're looking for. 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](include/ZeroTier.h) for `libzt`. For more information on the `libztcore` API see [include/ZeroTierOne.h](include/ZeroTierOne.h). We also provide bindings, frameworks, and packages for other languages and platforms in the [ports](ports) directory and example applications using them in the [examples](examples) directory.*
|
||||
*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](include/ZeroTierConstants.h) and will result in the generation of callback events. It is your responsibility to handle these events.
|
||||
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)`
|
||||
|
||||
*NOTE: The first argument `path` is a path where you will allow ZeroTier to store its 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):*
|
||||
At this stage if a cryptograph identity doesn't 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, node=%llx\n", msg->node->address);
|
||||
printf("ZTS_EVENT_NODE_ONLINE, nodeId=%llx\n", msg->node->address);
|
||||
// You can join networks now!
|
||||
}
|
||||
}
|
||||
@@ -54,6 +62,8 @@ It is worth noting that while `zts_stop()` will stop the service, the userspace
|
||||
|
||||
Lastly, 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.
|
||||
|
||||
<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:
|
||||
@@ -71,15 +81,19 @@ 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 your node comes online. 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.
|
||||
|
||||
If one wants to query the current reachability state of another node `zts_get_peer_status(uint64_t peerId)` can be used. 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](include/ZeroTier.h):
|
||||
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
|
||||
@@ -95,7 +109,7 @@ struct zts_callback_msg
|
||||
};
|
||||
```
|
||||
|
||||
As mentioned in a previous section, here's an example of a callback function:
|
||||
Here's an example of a callback function:
|
||||
|
||||
```
|
||||
void myZeroTierEventCallback(struct zts_callback_msg *msg)
|
||||
@@ -109,6 +123,8 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
@@ -123,7 +139,7 @@ ZTS_EVENT_PEER_P2P --- node=9d219039f3
|
||||
ZTS_EVENT_PEER_P2P --- node=a09acf0233
|
||||
```
|
||||
|
||||
### Node Events
|
||||
## Node Events
|
||||
|
||||
These events pertain to the state of the current node. Additionally, one can query the status of the node with `zts_get_node_status()`. This message type will arrive with a `zts_node_details` object accessible via `msg->node`.
|
||||
|
||||
@@ -137,7 +153,7 @@ ZTS_EVENT_NODE_NORMAL_TERMINATION
|
||||
```
|
||||
|
||||
|
||||
### Network Events
|
||||
## Network Events
|
||||
|
||||
These events pertain to the state of the indicated network. Additionally, one can query the status of the network with `zts_get_network_status(uint64_t networkId)`. 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`.
|
||||
|
||||
@@ -152,7 +168,7 @@ ZTS_EVENT_NETWORK_READY_IP6
|
||||
ZTS_EVENT_NETWORK_DOWN
|
||||
```
|
||||
|
||||
### Peer Events
|
||||
## 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.
|
||||
|
||||
@@ -162,7 +178,7 @@ ZTS_EVENT_PEER_RELAY
|
||||
ZTS_EVENT_PEER_UNREACHABLE
|
||||
```
|
||||
|
||||
### Path Events
|
||||
## 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.
|
||||
|
||||
@@ -172,7 +188,7 @@ ZTS_EVENT_PATH_ALIVE
|
||||
ZTS_EVENT_PATH_DEAD
|
||||
```
|
||||
|
||||
### Route Events
|
||||
## Route Events
|
||||
|
||||
This event type will arrive with a `zts_virtual_network_route` object for additional context.
|
||||
|
||||
@@ -181,7 +197,7 @@ ZTS_EVENT_ROUTE_ADDED
|
||||
ZTS_EVENT_ROUTE_REMOVED
|
||||
```
|
||||
|
||||
##### Address Events
|
||||
## 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.
|
||||
|
||||
@@ -191,7 +207,7 @@ ZTS_EVENT_ADDR_REMOVED_IP4
|
||||
ZTS_EVENT_ADDR_ADDED_IP6
|
||||
ZTS_EVENT_ADDR_REMOVED_IP6
|
||||
```
|
||||
### Network Stack Events (debugging)
|
||||
## 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.
|
||||
|
||||
@@ -200,7 +216,7 @@ ZTS_EVENT_STACK_UP
|
||||
ZTS_EVENT_STACK_DOWN
|
||||
```
|
||||
|
||||
### Netif Events (debugging)
|
||||
## 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.
|
||||
|
||||
@@ -211,6 +227,30 @@ 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*
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
# Threading
|
||||
|
||||
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 manner. 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.*
|
||||
|
||||
# C Example
|
||||
|
||||
@@ -289,6 +329,8 @@ int main()
|
||||
}
|
||||
```
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
# Java Example
|
||||
|
||||
Starting ZeroTier:
|
||||
|
||||
3
Makefile
3
Makefile
@@ -30,7 +30,8 @@ clean_macos:
|
||||
clean_android:
|
||||
-rm -rf ports/android/app/build
|
||||
-find ports -name ".externalNativeBuild" -exec rm -r "{}" \;
|
||||
|
||||
clean_products:
|
||||
-rm -rf products
|
||||
.PHONY: clean
|
||||
clean: clean_ios clean_macos clean_android
|
||||
-rm -rf tmp lib bin products
|
||||
|
||||
@@ -311,8 +311,7 @@ package_everything()
|
||||
{
|
||||
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
|
||||
LIBZT_VERSION=$(git describe)
|
||||
ZT_CORE_VERSION="1.2.12"
|
||||
PROD_NAME=$LIBZT_VERSION-$1
|
||||
PROD_NAME=$LIBZT_VERSION-$(date '+%Y%m%d')-$1
|
||||
PROD_DIR=$(pwd)/products/$PROD_NAME/
|
||||
# Make products directory
|
||||
LICENSE_DIR=$PROD_DIR/licenses
|
||||
@@ -324,9 +323,10 @@ package_everything()
|
||||
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
|
||||
#cp $(pwd)/README.md $PROD_DIR/doc
|
||||
cp $(pwd)/API.md $PROD_DIR/
|
||||
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
|
||||
# Header(s)
|
||||
mkdir -p $PROD_DIR/include
|
||||
cp $(pwd)/include/*.h $PROD_DIR/include
|
||||
@@ -361,6 +361,23 @@ package_everything()
|
||||
echo -e "\n"
|
||||
tree $PROD_DIR
|
||||
cat $PROD_DIR/VERSION
|
||||
# Final check. Display warnings if anything is missing
|
||||
FILES="README
|
||||
VERSION
|
||||
API.pdf
|
||||
doc/errno.h
|
||||
licenses/LWIP-LICENSE.BSD
|
||||
licenses/CONCURRENTQUEUE-LICENSE.BSD
|
||||
licenses/ZEROTIER-LICENSE.GPL-3
|
||||
licenses/ROUTE_H-LICENSE.APSL
|
||||
licenses/ROUTE_H-LICENSE
|
||||
licenses/LWIP-LICENSE.BSD"
|
||||
for f in $FILES
|
||||
do
|
||||
if [ ! -f "$PROD_DIR$f" ]; then
|
||||
echo "Warning: $PROD_DIR$f is missing"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Package both debug and release
|
||||
|
||||
Reference in New Issue
Block a user