Update C# bindings to 1.4.0 API

This commit is contained in:
Joseph Henry
2021-04-30 21:54:34 -07:00
parent 3e304cb25a
commit 6f42338f6e
19 changed files with 4679 additions and 3143 deletions

View File

@@ -9,9 +9,6 @@ jobs:
- name: Checkout repo
uses: actions/checkout@v2
- name: Install clang-format
run: sudo apt-get install clang-format
- name: Format code
run: ./build.sh format-code

View File

@@ -408,6 +408,28 @@ host-pinvoke()
cp -f $CACHE_DIR/lib/libzt.* $LIB_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR
# Test C#
if [[ $2 = *"test"* ]]; then
if [[ -z "${alice_path}" ]]; then
echo "Please set necessary environment variables for test"
exit 0
fi
# TODO: This should eventually be converted to a proper dotnet project
# Build C# managed API library
# -doc:$LIB_OUTPUT_DIR/ZeroTier.Sockets.xml
csc -target:library -out:$LIB_OUTPUT_DIR/ZeroTier.Sockets.dll src/bindings/csharp/*.cs
# Build selftest
mkdir -p $BIN_OUTPUT_DIR
csc -out:$BIN_OUTPUT_DIR/selftest.exe -reference:$LIB_OUTPUT_DIR/ZeroTier.Sockets.dll test/selftest.cs
# Copy shared libraries into bin directory so they can be discovered by dlopen
cp $LIB_OUTPUT_DIR/* $BIN_OUTPUT_DIR
# Start Alice as server
MONO_THREADS_SUSPEND=preemptive; mono --debug "$BIN_OUTPUT_DIR/selftest.exe" server $alice_path $testnet $port4 &
sleep 5
# Start Bob as client
MONO_THREADS_SUSPEND=preemptive; mono --debug "$BIN_OUTPUT_DIR/selftest.exe" client $bob_path $testnet $alice_ip4 $port4 &
fi
}
# Build shared library with Java JNI wrapper symbols exported (.jar)
@@ -560,7 +582,7 @@ format-code()
if [[ ! $(which clang-format) = "" ]];
then
# Eventually: find . -path ./ext -prune -false -o -type f \( -iname \*.c -o -iname \*.h -o -iname \*.cpp -o -iname \*.hpp \) -exec clang-format -i {} \;
clang-format -i include/*.h \
clang-format-11 -i include/*.h \
src/*.c \
src/*.cpp \
src/*.hpp \
@@ -597,37 +619,6 @@ test-c()
"$BIN_OUTPUT_DIR/selftest-c" $bob_path $testnet $port4 $alice_ip4 $port6 $alice_ip6 &
}
# Test C# API
test-cs()
{
if [[ -z "${alice_path}" ]]; then
echo "Please set necessary environment variables for test"
exit 0
fi
ARTIFACT="pinvoke"
# Default to debug so asserts aren't optimized out
BUILD_TYPE=${1:-debug}
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin
rm -rf $TARGET_BUILD_DIR
# Build C shared library exporting C# symbols
host-pinvoke $1
# TODO: This should eventually be converted to a proper dotnet project
# Build C# managed API library
csc -target:library -doc:$LIB_OUTPUT_DIR/ZeroTier.Sockets.xml -out:$LIB_OUTPUT_DIR/ZeroTier.Sockets.dll src/bindings/csharp/*.cs
# Build selftest
mkdir -p $BIN_OUTPUT_DIR
csc -out:$BIN_OUTPUT_DIR/selftest.exe -reference:$LIB_OUTPUT_DIR/ZeroTier.Sockets.dll test/selftest.cs
# Copy shared libraries into bin directory so they can be discovered by dlopen
cp $LIB_OUTPUT_DIR/* $BIN_OUTPUT_DIR
# Start Alice as server
mono --debug "$BIN_OUTPUT_DIR/selftest.exe" $alice_path $testnet $port4 $port6 &
sleep 10
# Start Bob as client
mono --debug "$BIN_OUTPUT_DIR/selftest.exe" $bob_path $testnet $port4 $alice_ip4 $port6 $alice_ip6 &
}
# Recursive deep clean
clean()
{

View File

@@ -2,54 +2,94 @@
using System;
using System.Threading;
using System.Net;
using System.Net.Sockets; // For SocketType, etc
using System.Text; // For Encoding
using System.Net.Sockets;
using System.Text;
/**
*
* Namespaces explained:
*
* ZeroTier.Core (API to control a ZeroTier Node)
* -> class ZeroTier.Core.Node
* -> class ZeroTier.Core.Event
*
* ZeroTier.Sockets (Socket API similar to System.Net.Sockets)
* -> class ZeroTier.Sockets.Socket
* -> class ZeroTier.Sockets.SocketException
*
* ZeroTier.Central (upcoming)
*
*/
using ZeroTier;
public class ExampleApp {
// ZeroTier Node instance
ZeroTier.Core.Node node;
/**
* Initialize and start ZeroTier
*/
public void StartZeroTier(string configFilePath, ushort servicePort, ulong networkId)
// Initialize and start ZeroTier
public void StartZeroTier(string configFilePath, ulong networkId)
{
node = new ZeroTier.Core.Node(configFilePath, OnZeroTierEvent, servicePort);
node = new ZeroTier.Core.Node();
// (OPTIONAL) Initialize node
node.InitFromStorage(configFilePath);
node.InitAllowNetworkCaching(false);
node.InitAllowPeerCaching(true);
// node.InitAllowIdentityCaching(true);
// node.InitAllowWorldCaching(false);
node.InitSetEventHandler(OnZeroTierEvent);
node.InitSetPort(0); // Will randomly attempt ports if set to 0
// (OPTIONAL) Set custom signed roots
// In this case we only allow ZeroTier to contact our Amsterdam root server
// To see examples of how to generate and sign roots definitions see docs.zerotier.com
var rootsData = new byte[] {
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xea, 0xc9, 0x0a, 0x00, 0x00, 0x01, 0x6c, 0xe3, 0xe2, 0x39, 0x55, 0x74,
0xeb, 0x27, 0x9d, 0xc9, 0xe7, 0x5a, 0x52, 0xbb, 0x91, 0x8f, 0xf7, 0x43, 0x3c, 0xbf, 0x77, 0x5a, 0x4b, 0x57,
0xb4, 0xe1, 0xe9, 0xa1, 0x01, 0x61, 0x3d, 0x25, 0x35, 0x60, 0xcb, 0xe3, 0x30, 0x18, 0x1e, 0x6e, 0x44, 0xef,
0x93, 0x89, 0xa0, 0x19, 0xb8, 0x7b, 0x36, 0x0b, 0x92, 0xff, 0x0f, 0x1b, 0xbe, 0x56, 0x5a, 0x46, 0x91, 0x36,
0xf1, 0xd4, 0x5c, 0x09, 0x05, 0xe5, 0xf5, 0xfb, 0xba, 0xe8, 0x13, 0x2d, 0x47, 0xa8, 0xe4, 0x1b, 0xa5, 0x1c,
0xcf, 0xb0, 0x2f, 0x27, 0x7e, 0x95, 0xa0, 0xdd, 0x49, 0xe1, 0x7d, 0xc0, 0x7e, 0x6d, 0xe3, 0x25, 0x91, 0x96,
0xc2, 0x55, 0xf9, 0x20, 0x6d, 0x2a, 0x5e, 0x1b, 0x41, 0xcb, 0x1f, 0x8d, 0x57, 0x27, 0x69, 0x3e, 0xcc, 0x7f,
0x0b, 0x36, 0x54, 0x6b, 0xd3, 0x80, 0x78, 0xf6, 0xd0, 0xec, 0xb4, 0x31, 0x6b, 0x87, 0x1b, 0x50, 0x08, 0xe4,
0x0b, 0xa9, 0xd4, 0xfd, 0x37, 0x79, 0x14, 0x6a, 0xf5, 0x12, 0xf2, 0x45, 0x39, 0xca, 0x23, 0x00, 0x39, 0xbc,
0xa3, 0x1e, 0xa8, 0x4e, 0x23, 0x2d, 0xc8, 0xdb, 0x9b, 0x0e, 0x52, 0x1b, 0x8d, 0x02, 0x72, 0x01, 0x99, 0x2f,
0xcf, 0x1d, 0xb7, 0x00, 0x20, 0x6e, 0xd5, 0x93, 0x50, 0xb3, 0x19, 0x16, 0xf7, 0x49, 0xa1, 0xf8, 0x5d, 0xff,
0xb3, 0xa8, 0x78, 0x7d, 0xcb, 0xf8, 0x3b, 0x8c, 0x6e, 0x94, 0x48, 0xd4, 0xe3, 0xea, 0x0e, 0x33, 0x69, 0x30,
0x1b, 0xe7, 0x16, 0xc3, 0x60, 0x93, 0x44, 0xa9, 0xd1, 0x53, 0x38, 0x50, 0xfb, 0x44, 0x60, 0xc5, 0x0a, 0xf4,
0x33, 0x22, 0xbc, 0xfc, 0x8e, 0x13, 0xd3, 0x30, 0x1a, 0x1f, 0x10, 0x03, 0xce, 0xb6, 0x00, 0x02, 0x04, 0xc3,
0xb5, 0xad, 0x9f, 0x27, 0x09, 0x06, 0x2a, 0x02, 0x6e, 0xa0, 0xc0, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x27, 0x09
};
node.InitSetRoots(rootsData, rootsData.Length);
node.Start(); // Network activity only begins after calling Start()
while (! node.Online) {
Thread.Sleep(50);
}
/* How you do this next part is up to you, but essentially we're waiting for the node
to signal to us via OnZeroTierEvent(ZeroTier.Core.Event) that it has access to the
internet and is able to talk to one of our root servers. As a convenience you can just
periodically check Node.IsOnline() instead of looking for the event via the callback. */
while (!node.IsOnline()) { Thread.Sleep(100); }
Console.WriteLine("Id : " + node.IdString);
Console.WriteLine("Version : " + node.Version);
Console.WriteLine("PrimaryPort : " + node.PrimaryPort);
Console.WriteLine("SecondaryPort : " + node.SecondaryPort);
Console.WriteLine("TertiaryPort : " + node.TertiaryPort);
/* After the node comes online you may now join/leave networks. You will receive
notifications via the callback function regarding the status of your join request as well
as any subsequent network-related events such as the assignment of an IP address, added
or removed routes, etc. */
node.Join(networkId);
Console.WriteLine("Waiting for join to complete...");
while (node.Networks.Count == 0) {
Thread.Sleep(50);
}
/* Note that ZeroTier.Sockets.Socket calls will fail if there are no routes available, for this
reason we should wait to make those calls until the node has indicated to us that at
least one network has been joined successfully. */
while (!node.HasRoutes()) { Thread.Sleep(100); }
// Wait until we've joined the network and we have routes + addresses
Console.WriteLine("Waiting for network to become transport ready...");
while (! node.IsNetworkTransportReady(networkId)) {
Thread.Sleep(50);
}
Console.WriteLine("Num of assigned addresses : " + node.GetNetworkAddresses(networkId).Count);
foreach (IPAddress addr in node.GetNetworkAddresses(networkId)) {
Console.WriteLine(" - Address: " + addr);
}
Console.WriteLine("Num of routes : " + node.GetNetworkRoutes(networkId).Count);
foreach (ZeroTier.Core.RouteInfo route in node.GetNetworkRoutes(networkId)) {
Console.WriteLine(
" - Route: target={0} via={1} flags={2} metric={3}",
route.Target.ToString(),
route.Via.ToString(),
route.Flags,
route.Metric);
}
}
/**
@@ -57,39 +97,43 @@ public class ExampleApp {
*/
public void StopZeroTier()
{
node.Stop();
node.Free();
}
/**
* (OPTIONAL)
*
* Your application should process event messages and return control as soon as possible. Blocking
* or otherwise time-consuming operations are not reccomended here.
* or otherwise time-consuming operations are not recommended here.
*/
public void OnZeroTierEvent(ZeroTier.Core.Event e)
{
Console.WriteLine("Event.eventCode = {0} ({1})", e.EventCode, e.EventName);
if (e.EventCode == ZeroTier.Constants.EVENT_NODE_ONLINE) {
Console.WriteLine("Event.Code = {0} ({1})", e.Code, e.Name);
/*
if (e.Code == ZeroTier.Constants.EVENT_NODE_ONLINE) {
Console.WriteLine("Node is online");
Console.WriteLine(" - Address (NodeId): " + node.NodeId.ToString("x16"));
Console.WriteLine(" - Address (NodeId): " + node.Id.ToString("x16"));
}
if (e.EventCode == ZeroTier.Constants.EVENT_NETWORK_OK) {
Console.WriteLine(" - Network ID: " + e.networkDetails.networkId.ToString("x16"));
if (e.Code == ZeroTier.Constants.EVENT_NETWORK_OK) {
Console.WriteLine(" - Network ID: " + e.NetworkInfo.Id.ToString("x16"));
}
*/
}
/**
* Example server
*/
public void YourServer(IPEndPoint localEndPoint) {
public void SocketServer(IPEndPoint localEndPoint)
{
string data = null;
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
Console.WriteLine(localEndPoint.ToString());
ZeroTier.Sockets.Socket listener = new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
ZeroTier.Sockets.Socket listener =
new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and
// listen for incoming connections.
@@ -97,170 +141,126 @@ public class ExampleApp {
try {
listener.Bind(localEndPoint);
listener.Listen(10);
// Start listening for connections.
while (true) {
Console.WriteLine("Waiting for a connection...");
// Program is suspended while waiting for an incoming connection.
bool nonblocking = true;
ZeroTier.Sockets.Socket handler;
Console.WriteLine("Server: Accepting...");
handler = listener.Accept();
if (nonblocking) { // Non-blocking style Accept() loop using Poll()
Console.WriteLine("Starting non-blocking Accept() loop...");
listener.Blocking = false;
// loop
int timeout = 100000; // microseconds (1 second)
while (true) {
Console.WriteLine("Polling... (for data or incoming connections)");
if (listener.Poll(timeout, SelectMode.SelectRead)) {
Console.WriteLine("Detected event (SelectRead). Accepting...");
handler = listener.Accept();
break;
}
//Thread.Sleep(5);
}
}
else { // Blocking style
Console.WriteLine("Starting blocking Accept() call...");
handler = listener.Accept();
}
data = null;
Console.WriteLine("Accepted connection from: " + handler.RemoteEndPoint.ToString());
Console.WriteLine("Server: Accepted connection from: " + handler.RemoteEndPoint.ToString());
// handler.ReceiveTimeout = 1000;
// An incoming connection needs to be processed.
while (true) {
for (int i = 0; i < 4; i++) {
int bytesRec = 0;
try {
Console.WriteLine("Receiving...");
Console.WriteLine("Server: Receiving...");
bytesRec = handler.Receive(bytes);
}
catch (ZeroTier.Sockets.SocketException e)
{
Console.WriteLine("ServiceErrorCode={0} SocketErrorCode={1}",
e.ServiceErrorCode, e.SocketErrorCode);
catch (ZeroTier.Sockets.SocketException e) {
Console.WriteLine(
"ServiceErrorCode={0} SocketErrorCode={1}",
e.ServiceErrorCode,
e.SocketErrorCode);
}
if (bytesRec > 0) {
Console.WriteLine("Bytes received: {0}", bytesRec);
Console.WriteLine("Server: Bytes received: {0}", bytesRec);
data = Encoding.ASCII.GetString(bytes, 0, bytesRec);
Console.WriteLine( "Text received : {0}", data);
//break;
Console.WriteLine("Server: Text received : {0}", data);
Thread.Sleep(1000);
// Echo the data back to the client.
byte[] msg = Encoding.ASCII.GetBytes(data);
handler.Send(msg);
}
else
{
System.GC.Collect();
Console.WriteLine("No data...");
Thread.Sleep(1000);
}
}
// Release the socket.
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
} catch (ZeroTier.Sockets.SocketException e) {
catch (ZeroTier.Sockets.SocketException e) {
Console.WriteLine(e);
Console.WriteLine("ServiceErrorCode={0} SocketErrorCode={1}",
e.ServiceErrorCode, e.SocketErrorCode);
Console.WriteLine("ServiceErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode);
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
/**
* Example client
*/
public void YourClient(IPEndPoint remoteServerEndPoint) {
public void SocketClient(IPEndPoint remoteServerEndPoint)
{
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try {
// Create a TCP/IP socket.
ZeroTier.Sockets.Socket sender = new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
ZeroTier.Sockets.Socket sender =
new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try {
Console.WriteLine("Socket connecting to {0}...",
remoteServerEndPoint.ToString());
Console.WriteLine("Client: Connecting to {0}...", remoteServerEndPoint.ToString());
sender.Connect(remoteServerEndPoint);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
Console.WriteLine("Client: Connected to {0}", sender.RemoteEndPoint.ToString());
// Encode the data string into a byte array.
for (int i = 0; i < 4; i++) {
byte[] msg = Encoding.ASCII.GetBytes("This is a test");
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
Console.WriteLine("Client: Sent ({0}) bytes", bytesSent);
Thread.Sleep(1000);
int bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}",
Encoding.ASCII.GetString(bytes,0,bytesRec));
Console.WriteLine("Client: Echoing {0}", Encoding.ASCII.GetString(bytes, 0, bytesRec));
Thread.Sleep(1000);
}
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
} catch (ArgumentNullException ane) {
}
catch (ArgumentNullException ane) {
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
} catch (ZeroTier.Sockets.SocketException e) {
}
catch (ZeroTier.Sockets.SocketException e) {
Console.WriteLine(e);
Console.WriteLine("ServiceErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode);
}
} catch (Exception e) {
}
catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
}
public class example
{
public class example {
static int Main(string[] args)
{
if (args.Length < 5 || args.Length > 6)
{
if (args.Length < 4 || args.Length > 5) {
Console.WriteLine("\nPlease specify either client or server mode and required arguments:");
Console.WriteLine(" Usage: example server <config_path> <ztServicePort> <nwid> <serverPort>");
Console.WriteLine(" Usage: example client <config_path> <ztServicePort> <nwid> <remoteServerIp> <remoteServerPort>\n");
Console.WriteLine(" Usage: example server <config_path> <nwid> <localPort>");
Console.WriteLine(" Usage: example client <config_path> <nwid> <remoteAddress> <remotePort>\n");
return 1;
}
string configFilePath = args[1];
ushort servicePort = (ushort)Int16.Parse(args[2]);
ulong networkId = (ulong)Int64.Parse(args[3], System.Globalization.NumberStyles.HexNumber);
ulong networkId = (ulong)Int64.Parse(args[2], System.Globalization.NumberStyles.HexNumber);
ExampleApp exampleApp = new ExampleApp();
if (args[0].Equals("server"))
{
if (args[0].Equals("server")) {
Console.WriteLine("Server mode...");
ushort serverPort = (ushort)Int16.Parse(args[4]);
exampleApp.StartZeroTier(configFilePath, servicePort, networkId);
ushort serverPort = (ushort)Int16.Parse(args[3]);
exampleApp.StartZeroTier(configFilePath, networkId);
IPAddress ipAddress = IPAddress.Parse("0.0.0.0");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, serverPort);
exampleApp.YourServer(localEndPoint);
exampleApp.SocketServer(localEndPoint);
}
if (args[0].Equals("client"))
{
if (args[0].Equals("client")) {
Console.WriteLine("Client mode...");
string serverIP = args[4];
int port = Int16.Parse(args[5]);
string serverIP = args[3];
int port = Int16.Parse(args[4]);
IPAddress ipAddress = IPAddress.Parse(serverIP);
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, port);
exampleApp.StartZeroTier(configFilePath, servicePort, networkId);
exampleApp.YourClient(remoteEndPoint);
exampleApp.StartZeroTier(configFilePath, networkId);
exampleApp.SocketClient(remoteEndPoint);
}
exampleApp.StopZeroTier();
return 0;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using System.Net;
using ZeroTier;
namespace ZeroTier.Core
{
public class AddressInfo {
public AddressInfo(IPAddress addr, ulong net_id)
{
_addr = addr;
_net_id = net_id;
}
public ulong _net_id;
public IPAddress _addr;
public IPAddress Address
{
get {
return _addr;
}
}
public ulong NetworkId
{
get {
return _net_id;
}
}
}
}

File diff suppressed because it is too large Load Diff

267
src/bindings/csharp/Constants.cs Normal file → Executable file
View File

@@ -4,7 +4,7 @@
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
@@ -13,28 +13,21 @@
using ZeroTier;
namespace ZeroTier
{
public class Constants
{
// General error codes
public static readonly int ERR_OK = 0;
public static readonly int ERR_SOCKET = -1;
public static readonly int ERR_SERVICE = -2;
public static readonly int ERR_ARG = -3;
public static readonly int ERR_NO_RESULT = -4;
public static readonly int ERR_GENERAL = -5;
namespace ZeroTier {
public class Constants {
public static readonly short ERR_OK = 0;
public static readonly short ERR_SOCKET = -1;
public static readonly short ERR_SERVICE = -2;
public static readonly short ERR_ARG = -3;
public static readonly short ERR_NO_RESULT = -4;
public static readonly short ERR_GENERAL = -5;
// Node events
public static readonly short EVENT_NODE_UP = 200;
public static readonly short EVENT_NODE_ONLINE = 201;
public static readonly short EVENT_NODE_OFFLINE = 202;
public static readonly short EVENT_NODE_DOWN = 203;
public static readonly short EVENT_NODE_IDENTITY_COLLISION = 204;
public static readonly short EVENT_NODE_UNRECOVERABLE_ERROR = 205;
public static readonly short EVENT_NODE_NORMAL_TERMINATION = 206;
public static readonly short ZTS_EVENT_NODE_FATAL_ERROR = 204;
// Network events
public static readonly short EVENT_NETWORK_NOT_FOUND = 210;
public static readonly short EVENT_NETWORK_CLIENT_TOO_OLD = 211;
public static readonly short EVENT_NETWORK_REQ_CONFIG = 212;
@@ -46,182 +39,107 @@ namespace ZeroTier
public static readonly short EVENT_NETWORK_DOWN = 218;
public static readonly short EVENT_NETWORK_UPDATE = 219;
// Network Stack events
public static readonly short EVENT_STACK_UP = 220;
public static readonly short EVENT_STACK_DOWN = 221;
// lwIP netif events
public static readonly short EVENT_NETIF_UP = 230;
public static readonly short EVENT_NETIF_DOWN = 231;
public static readonly short EVENT_NETIF_REMOVED = 232;
public static readonly short EVENT_NETIF_LINK_UP = 233;
public static readonly short EVENT_NETIF_LINK_DOWN = 234;
// Peer events
public static readonly short EVENT_PEER_DIRECT = 240;
public static readonly short EVENT_PEER_RELAY = 241;
public static readonly short EVENT_PEER_UNREACHABLE = 242;
public static readonly short EVENT_PEER_PATH_DISCOVERED = 243;
public static readonly short EVENT_PEER_PATH_DEAD = 244;
// Route events
public static readonly short EVENT_ROUTE_ADDED = 250;
public static readonly short EVENT_ROUTE_REMOVED = 251;
// Address events
public static readonly short EVENT_ADDR_ADDED_IP4 = 260;
public static readonly short EVENT_ADDR_REMOVED_IP4 = 261;
public static readonly short EVENT_ADDR_ADDED_IP6 = 262;
public static readonly short EVENT_ADDR_REMOVED_IP6 = 263;
public static readonly short EVENT_STORE_IDENTITY_SECRET = 270;
public static readonly short EVENT_STORE_IDENTITY_PUBLIC = 271;
public static readonly short EVENT_STORE_PLANET = 272;
public static readonly short EVENT_STORE_PEER = 273;
public static readonly short EVENT_STORE_NETWORK = 274;
// Socket error codes
public static readonly short EPERM = 1; /* Operation not permitted */
public static readonly short ENOENT = 2; /* No such file or directory */
public static readonly short ESRCH = 3; /* No such process */
public static readonly short EINTR = 4; /* Interrupted system call */
public static readonly short EIO = 5; /* I/O error */
public static readonly short ENXIO = 6; /* No such device or address */
public static readonly short E2BIG = 7; /* Arg list too long */
public static readonly short ENOEXEC = 8; /* Exec format error */
public static readonly short EBADF = 9; /* Bad file number */
public static readonly short ECHILD = 10; /* No child processes */
public static readonly short EAGAIN = 11; /* Try again */
public static readonly short ENOMEM = 12; /* Out of memory */
public static readonly short EACCES = 13; /* Permission denied */
public static readonly short EFAULT = 14; /* Bad address */
public static readonly short ENOTBLK = 15; /* Block device required */
public static readonly short EBUSY = 16; /* Device or resource busy */
public static readonly short EEXIST = 17; /* File exists */
public static readonly short EXDEV = 18; /* Cross-device link */
public static readonly short ENODEV = 19; /* No such device */
public static readonly short ENOTDIR = 20; /* Not a directory */
public static readonly short EISDIR = 21; /* Is a directory */
public static readonly short EINVAL = 22; /* Invalid argument */
public static readonly short ENFILE = 23; /* File table overflow */
public static readonly short EMFILE = 24; /* Too many open files */
public static readonly short ENOTTY = 25; /* Not a typewriter */
public static readonly short ETXTBSY = 26; /* Text file busy */
public static readonly short EFBIG = 27; /* File too large */
public static readonly short ENOSPC = 28; /* No space left on device */
public static readonly short ESPIPE = 29; /* Illegal seek */
public static readonly short EROFS = 30; /* Read-only file system */
public static readonly short EMLINK = 31; /* Too many links */
public static readonly short EPIPE = 32; /* Broken pipe */
public static readonly short EDOM = 33; /* Math argument out of domain of func */
public static readonly short ERANGE = 34; /* Math result not representable */
public static readonly short EDEADLK = 35; /* Resource deadlock would occur */
public static readonly short ENAMETOOLONG = 36; /* File name too long */
public static readonly short ENOLCK = 37; /* No record locks available */
public static readonly short ENOSYS = 38; /* Function not implemented */
public static readonly short ENOTEMPTY = 39; /* Directory not empty */
public static readonly short ELOOP = 40; /* Too many symbolic links encountered */
public static readonly short EWOULDBLOCK = EAGAIN; /* Operation would block */
public static readonly short ENOMSG = 42; /* No message of desired type */
public static readonly short EIDRM = 43; /* Identifier removed */
public static readonly short ECHRNG = 44; /* Channel number out of range */
public static readonly short EL2NSYNC = 45; /* Level 2 not synchronized */
public static readonly short EL3HLT = 46; /* Level 3 halted */
public static readonly short EL3RST = 47; /* Level 3 reset */
public static readonly short ELNRNG = 48; /* Link number out of range */
public static readonly short EUNATCH = 49; /* Protocol driver not attached */
public static readonly short ENOCSI = 50; /* No CSI structure available */
public static readonly short EL2HLT = 51; /* Level 2 halted */
public static readonly short EBADE = 52; /* Invalid exchange */
public static readonly short EBADR = 53; /* Invalid request descriptor */
public static readonly short EXFULL = 54; /* Exchange full */
public static readonly short ENOANO = 55; /* No anode */
public static readonly short EBADRQC = 56; /* Invalid request code */
public static readonly short EBADSLT = 57; /* Invalid slot */
public static readonly short EDEADLOCK = EDEADLK;
public static readonly short EBFONT = 59; /* Bad font file format */
public static readonly short ENOSTR = 60; /* Device not a stream */
public static readonly short ENODATA = 61; /* No data available */
public static readonly short ETIME = 62; /* Timer expired */
public static readonly short ENOSR = 63; /* Out of streams resources */
public static readonly short ENONET = 64; /* Machine is not on the network */
public static readonly short ENOPKG = 65; /* Package not installed */
public static readonly short EREMOTE = 66; /* Object is remote */
public static readonly short ENOLINK = 67; /* Link has been severed */
public static readonly short EADV = 68; /* Advertise error */
public static readonly short ESRMNT = 69; /* Srmount error */
public static readonly short ECOMM = 70; /* Communication error on send */
public static readonly short EPROTO = 71; /* Protocol error */
public static readonly short EMULTIHOP = 72; /* Multihop attempted */
public static readonly short EDOTDOT = 73; /* RFS specific error */
public static readonly short EBADMSG = 74; /* Not a data message */
public static readonly short EOVERFLOW = 75; /* Value too large for defined data type */
public static readonly short ENOTUNIQ = 76; /* Name not unique on network */
public static readonly short EBADFD = 77; /* File descriptor in bad state */
public static readonly short EREMCHG = 78; /* Remote address changed */
public static readonly short ELIBACC = 79; /* Can not access a needed shared library */
public static readonly short ELIBBAD = 80; /* Accessing a corrupted shared library */
public static readonly short ELIBSCN = 81; /* .lib section in a.out corrupted */
public static readonly short ELIBMAX = 82; /* Attempting to link in too many shared libraries */
public static readonly short ELIBEXEC = 83; /* Cannot exec a shared library directly */
public static readonly short EILSEQ = 84; /* Illegal byte sequence */
public static readonly short ERESTART = 85; /* Interrupted system call should be restarted */
public static readonly short ESTRPIPE = 86; /* Streams pipe error */
public static readonly short EUSERS = 87; /* Too many users */
public static readonly short ENOTSOCK = 88; /* Socket operation on non-socket */
public static readonly short EDESTADDRREQ = 89; /* Destination address required */
public static readonly short EMSGSIZE = 90; /* Message too long */
public static readonly short EPROTOTYPE = 91; /* Protocol wrong type for socket */
public static readonly short ENOPROTOOPT = 92; /* Protocol not available */
public static readonly short EPROTONOSUPPORT = 93; /* Protocol not supported */
public static readonly short ESOCKTNOSUPPORT = 94; /* Socket type not supported */
public static readonly short EOPNOTSUPP = 95; /* Operation not supported on transport endpoint */
public static readonly short EPFNOSUPPORT = 96; /* Protocol family not supported */
public static readonly short EAFNOSUPPORT = 97; /* Address family not supported by protocol */
public static readonly short EADDRINUSE = 98; /* Address already in use */
public static readonly short EADDRNOTAVAIL = 99; /* Cannot assign requested address */
public static readonly short ENETDOWN = 100; /* Network is down */
public static readonly short ENETUNREACH = 101; /* Network is unreachable */
public static readonly short ENETRESET = 102; /* Network dropped connection because of reset */
public static readonly short ECONNABORTED = 103; /* Software caused connection abort */
public static readonly short ECONNRESET = 104; /* Connection reset by peer */
public static readonly short ENOBUFS = 105; /* No buffer space available */
public static readonly short EISCONN = 106; /* Transport endpoint is already connected */
public static readonly short ENOTCONN = 107; /* Transport endpoint is not connected */
public static readonly short ESHUTDOWN = 108; /* Cannot send after transport endpoint shutdown */
public static readonly short ETOOMANYREFS = 109; /* Too many references: cannot splice */
public static readonly short ETIMEDOUT = 110; /* Connection timed out */
public static readonly short ECONNREFUSED = 111; /* Connection refused */
public static readonly short EHOSTDOWN = 112; /* Host is down */
public static readonly short EHOSTUNREACH = 113; /* No route to host */
public static readonly short EALREADY = 114; /* Operation already in progress */
public static readonly short EINPROGRESS = 115; /* Operation now in progress */
public static readonly short ESTALE = 116; /* Stale NFS file handle */
public static readonly short EUCLEAN = 117; /* Structure needs cleaning */
public static readonly short ENOTNAM = 118; /* Not a XENIX named type file */
public static readonly short ENAVAIL = 119; /* No XENIX semaphores available */
public static readonly short EISNAM = 120; /* Is a named type file */
public static readonly short EREMOTEIO = 121; /* Remote I/O error */
public static readonly short EDQUOT = 122; /* Quota exceeded */
public static readonly short ENOMEDIUM = 123; /* No medium found */
public static readonly short EMEDIUMTYPE = 124; /* Wrong medium type */
public static readonly short EPERM = 1;
public static readonly short ENOENT = 2;
public static readonly short ESRCH = 3;
public static readonly short EINTR = 4;
public static readonly short EIO = 5;
public static readonly short ENXIO = 6;
public static readonly short EBADF = 9;
public static readonly short EAGAIN = 11;
public static readonly short EWOULDBLOCK = 11;
public static readonly short ENOMEM = 12;
public static readonly short EACCES = 13;
public static readonly short EFAULT = 14;
public static readonly short EBUSY = 16;
public static readonly short EEXIST = 17;
public static readonly short ENODEV = 19;
public static readonly short EINVAL = 22;
public static readonly short ENFILE = 23;
public static readonly short EMFILE = 24;
public static readonly short ENOSYS = 38;
public static readonly short ENOTSOCK = 88;
public static readonly short EDESTADDRREQ = 89;
public static readonly short EMSGSIZE = 90;
public static readonly short EPROTOTYPE = 91;
public static readonly short ENOPROTOOPT = 92;
public static readonly short EPROTONOSUPPORT = 93;
public static readonly short ESOCKTNOSUPPORT = 94;
public static readonly short EOPNOTSUPP = 95;
public static readonly short EPFNOSUPPORT = 96;
public static readonly short EAFNOSUPPORT = 97;
public static readonly short EADDRINUSE = 98;
public static readonly short EADDRNOTAVAIL = 99;
public static readonly short ENETDOWN = 100;
public static readonly short ENETUNREACH = 101;
public static readonly short ECONNABORTED = 103;
public static readonly short ECONNRESET = 104;
public static readonly short ENOBUFS = 105;
public static readonly short EISCONN = 106;
public static readonly short ENOTCONN = 107;
public static readonly short ETIMEDOUT = 110;
public static readonly short EHOSTUNREACH = 113;
public static readonly short EALREADY = 114;
public static readonly short EINPROGRESS = 115;
// Common constants
public static readonly short MAC_ADDRSTRLEN = 18;
public static readonly short INET_ADDRSTRLEN = 16;
public static readonly short INET6_ADDRSTRLEN = 46;
public static readonly short IP_MAX_STR_LEN = 46;
public static readonly short STORE_DATA_LEN = 4096;
public static readonly short MAX_NETWORK_SHORT_NAME_LENGTH = 127;
public static readonly short MAX_NETWORK_ROUTES = 32;
public static readonly short MAX_ASSIGNED_ADDRESSES = 16;
public static readonly short MAX_PEER_NETWORK_PATHS = 16;
public static readonly short MAX_MULTICAST_SUBSCRIPTIONS = 1024;
/** 255.255.255.255 */
//public static readonly uint IPADDR_NONE =((uint32_t)0xffffffffUL);
/** 127.0.0.1 */
//public static readonly uint IPADDR_LOOPBACK =((uint32_t)0x7f000001UL);
/** 0.0.0.0 */
//public static readonly uint IPADDR_ANY =((uint32_t)0x00000000UL);
/** 255.255.255.255 */
//public static readonly uint IPADDR_BROADCAST =((uint32_t)0xffffffffUL);
// Peer roles
public static readonly byte PEER_ROLE_LEAF = 0;
public static readonly byte PEER_ROLE_MOON = 1;
public static readonly byte PEER_ROLE_PLANET = 2;
/** 255.255.255.255 */
//public static readonly uint INADDR_NONE =IPADDR_NONE;
/** 127.0.0.1 */
//public static readonly uint INADDR_LOOPBACK =IPADDR_LOOPBACK;
/** 0.0.0.0 */
//public static readonly uint INADDR_ANY =IPADDR_ANY;
/** 255.255.255.255 */
//public static readonly uint INADDR_BROADCAST =IPADDR_BROADCAST;
// Network status codes
public static readonly byte NETWORK_STATUS_REQUESTING_CONFIGURATION = 0;
public static readonly byte NETWORK_STATUS_OK = 1;
public static readonly byte NETWORK_STATUS_ACCESS_DENIED = 2;
public static readonly byte NETWORK_STATUS_NOT_FOUND = 3;
public static readonly byte NETWORK_STATUS_PORT_ERROR = 4;
public static readonly byte NETWORK_STATUS_CLIENT_TOO_OLD = 5;
//
public static readonly byte NETWORK_TYPE_PRIVATE = 0;
public static readonly byte NETWORK_TYPE_PUBLIC = 1;
// Socket protocol types
public static readonly short SOCK_STREAM = 0x0001;
@@ -250,21 +168,6 @@ namespace ZeroTier
public static readonly short MSG_DONTWAIT = 0x0008;
public static readonly short MSG_MORE = 0x0010;
// Macros for defining ioctl() command values
/*
public static readonly ulong IOCPARM_MASK = 0x7fU;
public static readonly ulong IOC_VOID = 0x20000000UL;
public static readonly ulong IOC_OUT = 0x40000000UL;
public static readonly ulong IOC_IN = 0x80000000UL;
public static readonly ulong IOC_INOUT = (IOC_IN | IOC_OUT);
public static readonly ulong IO(x,y) = (IOC_VOID | ((x)<<8)|(y));
public static readonly ulong IOR(x,y,t) = (IOC_OUT | (((long)sizeof(t) & IOCPARM_MASK)<<16) | ((x)<<8) | (y));
public static readonly ulong IOW(x,y,t) = (IOC_IN | (((long)sizeof(t) & IOCPARM_MASK)<<16) | ((x)<<8) | (y));
// ioctl() commands
public static readonly ulong FIONREAD = IOR('f', 127, unsigned long);
public static readonly ulong FIONBIO = IOW('f', 126, unsigned long);
*/
// Socket level option number
public static readonly short SOL_SOCKET = 0x0fff;
// Socket options
@@ -301,8 +204,10 @@ namespace ZeroTier
public static readonly short TCP_KEEPINTVL = 0x0004;
public static readonly short TCP_KEEPCNT = 0x0005;
// IPPROTO_IPV6 options
public static readonly short IPV6_CHECKSUM = 0x0007; // RFC3542: calculate and insert the ICMPv6 checksum for raw sockets.
public static readonly short IPV6_V6ONLY = 0x001b; // RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only.
public static readonly short IPV6_CHECKSUM =
0x0007; // RFC3542: calculate and insert the ICMPv6 checksum for raw sockets.
public static readonly short IPV6_V6ONLY =
0x001b; // RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only.
// UDPLITE options
public static readonly short UDPLITE_SEND_CSCOV = 0x01; // sender checksum coverage
public static readonly short UDPLITE_RECV_CSCOV = 0x02; // minimal receiver checksum coverage

145
src/bindings/csharp/Event.cs Normal file → Executable file
View File

@@ -4,7 +4,7 @@
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
@@ -17,140 +17,13 @@ using ZeroTier;
namespace ZeroTier.Core
{
/* Convenience structures for exposing lower level operational details to the user.
These structures do not have the same memory layout or content as those found in
include/ZeroTierSockets.h */
/// <summary>
/// Structure containing information about the local Node.
/// </summary>
public class NodeDetails
{
// Node ID
public ulong nodeId;
/**
* The port used by the service to send and receive
* all encapsulated traffic
*/
public ushort primaryPort;
public ushort secondaryPort;
public ushort tertiaryPort;
/**
* ZT version
*/
public byte versionMajor;
public byte versionMinor;
public byte versionRev;
}
public class MulticastSubscription
{
ulong macAddress;
uint AdditionalDistinguishingInformation;
}
/// <summary>
/// Structure containing information about virtual networks.
/// </summary>
public class NetworkDetails
{
public ulong networkId;
public ulong macAddress;
public string networkName;
//public byte status;
public byte type;
public ushort mtu;
public bool bridgingAllowed;
public bool broadcastEnabled;
//public int portError;
public IPAddress[] assignedAddresses;
public IPAddress[] routes;
public MulticastSubscription[] multicastSubscroptions;
}
/// <summary>
/// Structure containing state information about the low-level ethernet driver.
/// </summary>
public class NetifDetails
{
public ulong networkId;
public ulong macAddress;
public int mtu;
}
/// <summary>
/// Structure containing routing information for networks.
/// </summary>
public class RouteDetails
{
public EndPoint target;
public EndPoint via;
public ushort flags;
public ushort metric;
}
/// <summary>
/// Structure containing information about remote peer reachability.
/// </summary>
public class PeerDetails
{
ulong nodeId;
byte versionMajor;
byte versionMinor;
byte versionRev;
int latency;
byte role;
IPAddress[] paths;
}
/// <summary>
/// Structure containing information about assigned addresses.
/// </summary>
public class AddrDetails
{
ulong networkId;
IPAddress address;
}
/// <summary>
/// Class used to convey details of a low-level network event to the user.
/// </summary>
public class Event
{
int _eventCode;
string _eventName;
public NodeDetails nodeDetails;
public NetworkDetails networkDetails;
public NetifDetails netifDetails;
public RouteDetails routeDetails;
public PeerDetails peerDetails;
public AddrDetails addrDetails;
public Event(int eventCode, string eventName)
{
_eventCode = eventCode;
_eventName = eventName;
nodeDetails = null;
networkDetails = null;
netifDetails = null;
routeDetails = null;
peerDetails = null;
addrDetails = null;
}
public int EventCode {
get {
return _eventCode;
}
}
public string EventName {
get {
return _eventName;
}
}
public class Event {
public NodeInfo NodeInfo { get; set; }
public NetworkInfo NetworkInfo { get; set; }
public RouteInfo RouteInfo { get; set; }
public PeerInfo PeerInfo { get; set; }
public AddressInfo AddressInfo { get; set; }
public int Code { get; set; }
public string Name { get; set; }
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using System.Net;
using ZeroTier;
namespace ZeroTier.Core
{
public class MulticastInfo {
public ulong MACAddress;
public uint additionalDistinguishingInformation;
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using System.Net;
using System.Collections.Concurrent;
using System.Collections.Generic;
using ZeroTier;
namespace ZeroTier.Core
{
public class NetworkInfo {
public ulong Id { get; set; }
public ulong MACAddress;
public string Name;
public int Status;
public int Type;
public uint MTU;
public int DHCP;
public bool Bridge;
public bool BroadcastEnabled;
internal bool transportReady; // Synthetic value
public bool IsPrivate
{
get {
return Type == Constants.NETWORK_TYPE_PRIVATE;
}
}
public bool IsPublic
{
get {
return Type == Constants.NETWORK_TYPE_PUBLIC;
}
}
internal ConcurrentDictionary<string, IPAddress> _addrs = new ConcurrentDictionary<string, IPAddress>();
public ICollection<IPAddress> Addresses
{
get {
return _addrs.Values;
}
}
internal ConcurrentDictionary<string, ZeroTier.Core.RouteInfo> _routes =
new ConcurrentDictionary<string, ZeroTier.Core.RouteInfo>();
public ICollection<ZeroTier.Core.RouteInfo> Routes
{
get {
return _routes.Values;
}
}
}
}

1086
src/bindings/csharp/Node.cs Normal file → Executable file

File diff suppressed because it is too large Load Diff

46
src/bindings/csharp/NodeInfo.cs Executable file
View File

@@ -0,0 +1,46 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using System.Net;
using ZeroTier;
namespace ZeroTier.Core
{
/* Convenience structures for exposing lower level operational details to the user.
These structures do not have the same memory layout or content as those found in
include/ZeroTierSockets.h */
/// <summary>
/// Structure containing information about the local Node.
/// </summary>
public class NodeInfo {
// Node ID
public ulong Id { get; set; }
/**
* The port used by the service to send and receive
* all encapsulated traffic
*/
public ushort PrimaryPort { get; set; }
public ushort SecondaryPort { get; set; }
public ushort TertiaryPort { get; set; }
/**
* ZT version
*/
public byte VersionMajor { get; set; }
public byte VersionMinor { get; set; }
public byte VersionRev { get; set; }
}
}

68
src/bindings/csharp/PeerInfo.cs Executable file
View File

@@ -0,0 +1,68 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using System.Net;
using System.Collections.Concurrent;
using System.Collections.Generic;
using ZeroTier;
namespace ZeroTier.Core
{
public class PeerInfo {
public PeerInfo(ulong id, short versionMajor, short versionMinor, short versionRev, byte role)
{
_id = id;
_versionMajor = versionMajor;
_versionMinor = versionMinor;
_versionRev = versionRev;
_role = role;
}
ulong _id;
short _versionMajor;
short _versionMinor;
short _versionRev;
byte _role;
internal ConcurrentDictionary<string, IPEndPoint> _paths = new ConcurrentDictionary<string, IPEndPoint>();
public ICollection<IPEndPoint> Paths
{
get {
return _paths.Values;
}
}
public ulong Id
{
get {
return _id;
}
}
public byte Role
{
get {
return _role;
}
}
public string Version
{
get {
return string.Format("{0}.{1}.{2}", _versionMajor, _versionMinor, _versionRev);
}
}
}
}

0
src/bindings/csharp/README.md Normal file → Executable file
View File

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using System.Net;
using ZeroTier;
namespace ZeroTier.Core
{
public class RouteInfo {
public RouteInfo(IPAddress target, IPAddress via, ushort flags, ushort metric)
{
_target = target;
_via = via;
_flags = flags;
_metric = metric;
}
public IPAddress _target;
public IPAddress _via;
public ushort _flags;
public ushort _metric;
public IPAddress Target
{
get {
return _target;
}
}
public IPAddress Via
{
get {
return _via;
}
}
public ushort Flags
{
get {
return _flags;
}
}
public ushort Metric
{
get {
return _metric;
}
}
}
}

372
src/bindings/csharp/Socket.cs Normal file → Executable file
View File

@@ -4,30 +4,23 @@
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
using System; // For ObjectDisposedException
using System.Net; // For IPEndPoint
using System.Net.Sockets; // For ZeroTier.Sockets.SocketException
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using ZeroTier;
/// <summary>
/// ZeroTier SDK
/// </summary>
namespace ZeroTier.Sockets
{
/// <summary>
/// ZeroTier Socket - An lwIP socket mediated over a ZeroTier virtual link
/// </summary>
public class Socket
{
public class Socket {
/// <summary>No error.</summary>
public static readonly int ZTS_ERR_OK = 0;
/// <summary>Socket error, see Socket.ErrNo() for additional context.</summary>
@@ -44,7 +37,6 @@ namespace ZeroTier.Sockets
int _fd;
bool _isClosed;
bool _isListening;
bool _isBlocking;
bool _isBound;
bool _isConnected;
@@ -61,7 +53,6 @@ namespace ZeroTier.Sockets
{
_isClosed = false;
_isListening = false;
_isBlocking = false;
}
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
@@ -70,8 +61,7 @@ namespace ZeroTier.Sockets
int type = -1;
int protocol = -1;
// Map .NET socket parameters to ZeroTier equivalents
switch (addressFamily)
{
switch (addressFamily) {
case AddressFamily.InterNetwork:
family = Constants.AF_INET;
break;
@@ -82,8 +72,7 @@ namespace ZeroTier.Sockets
family = Constants.AF_UNSPEC;
break;
}
switch (socketType)
{
switch (socketType) {
case SocketType.Stream:
type = Constants.SOCK_STREAM;
break;
@@ -91,8 +80,7 @@ namespace ZeroTier.Sockets
type = Constants.SOCK_DGRAM;
break;
}
switch (protocolType)
{
switch (protocolType) {
case ProtocolType.Udp:
protocol = Constants.IPPROTO_UDP;
break;
@@ -103,8 +91,7 @@ namespace ZeroTier.Sockets
protocol = 0; // ?
break;
}
if ((_fd = zts_socket(family, type, protocol)) < 0)
{
if ((_fd = zts_socket(family, type, protocol)) < 0) {
throw new ZeroTier.Sockets.SocketException((int)_fd);
}
_socketFamily = addressFamily;
@@ -113,7 +100,8 @@ namespace ZeroTier.Sockets
InitializeInternalFlags();
}
private Socket(int fileDescriptor,
private Socket(
int fileDescriptor,
AddressFamily addressFamily,
SocketType socketType,
ProtocolType protocolType,
@@ -141,24 +129,11 @@ namespace ZeroTier.Sockets
if (remoteEndPoint == null) {
throw new ArgumentNullException("remoteEndPoint");
}
int err = Constants.ERR_OK;
if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork) {
err = zts_connect_easy(
int err = zts_simple_connect(
_fd,
Constants.AF_INET,
remoteEndPoint.Address.ToString(),
(ushort)remoteEndPoint.Port,
_connectTimeout);
}
if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6) {
Console.WriteLine("going to connect to: " + remoteEndPoint.ToString());
err = zts_connect_easy(
_fd,
Constants.AF_INET6,
remoteEndPoint.Address.ToString(),
(ushort)remoteEndPoint.Port,
_connectTimeout);
}
if (err < 0) {
throw new ZeroTier.Sockets.SocketException(err, ZeroTier.Core.Node.ErrNo);
}
@@ -180,19 +155,11 @@ namespace ZeroTier.Sockets
}
int err = Constants.ERR_OK;
if (localEndPoint.AddressFamily == AddressFamily.InterNetwork) {
err = zts_bind_easy(
_fd,
Constants.AF_INET,
"0.0.0.0",
(ushort)localEndPoint.Port);
err = zts_simple_bind(_fd, "0.0.0.0", (ushort)localEndPoint.Port);
}
if (localEndPoint.AddressFamily == AddressFamily.InterNetworkV6) {
// Todo: detect IPAddress.IPv6Any
err = zts_bind_easy(
_fd,
Constants.AF_INET6,
"::",
(ushort)localEndPoint.Port);
err = zts_simple_bind(_fd, "::", (ushort)localEndPoint.Port);
}
if (err < 0) {
throw new ZeroTier.Sockets.SocketException((int)err);
@@ -228,13 +195,11 @@ namespace ZeroTier.Sockets
throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET);
}
if (_isListening == false) {
throw new InvalidOperationException(
"Socket is not in a listening state. Call Listen() first");
throw new InvalidOperationException("Socket is not in a listening state. Call Listen() first");
}
IntPtr lpBuffer = Marshal.AllocHGlobal(ZeroTier.Constants.INET6_ADDRSTRLEN);
int port = 0;
int accepted_fd = zts_accept_easy(
_fd, lpBuffer, ZeroTier.Constants.INET6_ADDRSTRLEN, ref port);
int accepted_fd = zts_simple_accept(_fd, lpBuffer, ZeroTier.Constants.INET6_ADDRSTRLEN, ref port);
// Convert buffer to managed string
string str = Marshal.PtrToStringAnsi(lpBuffer);
Marshal.FreeHGlobal(lpBuffer);
@@ -242,8 +207,8 @@ namespace ZeroTier.Sockets
IPEndPoint clientEndPoint = new IPEndPoint(IPAddress.Parse(str), port);
Console.WriteLine("clientEndPoint = " + clientEndPoint.ToString());
// Create new socket by providing file descriptor returned from zts_accept call.
Socket clientSocket = new Socket(
accepted_fd, _socketFamily, _socketType, _socketProtocol, _localEndPoint, clientEndPoint);
Socket clientSocket =
new Socket(accepted_fd, _socketFamily, _socketType, _socketProtocol, _localEndPoint, clientEndPoint);
return clientSocket;
}
@@ -253,8 +218,7 @@ namespace ZeroTier.Sockets
throw new ObjectDisposedException("Socket has been closed");
}
int ztHow = 0;
switch (how)
{
switch (how) {
case SocketShutdown.Receive:
ztHow = Constants.O_RDONLY;
break;
@@ -279,8 +243,12 @@ namespace ZeroTier.Sockets
public bool Blocking
{
get { return Convert.ToBoolean(zts_get_blocking(_fd)); }
set { zts_set_blocking(_fd, Convert.ToInt32(value)); }
get {
return Convert.ToBoolean(zts_simple_get_blocking(_fd));
}
set {
zts_simple_set_blocking(_fd, Convert.ToInt32(value));
}
}
public bool Poll(int microSeconds, System.Net.Sockets.SelectMode mode)
@@ -297,8 +265,7 @@ namespace ZeroTier.Sockets
poll_set.events = (short)((byte)ZeroTier.Constants.POLLOUT);
}
if (mode == SelectMode.SelectError) {
poll_set.events = (short)((byte)ZeroTier.Constants.POLLERR |
(byte)ZeroTier.Constants.POLLNVAL);
poll_set.events = (short)((byte)ZeroTier.Constants.POLLERR | (byte)ZeroTier.Constants.POLLNVAL);
}
IntPtr poll_fd_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(zts_pollfd)));
Marshal.StructureToPtr(poll_set, poll_fd_ptr, false);
@@ -311,17 +278,15 @@ namespace ZeroTier.Sockets
poll_set = (zts_pollfd)Marshal.PtrToStructure(poll_fd_ptr, typeof(zts_pollfd));
if (result != 0) {
if (mode == SelectMode.SelectRead) {
result = Convert.ToInt32(((byte)poll_set.revents
& (byte)ZeroTier.Constants.POLLIN) != 0);
result = Convert.ToInt32(((byte)poll_set.revents & (byte)ZeroTier.Constants.POLLIN) != 0);
}
if (mode == SelectMode.SelectWrite) {
result = Convert.ToInt32(((byte)poll_set.revents
& (byte)ZeroTier.Constants.POLLOUT) != 0);
result = Convert.ToInt32(((byte)poll_set.revents & (byte)ZeroTier.Constants.POLLOUT) != 0);
}
if (mode == SelectMode.SelectError) {
result = Convert.ToInt32(((poll_set.revents
& (byte)ZeroTier.Constants.POLLERR) != 0) ||
((poll_set.revents & (byte)ZeroTier.Constants.POLLNVAL) != 0));
result = Convert.ToInt32(
((poll_set.revents & (byte)ZeroTier.Constants.POLLERR) != 0)
|| ((poll_set.revents & (byte)ZeroTier.Constants.POLLNVAL) != 0));
}
}
Marshal.FreeHGlobal(poll_fd_ptr);
@@ -362,47 +327,71 @@ namespace ZeroTier.Sockets
public int ReceiveTimeout
{
get { return zts_get_recv_timeout(_fd); }
get {
return zts_get_recv_timeout(_fd);
}
// TODO: microseconds
set { zts_set_recv_timeout(_fd, value, 0); }
set {
zts_set_recv_timeout(_fd, value, 0);
}
}
public int SendTimeout
{
get { return zts_get_send_timeout(_fd); }
get {
return zts_get_send_timeout(_fd);
}
// TODO: microseconds
set { zts_set_send_timeout(_fd, value, 0); }
set {
zts_set_send_timeout(_fd, value, 0);
}
}
public int ConnectTimeout
{
get { return _connectTimeout; }
set { _connectTimeout = value;}
get {
return _connectTimeout;
}
set {
_connectTimeout = value;
}
}
public int ReceiveBufferSize
{
get { return zts_get_recv_buf_size(_fd); }
set { zts_set_recv_buf_size(_fd, value); }
get {
return zts_get_recv_buf_size(_fd);
}
set {
zts_set_recv_buf_size(_fd, value);
}
}
public int SendBufferSize
{
get { return zts_get_send_buf_size(_fd); }
set { zts_set_send_buf_size(_fd, value); }
get {
return zts_get_send_buf_size(_fd);
}
set {
zts_set_send_buf_size(_fd, value);
}
}
public short Ttl
{
get { return Convert.ToInt16(zts_get_ttl(_fd)); }
set { zts_set_ttl(_fd, value); }
get {
return Convert.ToInt16(zts_get_ttl(_fd));
}
set {
zts_set_ttl(_fd, value);
}
}
public LingerOption LingerState
{
get {
LingerOption lo = new LingerOption(
Convert.ToBoolean(zts_get_linger_enabled(_fd)), zts_get_linger_value(_fd));
LingerOption lo =
new LingerOption(Convert.ToBoolean(zts_get_linger_enabled(_fd)), zts_get_linger_value(_fd));
return lo;
}
set {
@@ -412,39 +401,106 @@ namespace ZeroTier.Sockets
public bool NoDelay
{
get { return Convert.ToBoolean(zts_get_no_delay(_fd)); }
set { zts_set_no_delay(_fd, Convert.ToInt32(value)); }
get {
return Convert.ToBoolean(zts_get_no_delay(_fd));
}
set {
zts_set_no_delay(_fd, Convert.ToInt32(value));
}
}
public bool KeepAlive
{
get { return Convert.ToBoolean(zts_get_keepalive(_fd)); }
set { zts_set_keepalive(_fd, Convert.ToInt32(value)); }
get {
return Convert.ToBoolean(zts_get_keepalive(_fd));
}
set {
zts_set_keepalive(_fd, Convert.ToInt32(value));
}
}
public bool Connected { get { return _isConnected; } }
public bool Connected
{
get {
return _isConnected;
}
}
public bool IsBound { get { return _isBound; } }
public bool IsBound
{
get {
return _isBound;
}
}
public AddressFamily AddressFamily { get { return _socketFamily; } }
public AddressFamily AddressFamily
{
get {
return _socketFamily;
}
}
public SocketType SocketType { get { return _socketType; } }
public SocketType SocketType
{
get {
return _socketType;
}
}
public ProtocolType ProtocolType { get { return _socketProtocol; } }
public ProtocolType ProtocolType
{
get {
return _socketProtocol;
}
}
/* .NET has moved to OSSupportsIPv* but libzt isn't an OS so we keep this old convention */
public static bool SupportsIPv4 { get { return true; } }
public static bool SupportsIPv4
{
get {
return true;
}
}
/* .NET has moved to OSSupportsIPv* but libzt isn't an OS so we keep this old convention */
public static bool SupportsIPv6 { get { return true; } }
public static bool SupportsIPv6
{
get {
return true;
}
}
public EndPoint RemoteEndPoint { get { return _remoteEndPoint; } }
public EndPoint RemoteEndPoint
{
get {
return _remoteEndPoint;
}
}
public EndPoint LocalEndPoint { get { return _localEndPoint; } }
public EndPoint LocalEndPoint
{
get {
return _localEndPoint;
}
}
/* Structures and functions used internally to communicate with
lower-level C API defined in include/ZeroTierSockets.h */
[DllImport(
"libzt",
CharSet = CharSet.Ansi,
EntryPoint = "CSharp_zts_gethostbyname")] public static extern global::System.IntPtr
zts_gethostbyname(string jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_select")]
static extern int zts_select(
int jarg1,
global::System.Runtime.InteropServices.HandleRef jarg2,
global::System.Runtime.InteropServices.HandleRef jarg3,
global::System.Runtime.InteropServices.HandleRef jarg4,
global::System.Runtime.InteropServices.HandleRef jarg5);
[DllImport("libzt", EntryPoint = "CSharp_zts_get_all_stats")]
static extern int zts_get_all_stats(IntPtr arg1);
@@ -601,25 +657,123 @@ namespace ZeroTier.Sockets
[DllImport("libzt", EntryPoint = "CSharp_zts_del_dns_nameserver")]
static extern int zts_del_dns_nameserver(IntPtr arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_inet_ntop")]
static extern string zts_inet_ntop(int arg1, IntPtr arg2, string arg3, ushort arg4);
[DllImport("libzt", EntryPoint="CSharp_zts_inet_pton")]
static extern int zts_inet_pton(int arg1, string arg2, IntPtr arg3);
[DllImport("libzt", EntryPoint = "CSharp_zts_errno_get")]
static extern int zts_errno_get();
[DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_simple_accept")]
static extern int zts_simple_accept(int jarg1, IntPtr jarg2, int jarg3, ref int jarg4);
[DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_simple_tcp_client")]
static extern int zts_simple_tcp_client(string jarg1, int jarg2);
[DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_simple_tcp_server")]
static extern int zts_simple_tcp_server(
string jarg1,
int jarg2,
string jarg3,
int jarg4,
global::System.Runtime.InteropServices.HandleRef jarg5);
[DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_simple_udp_server")]
static extern int zts_simple_udp_server(string jarg1, int jarg2);
[DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_simple_udp_client")]
static extern int zts_simple_udp_client(string jarg1);
[DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_simple_bind")]
static extern int zts_simple_bind(int jarg1, string jarg2, int jarg3);
[DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_simple_connect")]
static extern int zts_simple_connect(int jarg1, string jarg2, int jarg3, int jarg4);
[DllImport("libzt", EntryPoint = "CSharp_zts_stats_get_all")]
static extern int zts_stats_get_all(global::System.Runtime.InteropServices.HandleRef jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_set_no_delay")]
static extern int zts_simple_set_no_delay(int jarg1, int jarg2);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_get_no_delay")]
static extern int zts_simple_get_no_delay(int jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_set_linger")]
static extern int zts_simple_set_linger(int jarg1, int jarg2, int jarg3);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_get_linger_enabled")]
static extern int zts_simple_get_linger_enabled(int jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_get_linger_value")]
static extern int zts_simple_get_linger_value(int jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_set_reuse_addr")]
static extern int zts_simple_set_reuse_addr(int jarg1, int jarg2);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_get_reuse_addr")]
static extern int zts_simple_get_reuse_addr(int jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_set_recv_timeout")]
static extern int zts_simple_set_recv_timeout(int jarg1, int jarg2, int jarg3);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_get_recv_timeout")]
static extern int zts_simple_get_recv_timeout(int jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_set_send_timeout")]
static extern int zts_simple_set_send_timeout(int jarg1, int jarg2, int jarg3);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_get_send_timeout")]
static extern int zts_simple_get_send_timeout(int jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_set_send_buf_size")]
static extern int zts_simple_set_send_buf_size(int jarg1, int jarg2);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_get_send_buf_size")]
static extern int zts_simple_get_send_buf_size(int jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_set_recv_buf_size")]
static extern int zts_simple_set_recv_buf_size(int jarg1, int jarg2);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_get_recv_buf_size")]
static extern int zts_simple_get_recv_buf_size(int jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_set_ttl")]
static extern int zts_simple_set_ttl(int jarg1, int jarg2);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_get_ttl")]
static extern int zts_simple_get_ttl(int jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_set_blocking")]
static extern int zts_simple_set_blocking(int jarg1, int jarg2);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_get_blocking")]
static extern int zts_simple_get_blocking(int jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_set_keepalive")]
static extern int zts_simple_set_keepalive(int jarg1, int jarg2);
[DllImport("libzt", EntryPoint = "CSharp_zts_simple_get_keepalive")]
static extern int zts_simple_get_keepalive(int jarg1);
[DllImport("libzt", EntryPoint = "CSharp_zts_util_delay")]
public static extern void zts_util_delay(int jarg1);
[DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_util_get_ip_family")]
static extern int zts_util_get_ip_family(string jarg1);
[DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_util_ipstr_to_saddr")]
static extern int zts_util_ipstr_to_saddr(
string jarg1,
int jarg2,
global::System.Runtime.InteropServices.HandleRef jarg3,
global::System.Runtime.InteropServices.HandleRef jarg4);
/// <value>The value of errno for the low-level socket layer</value>
public static int ErrNo {
public static int ErrNo
{
get {
return zts_errno_get();
}
}
[StructLayout(LayoutKind.Sequential)]
struct zts_sockaddr
{
[StructLayout(LayoutKind.Sequential)] struct zts_sockaddr {
public byte sa_len;
public byte sa_family;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
@@ -627,14 +781,12 @@ namespace ZeroTier.Sockets
}
[StructLayout(LayoutKind.Sequential)]
struct zts_in_addr
{
struct zts_in_addr {
public uint s_addr;
}
[StructLayout(LayoutKind.Sequential)]
struct zts_sockaddr_in
{
struct zts_sockaddr_in {
public byte sin_len;
public byte sin_family;
public short sin_port;
@@ -645,16 +797,14 @@ namespace ZeroTier.Sockets
}
[StructLayout(LayoutKind.Sequential)]
struct zts_pollfd
{
struct zts_pollfd {
public int fd;
public short events;
public short revents;
}
[StructLayout(LayoutKind.Sequential)]
struct zts_timeval
{
struct zts_timeval {
public long tv_sec;
public long tv_usec;
}

10
src/bindings/csharp/SocketException.cs Normal file → Executable file
View File

@@ -4,7 +4,7 @@
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
@@ -16,15 +16,17 @@ using System;
namespace ZeroTier.Sockets
{
/// <summary>Exception class for ZeroTier service and low-level socket errors</summary>
public class SocketException : Exception
{
public class SocketException : Exception {
public SocketException(int _serviceErrorCode)
: base(String.Format("ServiceErrorCode={0} (See Constants.cs for error code meanings)", _serviceErrorCode))
{
ServiceErrorCode = _serviceErrorCode;
}
public SocketException(int _serviceErrorCode, int _socketErrorCode)
: base(String.Format("ServiceErrorCode={0}, SocketErrorCode={1} (See Constants.cs for error code meanings)", _serviceErrorCode, _socketErrorCode))
: base(String.Format(
"ServiceErrorCode={0}, SocketErrorCode={1} (See Constants.cs for error code meanings)",
_serviceErrorCode,
_socketErrorCode))
{
ServiceErrorCode = _serviceErrorCode;
SocketErrorCode = _socketErrorCode;

20
src/bindings/csharp/zt.i Normal file → Executable file
View File

@@ -27,18 +27,18 @@
%ignore zts_sockaddr_storage;
%ignore zts_sockaddr_in6;
%ignore zts_callback_msg;
%ignore zts_node_details;
%ignore zts_network_details;
%ignore zts_netif_details;
%ignore zts_virtual_network_route;
%ignore zts_peer_details;
%ignore zts_addr_details;
%ignore zts_event_msg_t;
%ignore zts_node_info_t;
%ignore zts_net_info_t;
%ignore zts_netif_info_t;
%ignore zts_route_info_t;
%ignore zts_peer_info_t;
%ignore zts_addr_info_t;
#define ZTS_CSHARP=1
#define ZTS_ENABLE_PINVOKE 1
%{
#include "../../include/ZeroTierSockets.h"
#include "../../../include/ZeroTierSockets.h"
%}
// Typemap for our event callback
@@ -52,4 +52,4 @@
%enddef
%cs_callback(CppCallback, CSharpCallbackWithStruct)
%include "../../include/ZeroTierSockets.h"
%include "../../../include/ZeroTierSockets.h"

File diff suppressed because it is too large Load Diff

266
test/selftest.cs Normal file
View File

@@ -0,0 +1,266 @@
using System;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Text;
using ZeroTier;
public class ExampleApp {
// ZeroTier Node instance
ZeroTier.Core.Node node;
// Initialize and start ZeroTier
public void StartZeroTier(string configFilePath, ulong networkId)
{
node = new ZeroTier.Core.Node();
// (OPTIONAL) Initialize node
node.InitFromStorage(configFilePath);
node.InitAllowNetworkCaching(false);
node.InitAllowPeerCaching(true);
// node.InitAllowIdentityCaching(true);
// node.InitAllowWorldCaching(false);
node.InitSetEventHandler(OnZeroTierEvent);
node.InitSetPort(0); // Will randomly attempt ports if set to 0
// (OPTIONAL) Set custom signed roots
// In this case we only allow ZeroTier to contact our Amsterdam root server
// To see examples of how to generate and sign roots definitions see docs.zerotier.com
var rootsData = new byte[] {
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xea, 0xc9, 0x0a, 0x00, 0x00, 0x01, 0x6c, 0xe3, 0xe2, 0x39, 0x55, 0x74,
0xeb, 0x27, 0x9d, 0xc9, 0xe7, 0x5a, 0x52, 0xbb, 0x91, 0x8f, 0xf7, 0x43, 0x3c, 0xbf, 0x77, 0x5a, 0x4b, 0x57,
0xb4, 0xe1, 0xe9, 0xa1, 0x01, 0x61, 0x3d, 0x25, 0x35, 0x60, 0xcb, 0xe3, 0x30, 0x18, 0x1e, 0x6e, 0x44, 0xef,
0x93, 0x89, 0xa0, 0x19, 0xb8, 0x7b, 0x36, 0x0b, 0x92, 0xff, 0x0f, 0x1b, 0xbe, 0x56, 0x5a, 0x46, 0x91, 0x36,
0xf1, 0xd4, 0x5c, 0x09, 0x05, 0xe5, 0xf5, 0xfb, 0xba, 0xe8, 0x13, 0x2d, 0x47, 0xa8, 0xe4, 0x1b, 0xa5, 0x1c,
0xcf, 0xb0, 0x2f, 0x27, 0x7e, 0x95, 0xa0, 0xdd, 0x49, 0xe1, 0x7d, 0xc0, 0x7e, 0x6d, 0xe3, 0x25, 0x91, 0x96,
0xc2, 0x55, 0xf9, 0x20, 0x6d, 0x2a, 0x5e, 0x1b, 0x41, 0xcb, 0x1f, 0x8d, 0x57, 0x27, 0x69, 0x3e, 0xcc, 0x7f,
0x0b, 0x36, 0x54, 0x6b, 0xd3, 0x80, 0x78, 0xf6, 0xd0, 0xec, 0xb4, 0x31, 0x6b, 0x87, 0x1b, 0x50, 0x08, 0xe4,
0x0b, 0xa9, 0xd4, 0xfd, 0x37, 0x79, 0x14, 0x6a, 0xf5, 0x12, 0xf2, 0x45, 0x39, 0xca, 0x23, 0x00, 0x39, 0xbc,
0xa3, 0x1e, 0xa8, 0x4e, 0x23, 0x2d, 0xc8, 0xdb, 0x9b, 0x0e, 0x52, 0x1b, 0x8d, 0x02, 0x72, 0x01, 0x99, 0x2f,
0xcf, 0x1d, 0xb7, 0x00, 0x20, 0x6e, 0xd5, 0x93, 0x50, 0xb3, 0x19, 0x16, 0xf7, 0x49, 0xa1, 0xf8, 0x5d, 0xff,
0xb3, 0xa8, 0x78, 0x7d, 0xcb, 0xf8, 0x3b, 0x8c, 0x6e, 0x94, 0x48, 0xd4, 0xe3, 0xea, 0x0e, 0x33, 0x69, 0x30,
0x1b, 0xe7, 0x16, 0xc3, 0x60, 0x93, 0x44, 0xa9, 0xd1, 0x53, 0x38, 0x50, 0xfb, 0x44, 0x60, 0xc5, 0x0a, 0xf4,
0x33, 0x22, 0xbc, 0xfc, 0x8e, 0x13, 0xd3, 0x30, 0x1a, 0x1f, 0x10, 0x03, 0xce, 0xb6, 0x00, 0x02, 0x04, 0xc3,
0xb5, 0xad, 0x9f, 0x27, 0x09, 0x06, 0x2a, 0x02, 0x6e, 0xa0, 0xc0, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x27, 0x09
};
node.InitSetRoots(rootsData, rootsData.Length);
node.Start(); // Network activity only begins after calling Start()
while (! node.Online) {
Thread.Sleep(50);
}
Console.WriteLine("Id : " + node.IdString);
Console.WriteLine("Version : " + node.Version);
Console.WriteLine("PrimaryPort : " + node.PrimaryPort);
Console.WriteLine("SecondaryPort : " + node.SecondaryPort);
Console.WriteLine("TertiaryPort : " + node.TertiaryPort);
node.Join(networkId);
Console.WriteLine("Waiting for join to complete...");
while (node.Networks.Count == 0) {
Thread.Sleep(50);
}
// Wait until we've joined the network and we have routes + addresses
Console.WriteLine("Waiting for network to become transport ready...");
while (! node.IsNetworkTransportReady(networkId)) {
Thread.Sleep(50);
}
Console.WriteLine("Num of assigned addresses : " + node.GetNetworkAddresses(networkId).Count);
foreach (IPAddress addr in node.GetNetworkAddresses(networkId)) {
Console.WriteLine(" - Address: " + addr);
}
Console.WriteLine("Num of routes : " + node.GetNetworkRoutes(networkId).Count);
foreach (ZeroTier.Core.RouteInfo route in node.GetNetworkRoutes(networkId)) {
Console.WriteLine(
" - Route: target={0} via={1} flags={2} metric={3}",
route.Target.ToString(),
route.Via.ToString(),
route.Flags,
route.Metric);
}
}
/**
* Stop ZeroTier
*/
public void StopZeroTier()
{
node.Free();
}
/**
* (OPTIONAL)
*
* Your application should process event messages and return control as soon as possible. Blocking
* or otherwise time-consuming operations are not recommended here.
*/
public void OnZeroTierEvent(ZeroTier.Core.Event e)
{
Console.WriteLine("Event.Code = {0} ({1})", e.Code, e.Name);
/*
if (e.Code == ZeroTier.Constants.EVENT_NODE_ONLINE) {
Console.WriteLine("Node is online");
Console.WriteLine(" - Address (NodeId): " + node.Id.ToString("x16"));
}
if (e.Code == ZeroTier.Constants.EVENT_NETWORK_OK) {
Console.WriteLine(" - Network ID: " + e.NetworkInfo.Id.ToString("x16"));
}
*/
}
/**
* Example server
*/
public void SocketServer(IPEndPoint localEndPoint)
{
string data = null;
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
Console.WriteLine(localEndPoint.ToString());
ZeroTier.Sockets.Socket listener =
new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and
// listen for incoming connections.
try {
listener.Bind(localEndPoint);
listener.Listen(10);
ZeroTier.Sockets.Socket handler;
Console.WriteLine("Server: Accepting...");
handler = listener.Accept();
data = null;
Console.WriteLine("Server: Accepted connection from: " + handler.RemoteEndPoint.ToString());
for (int i = 0; i < 4; i++) {
int bytesRec = 0;
try {
Console.WriteLine("Server: Receiving...");
bytesRec = handler.Receive(bytes);
}
catch (ZeroTier.Sockets.SocketException e) {
Console.WriteLine(
"ServiceErrorCode={0} SocketErrorCode={1}",
e.ServiceErrorCode,
e.SocketErrorCode);
}
if (bytesRec > 0) {
Console.WriteLine("Server: Bytes received: {0}", bytesRec);
data = Encoding.ASCII.GetString(bytes, 0, bytesRec);
Console.WriteLine("Server: Text received : {0}", data);
Thread.Sleep(1000);
// Echo the data back to the client.
byte[] msg = Encoding.ASCII.GetBytes(data);
handler.Send(msg);
Thread.Sleep(1000);
}
}
// Release the socket.
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (ZeroTier.Sockets.SocketException e) {
Console.WriteLine(e);
Console.WriteLine("ServiceErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode);
}
}
/**
* Example client
*/
public void SocketClient(IPEndPoint remoteServerEndPoint)
{
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try {
// Create a TCP/IP socket.
ZeroTier.Sockets.Socket sender =
new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try {
Console.WriteLine("Client: Connecting to {0}...", remoteServerEndPoint.ToString());
sender.Connect(remoteServerEndPoint);
Console.WriteLine("Client: Connected to {0}", sender.RemoteEndPoint.ToString());
// Encode the data string into a byte array.
for (int i = 0; i < 4; i++) {
byte[] msg = Encoding.ASCII.GetBytes("This is a test");
int bytesSent = sender.Send(msg);
Console.WriteLine("Client: Sent ({0}) bytes", bytesSent);
Thread.Sleep(1000);
int bytesRec = sender.Receive(bytes);
Console.WriteLine("Client: Echoing {0}", Encoding.ASCII.GetString(bytes, 0, bytesRec));
Thread.Sleep(1000);
}
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
catch (ArgumentNullException ane) {
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (ZeroTier.Sockets.SocketException e) {
Console.WriteLine(e);
Console.WriteLine("ServiceErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode);
}
}
catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
}
public class example {
static int Main(string[] args)
{
if (args.Length < 4 || args.Length > 5) {
Console.WriteLine("\nPlease specify either client or server mode and required arguments:");
Console.WriteLine(" Usage: example server <config_path> <nwid> <localPort>");
Console.WriteLine(" Usage: example client <config_path> <nwid> <remoteAddress> <remotePort>\n");
return 1;
}
string configFilePath = args[1];
ulong networkId = (ulong)Int64.Parse(args[2], System.Globalization.NumberStyles.HexNumber);
ExampleApp exampleApp = new ExampleApp();
if (args[0].Equals("server")) {
Console.WriteLine("Server mode...");
ushort serverPort = (ushort)Int16.Parse(args[3]);
exampleApp.StartZeroTier(configFilePath, networkId);
IPAddress ipAddress = IPAddress.Parse("0.0.0.0");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, serverPort);
exampleApp.SocketServer(localEndPoint);
}
if (args[0].Equals("client")) {
Console.WriteLine("Client mode...");
string serverIP = args[3];
int port = Int16.Parse(args[4]);
IPAddress ipAddress = IPAddress.Parse(serverIP);
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, port);
exampleApp.StartZeroTier(configFilePath, networkId);
exampleApp.SocketClient(remoteEndPoint);
}
exampleApp.StopZeroTier();
return 0;
}
}