Add portability and consistency fixes for C API, remove cruft, slight internal restructuring

This commit is contained in:
Joseph Henry
2020-05-01 19:15:38 -07:00
parent 2c709277b9
commit a0b50530d3
29 changed files with 4359 additions and 4110 deletions

View File

@@ -17,8 +17,9 @@
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - An exception to the above rule is if you are using an Ad-hoc network, it has no
* controller and therefore requires no authorization.
* - 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:
@@ -50,28 +51,27 @@
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* [ 0] ZTS_ERR_OK - No error.
* [-1] ZTS_ERR - Error (see zts_errno for more information).
* [-2] ZTS_ERR_INVALID_ARG - An argument provided is invalid.
* [-3] ZTS_ERR_SERVICE - ZT is not yet initialized. Try again.
* [-4] ZTS_ERR_INVALID_OP - Operation is not permitted (Doesn't make sense in this state).
* [-5] ZTS_ERR_NO_RESULT - Call succeeded but no result was available. Not always an error.
* [-6] ZTS_ERR_GENERAL - General internal failure. Consider filing a bug report.
* ZTS_ERR_OK 0 // No error
* ZTS_ERR_SOCKET -1 // Socket error, see zts_errno
* ZTS_ERR_SERVICE -2 // You probably did something at the wrong time
* ZTS_ERR_ARG -3 // Invalid argument
* ZTS_ERR_NO_RESULT -4 // No result (not necessarily an error)
* ZTS_ERR_GENERAL -5 // 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.
* These error values are defined in: libzt/ext/lwip/src/include/lwip/errno.h
* and closely map to standard Linux error values.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - Since libzt re-implements a socket API probably very similar to your host OS's own
* API it may be tempting to mix and match host OS structures and functions with those
* of libzt. This may work on occasion, but you are tempting fate, so here are a few
* guidelines:
* - 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:
*
@@ -82,55 +82,23 @@
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
* If you are calling a host OS function, use your host OS's constants (and structures!):
*
* inet_ntop(AF_INET6, &(in6->sin6_addr), ...); (CORRECT)
* inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ...); (INCORRECT)
*
* If you are calling a host OS function but passing a zts_* structure, this can
* work sometimes but you should take care to pass the correct host OS constants:
*
* struct zts_sockaddr_in6 in6;
* ...
* inet_ntop(AF_INET6, &(in6->sin6_addr), dstStr, INET6_ADDRSTRLEN);
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#include <stdlib.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
void delay_ms(long ms)
{
#if defined(_WIN32)
Sleep(ms);
#else
usleep(ms*1000);
#endif
}
#include "ZeroTier.h"
#include "ZeroTierSockets.h"
bool nodeReady = false;
bool networkReady = false;
// Example callbacks
void myZeroTierEventCallback(struct zts_callback_msg *msg)
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
@@ -146,8 +114,8 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
printf("ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQUESTING_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQUESTING_CONFIG --- Requesting config for network %llx, please wait a few seconds...\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",
@@ -174,23 +142,22 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
printf("ZTS_EVENT_NETIF_DOWN --- network=%llx, mac=%llx\n",
msg->netif->nwid,
msg->netif->mac);
networkReady = true;
}
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[INET6_ADDRSTRLEN];
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
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 you don't recognize the peer ID, don't panic, this is most likely one of our root servers
if (msg->eventCode == ZTS_EVENT_PEER_P2P) {
printf("ZTS_EVENT_PEER_P2P --- There is now a direct path to peer %llx\n",
// Don't worry if you don't recognize a peer ID, it's most likely our infrastructure
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- There is now a direct path to peer %llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
@@ -238,14 +205,14 @@ int main(int argc, char **argv)
uint64_t adhoc_nwid = zts_generate_adhoc_nwid_from_range(adhocStartPort, adhocEndPort);
int err = ZTS_ERR_OK;
zts_set_network_caching(false);
zts_allow_network_caching(false);
if((err = zts_start(argv[1], &myZeroTierEventCallback, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (!nodeReady) { delay_ms(50); }
while (!nodeReady) { 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) {
@@ -253,12 +220,12 @@ int main(int argc, char **argv)
exit(1);
}
printf("Joining network %llx\n", adhoc_nwid);
while (!networkReady) { delay_ms(50); }
while (!networkReady) { zts_delay_ms(50); }
// Idle and just show callback events, stack statistics, etc
printf("Node will now idle...\n");
while (true) { delay_ms(1000); }
while (true) { zts_delay_ms(1000); }
// Shut down service and stack threads

View File

@@ -3,38 +3,20 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
void delay_ms(long ms)
{
#if defined(_WIN32)
Sleep(ms);
#else
usleep(ms*1000);
#endif
}
#include "ZeroTier.h"
#include "ZeroTierSockets.h"
bool nodeReady = false;
bool networkReady = false;
// Example callbacks
void myZeroTierEventCallback(struct zts_callback_msg *msg)
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
@@ -53,8 +35,8 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
printf("ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQUESTING_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQUESTING_CONFIG --- Requesting config for network %llx, please wait a few seconds...\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",
@@ -76,36 +58,36 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP4) {
char ipstr[INET_ADDRSTRLEN];
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
inet_ntop(AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
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[INET6_ADDRSTRLEN];
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
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[INET_ADDRSTRLEN];
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
inet_ntop(AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
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[INET6_ADDRSTRLEN];
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
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->eventCode == ZTS_EVENT_PEER_P2P) {
printf("ZTS_EVENT_PEER_P2P --- node=%llx\n", msg->peer->address);
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- node=%llx\n", msg->peer->address);
// A direct path is known for nodeId
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
@@ -127,8 +109,9 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - An exception to the above rule is if you are using an Ad-hoc network, it has no
* controller and therefore requires no authorization.
* - 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:
@@ -160,28 +143,27 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* [ 0] ZTS_ERR_OK - No error.
* [-1] ZTS_ERR - Error (see zts_errno for more information).
* [-2] ZTS_ERR_INVALID_ARG - An argument provided is invalid.
* [-3] ZTS_ERR_SERVICE - ZT is not yet initialized. Try again.
* [-4] ZTS_ERR_INVALID_OP - Operation is not permitted (Doesn't make sense in this state).
* [-5] ZTS_ERR_NO_RESULT - Call succeeded but no result was available. Not always an error.
* [-6] ZTS_ERR_GENERAL - General internal failure. Consider filing a bug report.
* ZTS_ERR_OK 0 // No error
* ZTS_ERR_SOCKET -1 // Socket error, see zts_errno
* ZTS_ERR_SERVICE -2 // You probably did something at the wrong time
* ZTS_ERR_ARG -3 // Invalid argument
* ZTS_ERR_NO_RESULT -4 // No result (not necessarily an error)
* ZTS_ERR_GENERAL -5 // 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.
* These error values are defined in: libzt/ext/lwip/src/include/lwip/errno.h
* and closely map to standard Linux error values.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - Since libzt re-implements a socket API probably very similar to your host OS's own
* API it may be tempting to mix and match host OS structures and functions with those
* of libzt. This may work on occasion, but you are tempting fate, so here are a few
* guidelines:
* - 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:
*
@@ -192,19 +174,8 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
* If you are calling a host OS function, use your host OS's constants (and structures!):
*
* inet_ntop(AF_INET6, &(in6->sin6_addr), ...); (CORRECT)
* inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ...); (INCORRECT)
*
* If you are calling a host OS function but passing a zts_* structure, this can
* work sometimes but you should take care to pass the correct host OS constants:
*
* struct zts_sockaddr_in6 in6;
* ...
* inet_ntop(AF_INET6, &(in6->sin6_addr), dstStr, INET6_ADDRSTRLEN);
*/
int main(int argc, char **argv)
@@ -220,11 +191,11 @@ int main(int argc, char **argv)
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);
in4.sin_port = zts_htons(remotePort);
#if defined(_WIN32)
in4.sin_addr.S_addr = inet_addr(remoteAddr.c_str());;
in4.sin_addr.S_addr = zts_inet_addr(remoteAddr.c_str());
#else
in4.sin_addr.s_addr = inet_addr(remoteAddr.c_str());;
in4.sin_addr.s_addr = zts_inet_addr(remoteAddr.c_str());
#endif
in4.sin_family = ZTS_AF_INET;
@@ -237,7 +208,7 @@ int main(int argc, char **argv)
exit(1);
}
printf("Waiting for node to come online...\n");
while (!nodeReady) { delay_ms(50); }
while (!nodeReady) { zts_delay_ms(50); }
printf("This node's identity is stored in %s\n", argv[1]);
if((err = zts_join(nwid)) != ZTS_ERR_OK) {
@@ -246,7 +217,7 @@ int main(int argc, char **argv)
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (!networkReady) { delay_ms(50); }
while (!networkReady) { zts_delay_ms(50); }
// Socket-like API example
@@ -262,7 +233,7 @@ int main(int argc, char **argv)
// 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 sockaddr *)&in4, sizeof(in4))) < 0) {
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);
@@ -271,7 +242,7 @@ int main(int argc, char **argv)
printf("Error creating ZeroTier socket (fd=%d, zts_errno=%d). Exiting.\n", fd, zts_errno);
exit(1);
}
delay_ms(250);
zts_delay_ms(250);
}
else {
printf("Connected.\n");

View File

@@ -17,8 +17,9 @@
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - An exception to the above rule is if you are using an Ad-hoc network, it has no
* controller and therefore requires no authorization.
* - 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:
@@ -50,28 +51,27 @@
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* [ 0] ZTS_ERR_OK - No error.
* [-1] ZTS_ERR - Error (see zts_errno for more information).
* [-2] ZTS_ERR_INVALID_ARG - An argument provided is invalid.
* [-3] ZTS_ERR_SERVICE - ZT is not yet initialized. Try again.
* [-4] ZTS_ERR_INVALID_OP - Operation is not permitted (Doesn't make sense in this state).
* [-5] ZTS_ERR_NO_RESULT - Call succeeded but no result was available. Not always an error.
* [-6] ZTS_ERR_GENERAL - General internal failure. Consider filing a bug report.
* ZTS_ERR_OK 0 // No error
* ZTS_ERR_SOCKET -1 // Socket error, see zts_errno
* ZTS_ERR_SERVICE -2 // You probably did something at the wrong time
* ZTS_ERR_ARG -3 // Invalid argument
* ZTS_ERR_NO_RESULT -4 // No result (not necessarily an error)
* ZTS_ERR_GENERAL -5 // 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.
* These error values are defined in: libzt/ext/lwip/src/include/lwip/errno.h
* and closely map to standard Linux error values.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - Since libzt re-implements a socket API probably very similar to your host OS's own
* API it may be tempting to mix and match host OS structures and functions with those
* of libzt. This may work on occasion, but you are tempting fate, so here are a few
* guidelines:
* - 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:
*
@@ -82,55 +82,23 @@
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
* If you are calling a host OS function, use your host OS's constants (and structures!):
*
* inet_ntop(AF_INET6, &(in6->sin6_addr), ...); (CORRECT)
* inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ...); (INCORRECT)
*
* If you are calling a host OS function but passing a zts_* structure, this can
* work sometimes but you should take care to pass the correct host OS constants:
*
* struct zts_sockaddr_in6 in6;
* ...
* inet_ntop(AF_INET6, &(in6->sin6_addr), dstStr, INET6_ADDRSTRLEN);
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#include <stdlib.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
void delay_ms(long ms)
{
#if defined(_WIN32)
Sleep(ms);
#else
usleep(ms*1000);
#endif
}
#include "ZeroTier.h"
#include "ZeroTierSockets.h"
bool nodeReady = false;
bool networkReady = false;
// Example callbacks
void myZeroTierEventCallback(struct zts_callback_msg *msg)
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
@@ -149,8 +117,8 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
printf("ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQUESTING_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQUESTING_CONFIG --- Requesting config for network %llx, please wait a few seconds...\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",
@@ -182,43 +150,42 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
printf("ZTS_EVENT_NETIF_DOWN --- network=%llx, mac=%llx\n",
msg->netif->nwid,
msg->netif->mac);
networkReady = true;
}
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP4) {
char ipstr[INET_ADDRSTRLEN];
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
inet_ntop(AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
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[INET6_ADDRSTRLEN];
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
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[INET_ADDRSTRLEN];
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
inet_ntop(AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
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[INET6_ADDRSTRLEN];
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
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->eventCode == ZTS_EVENT_PEER_P2P) {
printf("ZTS_EVENT_PEER_P2P --- node=%llx\n", msg->peer->address);
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- node=%llx\n", msg->peer->address);
// A direct path is known for nodeId
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
@@ -238,17 +205,17 @@ void printPeerDetails(struct zts_peer_details *pd)
pd->pathCount);
// Print all known paths for each peer
for (unsigned int j=0; j<pd->pathCount; j++) {
char ipstr[INET6_ADDRSTRLEN];
char ipstr[ZTS_INET6_ADDRSTRLEN];
int port = 0;
struct sockaddr *sa = (struct sockaddr *)&(pd->paths[j].address);
if (sa->sa_family == AF_INET) {
struct zts_sockaddr *sa = (struct zts_sockaddr *)&(pd->paths[j].address);
if (sa->sa_family == ZTS_AF_INET) { // TODO: Probably broken
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)sa;
inet_ntop(AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
port = ntohs(in4->sin_port);
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
port = zts_ntohs(in4->sin_port);
}
if (sa->sa_family == AF_INET6) {
if (sa->sa_family == ZTS_AF_INET6) {
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)sa;
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
}
printf("\tpath[%d]=%s, port=%d\n", j, ipstr, port);
}
@@ -261,22 +228,17 @@ void getSinglePeerDetails(uint64_t peerId)
if (err == ZTS_ERR_OK) {
printf("(%d) call succeeded\n", err);
} if (err == ZTS_ERR_INVALID_ARG) {
printPeerDetails(&pd);
} if (err == ZTS_ERR_ARG) {
printf("(%d) invalid argument\n", err);
return;
} if (err == ZTS_ERR_SERVICE) {
printf("(%d) error: service is unavailable\n", err);
return;
} if (err == ZTS_ERR_INVALID_OP) {
printf("(%d) error: invalid API operation\n", err);
printf("(%d) error: invalid API operation or service error\n", err);
return;
} if (err == ZTS_ERR_NO_RESULT) {
printf("(%d) error: object or result not found\n", err);
return;
}
if (err == 0) { // ZTS_ERR_OK
printPeerDetails(&pd);
}
}
// Similar to "zerotier-cli listpeers"
@@ -348,7 +310,7 @@ int main(int argc, char **argv)
exit(1);
}
printf("Waiting for node to come online...\n");
while (!nodeReady) { delay_ms(50); }
while (!nodeReady) { zts_delay_ms(50); }
printf("This node ID is %llx\n", zts_get_node_id());
printf("This node's identity is stored in %s\n", argv[1]);
@@ -358,7 +320,7 @@ int main(int argc, char **argv)
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (!networkReady) { delay_ms(50); }
while (!networkReady) { zts_delay_ms(50); }
// Get multiple peer's details
getAllPeerDetails();
@@ -379,7 +341,7 @@ int main(int argc, char **argv)
// Idle and just show callback events, stack statistics, etc
while (true) {
delay_ms(1000);
zts_delay_ms(1000);
status = zts_get_node_status();
printf("zts_get_node_status()=%d\n", status);
display_stack_stats();

188
examples/cpp/earthtest.cpp Normal file
View File

@@ -0,0 +1,188 @@
/**
* 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_P2P 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_P2P 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 0 // No error
* ZTS_ERR_SOCKET -1 // Socket error, see zts_errno
* ZTS_ERR_SERVICE -2 // You probably did something at the wrong time
* ZTS_ERR_ARG -3 // Invalid argument
* ZTS_ERR_NO_RESULT -4 // No result (not necessarily an error)
* ZTS_ERR_GENERAL -5 // Consider filing a bug report
*
* Category 2: Sockets (zts_socket, zts_bind, zts_connect, zts_listen, etc).
* Errors returned by these functions can be the same as the above. With
* the added possibility of zts_errno being set. Much like standard
* errno this will provide a more specific reason for an error's occurrence.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - While the ZeroTier socket interface can coexist with your host OS's own interface in
* the same file with no type and naming conflicts, try not to mix and match host
* OS/libzt structures, functions, or constants. It may look similar and may even work
* some of the time but there enough differences that it will cause headaches. Here
* are a few guidelines:
*
* If you are calling a zts_* function, use the appropriate ZTS_* constants:
*
* zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
* zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
*
* If you are calling a zts_* function, use the appropriate zts_* structure:
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "ZeroTierSockets.h"
bool nodeReady = false;
bool networkReady = false;
// Example callbacks
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
nodeReady = 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");
nodeReady = 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);
networkReady = 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);
}
// Don't worry if you don't recognize a peer ID, it's most likely our infrastructure
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- There is now a direct path to peer %llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
printf("ZTS_EVENT_PEER_RELAY --- No direct path to peer %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;
zts_allow_network_caching(false);
if((err = zts_start(argv[1], &myZeroTierEventCallback, ztServicePort)) != ZTS_ERR_OK) {
printf("Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
printf("Waiting for node to come online...\n");
while (!nodeReady) { 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 (!networkReady) { 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

@@ -3,38 +3,20 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <inttypes.h>
#if defined(_WIN32)
#include <WinSock2.h>
#include <stdint.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
void delay_ms(long ms)
{
#if defined(_WIN32)
Sleep(ms);
#else
usleep(ms*1000);
#endif
}
#include "ZeroTier.h"
#include "ZeroTierSockets.h"
bool nodeReady = false;
bool networkReady = false;
// Example callbacks
void myZeroTierEventCallback(struct zts_callback_msg *msg)
void myZeroTierEventCallback(void *msgPtr)
{
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
@@ -53,8 +35,8 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
printf("ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQUESTING_CONFIG) {
printf("ZTS_EVENT_NETWORK_REQUESTING_CONFIG --- Requesting config for network %llx, please wait a few seconds...\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",
@@ -76,36 +58,36 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP4) {
char ipstr[INET_ADDRSTRLEN];
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
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[INET6_ADDRSTRLEN];
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
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[INET_ADDRSTRLEN];
char ipstr[ZTS_INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg->addr->addr);
inet_ntop(ZTS_AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
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[INET6_ADDRSTRLEN];
char ipstr[ZTS_INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
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->eventCode == ZTS_EVENT_PEER_P2P) {
printf("ZTS_EVENT_PEER_P2P --- node=%llx\n", msg->peer->address);
if (msg->eventCode == ZTS_EVENT_PEER_DIRECT) {
printf("ZTS_EVENT_PEER_DIRECT --- node=%llx\n", msg->peer->address);
// A direct path is known for nodeId
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
@@ -127,8 +109,9 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - An exception to the above rule is if you are using an Ad-hoc network, it has no
* controller and therefore requires no authorization.
* - 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:
@@ -160,28 +143,27 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
* Category 1: Control functions (zts_start, zts_join, zts_get_peer_status, etc). Errors
* returned by these functions can be any of the following:
*
* [ 0] ZTS_ERR_OK - No error.
* [-1] ZTS_ERR - Error (see zts_errno for more information).
* [-2] ZTS_ERR_INVALID_ARG - An argument provided is invalid.
* [-3] ZTS_ERR_SERVICE - ZT is not yet initialized. Try again.
* [-4] ZTS_ERR_INVALID_OP - Operation is not permitted (Doesn't make sense in this state).
* [-5] ZTS_ERR_NO_RESULT - Call succeeded but no result was available. Not always an error.
* [-6] ZTS_ERR_GENERAL - General internal failure. Consider filing a bug report.
* ZTS_ERR_OK 0 // No error
* ZTS_ERR_SOCKET -1 // Socket error, see zts_errno
* ZTS_ERR_SERVICE -2 // You probably did something at the wrong time
* ZTS_ERR_ARG -3 // Invalid argument
* ZTS_ERR_NO_RESULT -4 // No result (not necessarily an error)
* ZTS_ERR_GENERAL -5 // 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.
* These error values are defined in: libzt/ext/lwip/src/include/lwip/errno.h
* and closely map to standard Linux error values.
* See ZeroTierSockets.h for values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - Since libzt re-implements a socket API probably very similar to your host OS's own
* API it may be tempting to mix and match host OS structures and functions with those
* of libzt. This may work on occasion, but you are tempting fate, so here are a few
* guidelines:
* - 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:
*
@@ -192,19 +174,8 @@ void myZeroTierEventCallback(struct zts_callback_msg *msg)
*
* struct zts_sockaddr_in in4; <------ Note the zts_* prefix
* ...
* zts_bind(fd, (struct sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
* zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
* If you are calling a host OS function, use your host OS's constants (and structures!):
*
* inet_ntop(AF_INET6, &(in6->sin6_addr), ...); (CORRECT)
* inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ...); (INCORRECT)
*
* If you are calling a host OS function but passing a zts_* structure, this can
* work sometimes but you should take care to pass the correct host OS constants:
*
* struct zts_sockaddr_in6 in6;
* ...
* inet_ntop(AF_INET6, &(in6->sin6_addr), dstStr, INET6_ADDRSTRLEN);
*/
int main(int argc, char **argv)
@@ -219,11 +190,11 @@ int main(int argc, char **argv)
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);
in4.sin_port = zts_htons(serverBindPort);
#if defined(_WIN32)
in4.sin_addr.S_addr = INADDR_ANY;
in4.sin_addr.S_addr = ZTS_INADDR_ANY;
#else
in4.sin_addr.s_addr = INADDR_ANY;
in4.sin_addr.s_addr = ZTS_INADDR_ANY;
#endif
in4.sin_family = ZTS_AF_INET;
@@ -237,7 +208,7 @@ int main(int argc, char **argv)
exit(1);
}
printf("Waiting for node to come online...\n");
while (!nodeReady) { delay_ms(50); }
while (!nodeReady) { zts_delay_ms(50); }
printf("This node's identity is stored in %s\n", argv[1]);
if((err = zts_join(nwid)) != ZTS_ERR_OK) {
@@ -246,7 +217,7 @@ int main(int argc, char **argv)
}
printf("Joining network %llx\n", nwid);
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
while (!networkReady) { delay_ms(50); }
while (!networkReady) { zts_delay_ms(50); }
// Socket-like API example
@@ -256,7 +227,7 @@ int main(int argc, char **argv)
exit(1);
}
printf("Binding...\n");
if ((err = zts_bind(fd, (struct sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)) {
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);
}
@@ -272,17 +243,17 @@ int main(int argc, char **argv)
memset(recvBuf, 0, sizeof(recvBuf));
while (true) {
socklen_t client_addrlen = sizeof(zts_sockaddr_in);
if ((accfd = zts_accept(fd, (struct sockaddr *)&acc_in4, &client_addrlen)) < 0) {
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);
}
socklen_t peer_addrlen = sizeof(struct zts_sockaddr_storage);
zts_getpeername(accfd, (struct sockaddr*)&acc_in4, &peer_addrlen);
zts_socklen_t peer_addrlen = sizeof(struct zts_sockaddr_storage);
zts_getpeername(accfd, (struct zts_sockaddr*)&acc_in4, &peer_addrlen);
char ipstr[INET_ADDRSTRLEN];
char ipstr[ZTS_INET_ADDRSTRLEN];
memset(ipstr, 0, sizeof(ipstr));
inet_ntop(AF_INET, &(acc_in4.sin_addr), ipstr, INET_ADDRSTRLEN);
printf("Accepted connection from %s:%d\n", ipstr, ntohs(acc_in4.sin_port));
zts_inet_ntop(ZTS_AF_INET, &(acc_in4.sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
printf("Accepted connection from %s:%d\n", ipstr, zts_ntohs(acc_in4.sin_port));
printf("Reading message string from client...\n");
if((bytes = zts_read(accfd, recvBuf, sizeof(recvBuf))) < 0) {

View File

@@ -0,0 +1,247 @@
/**
* libzt API example
*
* Specify location of zt.framework and link to standard C++ library:
*
* clang -lc++ -framework Foundation -F . -framework zt adhoc.m -o adhoc;
*
* Pingable node joined to controller-less adhoc network with a 6PLANE addressing scheme
*/
#import <Foundation/Foundation.h>
#import <zt/ZeroTier.h>
#include <arpa/inet.h>
/**
*
* IDENTITIES and AUTHORIZATION:
*
* - Upon the first execution of this code, a new identity will be generated and placed in
* the location given in the first argument to zts_start(path, ...). If you accidentally
* duplicate the identity files and use them simultaneously in a different node instance
* you will experience undefined behavior and it is likely nothing will work.
*
* - You must authorize the node ID provided by the ZTS_EVENT_NODE_ONLINE callback to join
* your network, otherwise nothing will happen. This can be done manually or via
* our web API: https://my.zerotier.com/help/api
*
* - An exception to the above rule is if you are using an Ad-hoc network, it has no
* controller and therefore requires no authorization.
*
*
* ESTABLISHING A CONNECTION:
*
* - Creating a standard socket connection generally works the same as it would using
* an ordinary socket interface, however with libzt there is a subtle difference in
* how connections are established which may cause confusion:
*
* The underlying virtual ZT layer creates what are called "transport-triggered links"
* between nodes. That is, links are not established until an attempt to communicate
* with a peer has taken place. The side effect is that the first few packets sent from
* a libzt instance are usually relayed via our free infrastructure and it isn't until a
* root server has passed contact information to both peers that a direct connection will be
* established. Therefore, it is required that multiple connection attempts be undertaken
* when initially communicating with a peer. After a transport-triggered link is
* established libzt will inform you via ZTS_EVENT_PEER_P2P 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_P2P 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:
*
* [ 0] ZTS_ERR_OK - No error.
* [-1] ZTS_ERR - Error (see zts_errno for more information).
* [-2] ZTS_ERR_INVALID_ARG - An argument provided is invalid.
* [-3] ZTS_ERR_SERVICE - ZT is not yet initialized. Try again.
* [-4] ZTS_ERR_INVALID_OP - Operation is not permitted (Doesn't make sense in this state).
* [-5] ZTS_ERR_NO_RESULT - Call succeeded but no result was available. Not always an error.
* [-6] ZTS_ERR_GENERAL - General internal failure. 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.
* These error values are defined in: libzt/ext/lwip/src/include/lwip/errno.h
* and closely map to standard Linux error values.
*
*
* API COMPATIBILITY WITH HOST OS:
*
* - Since libzt re-implements a socket API probably very similar to your host OS's own
* API it may be tempting to mix and match host OS structures and functions with those
* of libzt. This may work on occasion, but you are tempting fate, so 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 sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
*
* If you are calling a host OS function, use your host OS's constants (and structures!):
*
* inet_ntop(AF_INET6, &(in6->sin6_addr), ...); (CORRECT)
* inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ...); (INCORRECT)
*
* If you are calling a host OS function but passing a zts_* structure, this can
* work sometimes but you should take care to pass the correct host OS constants:
*
* struct zts_sockaddr_in6 in6;
* ...
* inet_ntop(AF_INET6, &(in6->sin6_addr), dstStr, INET6_ADDRSTRLEN);
*/
void delay_ms(long ms) { usleep(ms*1000); }
bool nodeReady = false;
bool networkReady = false;
// Example callbacks
void myZeroTierEventCallback(struct zts_callback_msg *msg)
{
// Node events
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
NSLog(@"ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->address);
nodeReady = true;
}
if (msg->eventCode == ZTS_EVENT_NODE_OFFLINE) {
NSLog(@"ZTS_EVENT_NODE_OFFLINE --- Check your physical Internet connection, router, firewall, etc. What ports are you blocking?\n");
nodeReady = false;
}
// Virtual network events
if (msg->eventCode == ZTS_EVENT_NETWORK_NOT_FOUND) {
NSLog(@"ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_REQUESTING_CONFIG) {
NSLog(@"ZTS_EVENT_NETWORK_REQUESTING_CONFIG --- Requesting config for network %llx, please wait a few seconds...\n", msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
NSLog(@"ZTS_EVENT_NETWORK_ACCESS_DENIED --- Access to virtual network %llx has been denied. Did you authorize the node yet?\n",
msg->network->nwid);
}
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
NSLog(@"ZTS_EVENT_NETWORK_READY_IP6 --- Network config received. IPv6 traffic can now be sent over network %llx\n",
msg->network->nwid);
networkReady = true;
}
if (msg->eventCode == ZTS_EVENT_NETWORK_DOWN) {
NSLog(@"ZTS_EVENT_NETWORK_DOWN --- %llx\n", msg->network->nwid);
}
// Network stack events
if (msg->eventCode == ZTS_EVENT_NETIF_UP) {
NSLog(@"ZTS_EVENT_NETIF_UP --- network=%llx, mac=%llx, mtu=%d\n",
msg->netif->nwid,
msg->netif->mac,
msg->netif->mtu);
networkReady = true;
}
if (msg->eventCode == ZTS_EVENT_NETIF_DOWN) {
NSLog(@"ZTS_EVENT_NETIF_DOWN --- network=%llx, mac=%llx\n",
msg->netif->nwid,
msg->netif->mac);
networkReady = true;
}
// Address events
if (msg->eventCode == ZTS_EVENT_ADDR_ADDED_IP6) {
char ipstr[INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
NSLog(@"ZTS_EVENT_ADDR_NEW_IP6 --- Join %llx and ping me at %s\n",
msg->addr->nwid, ipstr);
}
// Peer events
// If you don't recognize the peer ID, don't panic, this is most likely one of our root servers
if (msg->eventCode == ZTS_EVENT_PEER_P2P) {
NSLog(@"ZTS_EVENT_PEER_P2P --- There is now a direct path to peer %llx\n",
msg->peer->address);
}
if (msg->eventCode == ZTS_EVENT_PEER_RELAY) {
NSLog(@"ZTS_EVENT_PEER_RELAY --- No direct path to peer %llx\n",
msg->peer->address);
}
}
/*
Ad-hoc Network:
ffSSSSEEEE000000
| | | |
| | | Reserved for future use, must be 0
| | End of port range (hex)
| Start of port range (hex)
Reserved ZeroTier address prefix indicating a controller-less network.
Ad-hoc networks are public (no access control) networks that have no network controller. Instead
their configuration and other credentials are generated locally. Ad-hoc networks permit only IPv6
UDP and TCP unicast traffic (no multicast or broadcast) using 6plane format NDP-emulated IPv6
addresses. In addition an ad-hoc network ID encodes an IP port range. UDP packets and TCP SYN
(connection open) packets are only allowed to destination ports within the encoded range.
For example ff00160016000000 is an ad-hoc network allowing only SSH, while ff0000ffff000000 is an
ad-hoc network allowing any UDP or TCP port.
Keep in mind that these networks are public and anyone in the entire world can join them. Care must
be taken to avoid exposing vulnerable services or sharing unwanted files or other resources.
*/
int main(int argc, char **argv)
{
if (argc != 5) {
NSLog(@"\nlibzt example\n");
NSLog(@"adhoc <config_file_path> <adhocStartPort> <adhocEndPort> <ztServicePort>\n");
exit(0);
}
int adhocStartPort = atoi(argv[2]); // Start of port range your application will use
int adhocEndPort = atoi(argv[3]); // End of port range your application will use
int ztServicePort = atoi(argv[4]); // Port ZT uses to send encrypted UDP packets to peers (try something like 9994)
uint64_t adhoc_nwid = zts_generate_adhoc_nwid_from_range(adhocStartPort, adhocEndPort);
int err = ZTS_ERR_OK;
zts_set_network_caching(false);
if((err = zts_start(argv[1], &myZeroTierEventCallback, ztServicePort)) != ZTS_ERR_OK) {
NSLog(@"Unable to start service, error = %d. Exiting.\n", err);
exit(1);
}
NSLog(@"Waiting for node to come online...\n");
while (!nodeReady) { delay_ms(50); }
NSLog(@"This node's identity is stored in %s\n", argv[1]);
if((err = zts_join(adhoc_nwid)) != ZTS_ERR_OK) {
NSLog(@"Unable to join network, error = %d. Exiting.\n", err);
exit(1);
}
NSLog(@"Joining network %llx\n", adhoc_nwid);
while (!networkReady) { delay_ms(50); }
// Idle and just show callback events, stack statistics, etc
NSLog(@"Node will now idle...\n");
while (true) { delay_ms(1000); }
// Shut down service and stack threads
zts_stop();
return 0;
}

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

@@ -0,0 +1,143 @@
/**
* libzt Swift example
*
* swiftc -lc++ -import-objc-header ../../include/ZeroTierSockets.h -L. -lzt main.swift -o main;
* ./main
*/
import Swift
import Foundation
var nodeReady:Bool = false
var networkReady:Bool = false
let myZeroTierEventCallback : @convention(c) (UnsafeMutableRawPointer?) -> Void =
{
(msgPtr) -> Void in
let msg = msgPtr?.bindMemory(to: zts_callback_msg.self, capacity: 1)
var eventCode = msg!.pointee.eventCode
let node = msg?.pointee.node;
let network = msg?.pointee.network;
switch Int32(eventCode)
{
case ZTS_EVENT_NODE_ONLINE:
let nodeId:UInt64 = node!.pointee.address
print(String(format: "ZTS_EVENT_NODE_ONLINE (%llx)", nodeId))
nodeReady = true;
case ZTS_EVENT_NODE_OFFLINE:
print("ZTS_EVENT_NODE_OFFLINE\n")
nodeReady = false;
case ZTS_EVENT_NODE_NORMAL_TERMINATION:
print("ZTS_EVENT_NODE_NORMAL_TERMINATION\n")
case ZTS_EVENT_NETWORK_NOT_FOUND:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_NOT_FOUND (%llx)", networkId))
case ZTS_EVENT_NETWORK_REQUESTING_CONFIG:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_REQUESTING_CONFIG (%llx)", networkId))
case ZTS_EVENT_NETWORK_ACCESS_DENIED:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_ACCESS_DENIED (%llx)", networkId))
case ZTS_EVENT_NETWORK_READY_IP4:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_READY_IP4 (%llx)", networkId))
networkReady = true;
case ZTS_EVENT_NETWORK_READY_IP6:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_READY_IP6 (%llx)", networkId))
networkReady = true;
case ZTS_EVENT_NETWORK_DOWN:
let networkId:UInt64 = network!.pointee.nwid
print(String(format: "ZTS_EVENT_NETWORK_DOWN (%llx)", networkId))
/*
// Network stack events
case ZTS_EVENT_NETIF_UP:
print("ZTS_EVENT_NETIF_UP --- network=%llx, mac=%llx, mtu=%d\n",
msg.netif->nwid,
msg.netif->mac,
msg.netif->mtu)
//networkReady = true;
case ZTS_EVENT_NETIF_DOWN:
print("ZTS_EVENT_NETIF_DOWN --- network=%llx, mac=%llx\n",
msg.netif->nwid,
msg.netif->mac)
//networkReady = true;
// Address events
case ZTS_EVENT_ADDR_ADDED_IP4:
print("ZTS_EVENT_ADDR_ADDED_IP4")
/*
char ipstr[INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg.addr->addr);
inet_ntop(AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
print("ZTS_EVENT_ADDR_NEW_IP4 --- This node's virtual address on network %llx is %s\n",
msg.addr->nwid, ipstr)
*/
case ZTS_EVENT_ADDR_ADDED_IP6:
print("ZTS_EVENT_ADDR_ADDED_IP6")
/*
char ipstr[INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg.addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
print("ZTS_EVENT_ADDR_NEW_IP6 --- This node's virtual address on network %llx is %s\n",
msg.addr->nwid, ipstr)
*/
case ZTS_EVENT_ADDR_REMOVED_IP4:
print("ZTS_EVENT_ADDR_REMOVED_IP4")
/*
char ipstr[INET_ADDRSTRLEN];
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)&(msg.addr->addr);
inet_ntop(AF_INET, &(in4->sin_addr), ipstr, INET_ADDRSTRLEN);
print("ZTS_EVENT_ADDR_REMOVED_IP4 --- The virtual address %s for this node on network %llx has been removed.\n",
ipstr, msg.addr->nwid)
*/
case ZTS_EVENT_ADDR_REMOVED_IP6:
print("ZTS_EVENT_ADDR_REMOVED_IP6")
/*
char ipstr[INET6_ADDRSTRLEN];
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)&(msg.addr->addr);
inet_ntop(AF_INET6, &(in6->sin6_addr), ipstr, INET6_ADDRSTRLEN);
print("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
case ZTS_EVENT_PEER_P2P:
print("ZTS_EVENT_PEER_P2P --- node=%llx\n", msg.peer->address)
case ZTS_EVENT_PEER_RELAY:
print("ZTS_EVENT_PEER_RELAY --- node=%llx\n", msg.peer->address)
*/
default:
print("UNKNOWN_EVENT")
}
}
func main()
{
print("waiting for node to come online...")
zts_start("../../config_path_a", myZeroTierEventCallback, 0)
while(!nodeReady) {
sleep(1)
}
print("Joining network")
}
main()