Remove C++ examples (To be replaced with C examples)

This commit is contained in:
Joseph Henry
2021-04-18 00:06:54 -07:00
parent 00880628fd
commit 7e05f13295
9 changed files with 0 additions and 2707 deletions

View File

@@ -1,284 +0,0 @@
/**
* 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 "ZeroTierSockets.h"
#include <stdio.h>
#include <stdlib.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 on_zts_event(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], &on_zts_event, 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;
}

View File

@@ -1,113 +0,0 @@
#include "ZeroTierSockets.h"
#include <iomanip>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
// For optional JSON parsing
#include "../ext/ZeroTierOne/ext/json/json.hpp"
void process_response(char* response, int http_response_code)
{
if (http_response_code == 0) {
// Request failed at library level, do nothing. There would be no HTTP code at this point.
return;
}
printf("Raw response string (%d) = %s\n", http_response_code, response);
// Parse into navigable JSON object
if (http_response_code < 200 || http_response_code >= 300) {
return;
}
nlohmann::json res = nlohmann::json::parse(response);
if (! res.is_object()) {
fprintf(stderr, "Unable to parse (root element is not a JSON object)");
}
// Pretty print JSON blob
std::cout << std::setw(4) << res << std::endl;
}
int main(int argc, char** argv)
{
if (argc != 3) {
printf("\nlibzt example central API client\n");
printf("centralapi <central_url> <api_token>\n");
exit(0);
}
std::string central_url = argv[1]; // API endpoint
std::string api_token = argv[2]; // User token (generate at my.zerotier.com)
/**
* This example demonstrates how to use the ZeroTier Central API to:
*
* - Get the status of our hosted service (or your own)
* - Create a network
* - Get the full configuration of a network
* - Authorize/Deauthorize nodes on a network
*
* This example does not start a node (though you can if you wish.) This portion of the
* libzt API is merely a wrapper around our web API endpoint (https://my.zerotier.com/help/api).
* The HTTP requests are done via libcurl. This API is thread-safe but not multithreaded.
*
* Error Codes:
* -2 : [ZTS_ERR_SERVICE] The API may not have been initialized properly
* -3 : [ZTS_ERR_ARG] Invalid argument
* [100-500] : Standard HTTP error codes
*
* Usage example: centralapi https://my.zerotier.com e7no7nVRFItge7no7cVR5Ibge7no8nV1
*
*/
int err = ZTS_ERR_OK;
// Buffer to store server response as JSON string blobs
char rbuf[ZTS_CENTRAL_RESP_BUF_DEFAULT_SZ];
// Provide URL to Central API server and user API token generated at https://my.zerotier.com
printf("Initializing Central API client...\n");
if ((err = zts_central_init(
central_url.c_str(),
api_token.c_str(),
rbuf,
ZTS_CENTRAL_RESP_BUF_DEFAULT_SZ))
!= ZTS_ERR_OK) {
fprintf(stderr, "Error while initializing client's Central API parameters\n");
return 0;
}
zts_central_set_verbose(false); // (optiona) Turn on reporting from libcurl
zts_central_set_access_mode(ZTS_CENTRAL_READ | ZTS_CENTRAL_WRITE);
int http_res_code = 0;
// Get hosted service status
printf("Requesting Central API server status (/api/status):\n");
if ((err = zts_central_get_status(&http_res_code)) != ZTS_ERR_OK) {
fprintf(stderr, "Error (%d) making the request.\n", err);
}
else {
process_response(rbuf, http_res_code);
}
// Get network config
int64_t nwid = 0x1234567890abcdef;
printf("Requesting network config: /api/network/%llx\n", nwid);
if ((err = zts_central_get_network(&http_res_code, nwid)) != ZTS_ERR_OK) {
fprintf(stderr, "Error (%d) making the request.\n", err);
}
else {
process_response(rbuf, http_res_code);
}
// Authorize a node on a network
int64_t nodeid = 0x9934343434;
printf("Authorizing: /api/network/%llx/member/%llx\n", nwid, nodeid);
if ((err = zts_central_set_node_auth(&http_res_code, nwid, nodeid, ZTS_CENTRAL_NODE_AUTH_TRUE))
!= ZTS_ERR_OK) {
fprintf(stderr, "Error (%d) making the request.\n", err);
}
else {
process_response(rbuf, http_res_code);
}
return 0;
}

View File

