This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
zhangyang-libzt/examples/csharp/Node.cs
2021-01-04 21:03:57 -08:00

493 lines
15 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c)2013-2020 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: 2024-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.Runtime.InteropServices;
using System;
// Prototype of callback used by ZeroTier to signal events to C# application
public delegate void CSharpCallbackWithStruct(IntPtr msgPtr);
/// <summary>
/// ZeroTier SDK
/// </summary>
namespace ZeroTier
{
public delegate void ZeroTierManagedEventCallback(ZeroTier.Event nodeEvent);
/// <summary>
/// ZeroTier Node - Virtual network subsystem
/// </summary>
public class Node
{
static ulong _nodeId = 0x0;
static bool _isOnline = false;
static bool _joinedAtLeastOneNetwork = false;
static bool _hasBeenFreed = false;
string _configFilePath;
ushort _servicePort;
static ZeroTierManagedEventCallback _managedCallback;
// Callback used internally to ferry events from the C++ layer
static void myZeroTierEventCallback(IntPtr msgPtr)
{
// Marshal the callback message pointer to a structure that we can inspect
zts_callback_msg msg =
(zts_callback_msg)Marshal.PtrToStructure(msgPtr, typeof(zts_callback_msg));
ZeroTier.Event newEvent = null;
// Node events
if (msg.eventCode == Constants.EVENT_NODE_UP) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_UP");
}
if (msg.eventCode == Constants.EVENT_NODE_ONLINE) {
_isOnline = true;
// Marshal the node details pointer to a structure
zts_node_details details =
(zts_node_details)Marshal.PtrToStructure(msg.node, typeof(zts_node_details));
_nodeId = details.address;
newEvent = new ZeroTier.Event(msg.eventCode, "EVENT_NODE_ONLINE");
}
if (msg.eventCode == Constants.EVENT_NODE_OFFLINE) {
_isOnline = false;
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_OFFLINE");
}
if (msg.eventCode == Constants.EVENT_NODE_NORMAL_TERMINATION) {
_isOnline = false;
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_NORMAL_TERMINATION");
}
if (msg.eventCode == Constants.EVENT_NODE_DOWN) {
_isOnline = false;
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_DOWN");
}
if (msg.eventCode == Constants.EVENT_NODE_IDENTITY_COLLISION) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_IDENTITY_COLLISION");
_isOnline = false;
}
if (msg.eventCode == Constants.EVENT_NODE_UNRECOVERABLE_ERROR) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NODE_UNRECOVERABLE_ERROR");
_isOnline = false;
}
// Network events
if (msg.eventCode == Constants.EVENT_NETWORK_NOT_FOUND) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_NOT_FOUND");
}
if (msg.eventCode == Constants.EVENT_NETWORK_REQ_CONFIG) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_REQ_CONFIG");
}
if (msg.eventCode == Constants.EVENT_NETWORK_ACCESS_DENIED) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_ACCESS_DENIED");
}
if (msg.eventCode == Constants.EVENT_NETWORK_READY_IP4) {
_joinedAtLeastOneNetwork = true;
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_READY_IP4");
}
if (msg.eventCode == Constants.EVENT_NETWORK_READY_IP6) {
_joinedAtLeastOneNetwork = true;
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_READY_IP6");
}
if (msg.eventCode == Constants.EVENT_NETWORK_DOWN) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_DOWN");
}
if (msg.eventCode == Constants.EVENT_NETWORK_CLIENT_TOO_OLD) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_CLIENT_TOO_OLD");
}
if (msg.eventCode == Constants.EVENT_NETWORK_REQ_CONFIG) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_REQ_CONFIG");
}
if (msg.eventCode == Constants.EVENT_NETWORK_OK) {
zts_network_details unmanagedDetails =
(zts_network_details)Marshal.PtrToStructure(msg.network, typeof(zts_network_details));
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_OK");
newEvent.networkDetails = new NetworkDetails();
newEvent.networkDetails.networkId = unmanagedDetails.nwid;
}
if (msg.eventCode == Constants.EVENT_NETWORK_ACCESS_DENIED) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_ACCESS_DENIED");
}
if (msg.eventCode == Constants.EVENT_NETWORK_READY_IP4_IP6) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_READY_IP4_IP6");
}
if (msg.eventCode == Constants.EVENT_NETWORK_UPDATE) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETWORK_UPDATE");
}
// Stack events
if (msg.eventCode == Constants.EVENT_STACK_UP) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_STACK_UP");
}
if (msg.eventCode == Constants.EVENT_STACK_DOWN) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_STACK_DOWN");
}
// Address events
if (msg.eventCode == Constants.EVENT_ADDR_ADDED_IP4) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ADDR_ADDED_IP4");
}
if (msg.eventCode == Constants.EVENT_ADDR_ADDED_IP6) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ADDR_ADDED_IP6");
}
if (msg.eventCode == Constants.EVENT_ADDR_REMOVED_IP4) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ADDR_REMOVED_IP4");
}
if (msg.eventCode == Constants.EVENT_ADDR_REMOVED_IP6) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ADDR_REMOVED_IP6");
}
// peer events
if (msg.eventCode == Constants.EVENT_PEER_DIRECT) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_DIRECT");
}
if (msg.eventCode == Constants.EVENT_PEER_RELAY) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_RELAY");
}
// newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_UNREACHABLE");
if (msg.eventCode == Constants.EVENT_PEER_PATH_DISCOVERED) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_PATH_DISCOVERED");
}
if (msg.eventCode == Constants.EVENT_PEER_PATH_DEAD) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_PEER_PATH_DEAD");
}
// Route events
if (msg.eventCode == Constants.EVENT_ROUTE_ADDED) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ROUTE_ADDED");
}
if (msg.eventCode == Constants.EVENT_ROUTE_REMOVED) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ROUTE_REMOVED");
}
// Netif events
if (msg.eventCode == Constants.EVENT_NETIF_UP) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_UP");
}
if (msg.eventCode == Constants.EVENT_NETIF_DOWN) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_DOWN");
}
if (msg.eventCode == Constants.EVENT_NETIF_REMOVED) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_REMOVED");
}
if (msg.eventCode == Constants.EVENT_NETIF_LINK_UP) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_LINK_UP");
}
if (msg.eventCode == Constants.EVENT_NETIF_LINK_DOWN) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_NETIF_LINK_DOWN");
}
if (msg.eventCode == Constants.EVENT_ADDR_REMOVED_IP6) {
newEvent = new ZeroTier.Event(msg.eventCode,"EVENT_ADDR_REMOVED_IP6");
}
// Pass the converted Event to the managed callback (visible to user)
if (newEvent != null) {
_managedCallback(newEvent);
}
}
/// <summary>
/// Creates a new Node. Start this object by calling Start().
/// </summary>
/// <param name="configFilePath">Where keys and config files will be stored on the filesystem</param>
/// <param name="managedCallback">Where you would like to receive ZeroTier event notifications</param>
/// <param name="servicePort">The port ZeroTier will use to send its encrypted </param>
/// <returns></returns>
public Node(string configFilePath, ZeroTierManagedEventCallback managedCallback, UInt16 servicePort)
{
if (String.IsNullOrEmpty(configFilePath)) {
throw new ArgumentNullException(nameof(configFilePath));
}
if (managedCallback == null) {
throw new ArgumentNullException(nameof(managedCallback));
}
_nodeId = 0x0;
_configFilePath = configFilePath;
_servicePort = servicePort;
_managedCallback = new ZeroTierManagedEventCallback(managedCallback);
}
/// <summary>
/// Starts the ZeroTier node/service
/// </summary>
/// <returns></returns>
public int Start()
{
if (_hasBeenFreed == true) {
throw new ObjectDisposedException("ZeroTier Node has previously been freed. Restart application to create new instance.");
}
return zts_start(_configFilePath,myZeroTierEventCallback,_servicePort);
}
/// <summary>
/// Frees (most) resources used by ZeroTier. ZeroTier may not be started again after this call.
/// </summary>
/// <returns></returns>
public int Free()
{
_nodeId = 0x0;
_hasBeenFreed = true;
return zts_free();
}
/// <summary>
/// Stop all ZeroTier service activity. The service may be started again with Start().
/// </summary>
/// <returns></returns>
public int Stop()
{
_nodeId = 0x0;
return zts_stop();
}
/// <summary>
/// Restarts the ZeroTier service, internal stack and driver. (Mostly used for debugging.)
/// </summary>
/// <returns></returns>
public int Restart()
{
_nodeId = 0x0;
return zts_restart();
}
/// <summary>
/// Requests to join a ZeroTier network. Remember to authorize your node/device.
/// </summary>
/// <param name="nwid">Network ID</param>
/// <returns></returns>
public int Join(ulong nwid)
{
return zts_join(nwid);
}
/// <summary>
/// Leaves a ZeroTier network.
/// </summary>
/// <param name="nwid"></param>
/// <returns></returns>
public int Leave(ulong nwid)
{
return zts_leave(nwid);
}
/// <summary>
/// Returns whether the Node is online (able to reach the internet.)
/// </summary>
/// <returns></returns>
public bool IsOnline()
{
return _isOnline;
}
/// <summary>
/// Returns whether routing information is available from at least one ZeroTier network.
/// </summary>
/// <returns></returns>
public bool HasRoutes()
{
return _joinedAtLeastOneNetwork;
}
public ulong NodeId
{
get {
return _nodeId;
}
}
/* Structures and functions used internally to communicate with
lower-level C API defined in include/ZeroTierSockets.h */
[DllImport("libzt", EntryPoint="CSharp_zts_start")]
static extern int zts_start(string arg1, CSharpCallbackWithStruct arg2, ushort arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_stop")]
static extern int zts_stop();
[DllImport("libzt", EntryPoint="CSharp_zts_restart")]
static extern int zts_restart();
[DllImport("libzt", EntryPoint="CSharp_zts_free")]
static extern int zts_free();
[DllImport("libzt", EntryPoint="CSharp_zts_join")]
static extern int zts_join(ulong arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_leave")]
static extern int zts_leave(ulong arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_allow_network_caching")]
static extern int zts_allow_network_caching(byte arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_allow_peer_caching")]
static extern int zts_allow_peer_caching(byte arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_allow_local_conf")]
static extern int zts_allow_local_conf(byte arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_orbit")]
static extern int zts_orbit(ulong arg1, ulong arg2);
[DllImport("libzt", EntryPoint="CSharp_zts_deorbit")]
static extern int zts_deorbit(ulong arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_get_6plane_addr")]
static extern int zts_get_6plane_addr(IntPtr arg1, ulong arg2, ulong arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_get_rfc4193_addr")]
static extern int zts_get_rfc4193_addr(IntPtr arg1, ulong arg2, ulong arg3);
[DllImport("libzt", EntryPoint="CSharp_zts_generate_adhoc_nwid_from_range")]
static extern ulong zts_generate_adhoc_nwid_from_range(ushort arg1, ushort arg2);
[DllImport("libzt", EntryPoint="CSharp_zts_delay_ms")]
static extern void zts_delay_ms(int arg1);
[DllImport("libzt", EntryPoint="CSharp_zts_errno_get")]
static extern int zts_errno_get();
[StructLayout(LayoutKind.Sequential)]
struct zts_node_details
{
public ulong address;
}
/**
* Virtual network configuration
*/
[StructLayout(LayoutKind.Sequential)]
struct zts_network_details
{
/**
* 64-bit ZeroTier network ID
*/
public ulong nwid;
/**
* Ethernet MAC (48 bits) that should be assigned to port
*/
public ulong mac;
/**
* Network name (from network configuration master)
*/
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] name;
/**
* Network configuration request status
*/
public byte status; // ?
/**
* Network type
*/
public byte type; // ?
/**
* Maximum interface MTU
*/
public uint mtu;
/**
* If nonzero, the network this port belongs to indicates DHCP availability
*
* This is a suggestion. The underlying implementation is free to ignore it
* for security or other reasons. This is simply a netconf parameter that
* means 'DHCP is available on this network.'
*/
public int dhcp;
/**
* If nonzero, this port is allowed to bridge to other networks
*
* This is informational. If this is false (0), bridged packets will simply
* be dropped and bridging won't work.
*/
public int bridge;
/**
* If nonzero, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic
*/
public int broadcastEnabled;
/**
* If the network is in PORT_ERROR state, this is the (negative) error code most recently reported
*/
public int portError;
/**
* Revision number as reported by controller or 0 if still waiting for config
*/
public ulong netconfRevision;
/**
* Number of assigned addresses
*/
public uint assignedAddressCount;
/**
* ZeroTier-assigned addresses (in sockaddr_storage structures)
*
* For IP, the port number of the sockaddr_XX structure contains the number
* of bits in the address netmask. Only the IP address and port are used.
* Other fields like interface number can be ignored.
*
* This is only used for ZeroTier-managed address assignments sent by the
* virtual network's configuration master.
*/
//struct zts_sockaddr_storage assignedAddresses[ZTS_MAX_ZT_ASSIGNED_ADDRESSES];
/**
* Number of ZT-pushed routes
*/
public uint routeCount;
/**
* Routes (excluding those implied by assigned addresses and their masks)
*/
//ZTS_VirtualNetworkRoute routes[ZTS_MAX_NETWORK_ROUTES];
/**
* Number of multicast groups subscribed
*/
public uint multicastSubscriptionCount;
/**
* Multicast groups to which this network's device is subscribed
*/
//struct {
// uint64_t mac; /* MAC in lower 48 bits */
// uint32_t adi; /* Additional distinguishing information, usually zero except for IPv4 ARP groups */
//} multicastSubscriptions[ZTS_MAX_MULTICAST_SUBSCRIPTIONS];
}
[StructLayout(LayoutKind.Sequential)]
struct zts_callback_msg
{
public short eventCode;
[MarshalAs(UnmanagedType.LPStruct, SizeConst = 4)]
public IntPtr node;
public IntPtr network;
}
/// <summary>
/// Gets the value of errno from the unmanaged region
/// </summary>
/// <value></value>
public static int ErrNo {
get {
return zts_errno_get();
}
}
}
}