Updated README.md and test/
This commit is contained in:
@@ -2,15 +2,15 @@
|
|||||||
Library edition of [ZeroTier](https://github.com/zerotier/ZeroTierOne)
|
Library edition of [ZeroTier](https://github.com/zerotier/ZeroTierOne)
|
||||||
***
|
***
|
||||||
|
|
||||||
<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" vspace="9"></a>
|
<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 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. 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?pk_campaign=github_libzt)
|
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)
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
For a complete example, see [test/simple.cpp](test/simple.cpp), and anything in the [examples](examples) directory. With no error checking, a paraphrased example is as follows:
|
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:
|
||||||
|
|
||||||
```
|
```
|
||||||
#include "ZeroTier.h"
|
#include "ZeroTier.h"
|
||||||
@@ -38,6 +38,8 @@ int main()
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The complete API specification can be found here: [API.md](API.md)
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|||||||
280
test/example.cpp
Normal file
280
test/example.cpp
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
73
test/simple.cpp
Normal file
73
test/simple.cpp
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user