@@ -1,347 +0,0 @@
/**
* libzt API example
*/
#include "ZeroTierSockets.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
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 on_zts_event(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 = htons(remotePort);
#if defined(_WIN32)
zts_inet_pton(ZTS_AF_INET, remoteAddr.c_str(), &(in4.sin_addr.S_addr));
#else
zts_inet_pton(ZTS_AF_INET, remoteAddr.c_str(), &(in4.sin_addr.s_addr));
#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], &on_zts_event, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (! myNode.online) {
zts_delay_ms(50);
}
printf("This node's identity is stored in %s\n", argv[1]);
if ((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (! myNode.joinedAtLeastOneNetwork) {
zts_delay_ms(50);
}
// Socket-like API example
char* msgStr = (char*)"Welcome to the machine";
int bytes = 0, fd;
char recvBuf[128];
memset(recvBuf, 0, sizeof(recvBuf));
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
printf("Error creating ZeroTier socket (fd=%d, zts_errno=%d). Exiting.\n", fd, zts_errno);
exit(1);
}
// Retries are often required since ZT uses transport-triggered links (explained above)
for (;;) {
printf("Connecting to remote host...\n");
if ((err = zts_connect(fd, (const struct zts_sockaddr*)&in4, sizeof(in4))) < 0) {
printf(
"Error connecting to remote host (fd=%d, ret=%d, zts_errno=%d). Trying again.\n",
fd,
err,
zts_errno);
zts_close(fd);
printf("Creating socket...\n");
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
printf(
"Error creating ZeroTier socket (fd=%d, zts_errno=%d). Exiting.\n",
fd,
zts_errno);
exit(1);
}
zts_delay_ms(250);
}
else {
printf("Connected.\n");
break;
}
}
printf("Sending message string to server...\n");
if ((bytes = zts_write(fd, msgStr, strlen(msgStr))) < 0) {
printf(
"Error writing to socket (fd=%d, ret=%d, zts_errno=%d). Exiting.\n",
fd,
bytes,
zts_errno);
exit(1);
}
printf("Sent %d bytes: %s\n", bytes, msgStr);
printf("Reading message string from server...\n");
if ((bytes = zts_read(fd, recvBuf, sizeof(recvBuf))) < 0) {
printf(
"Error writing to socket (fd=%d, ret=%d, zts_errno=%d). Exiting.\n",
fd,
bytes,
zts_errno);
exit(1);
}
printf("Read %d bytes: %s\n", bytes, recvBuf);
printf("Closing socket\n");
zts_close(fd);
printf("Shutting down service\n");
zts_stop();
return 0;
}

View File

@@ -1,479 +0,0 @@
/**
* 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 "ZeroTierSockets.h"
#include <stdio.h>
#include <stdlib.h>
#include <string>
#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 = 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 on_zts_event(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(), &on_zts_event, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (! myNode.online) {
zts_delay_ms(50);
}
printf("This node's identity is stored in %s\n", argv[1]);
if ((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (! myNode.joinedAtLeastOneNetwork) {
zts_delay_ms(50);
}
// Idle and just show callback events, stack statistics, etc
// Alternatively, this is where you could start making calls to the socket API
/*
while(true) {
display_stack_stats();
zts_delay_ms(1000);
}
*/
int delay = 500000;
printf("This program will delay for %d seconds and then shut down.\n", (delay / 1000));
zts_delay_ms(delay);
// printf("Leaving network %llx\n", nwid);
// zts_leave(nwid);
// zts_delay_ms(3000); /* added for demo purposes so that events show up */
printf("Stopping ZeroTier\n");
zts_stop();
zts_delay_ms(delay); /* added for demo purposes so that events show up */
printf("Stopping network stack\n");
zts_free();
zts_delay_ms(delay); /* added for demo purposes so that events show up */
return 0;
}

View File

