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 - name: Checkout repo
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Install clang-format
run: sudo apt-get install clang-format
- name: Format code - name: Format code
run: ./build.sh format-code run: ./build.sh format-code

View File

@@ -408,6 +408,28 @@ host-pinvoke()
cp -f $CACHE_DIR/lib/libzt.* $LIB_OUTPUT_DIR cp -f $CACHE_DIR/lib/libzt.* $LIB_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n" echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR $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) # Build shared library with Java JNI wrapper symbols exported (.jar)
@@ -560,7 +582,7 @@ format-code()
if [[ ! $(which clang-format) = "" ]]; if [[ ! $(which clang-format) = "" ]];
then 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 {} \; # 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/*.c \
src/*.cpp \ src/*.cpp \
src/*.hpp \ src/*.hpp \
@@ -597,37 +619,6 @@ test-c()
"$BIN_OUTPUT_DIR/selftest-c" $bob_path $testnet $port4 $alice_ip4 $port6 $alice_ip6 & "$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 # Recursive deep clean
clean() clean()
{ {

View File

@@ -2,54 +2,94 @@
using System; using System;
using System.Threading; using System.Threading;
using System.Net; using System.Net;
using System.Net.Sockets; // For SocketType, etc using System.Net.Sockets;
using System.Text; // For Encoding 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; using ZeroTier;
public class ExampleApp { public class ExampleApp {
// ZeroTier Node instance
ZeroTier.Core.Node node; ZeroTier.Core.Node node;
/** // Initialize and start ZeroTier
* Initialize and start ZeroTier
*/ public void StartZeroTier(string configFilePath, ulong networkId)
public void StartZeroTier(string configFilePath, ushort servicePort, 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() 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 Console.WriteLine("Id : " + node.IdString);
to signal to us via OnZeroTierEvent(ZeroTier.Core.Event) that it has access to the Console.WriteLine("Version : " + node.Version);
internet and is able to talk to one of our root servers. As a convenience you can just Console.WriteLine("PrimaryPort : " + node.PrimaryPort);
periodically check Node.IsOnline() instead of looking for the event via the callback. */ Console.WriteLine("SecondaryPort : " + node.SecondaryPort);
while (!node.IsOnline()) { Thread.Sleep(100); } 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); 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 // Wait until we've joined the network and we have routes + addresses
reason we should wait to make those calls until the node has indicated to us that at Console.WriteLine("Waiting for network to become transport ready...");
least one network has been joined successfully. */ while (! node.IsNetworkTransportReady(networkId)) {
while (!node.HasRoutes()) { Thread.Sleep(100); } 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() public void StopZeroTier()
{ {
node.Stop(); node.Free();
} }
/** /**
* (OPTIONAL)
*
* Your application should process event messages and return control as soon as possible. Blocking * 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) public void OnZeroTierEvent(ZeroTier.Core.Event e)
{ {
Console.WriteLine("Event.eventCode = {0} ({1})", e.EventCode, e.EventName); Console.WriteLine("Event.Code = {0} ({1})", e.Code, e.Name);
/*
if (e.EventCode == ZeroTier.Constants.EVENT_NODE_ONLINE) { if (e.Code == ZeroTier.Constants.EVENT_NODE_ONLINE) {
Console.WriteLine("Node is 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) { if (e.Code == ZeroTier.Constants.EVENT_NETWORK_OK) {
Console.WriteLine(" - Network ID: " + e.networkDetails.networkId.ToString("x16")); Console.WriteLine(" - Network ID: " + e.NetworkInfo.Id.ToString("x16"));
} }
*/
} }
/** /**
* Example server * Example server
*/ */
public void YourServer(IPEndPoint localEndPoint) { public void SocketServer(IPEndPoint localEndPoint)
{
string data = null; string data = null;
// Data buffer for incoming data. // Data buffer for incoming data.
byte[] bytes = new Byte[1024]; byte[] bytes = new Byte[1024];
Console.WriteLine(localEndPoint.ToString()); Console.WriteLine(localEndPoint.ToString());
ZeroTier.Sockets.Socket listener = new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork, ZeroTier.Sockets.Socket listener =
SocketType.Stream, ProtocolType.Tcp ); new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and // Bind the socket to the local endpoint and
// listen for incoming connections. // listen for incoming connections.
@@ -97,170 +141,126 @@ public class ExampleApp {
try { try {
listener.Bind(localEndPoint); listener.Bind(localEndPoint);
listener.Listen(10); 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; 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; data = null;
Console.WriteLine("Accepted connection from: " + handler.RemoteEndPoint.ToString()); Console.WriteLine("Server: Accepted connection from: " + handler.RemoteEndPoint.ToString());
// handler.ReceiveTimeout = 1000; for (int i = 0; i < 4; i++) {
// An incoming connection needs to be processed.
while (true) {
int bytesRec = 0; int bytesRec = 0;
try { try {
Console.WriteLine("Receiving..."); Console.WriteLine("Server: Receiving...");
bytesRec = handler.Receive(bytes); bytesRec = handler.Receive(bytes);
} }
catch (ZeroTier.Sockets.SocketException e) catch (ZeroTier.Sockets.SocketException e) {
{ Console.WriteLine(
Console.WriteLine("ServiceErrorCode={0} SocketErrorCode={1}", "ServiceErrorCode={0} SocketErrorCode={1}",
e.ServiceErrorCode, e.SocketErrorCode); e.ServiceErrorCode,
e.SocketErrorCode);
} }
if (bytesRec > 0) { if (bytesRec > 0) {
Console.WriteLine("Bytes received: {0}", bytesRec); Console.WriteLine("Server: Bytes received: {0}", bytesRec);
data = Encoding.ASCII.GetString(bytes,0,bytesRec); data = Encoding.ASCII.GetString(bytes, 0, bytesRec);
Console.WriteLine( "Text received : {0}", data); Console.WriteLine("Server: Text received : {0}", data);
//break; Thread.Sleep(1000);
// Echo the data back to the client. // Echo the data back to the client.
byte[] msg = Encoding.ASCII.GetBytes(data); byte[] msg = Encoding.ASCII.GetBytes(data);
handler.Send(msg); handler.Send(msg);
} Thread.Sleep(1000);
else
{
System.GC.Collect();
Console.WriteLine("No data...");
} }
} }
// Release the socket.
handler.Shutdown(SocketShutdown.Both); handler.Shutdown(SocketShutdown.Both);
handler.Close(); handler.Close();
} }
catch (ZeroTier.Sockets.SocketException e) {
} catch (ZeroTier.Sockets.SocketException e) {
Console.WriteLine(e); Console.WriteLine(e);
Console.WriteLine("ServiceErrorCode={0} SocketErrorCode={1}", Console.WriteLine("ServiceErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode);
e.ServiceErrorCode, e.SocketErrorCode);
} }
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
} }
/** /**
* Example client * Example client
*/ */
public void YourClient(IPEndPoint remoteServerEndPoint) { public void SocketClient(IPEndPoint remoteServerEndPoint)
{
// Data buffer for incoming data. // Data buffer for incoming data.
byte[] bytes = new byte[1024]; byte[] bytes = new byte[1024];
// Connect to a remote device. // Connect to a remote device.
try { try {
// Create a TCP/IP socket. // Create a TCP/IP socket.
ZeroTier.Sockets.Socket sender = new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork, ZeroTier.Sockets.Socket sender =
SocketType.Stream, ProtocolType.Tcp ); new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try { try {
Console.WriteLine("Socket connecting to {0}...", Console.WriteLine("Client: Connecting to {0}...", remoteServerEndPoint.ToString());
remoteServerEndPoint.ToString());
sender.Connect(remoteServerEndPoint); sender.Connect(remoteServerEndPoint);
Console.WriteLine("Client: Connected to {0}", sender.RemoteEndPoint.ToString());
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
// Encode the data string into a byte array. // Encode the data string into a byte array.
for (int i = 0; i < 4; i++) {
byte[] msg = Encoding.ASCII.GetBytes("This is a test"); byte[] msg = Encoding.ASCII.GetBytes("This is a test");
// Send the data through the socket.
int bytesSent = sender.Send(msg); int bytesSent = sender.Send(msg);
Console.WriteLine("Client: Sent ({0}) bytes", bytesSent);
// Receive the response from the remote device. Thread.Sleep(1000);
int bytesRec = sender.Receive(bytes); int bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}", Console.WriteLine("Client: Echoing {0}", Encoding.ASCII.GetString(bytes, 0, bytesRec));
Encoding.ASCII.GetString(bytes,0,bytesRec)); Thread.Sleep(1000);
}
// Release the socket. // Release the socket.
sender.Shutdown(SocketShutdown.Both); sender.Shutdown(SocketShutdown.Both);
sender.Close(); sender.Close();
}
} catch (ArgumentNullException ane) { catch (ArgumentNullException ane) {
Console.WriteLine("ArgumentNullException : {0}",ane.ToString()); Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
} catch (ZeroTier.Sockets.SocketException e) { }
catch (ZeroTier.Sockets.SocketException e) {
Console.WriteLine(e); Console.WriteLine(e);
Console.WriteLine("ServiceErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode); Console.WriteLine("ServiceErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode);
} }
} catch (Exception e) { }
Console.WriteLine( e.ToString()); catch (Exception e) {
Console.WriteLine(e.ToString());
} }
} }
} }
public class example public class example {
{
static int Main(string[] args) 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("\nPlease specify either client or server mode and required arguments:");
Console.WriteLine(" Usage: example server <config_path> <ztServicePort> <nwid> <serverPort>"); Console.WriteLine(" Usage: example server <config_path> <nwid> <localPort>");
Console.WriteLine(" Usage: example client <config_path> <ztServicePort> <nwid> <remoteServerIp> <remoteServerPort>\n"); Console.WriteLine(" Usage: example client <config_path> <nwid> <remoteAddress> <remotePort>\n");
return 1; return 1;
} }
string configFilePath = args[1]; string configFilePath = args[1];
ushort servicePort = (ushort)Int16.Parse(args[2]); ulong networkId = (ulong)Int64.Parse(args[2], System.Globalization.NumberStyles.HexNumber);
ulong networkId = (ulong)Int64.Parse(args[3], System.Globalization.NumberStyles.HexNumber);
ExampleApp exampleApp = new ExampleApp(); ExampleApp exampleApp = new ExampleApp();
if (args[0].Equals("server")) if (args[0].Equals("server")) {
{
Console.WriteLine("Server mode..."); Console.WriteLine("Server mode...");
ushort serverPort = (ushort)Int16.Parse(args[4]); ushort serverPort = (ushort)Int16.Parse(args[3]);
exampleApp.StartZeroTier(configFilePath, servicePort, networkId); exampleApp.StartZeroTier(configFilePath, networkId);
IPAddress ipAddress = IPAddress.Parse("0.0.0.0"); IPAddress ipAddress = IPAddress.Parse("0.0.0.0");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, serverPort); 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..."); Console.WriteLine("Client mode...");
string serverIP = args[4]; string serverIP = args[3];
int port = Int16.Parse(args[5]); int port = Int16.Parse(args[4]);
IPAddress ipAddress = IPAddress.Parse(serverIP); IPAddress ipAddress = IPAddress.Parse(serverIP);
IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, port); IPEndPoint remoteEndPoint = new IPEndPoint(ipAddress, port);
exampleApp.StartZeroTier(configFilePath, servicePort, networkId); exampleApp.StartZeroTier(configFilePath, networkId);
exampleApp.YourClient(remoteEndPoint); exampleApp.SocketClient(remoteEndPoint);
} }
exampleApp.StopZeroTier(); exampleApp.StopZeroTier();
return 0; 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