@@ -1,238 +0,0 @@
/**
* libzt API example
*
* Pingable node joined to public ZT network "earth"
*/
/**
*
* 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 "ZeroTierSockets.h"
#include <stdio.h>
#include <stdlib.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 on_zts_event(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], &on_zts_event, 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;
if ((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", nwid);
while (! myNode.joinedAtLeastOneNetwork) {
zts_delay_ms(50);
}
// Idle and just show callback events, stack statistics, etc
printf("Node will now idle...\n");
while (true) {
zts_delay_ms(1000);
}
// Shut down service and stack threads
zts_stop();
return 0;
}

View File

@@ -1,127 +0,0 @@
/**
* libzt API example
*
* Demonstrates how to manage ZeroTier node identities (public/secret keypairs) without
* local storage. In this mode you are responsible for saving keys.
*/
#include "ZeroTierSockets.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.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 on_zts_event(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_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;
}
}
#define KEY_BUF_LEN 2048
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;
// BEGIN key handling
// Do not allow ZT to write anything to disk
zts_disable_local_storage(1);
// Buffer used to store identity keypair (if someone can read this, they can impersonate your
// node!)
char keypair[KEY_BUF_LEN];
memset(keypair, 0, KEY_BUF_LEN);
printf("\n\nGenerating new identity...\n");
uint16_t keypair_len = KEY_BUF_LEN;
zts_generate_orphan_identity(keypair, &keypair_len);
printf("keypair(len=%d) = [%s]\n", keypair_len, keypair);
// Verification is not necessary, but could be useful after reading identities from
// your custom data store.
printf("\n\nVerifying ident...\n");
if (zts_verify_identity(keypair)) {
printf("\tIdentity is valid\n");
}
else {
printf("\tIdentity is invalid\n");
}
printf("\n\nStarting node with generated identity...\n");
zts_start_with_identity(keypair, keypair_len, &on_zts_event, ztServicePort);
printf("\n\nWaiting for node to come online...\n");
while (! myNode.online) {
zts_delay_ms(50);
}
printf("\n\nAs a test, copy node's identity keypair back into buffer...\n");
memset(keypair, 0, KEY_BUF_LEN);
keypair_len = KEY_BUF_LEN;
zts_get_node_identity(keypair, &keypair_len);
printf("keypair(len=%d) = [%s]\n", keypair_len, keypair);
// END key handling
uint64_t nwid = 0x8056c2e21c000001;
if ((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", nwid);
while (! myNode.joinedAtLeastOneNetwork) {
zts_delay_ms(50);
}
// Idle and just show callback events, stack statistics, etc
printf("Node will now idle...\n");
while (true) {
zts_delay_ms(1000);
}
// Shut down service and stack threads
zts_stop();
return 0;
}

View File

@@ -1,346 +0,0 @@
/**
* 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 "ZeroTierSockets.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
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 on_zts_event(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 = htons(remotePort);
#if defined(_WIN32)
zts_inet_pton(ZTS_AF_INET, remoteAddr.c_str(), &(in4.sin_addr.S_addr));
#else
zts_inet_pton(ZTS_AF_INET, remoteAddr.c_str(), &(in4.sin_addr.s_addr));
#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], &on_zts_event, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (! myNode.online) {
zts_delay_ms(50);
}
printf("This node's identity is stored in %s\n", argv[1]);
if ((err = zts_join(nwid)) != ZTS_ERR_OK) {
printf("Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (! myNode.joinedAtLeastOneNetwork) {
zts_delay_ms(50);
}
// Socket-like API example
char* msgStr = (char*)"Welcome to the machine";
int bytes = 0, fd;
char recvBuf[128];
memset(recvBuf, 0, sizeof(recvBuf));
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
printf("Error creating ZeroTier socket (fd=%d, zts_errno=%d). Exiting.\n", fd, zts_errno);
exit(1);
}
// Retries are often required since ZT uses transport-triggered links (explained above)
for (;;) {
printf("Connecting to remote host...\n");
if ((err = zts_connect(fd, (const struct zts_sockaddr*)&in4, sizeof(in4))) < 0) {
printf(
"Error connecting to remote host (fd=%d, ret=%d, zts_errno=%d). Trying again.\n",
fd,
err,
zts_errno);
zts_close(fd);
printf("Creating socket...\n");
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
printf(
"Error creating ZeroTier socket (fd=%d, zts_errno=%d). Exiting.\n",
fd,
zts_errno);
exit(1);
}
zts_delay_ms(250);
}
else {
printf("Connected.\n");
break;
}
}
// Wait random intervals to send a message to the server
// The non-blocking aspect of this example is server-side
while (1) {
if ((bytes = zts_send(fd, msgStr, strlen(msgStr), 0)) < 0) {
printf(
"Error writing to socket (fd=%d, ret=%d, zts_errno=%d). Exiting.\n",
fd,
bytes,
zts_errno);
exit(1);
}
printf("zts_send()=%d\n", bytes);
zts_delay_ms((rand() % 100) * 50);
}
printf("Read %d bytes: %s\n", bytes, recvBuf);
printf("Closing socket\n");
zts_close(fd);
printf("Shutting down service\n");
zts_stop();
return 0;
}

View File

@@ -1,407 +0,0 @@
/**
* 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 "ZeroTierSockets.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.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 on_zts_event(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 = 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], &on_zts_event, 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, 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;
}

View File

@@ -1,366 +0,0 @@
/**
* libzt API example
*/
#include "ZeroTierSockets.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
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 on_zts_event(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 = 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], &on_zts_event, 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, 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;
}