271
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 * Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory. * 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 * 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. * of this software will be governed by version 2.0 of the Apache License.
@@ -13,28 +13,21 @@
using ZeroTier; using ZeroTier;
namespace ZeroTier namespace ZeroTier {
{ public class Constants {
public class Constants public static readonly short ERR_OK = 0;
{ public static readonly short ERR_SOCKET = -1;
// General error codes public static readonly short ERR_SERVICE = -2;
public static readonly int ERR_OK = 0; public static readonly short ERR_ARG = -3;
public static readonly int ERR_SOCKET = -1; public static readonly short ERR_NO_RESULT = -4;
public static readonly int ERR_SERVICE = -2; public static readonly short ERR_GENERAL = -5;
public static readonly int ERR_ARG = -3;
public static readonly int ERR_NO_RESULT = -4;
public static readonly int ERR_GENERAL = -5;
// Node events
public static readonly short EVENT_NODE_UP = 200; public static readonly short EVENT_NODE_UP = 200;
public static readonly short EVENT_NODE_ONLINE = 201; public static readonly short EVENT_NODE_ONLINE = 201;
public static readonly short EVENT_NODE_OFFLINE = 202; public static readonly short EVENT_NODE_OFFLINE = 202;
public static readonly short EVENT_NODE_DOWN = 203; public static readonly short EVENT_NODE_DOWN = 203;
public static readonly short EVENT_NODE_IDENTITY_COLLISION = 204; public static readonly short ZTS_EVENT_NODE_FATAL_ERROR = 204;
public static readonly short EVENT_NODE_UNRECOVERABLE_ERROR = 205;
public static readonly short EVENT_NODE_NORMAL_TERMINATION = 206;
// Network events
public static readonly short EVENT_NETWORK_NOT_FOUND = 210; 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_CLIENT_TOO_OLD = 211;
public static readonly short EVENT_NETWORK_REQ_CONFIG = 212; 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_DOWN = 218;
public static readonly short EVENT_NETWORK_UPDATE = 219; 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_UP = 220;
public static readonly short EVENT_STACK_DOWN = 221; 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_UP = 230;
public static readonly short EVENT_NETIF_DOWN = 231; public static readonly short EVENT_NETIF_DOWN = 231;
public static readonly short EVENT_NETIF_REMOVED = 232; public static readonly short EVENT_NETIF_REMOVED = 232;
public static readonly short EVENT_NETIF_LINK_UP = 233; public static readonly short EVENT_NETIF_LINK_UP = 233;
public static readonly short EVENT_NETIF_LINK_DOWN = 234; 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_DIRECT = 240;
public static readonly short EVENT_PEER_RELAY = 241; public static readonly short EVENT_PEER_RELAY = 241;
public static readonly short EVENT_PEER_UNREACHABLE = 242; public static readonly short EVENT_PEER_UNREACHABLE = 242;
public static readonly short EVENT_PEER_PATH_DISCOVERED = 243; public static readonly short EVENT_PEER_PATH_DISCOVERED = 243;
public static readonly short EVENT_PEER_PATH_DEAD = 244; 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_ADDED = 250;
public static readonly short EVENT_ROUTE_REMOVED = 251; 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_ADDED_IP4 = 260;
public static readonly short EVENT_ADDR_REMOVED_IP4 = 261; public static readonly short EVENT_ADDR_REMOVED_IP4 = 261;
public static readonly short EVENT_ADDR_ADDED_IP6 = 262; public static readonly short EVENT_ADDR_ADDED_IP6 = 262;
public static readonly short EVENT_ADDR_REMOVED_IP6 = 263; 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 // Socket error codes
public static readonly short EPERM = 1; /* Operation not permitted */ public static readonly short EPERM = 1;
public static readonly short ENOENT = 2; /* No such file or directory */ public static readonly short ENOENT = 2;
public static readonly short ESRCH = 3; /* No such process */ public static readonly short ESRCH = 3;
public static readonly short EINTR = 4; /* Interrupted system call */ public static readonly short EINTR = 4;
public static readonly short EIO = 5; /* I/O error */ public static readonly short EIO = 5;
public static readonly short ENXIO = 6; /* No such device or address */ public static readonly short ENXIO = 6;
public static readonly short E2BIG = 7; /* Arg list too long */ public static readonly short EBADF = 9;
public static readonly short ENOEXEC = 8; /* Exec format error */ public static readonly short EAGAIN = 11;
public static readonly short EBADF = 9; /* Bad file number */ public static readonly short EWOULDBLOCK = 11;
public static readonly short ECHILD = 10; /* No child processes */ public static readonly short ENOMEM = 12;
public static readonly short EAGAIN = 11; /* Try again */ public static readonly short EACCES = 13;
public static readonly short ENOMEM = 12; /* Out of memory */ public static readonly short EFAULT = 14;
public static readonly short EACCES = 13; /* Permission denied */ public static readonly short EBUSY = 16;
public static readonly short EFAULT = 14; /* Bad address */ public static readonly short EEXIST = 17;
public static readonly short ENOTBLK = 15; /* Block device required */ public static readonly short ENODEV = 19;
public static readonly short EBUSY = 16; /* Device or resource busy */ public static readonly short EINVAL = 22;
public static readonly short EEXIST = 17; /* File exists */ public static readonly short ENFILE = 23;
public static readonly short EXDEV = 18; /* Cross-device link */ public static readonly short EMFILE = 24;
public static readonly short ENODEV = 19; /* No such device */ public static readonly short ENOSYS = 38;
public static readonly short ENOTDIR = 20; /* Not a directory */ public static readonly short ENOTSOCK = 88;
public static readonly short EISDIR = 21; /* Is a directory */ public static readonly short EDESTADDRREQ = 89;
public static readonly short EINVAL = 22; /* Invalid argument */ public static readonly short EMSGSIZE = 90;
public static readonly short ENFILE = 23; /* File table overflow */ public static readonly short EPROTOTYPE = 91;
public static readonly short EMFILE = 24; /* Too many open files */ public static readonly short ENOPROTOOPT = 92;
public static readonly short ENOTTY = 25; /* Not a typewriter */ public static readonly short EPROTONOSUPPORT = 93;
public static readonly short ETXTBSY = 26; /* Text file busy */ public static readonly short ESOCKTNOSUPPORT = 94;
public static readonly short EFBIG = 27; /* File too large */ public static readonly short EOPNOTSUPP = 95;
public static readonly short ENOSPC = 28; /* No space left on device */ public static readonly short EPFNOSUPPORT = 96;
public static readonly short ESPIPE = 29; /* Illegal seek */ public static readonly short EAFNOSUPPORT = 97;
public static readonly short EROFS = 30; /* Read-only file system */ public static readonly short EADDRINUSE = 98;
public static readonly short EMLINK = 31; /* Too many links */ public static readonly short EADDRNOTAVAIL = 99;
public static readonly short EPIPE = 32; /* Broken pipe */ public static readonly short ENETDOWN = 100;
public static readonly short EDOM = 33; /* Math argument out of domain of func */ public static readonly short ENETUNREACH = 101;
public static readonly short ERANGE = 34; /* Math result not representable */ public static readonly short ECONNABORTED = 103;
public static readonly short EDEADLK = 35; /* Resource deadlock would occur */ public static readonly short ECONNRESET = 104;
public static readonly short ENAMETOOLONG = 36; /* File name too long */ public static readonly short ENOBUFS = 105;
public static readonly short ENOLCK = 37; /* No record locks available */ public static readonly short EISCONN = 106;
public static readonly short ENOSYS = 38; /* Function not implemented */ public static readonly short ENOTCONN = 107;
public static readonly short ENOTEMPTY = 39; /* Directory not empty */ public static readonly short ETIMEDOUT = 110;
public static readonly short ELOOP = 40; /* Too many symbolic links encountered */ public static readonly short EHOSTUNREACH = 113;
public static readonly short EWOULDBLOCK = EAGAIN; /* Operation would block */ public static readonly short EALREADY = 114;
public static readonly short ENOMSG = 42; /* No message of desired type */ public static readonly short EINPROGRESS = 115;
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 */
// Common constants
public static readonly short MAC_ADDRSTRLEN = 18;
public static readonly short INET_ADDRSTRLEN = 16; public static readonly short INET_ADDRSTRLEN = 16;
public static readonly short INET6_ADDRSTRLEN = 46; 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 */ // Peer roles
//public static readonly uint IPADDR_NONE =((uint32_t)0xffffffffUL); public static readonly byte PEER_ROLE_LEAF = 0;
/** 127.0.0.1 */ public static readonly byte PEER_ROLE_MOON = 1;
//public static readonly uint IPADDR_LOOPBACK =((uint32_t)0x7f000001UL); public static readonly byte PEER_ROLE_PLANET = 2;
/** 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);
/** 255.255.255.255 */ // Network status codes
//public static readonly uint INADDR_NONE =IPADDR_NONE; public static readonly byte NETWORK_STATUS_REQUESTING_CONFIGURATION = 0;
/** 127.0.0.1 */ public static readonly byte NETWORK_STATUS_OK = 1;
//public static readonly uint INADDR_LOOPBACK =IPADDR_LOOPBACK; public static readonly byte NETWORK_STATUS_ACCESS_DENIED = 2;
/** 0.0.0.0 */ public static readonly byte NETWORK_STATUS_NOT_FOUND = 3;
//public static readonly uint INADDR_ANY =IPADDR_ANY; public static readonly byte NETWORK_STATUS_PORT_ERROR = 4;
/** 255.255.255.255 */ public static readonly byte NETWORK_STATUS_CLIENT_TOO_OLD = 5;
//public static readonly uint INADDR_BROADCAST =IPADDR_BROADCAST;
//
public static readonly byte NETWORK_TYPE_PRIVATE = 0;
public static readonly byte NETWORK_TYPE_PUBLIC = 1;
// Socket protocol types // Socket protocol types
public static readonly short SOCK_STREAM = 0x0001; 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_DONTWAIT = 0x0008;
public static readonly short MSG_MORE = 0x0010; 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 // Socket level option number
public static readonly short SOL_SOCKET = 0x0fff; public static readonly short SOL_SOCKET = 0x0fff;
// Socket options // Socket options
@@ -301,8 +204,10 @@ namespace ZeroTier
public static readonly short TCP_KEEPINTVL = 0x0004; public static readonly short TCP_KEEPINTVL = 0x0004;
public static readonly short TCP_KEEPCNT = 0x0005; public static readonly short TCP_KEEPCNT = 0x0005;
// IPPROTO_IPV6 options // 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_CHECKSUM =
public static readonly short IPV6_V6ONLY = 0x001b; // RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. 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 // UDPLITE options
public static readonly short UDPLITE_SEND_CSCOV = 0x01; // sender checksum coverage public static readonly short UDPLITE_SEND_CSCOV = 0x01; // sender checksum coverage
public static readonly short UDPLITE_RECV_CSCOV = 0x02; // minimal receiver checksum coverage public static readonly short UDPLITE_RECV_CSCOV = 0x02; // minimal receiver checksum coverage
@@ -341,7 +246,7 @@ namespace ZeroTier
public static readonly short O_NDELAY = O_NONBLOCK; public static readonly short O_NDELAY = O_NONBLOCK;
public static readonly short O_RDONLY = 2; public static readonly short O_RDONLY = 2;
public static readonly short O_WRONLY = 4; public static readonly short O_WRONLY = 4;
public static readonly short O_RDWR = (short)(O_RDONLY|O_WRONLY); public static readonly short O_RDWR = (short)(O_RDONLY | O_WRONLY);
public static readonly short MSG_TRUNC = 0x04; public static readonly short MSG_TRUNC = 0x04;
public static readonly short MSG_CTRUNC = 0x08; public static readonly short MSG_CTRUNC = 0x08;
@@ -349,5 +254,5 @@ namespace ZeroTier
public static readonly short SHUT_RD = 0x0; public static readonly short SHUT_RD = 0x0;
public static readonly short SHUT_WR = 0x1; public static readonly short SHUT_WR = 0x1;
public static readonly short SHUT_RDWR = 0x2; public static readonly short SHUT_RDWR = 0x2;
} }
} }

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 * Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory. * 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 * 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. * of this software will be governed by version 2.0 of the Apache License.
@@ -17,140 +17,13 @@ using ZeroTier;
namespace ZeroTier.Core namespace ZeroTier.Core
{ {
/* Convenience structures for exposing lower level operational details to the user. public class Event {
These structures do not have the same memory layout or content as those found in public NodeInfo NodeInfo { get; set; }
include/ZeroTierSockets.h */ public NetworkInfo NetworkInfo { get; set; }
public RouteInfo RouteInfo { get; set; }
/// <summary> public PeerInfo PeerInfo { get; set; }
/// Structure containing information about the local Node. public AddressInfo AddressInfo { get; set; }
/// </summary> public int Code { get; set; }
public class NodeDetails public string Name { get; set; }
{
// 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;
}
}
} }
} }

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;
}
}
}
}

1088
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;
}
}
}
}

478
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 * Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory. * 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 * 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. * of this software will be governed by version 2.0 of the Apache License.
*/ */
/****/ /****/
using System; // For ObjectDisposedException using System;
using System.Net; // For IPEndPoint using System.Net;
using System.Net.Sockets; // For ZeroTier.Sockets.SocketException using System.Net.Sockets;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using ZeroTier; using ZeroTier;
/// <summary>
/// ZeroTier SDK
/// </summary>
namespace ZeroTier.Sockets namespace ZeroTier.Sockets
{ {
/// <summary> public class Socket {
/// ZeroTier Socket - An lwIP socket mediated over a ZeroTier virtual link
/// </summary>
public class Socket
{
/// <summary>No error.</summary> /// <summary>No error.</summary>
public static readonly int ZTS_ERR_OK = 0; public static readonly int ZTS_ERR_OK = 0;
/// <summary>Socket error, see Socket.ErrNo() for additional context.</summary> /// <summary>Socket error, see Socket.ErrNo() for additional context.</summary>
@@ -44,7 +37,6 @@ namespace ZeroTier.Sockets
int _fd; int _fd;
bool _isClosed; bool _isClosed;
bool _isListening; bool _isListening;
bool _isBlocking;
bool _isBound; bool _isBound;
bool _isConnected; bool _isConnected;
@@ -61,7 +53,6 @@ namespace ZeroTier.Sockets
{ {
_isClosed = false; _isClosed = false;
_isListening = false; _isListening = false;
_isBlocking = false;
} }
public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
@@ -70,8 +61,7 @@ namespace ZeroTier.Sockets
int type = -1; int type = -1;
int protocol = -1; int protocol = -1;
// Map .NET socket parameters to ZeroTier equivalents // Map .NET socket parameters to ZeroTier equivalents
switch (addressFamily) switch (addressFamily) {
{
case AddressFamily.InterNetwork: case AddressFamily.InterNetwork:
family = Constants.AF_INET; family = Constants.AF_INET;
break; break;
@@ -82,8 +72,7 @@ namespace ZeroTier.Sockets
family = Constants.AF_UNSPEC; family = Constants.AF_UNSPEC;
break; break;
} }
switch (socketType) switch (socketType) {
{
case SocketType.Stream: case SocketType.Stream:
type = Constants.SOCK_STREAM; type = Constants.SOCK_STREAM;
break; break;
@@ -91,8 +80,7 @@ namespace ZeroTier.Sockets
type = Constants.SOCK_DGRAM; type = Constants.SOCK_DGRAM;
break; break;
} }
switch (protocolType) switch (protocolType) {
{
case ProtocolType.Udp: case ProtocolType.Udp:
protocol = Constants.IPPROTO_UDP; protocol = Constants.IPPROTO_UDP;
break; break;
@@ -103,8 +91,7 @@ namespace ZeroTier.Sockets
protocol = 0; // ? protocol = 0; // ?
break; break;
} }
if ((_fd = zts_socket(family, type, protocol)) < 0) if ((_fd = zts_socket(family, type, protocol)) < 0) {
{
throw new ZeroTier.Sockets.SocketException((int)_fd); throw new ZeroTier.Sockets.SocketException((int)_fd);
} }
_socketFamily = addressFamily; _socketFamily = addressFamily;
@@ -113,7 +100,8 @@ namespace ZeroTier.Sockets
InitializeInternalFlags(); InitializeInternalFlags();
} }
private Socket(int fileDescriptor, private Socket(
int fileDescriptor,
AddressFamily addressFamily, AddressFamily addressFamily,
SocketType socketType, SocketType socketType,
ProtocolType protocolType, ProtocolType protocolType,
@@ -141,24 +129,11 @@ namespace ZeroTier.Sockets
if (remoteEndPoint == null) { if (remoteEndPoint == null) {
throw new ArgumentNullException("remoteEndPoint"); throw new ArgumentNullException("remoteEndPoint");
} }
int err = Constants.ERR_OK; int err = zts_simple_connect(
if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork) {
err = zts_connect_easy(
_fd, _fd,
Constants.AF_INET,
remoteEndPoint.Address.ToString(), remoteEndPoint.Address.ToString(),
(ushort)remoteEndPoint.Port, (ushort)remoteEndPoint.Port,
_connectTimeout); _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) { if (err < 0) {
throw new ZeroTier.Sockets.SocketException(err, ZeroTier.Core.Node.ErrNo); throw new ZeroTier.Sockets.SocketException(err, ZeroTier.Core.Node.ErrNo);
} }
@@ -180,19 +155,11 @@ namespace ZeroTier.Sockets
} }
int err = Constants.ERR_OK; int err = Constants.ERR_OK;
if (localEndPoint.AddressFamily == AddressFamily.InterNetwork) { if (localEndPoint.AddressFamily == AddressFamily.InterNetwork) {
err = zts_bind_easy( err = zts_simple_bind(_fd, "0.0.0.0", (ushort)localEndPoint.Port);
_fd,
Constants.AF_INET,
"0.0.0.0",
(ushort)localEndPoint.Port);
} }
if (localEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { if (localEndPoint.AddressFamily == AddressFamily.InterNetworkV6) {
// Todo: detect IPAddress.IPv6Any // Todo: detect IPAddress.IPv6Any
err = zts_bind_easy( err = zts_simple_bind(_fd, "::", (ushort)localEndPoint.Port);
_fd,
Constants.AF_INET6,
"::",
(ushort)localEndPoint.Port);
} }
if (err < 0) { if (err < 0) {
throw new ZeroTier.Sockets.SocketException((int)err); throw new ZeroTier.Sockets.SocketException((int)err);
@@ -228,13 +195,11 @@ namespace ZeroTier.Sockets
throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET); throw new ZeroTier.Sockets.SocketException((int)Constants.ERR_SOCKET);
} }
if (_isListening == false) { if (_isListening == false) {
throw new InvalidOperationException( throw new InvalidOperationException("Socket is not in a listening state. Call Listen() first");
"Socket is not in a listening state. Call Listen() first");
} }
IntPtr lpBuffer = Marshal.AllocHGlobal(ZeroTier.Constants.INET6_ADDRSTRLEN); IntPtr lpBuffer = Marshal.AllocHGlobal(ZeroTier.Constants.INET6_ADDRSTRLEN);
int port = 0; int port = 0;
int accepted_fd = zts_accept_easy( int accepted_fd = zts_simple_accept(_fd, lpBuffer, ZeroTier.Constants.INET6_ADDRSTRLEN, ref port);
_fd, lpBuffer, ZeroTier.Constants.INET6_ADDRSTRLEN, ref port);
// Convert buffer to managed string // Convert buffer to managed string
string str = Marshal.PtrToStringAnsi(lpBuffer); string str = Marshal.PtrToStringAnsi(lpBuffer);
Marshal.FreeHGlobal(lpBuffer); Marshal.FreeHGlobal(lpBuffer);
@@ -242,8 +207,8 @@ namespace ZeroTier.Sockets
IPEndPoint clientEndPoint = new IPEndPoint(IPAddress.Parse(str), port); IPEndPoint clientEndPoint = new IPEndPoint(IPAddress.Parse(str), port);
Console.WriteLine("clientEndPoint = " + clientEndPoint.ToString()); Console.WriteLine("clientEndPoint = " + clientEndPoint.ToString());
// Create new socket by providing file descriptor returned from zts_accept call. // Create new socket by providing file descriptor returned from zts_accept call.
Socket clientSocket = new Socket( Socket clientSocket =
accepted_fd, _socketFamily, _socketType, _socketProtocol, _localEndPoint, clientEndPoint); new Socket(accepted_fd, _socketFamily, _socketType, _socketProtocol, _localEndPoint, clientEndPoint);
return clientSocket; return clientSocket;
} }
@@ -253,8 +218,7 @@ namespace ZeroTier.Sockets
throw new ObjectDisposedException("Socket has been closed"); throw new ObjectDisposedException("Socket has been closed");
} }
int ztHow = 0; int ztHow = 0;
switch (how) switch (how) {
{
case SocketShutdown.Receive: case SocketShutdown.Receive:
ztHow = Constants.O_RDONLY; ztHow = Constants.O_RDONLY;
break; break;
@@ -279,8 +243,12 @@ namespace ZeroTier.Sockets
public bool Blocking public bool Blocking
{ {
get { return Convert.ToBoolean(zts_get_blocking(_fd)); } get {
set { zts_set_blocking(_fd, Convert.ToInt32(value)); } 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) 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); poll_set.events = (short)((byte)ZeroTier.Constants.POLLOUT);
} }
if (mode == SelectMode.SelectError) { if (mode == SelectMode.SelectError) {
poll_set.events = (short)((byte)ZeroTier.Constants.POLLERR | poll_set.events = (short)((byte)ZeroTier.Constants.POLLERR | (byte)ZeroTier.Constants.POLLNVAL);
(byte)ZeroTier.Constants.POLLNVAL);
} }
IntPtr poll_fd_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(zts_pollfd))); IntPtr poll_fd_ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(zts_pollfd)));
Marshal.StructureToPtr(poll_set, poll_fd_ptr, false); 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)); poll_set = (zts_pollfd)Marshal.PtrToStructure(poll_fd_ptr, typeof(zts_pollfd));
if (result != 0) { if (result != 0) {
if (mode == SelectMode.SelectRead) { if (mode == SelectMode.SelectRead) {
result = Convert.ToInt32(((byte)poll_set.revents result = Convert.ToInt32(((byte)poll_set.revents & (byte)ZeroTier.Constants.POLLIN) != 0);
& (byte)ZeroTier.Constants.POLLIN) != 0);
} }
if (mode == SelectMode.SelectWrite) { if (mode == SelectMode.SelectWrite) {
result = Convert.ToInt32(((byte)poll_set.revents result = Convert.ToInt32(((byte)poll_set.revents & (byte)ZeroTier.Constants.POLLOUT) != 0);
& (byte)ZeroTier.Constants.POLLOUT) != 0);
} }
if (mode == SelectMode.SelectError) { if (mode == SelectMode.SelectError) {
result = Convert.ToInt32(((poll_set.revents result = Convert.ToInt32(
& (byte)ZeroTier.Constants.POLLERR) != 0) || ((poll_set.revents & (byte)ZeroTier.Constants.POLLERR) != 0)
((poll_set.revents & (byte)ZeroTier.Constants.POLLNVAL) != 0)); || ((poll_set.revents & (byte)ZeroTier.Constants.POLLNVAL) != 0));
} }
} }
Marshal.FreeHGlobal(poll_fd_ptr); Marshal.FreeHGlobal(poll_fd_ptr);
@@ -362,47 +327,71 @@ namespace ZeroTier.Sockets
public int ReceiveTimeout public int ReceiveTimeout
{ {
get { return zts_get_recv_timeout(_fd); } get {
return zts_get_recv_timeout(_fd);
}
// TODO: microseconds // TODO: microseconds
set { zts_set_recv_timeout(_fd, value, 0); } set {
zts_set_recv_timeout(_fd, value, 0);
}
} }
public int SendTimeout public int SendTimeout
{ {
get { return zts_get_send_timeout(_fd); } get {
return zts_get_send_timeout(_fd);
}
// TODO: microseconds // TODO: microseconds
set { zts_set_send_timeout(_fd, value, 0); } set {
zts_set_send_timeout(_fd, value, 0);
}
} }
public int ConnectTimeout public int ConnectTimeout
{ {
get { return _connectTimeout; } get {
set { _connectTimeout = value;} return _connectTimeout;
}
set {
_connectTimeout = value;
}
} }
public int ReceiveBufferSize public int ReceiveBufferSize
{ {
get { return zts_get_recv_buf_size(_fd); } get {
set { zts_set_recv_buf_size(_fd, value); } return zts_get_recv_buf_size(_fd);
}
set {
zts_set_recv_buf_size(_fd, value);
}
} }
public int SendBufferSize public int SendBufferSize
{ {
get { return zts_get_send_buf_size(_fd); } get {
set { zts_set_send_buf_size(_fd, value); } return zts_get_send_buf_size(_fd);
}
set {
zts_set_send_buf_size(_fd, value);
}
} }
public short Ttl public short Ttl
{ {
get { return Convert.ToInt16(zts_get_ttl(_fd)); } get {
set { zts_set_ttl(_fd, value); } return Convert.ToInt16(zts_get_ttl(_fd));
}
set {
zts_set_ttl(_fd, value);
}
} }
public LingerOption LingerState public LingerOption LingerState
{ {
get { get {
LingerOption lo = new LingerOption( LingerOption lo =
Convert.ToBoolean(zts_get_linger_enabled(_fd)), zts_get_linger_value(_fd)); new LingerOption(Convert.ToBoolean(zts_get_linger_enabled(_fd)), zts_get_linger_value(_fd));
return lo; return lo;
} }
set { set {
@@ -412,214 +401,379 @@ namespace ZeroTier.Sockets
public bool NoDelay public bool NoDelay
{ {
get { return Convert.ToBoolean(zts_get_no_delay(_fd)); } get {
set { zts_set_no_delay(_fd, Convert.ToInt32(value)); } return Convert.ToBoolean(zts_get_no_delay(_fd));
}
set {
zts_set_no_delay(_fd, Convert.ToInt32(value));
}
} }
public bool KeepAlive public bool KeepAlive
{ {
get { return Convert.ToBoolean(zts_get_keepalive(_fd)); } get {
set { zts_set_keepalive(_fd, Convert.ToInt32(value)); } 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 */ /* .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 */ /* .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 /* Structures and functions used internally to communicate with
lower-level C API defined in include/ZeroTierSockets.h */ lower-level C API defined in include/ZeroTierSockets.h */
[DllImport("libzt", EntryPoint="CSharp_zts_get_all_stats")] [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); static extern int zts_get_all_stats(IntPtr arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_get_protocol_stats")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_protocol_stats")]
static extern int zts_get_protocol_stats(int arg1, IntPtr arg2); static extern int zts_get_protocol_stats(int arg1, IntPtr arg2);
[DllImport("libzt", EntryPoint="CSharp_zts_socket")] [DllImport("libzt", EntryPoint = "CSharp_zts_socket")]
static extern int zts_socket(int arg1, int arg2, int arg3); static extern int zts_socket(int arg1, int arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_connect")] [DllImport("libzt", EntryPoint = "CSharp_zts_connect")]
static extern int zts_connect(int arg1, IntPtr arg2, ushort arg3); static extern int zts_connect(int arg1, IntPtr arg2, ushort arg3);
[DllImport("libzt", CharSet=CharSet.Ansi, EntryPoint="CSharp_zts_connect_easy")] [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_connect_easy")]
static extern int zts_connect_easy(int arg1, int arg2, string arg3, ushort arg4, int arg5); static extern int zts_connect_easy(int arg1, int arg2, string arg3, ushort arg4, int arg5);
[DllImport("libzt", EntryPoint="CSharp_zts_bind")] [DllImport("libzt", EntryPoint = "CSharp_zts_bind")]
static extern int zts_bind(int arg1, IntPtr arg2, ushort arg3); static extern int zts_bind(int arg1, IntPtr arg2, ushort arg3);
[DllImport("libzt", CharSet=CharSet.Ansi, EntryPoint="CSharp_zts_bind_easy")] [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_bind_easy")]
static extern int zts_bind_easy(int arg1, int arg2, string arg3, ushort arg4); static extern int zts_bind_easy(int arg1, int arg2, string arg3, ushort arg4);
[DllImport("libzt", EntryPoint="CSharp_zts_listen")] [DllImport("libzt", EntryPoint = "CSharp_zts_listen")]
static extern int zts_listen(int arg1, int arg2); static extern int zts_listen(int arg1, int arg2);
[DllImport("libzt", EntryPoint="CSharp_zts_accept")] [DllImport("libzt", EntryPoint = "CSharp_zts_accept")]
static extern int zts_accept(int arg1, IntPtr arg2, IntPtr arg3); static extern int zts_accept(int arg1, IntPtr arg2, IntPtr arg3);
[DllImport("libzt", CharSet=CharSet.Ansi, EntryPoint="CSharp_zts_accept_easy")] [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_accept_easy")]
static extern int zts_accept_easy(int arg1, IntPtr remoteAddrStr, int arg2, ref int arg3); static extern int zts_accept_easy(int arg1, IntPtr remoteAddrStr, int arg2, ref int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_setsockopt")] [DllImport("libzt", EntryPoint = "CSharp_zts_setsockopt")]
static extern int zts_setsockopt(int arg1, int arg2, int arg3, IntPtr arg4, ushort arg5); static extern int zts_setsockopt(int arg1, int arg2, int arg3, IntPtr arg4, ushort arg5);
[DllImport("libzt", EntryPoint="CSharp_zts_getsockopt")] [DllImport("libzt", EntryPoint = "CSharp_zts_getsockopt")]
static extern int zts_getsockopt(int arg1, int arg2, int arg3, IntPtr arg4, IntPtr arg5); static extern int zts_getsockopt(int arg1, int arg2, int arg3, IntPtr arg4, IntPtr arg5);
[DllImport("libzt", EntryPoint="CSharp_zts_getsockname")] [DllImport("libzt", EntryPoint = "CSharp_zts_getsockname")]
static extern int zts_getsockname(int arg1, IntPtr arg2, IntPtr arg3); static extern int zts_getsockname(int arg1, IntPtr arg2, IntPtr arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_getpeername")] [DllImport("libzt", EntryPoint = "CSharp_zts_getpeername")]
static extern int zts_getpeername(int arg1, IntPtr arg2, IntPtr arg3); static extern int zts_getpeername(int arg1, IntPtr arg2, IntPtr arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_close")] [DllImport("libzt", EntryPoint = "CSharp_zts_close")]
static extern int zts_close(int arg1); static extern int zts_close(int arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_fcntl")] [DllImport("libzt", EntryPoint = "CSharp_zts_fcntl")]
static extern int zts_fcntl(int arg1, int arg2, int arg3); static extern int zts_fcntl(int arg1, int arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_poll")] [DllImport("libzt", EntryPoint = "CSharp_zts_poll")]
static extern int zts_poll(IntPtr arg1, uint arg2, int arg3); static extern int zts_poll(IntPtr arg1, uint arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_ioctl")] [DllImport("libzt", EntryPoint = "CSharp_zts_ioctl")]
static extern int zts_ioctl(int arg1, uint arg2, IntPtr arg3); static extern int zts_ioctl(int arg1, uint arg2, IntPtr arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_send")] [DllImport("libzt", EntryPoint = "CSharp_zts_send")]
static extern int zts_send(int arg1, IntPtr arg2, uint arg3, int arg4); static extern int zts_send(int arg1, IntPtr arg2, uint arg3, int arg4);
[DllImport("libzt", EntryPoint="CSharp_zts_sendto")] [DllImport("libzt", EntryPoint = "CSharp_zts_sendto")]
static extern int zts_sendto(int arg1, IntPtr arg2, uint arg3, int arg4, IntPtr arg5, ushort arg6); static extern int zts_sendto(int arg1, IntPtr arg2, uint arg3, int arg4, IntPtr arg5, ushort arg6);
[DllImport("libzt", EntryPoint="CSharp_zts_sendmsg")] [DllImport("libzt", EntryPoint = "CSharp_zts_sendmsg")]
static extern int zts_sendmsg(int arg1, IntPtr arg2, int arg3); static extern int zts_sendmsg(int arg1, IntPtr arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_recv")] [DllImport("libzt", EntryPoint = "CSharp_zts_recv")]
static extern int zts_recv(int arg1, IntPtr arg2, uint arg3, int arg4); static extern int zts_recv(int arg1, IntPtr arg2, uint arg3, int arg4);
[DllImport("libzt", EntryPoint="CSharp_zts_recvfrom")] [DllImport("libzt", EntryPoint = "CSharp_zts_recvfrom")]
static extern int zts_recvfrom(int arg1, IntPtr arg2, uint arg3, int arg4, IntPtr arg5, IntPtr arg6); static extern int zts_recvfrom(int arg1, IntPtr arg2, uint arg3, int arg4, IntPtr arg5, IntPtr arg6);
[DllImport("libzt", EntryPoint="CSharp_zts_recvmsg")] [DllImport("libzt", EntryPoint = "CSharp_zts_recvmsg")]
static extern int zts_recvmsg(int arg1, IntPtr arg2, int arg3); static extern int zts_recvmsg(int arg1, IntPtr arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_read")] [DllImport("libzt", EntryPoint = "CSharp_zts_read")]
static extern int zts_read(int arg1, IntPtr arg2, uint arg3); static extern int zts_read(int arg1, IntPtr arg2, uint arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_readv")] [DllImport("libzt", EntryPoint = "CSharp_zts_readv")]
static extern int zts_readv(int arg1, IntPtr arg2, int arg3); static extern int zts_readv(int arg1, IntPtr arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_write")] [DllImport("libzt", EntryPoint = "CSharp_zts_write")]
static extern int zts_write(int arg1, IntPtr arg2, uint arg3); static extern int zts_write(int arg1, IntPtr arg2, uint arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_writev")] [DllImport("libzt", EntryPoint = "CSharp_zts_writev")]
static extern int zts_writev(int arg1, IntPtr arg2, int arg3); static extern int zts_writev(int arg1, IntPtr arg2, int arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_shutdown")] [DllImport("libzt", EntryPoint = "CSharp_zts_shutdown")]
static extern int zts_shutdown(int arg1, int arg2); static extern int zts_shutdown(int arg1, int arg2);
[DllImport("libzt", EntryPoint="CSharp_zts_set_no_delay")] [DllImport("libzt", EntryPoint = "CSharp_zts_set_no_delay")]
static extern int zts_set_no_delay(int fd, int enabled); static extern int zts_set_no_delay(int fd, int enabled);
[DllImport("libzt", EntryPoint="CSharp_zts_get_no_delay")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_no_delay")]
static extern int zts_get_no_delay(int fd); static extern int zts_get_no_delay(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_linger")] [DllImport("libzt", EntryPoint = "CSharp_zts_set_linger")]
static extern int zts_set_linger(int fd, int enabled, int value); static extern int zts_set_linger(int fd, int enabled, int value);
[DllImport("libzt", EntryPoint="CSharp_zts_get_linger_enabled")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_linger_enabled")]
static extern int zts_get_linger_enabled(int fd); static extern int zts_get_linger_enabled(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_get_linger_value")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_linger_value")]
static extern int zts_get_linger_value(int fd); static extern int zts_get_linger_value(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_reuse_addr")] [DllImport("libzt", EntryPoint = "CSharp_zts_set_reuse_addr")]
static extern int zts_set_reuse_addr(int fd, int enabled); static extern int zts_set_reuse_addr(int fd, int enabled);
[DllImport("libzt", EntryPoint="CSharp_zts_get_reuse_addr")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_reuse_addr")]
static extern int zts_get_reuse_addr(int fd); static extern int zts_get_reuse_addr(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_recv_timeout")] [DllImport("libzt", EntryPoint = "CSharp_zts_set_recv_timeout")]
static extern int zts_set_recv_timeout(int fd, int seconds, int microseconds); static extern int zts_set_recv_timeout(int fd, int seconds, int microseconds);
[DllImport("libzt", EntryPoint="CSharp_zts_get_recv_timeout")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_recv_timeout")]
static extern int zts_get_recv_timeout(int fd); static extern int zts_get_recv_timeout(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_send_timeout")] [DllImport("libzt", EntryPoint = "CSharp_zts_set_send_timeout")]
static extern int zts_set_send_timeout(int fd, int seconds, int microseconds); static extern int zts_set_send_timeout(int fd, int seconds, int microseconds);
[DllImport("libzt", EntryPoint="CSharp_zts_get_send_timeout")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_send_timeout")]
static extern int zts_get_send_timeout(int fd); static extern int zts_get_send_timeout(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_send_buf_size")] [DllImport("libzt", EntryPoint = "CSharp_zts_set_send_buf_size")]
static extern int zts_set_send_buf_size(int fd, int size); static extern int zts_set_send_buf_size(int fd, int size);
[DllImport("libzt", EntryPoint="CSharp_zts_get_send_buf_size")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_send_buf_size")]
static extern int zts_get_send_buf_size(int fd); static extern int zts_get_send_buf_size(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_recv_buf_size")] [DllImport("libzt", EntryPoint = "CSharp_zts_set_recv_buf_size")]
static extern int zts_set_recv_buf_size(int fd, int size); static extern int zts_set_recv_buf_size(int fd, int size);
[DllImport("libzt", EntryPoint="CSharp_zts_get_recv_buf_size")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_recv_buf_size")]
static extern int zts_get_recv_buf_size(int fd); static extern int zts_get_recv_buf_size(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_ttl")] [DllImport("libzt", EntryPoint = "CSharp_zts_set_ttl")]
static extern int zts_set_ttl(int fd, int ttl); static extern int zts_set_ttl(int fd, int ttl);
[DllImport("libzt", EntryPoint="CSharp_zts_get_ttl")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_ttl")]
static extern int zts_get_ttl(int fd); static extern int zts_get_ttl(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_blocking")] [DllImport("libzt", EntryPoint = "CSharp_zts_set_blocking")]
static extern int zts_set_blocking(int fd, int enabled); static extern int zts_set_blocking(int fd, int enabled);
[DllImport("libzt", EntryPoint="CSharp_zts_get_blocking")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_blocking")]
static extern int zts_get_blocking(int fd); static extern int zts_get_blocking(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_set_keepalive")] [DllImport("libzt", EntryPoint = "CSharp_zts_set_keepalive")]
static extern int zts_set_keepalive(int fd, int enabled); static extern int zts_set_keepalive(int fd, int enabled);
[DllImport("libzt", EntryPoint="CSharp_zts_get_keepalive")] [DllImport("libzt", EntryPoint = "CSharp_zts_get_keepalive")]
static extern int zts_get_keepalive(int fd); static extern int zts_get_keepalive(int fd);
[DllImport("libzt", EntryPoint="CSharp_zts_add_dns_nameserver")] [DllImport("libzt", EntryPoint = "CSharp_zts_add_dns_nameserver")]
static extern int zts_add_dns_nameserver(IntPtr arg1); static extern int zts_add_dns_nameserver(IntPtr arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_del_dns_nameserver")] [DllImport("libzt", EntryPoint = "CSharp_zts_del_dns_nameserver")]
static extern int zts_del_dns_nameserver(IntPtr arg1); static extern int zts_del_dns_nameserver(IntPtr arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_inet_ntop")] [DllImport("libzt", EntryPoint = "CSharp_zts_errno_get")]
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(); 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> /// <value>The value of errno for the low-level socket layer</value>
public static int ErrNo { public static int ErrNo
{
get { get {
return zts_errno_get(); return zts_errno_get();
} }
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)] struct zts_sockaddr {
struct zts_sockaddr
{
public byte sa_len; public byte sa_len;
public byte sa_family; public byte sa_family;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
@@ -627,14 +781,12 @@ namespace ZeroTier.Sockets
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
struct zts_in_addr struct zts_in_addr {
{
public uint s_addr; public uint s_addr;
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
struct zts_sockaddr_in struct zts_sockaddr_in {
{
public byte sin_len; public byte sin_len;
public byte sin_family; public byte sin_family;
public short sin_port; public short sin_port;
@@ -645,16 +797,14 @@ namespace ZeroTier.Sockets
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
struct zts_pollfd struct zts_pollfd {
{
public int fd; public int fd;
public short events; public short events;
public short revents; public short revents;
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
struct zts_timeval struct zts_timeval {
{
public long tv_sec; public long tv_sec;
public long tv_usec; 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 * Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory. * 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 * 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. * of this software will be governed by version 2.0 of the Apache License.
@@ -16,15 +16,17 @@ using System;
namespace ZeroTier.Sockets namespace ZeroTier.Sockets
{ {
/// <summary>Exception class for ZeroTier service and low-level socket errors</summary> /// <summary>Exception class for ZeroTier service and low-level socket errors</summary>
public class SocketException : Exception public class SocketException : Exception {
{
public SocketException(int _serviceErrorCode) public SocketException(int _serviceErrorCode)
: base(String.Format("ServiceErrorCode={0} (See Constants.cs for error code meanings)", _serviceErrorCode)) : base(String.Format("ServiceErrorCode={0} (See Constants.cs for error code meanings)", _serviceErrorCode))
{ {
ServiceErrorCode = _serviceErrorCode; ServiceErrorCode = _serviceErrorCode;
} }
public SocketException(int _serviceErrorCode, int _socketErrorCode) 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; ServiceErrorCode = _serviceErrorCode;
SocketErrorCode = _socketErrorCode; 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_storage;
%ignore zts_sockaddr_in6; %ignore zts_sockaddr_in6;
%ignore zts_callback_msg; %ignore zts_event_msg_t;
%ignore zts_node_details; %ignore zts_node_info_t;
%ignore zts_network_details; %ignore zts_net_info_t;
%ignore zts_netif_details; %ignore zts_netif_info_t;
%ignore zts_virtual_network_route; %ignore zts_route_info_t;
%ignore zts_peer_details; %ignore zts_peer_info_t;
%ignore zts_addr_details; %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 // Typemap for our event callback
@@ -52,4 +52,4 @@
%enddef %enddef
%cs_callback(CppCallback, CSharpCallbackWithStruct) %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;
}
}