/* * 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; using System.Net; using System.Net.Sockets; using System.Collections.Generic; using System.Collections.Concurrent; using System.Runtime.InteropServices; using ZeroTier; // Prototype of callback used by ZeroTier to signal events to C# application [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void CSharpCallbackWithStruct(IntPtr msgPtr); namespace ZeroTier.Core { public delegate void ZeroTierManagedEventCallback(ZeroTier.Core.Event nodeEvent); public class Node { static ulong _id = 0x0; static ushort _primaryPort; static ushort _secondaryPort; static ushort _tertiaryPort; static int _versionMajor; static int _versionMinor; static int _versionRev; static bool _isOnline = false; static bool _hasBeenFreed = false; string _configFilePath; ushort _servicePort; static ZeroTierManagedEventCallback _managedCallback; CSharpCallbackWithStruct _unmanagedCallback; ConcurrentDictionary _networks = new ConcurrentDictionary(); ConcurrentDictionary _peers = new ConcurrentDictionary(); public Node() { ClearNode(); } void ClearNode() { _id = 0x0; _primaryPort = 0; _secondaryPort = 0; _tertiaryPort = 0; _versionMajor = 0; _versionMinor = 0; _versionRev = 0; _isOnline = false; _configFilePath = string.Empty; _servicePort = 0; _networks.Clear(); _peers.Clear(); } public int InitFromStorage(string configFilePath) { if (String.IsNullOrEmpty(configFilePath)) { throw new ArgumentNullException("configFilePath"); } int res = Constants.ERR_OK; Console.WriteLine("path = " + configFilePath); if ((res = zts_init_from_storage(configFilePath)) == Constants.ERR_OK) { _configFilePath = configFilePath; } return res; } public int InitSetEventHandler(ZeroTierManagedEventCallback managedCallback) { if (managedCallback == null) { throw new ArgumentNullException("managedCallback"); } int res = Constants.ERR_OK; if ((res = zts_init_set_event_handler(OnZeroTierEvent)) == Constants.ERR_OK) { _unmanagedCallback = OnZeroTierEvent; _managedCallback = new ZeroTierManagedEventCallback(managedCallback); } return res; } public int InitSetPort(UInt16 port) { int res = Constants.ERR_OK; if ((res = zts_init_set_port(port)) == Constants.ERR_OK) { _servicePort = port; } return res; } public int InitSetRoots(byte[] roots_data, int len) { IntPtr unmanagedPointer = Marshal.AllocHGlobal(roots_data.Length); Marshal.Copy(roots_data, 0, unmanagedPointer, roots_data.Length); int res = zts_init_set_roots(unmanagedPointer, len); Marshal.FreeHGlobal(unmanagedPointer); return res; } public int InitAllowNetworkCaching(bool allowed) { return zts_init_allow_net_cache(Convert.ToByte(allowed)); } public int InitAllowPeerCaching(bool allowed) { return zts_init_allow_peer_cache(Convert.ToByte(allowed)); } void OnZeroTierEvent(IntPtr msgPtr) { zts_event_msg_t msg = (zts_event_msg_t)Marshal.PtrToStructure(msgPtr, typeof(zts_event_msg_t)); ZeroTier.Core.Event newEvent = null; // Node if (msg.node != IntPtr.Zero) { zts_node_info_t details = (zts_node_info_t)Marshal.PtrToStructure(msg.node, typeof(zts_node_info_t)); newEvent = new ZeroTier.Core.Event(); newEvent.Code = msg.event_code; _id = details.node_id; _primaryPort = details.primary_port; _secondaryPort = details.secondary_port; _tertiaryPort = details.tertiary_port; _versionMajor = details.ver_major; _versionMinor = details.ver_minor; _versionRev = details.ver_rev; _isOnline = Convert.ToBoolean(zts_node_is_online()); if (msg.event_code == Constants.EVENT_NODE_UP) { newEvent.Name = "EVENT_NODE_UP"; } if (msg.event_code == Constants.EVENT_NODE_ONLINE) { newEvent.Name = "EVENT_NODE_ONLINE"; } if (msg.event_code == Constants.EVENT_NODE_OFFLINE) { newEvent.Name = "EVENT_NODE_OFFLINE"; } if (msg.event_code == Constants.EVENT_NODE_DOWN) { newEvent.Name = "EVENT_NODE_DOWN"; } if (msg.event_code == Constants.ZTS_EVENT_NODE_FATAL_ERROR) { newEvent.Name = "EVENT_NODE_FATAL_ERROR"; } } // Network if (msg.network != IntPtr.Zero) { zts_net_info_t net_info = (zts_net_info_t)Marshal.PtrToStructure(msg.network, typeof(zts_net_info_t)); newEvent = new ZeroTier.Core.Event(); newEvent.Code = msg.event_code; // Update network info as long as we aren't tearing down the network if (msg.event_code != Constants.EVENT_NETWORK_DOWN) { ulong networkId = net_info.net_id; NetworkInfo ni = _networks.GetOrAdd(networkId, new NetworkInfo()); newEvent.NetworkInfo = ni; newEvent.NetworkInfo.Id = net_info.net_id; newEvent.NetworkInfo.MACAddress = net_info.mac; newEvent.NetworkInfo.Name = System.Text.Encoding.Default.GetString(net_info.name); newEvent.NetworkInfo.Status = net_info.status; newEvent.NetworkInfo.Type = net_info.type; newEvent.NetworkInfo.MTU = net_info.mtu; newEvent.NetworkInfo.DHCP = net_info.dhcp; newEvent.NetworkInfo.Bridge = Convert.ToBoolean(net_info.bridge); newEvent.NetworkInfo.BroadcastEnabled = Convert.ToBoolean(net_info.broadcast_enabled); zts_core_lock_obtain(); // Get assigned addresses ConcurrentDictionary newAddrsDict = new ConcurrentDictionary(); IntPtr addrBuffer = Marshal.AllocHGlobal(ZeroTier.Constants.INET6_ADDRSTRLEN); int addr_count = zts_core_query_addr_count(networkId); for (int idx = 0; idx < addr_count; idx++) { zts_core_query_addr(networkId, idx, addrBuffer, ZeroTier.Constants.INET6_ADDRSTRLEN); // Convert buffer to managed string string str = Marshal.PtrToStringAnsi(addrBuffer); IPAddress addr = IPAddress.Parse(str); newAddrsDict[addr.ToString()] = addr; } // Update addresses in NetworkInfo object // TODO: This update block works but could use a re-think, I think. // Step 1. Remove addresses not present in new concurrent dict. if (! ni._addrs.IsEmpty) { foreach (string key in ni._addrs.Keys) { if (! newAddrsDict.Keys.Contains(key)) { ni._addrs.TryRemove(key, out _); } } } else { ni._addrs = newAddrsDict; } // Step 2. Add addresses not present in existing concurrent dict. foreach (string key in newAddrsDict.Keys) { if (! ni._addrs.Keys.Contains(key)) { ni._addrs[key] = newAddrsDict[key]; } } Marshal.FreeHGlobal(addrBuffer); addrBuffer = IntPtr.Zero; // Get managed routes ConcurrentDictionary newRoutesDict = new ConcurrentDictionary(); IntPtr targetBuffer = Marshal.AllocHGlobal(ZeroTier.Constants.INET6_ADDRSTRLEN); IntPtr viaBuffer = Marshal.AllocHGlobal(ZeroTier.Constants.INET6_ADDRSTRLEN); int route_count = zts_core_query_route_count(networkId); ushort flags = 0, metric = 0; for (int idx = 0; idx < route_count; idx++) { zts_core_query_route( networkId, idx, targetBuffer, viaBuffer, ZeroTier.Constants.INET6_ADDRSTRLEN, ref flags, ref metric); // Convert buffer to managed string try { string targetStr = Marshal.PtrToStringAnsi(targetBuffer); IPAddress targetAddr = IPAddress.Parse(targetStr); string viaStr = Marshal.PtrToStringAnsi(viaBuffer); IPAddress viaAddr = IPAddress.Parse(viaStr); RouteInfo route = new RouteInfo(targetAddr, viaAddr, flags, metric); // Add to NetworkInfo object newRoutesDict[targetStr] = route; } catch { Console.WriteLine("error while parsing route"); } } // TODO: This update block works but could use a re-think, I think. // Step 1. Remove routes not present in new concurrent dict. if (! ni._routes.IsEmpty) { foreach (string key in ni._routes.Keys) { if (! newRoutesDict.Keys.Contains(key)) { ni._routes.TryRemove(key, out _); } } } else { ni._routes = newRoutesDict; } // Step 2. Add routes not present in existing concurrent dict. foreach (string key in newRoutesDict.Keys) { if (! ni._routes.Keys.Contains(key)) { ni._routes[key] = newRoutesDict[key]; } } Marshal.FreeHGlobal(targetBuffer); Marshal.FreeHGlobal(viaBuffer); targetBuffer = IntPtr.Zero; viaBuffer = IntPtr.Zero; // Get multicast subscriptions zts_core_lock_release(); // Update synthetic "readiness" value ni.transportReady = (route_count > 0) && (addr_count > 0) ? true : false; } // EVENT_NETWORK_DOWN if (msg.event_code == Constants.EVENT_NETWORK_NOT_FOUND) { newEvent.Name = "EVENT_NETWORK_NOT_FOUND " + net_info.net_id.ToString("x16"); } if (msg.event_code == Constants.EVENT_NETWORK_REQ_CONFIG) { newEvent.Name = "EVENT_NETWORK_REQ_CONFIG " + net_info.net_id.ToString("x16"); } if (msg.event_code == Constants.EVENT_NETWORK_ACCESS_DENIED) { newEvent.Name = "EVENT_NETWORK_ACCESS_DENIED " + net_info.net_id.ToString("x16"); } if (msg.event_code == Constants.EVENT_NETWORK_READY_IP4) { newEvent.Name = "EVENT_NETWORK_READY_IP4 " + net_info.net_id.ToString("x16"); } if (msg.event_code == Constants.EVENT_NETWORK_READY_IP6) { newEvent.Name = "EVENT_NETWORK_READY_IP6 " + net_info.net_id.ToString("x16"); } if (msg.event_code == Constants.EVENT_NETWORK_DOWN) { newEvent.Name = "EVENT_NETWORK_DOWN " + net_info.net_id.ToString("x16"); } if (msg.event_code == Constants.EVENT_NETWORK_CLIENT_TOO_OLD) { newEvent.Name = "EVENT_NETWORK_CLIENT_TOO_OLD " + net_info.net_id.ToString("x16"); } if (msg.event_code == Constants.EVENT_NETWORK_REQ_CONFIG) { newEvent.Name = "EVENT_NETWORK_REQ_CONFIG " + net_info.net_id.ToString("x16"); } if (msg.event_code == Constants.EVENT_NETWORK_OK) { newEvent.Name = "EVENT_NETWORK_OK " + net_info.net_id.ToString("x16"); } if (msg.event_code == Constants.EVENT_NETWORK_ACCESS_DENIED) { newEvent.Name = "EVENT_NETWORK_ACCESS_DENIED " + net_info.net_id.ToString("x16"); } if (msg.event_code == Constants.EVENT_NETWORK_READY_IP4_IP6) { newEvent.Name = "EVENT_NETWORK_READY_IP4_IP6 " + net_info.net_id.ToString("x16"); } if (msg.event_code == Constants.EVENT_NETWORK_UPDATE) { newEvent.Name = "EVENT_NETWORK_UPDATE " + net_info.net_id.ToString("x16"); } } // Route if (msg.route != IntPtr.Zero) { zts_route_info_t route_info = (zts_route_info_t)Marshal.PtrToStructure(msg.route, typeof(zts_route_info_t)); newEvent = new ZeroTier.Core.Event(); newEvent.Code = msg.event_code; newEvent.RouteInfo = default; // new RouteInfo(); if (msg.event_code == Constants.EVENT_ROUTE_ADDED) { newEvent.Name = "EVENT_ROUTE_ADDED"; } if (msg.event_code == Constants.EVENT_ROUTE_REMOVED) { newEvent.Name = "EVENT_ROUTE_REMOVED"; } } // Peer if (msg.peer != IntPtr.Zero) { zts_peer_info_t peer_info = (zts_peer_info_t)Marshal.PtrToStructure(msg.peer, typeof(zts_peer_info_t)); newEvent = new ZeroTier.Core.Event(); newEvent.Code = msg.event_code; newEvent.PeerInfo = default; // new PeerInfo(); if (peer_info.role == Constants.PEER_ROLE_PLANET) { Console.WriteLine("ROOT"); } if (msg.event_code == Constants.EVENT_PEER_DIRECT) { newEvent.Name = "EVENT_PEER_DIRECT"; } if (msg.event_code == Constants.EVENT_PEER_RELAY) { newEvent.Name = "EVENT_PEER_RELAY"; } // newEvent = new ZeroTier.Core.Event(msg.event_code,"EVENT_PEER_UNREACHABLE"); if (msg.event_code == Constants.EVENT_PEER_PATH_DISCOVERED) { newEvent.Name = "EVENT_PEER_PATH_DISCOVERED"; } if (msg.event_code == Constants.EVENT_PEER_PATH_DEAD) { newEvent.Name = "EVENT_PEER_PATH_DEAD"; } } // Address if (msg.addr != IntPtr.Zero) { zts_addr_info_t unmanagedDetails = (zts_addr_info_t)Marshal.PtrToStructure(msg.addr, typeof(zts_addr_info_t)); newEvent = new ZeroTier.Core.Event(); newEvent.Code = msg.event_code; newEvent.AddressInfo = default; // new AddressInfo(); if (msg.event_code == Constants.EVENT_ADDR_ADDED_IP4) { newEvent.Name = "EVENT_ADDR_ADDED_IP4"; } if (msg.event_code == Constants.EVENT_ADDR_ADDED_IP6) { newEvent.Name = "EVENT_ADDR_ADDED_IP6"; } if (msg.event_code == Constants.EVENT_ADDR_REMOVED_IP4) { newEvent.Name = "EVENT_ADDR_REMOVED_IP4"; } if (msg.event_code == Constants.EVENT_ADDR_REMOVED_IP6) { newEvent.Name = "EVENT_ADDR_REMOVED_IP6"; } } // Storage if (msg.cache != IntPtr.Zero) { newEvent = new ZeroTier.Core.Event(); newEvent.Code = msg.event_code; newEvent.AddressInfo = default; // new AddressInfo(); if (msg.event_code == Constants.EVENT_STORE_IDENTITY_SECRET) { newEvent.Name = "EVENT_STORE_IDENTITY_SECRET"; } if (msg.event_code == Constants.EVENT_STORE_IDENTITY_PUBLIC) { newEvent.Name = "EVENT_STORE_IDENTITY_PUBLIC"; } if (msg.event_code == Constants.EVENT_STORE_PLANET) { newEvent.Name = "EVENT_STORE_PLANET"; } if (msg.event_code == Constants.EVENT_STORE_PEER) { newEvent.Name = "EVENT_STORE_PEER"; } if (msg.event_code == Constants.EVENT_STORE_NETWORK) { newEvent.Name = "EVENT_STORE_NETWORK"; } } // Pass the converted Event to the managed callback (visible to user) if (newEvent != null) { _managedCallback(newEvent); } } public List Networks { get { return new List(_networks.Values); } } public List Peers { get { return new List(_peers.Values); } } public bool IsNetworkTransportReady(ulong networkId) { try { return _networks[networkId].transportReady && (_networks[networkId].Status == Constants.NETWORK_STATUS_OK); } catch (KeyNotFoundException) { return false; } } public List GetNetworkAddresses(ulong networkId) { try { return new List(_networks[networkId].Addresses); } catch (KeyNotFoundException) { } return new List(); } public List GetNetworkRoutes(ulong networkId) { try { return new List(_networks[networkId].Routes); } catch (KeyNotFoundException) { } return new List(); } /* public NetworkInfo GetNetwork(ulong networkId) { try { return _networks[networkId]; } catch (KeyNotFoundException) { } return null; } */ public int Start() { if (_hasBeenFreed == true) { throw new ObjectDisposedException( "ZeroTier Node has previously been freed. Restart application to create new instance."); } return zts_node_start(); } public int Free() { _id = 0x0; _hasBeenFreed = true; ClearNode(); return zts_node_free(); } public int Stop() { _id = 0x0; ClearNode(); return zts_node_stop(); } public int Join(ulong networkId) { /* The NetworkInfo object will only be added to _networks and populated when a response from the controller is received */ return zts_net_join(networkId); } public int Leave(ulong networkId) { int res = Constants.ERR_OK; if (zts_net_leave(networkId) == Constants.ERR_OK) { _networks.TryRemove(networkId, out _); } return res; } public bool Online { get { return _isOnline; } } public ulong Id { get { return _id; } } public string IdString { get { return _id.ToString("x16").TrimStart('0'); } } public string IdStr { get { return string.Format("{0}", _id.ToString("x16")); } } public ushort PrimaryPort { get { return _primaryPort; } } public ushort SecondaryPort { get { return _secondaryPort; } } public ushort TertiaryPort { get { return _tertiaryPort; } } public string Version { get { return string.Format("{0}.{1}.{2}", _versionMajor, _versionMinor, _versionRev); } } [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_id_new")] static extern int zts_id_new(string arg1, global::System.Runtime.InteropServices.HandleRef arg2); [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_id_pair_is_valid")] static extern int zts_id_pair_is_valid(string arg1, int arg2); [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_init_from_storage")] static extern int zts_init_from_storage(string arg1); [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_init_from_memory")] static extern int zts_init_from_memory(string arg1, ushort arg2); [DllImport("libzt", EntryPoint = "CSharp_zts_init_set_event_handler")] static extern int zts_init_set_event_handler(CSharpCallbackWithStruct arg1); [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_init_blacklist_if")] static extern int zts_init_blacklist_if(string arg1, int arg2); [DllImport("libzt", EntryPoint = "CSharp_zts_init_set_roots")] static extern int zts_init_set_roots(IntPtr roots_data, int len); [DllImport("libzt", EntryPoint = "CSharp_zts_init_set_port")] static extern int zts_init_set_port(ushort arg1); // Core query API [DllImport("libzt", EntryPoint = "CSharp_zts_core_lock_obtain")] static extern int zts_core_lock_obtain(); [DllImport("libzt", EntryPoint = "CSharp_zts_core_lock_release")] static extern int zts_core_lock_release(); [DllImport("libzt", EntryPoint = "CSharp_zts_core_query_addr_count")] static extern int zts_core_query_addr_count(ulong net_id); [DllImport("libzt", EntryPoint = "CSharp_zts_core_query_addr")] static extern int zts_core_query_addr(ulong net_id, int idx, IntPtr dst, int len); [DllImport("libzt", EntryPoint = "CSharp_zts_core_query_route_count")] static extern int zts_core_query_route_count(ulong net_id); [DllImport("libzt", EntryPoint = "CSharp_zts_core_query_route")] static extern int zts_core_query_route( ulong net_id, int idx, IntPtr target, IntPtr via, int len, ref ushort flags, ref ushort metric); [DllImport("libzt", EntryPoint = "CSharp_zts_core_query_path_count")] static extern int zts_core_query_path_count(ulong peer_id); [DllImport("libzt", EntryPoint = "CSharp_zts_core_query_path")] static extern int zts_core_query_path(ulong peer_id, int idx, IntPtr dst, int len); [DllImport("libzt", EntryPoint = "CSharp_zts_core_query_mc_count")] static extern int zts_core_query_mc_count(ulong net_id); [DllImport("libzt", EntryPoint = "CSharp_zts_core_query_mc")] static extern int zts_core_query_mc(ulong net_id, int idx, ref ulong mac, ref uint adi); // init [DllImport("libzt", EntryPoint = "CSharp_zts_init_allow_net_cache")] static extern int zts_init_allow_net_cache(int arg1); [DllImport("libzt", EntryPoint = "CSharp_zts_init_allow_peer_cache")] static extern int zts_init_allow_peer_cache(int arg1); [DllImport("libzt", EntryPoint = "CSharp_zts_init_clear")] static extern int zts_init_clear(); // addr [DllImport("libzt", EntryPoint = "CSharp_zts_addr_is_assigned")] static extern int zts_addr_is_assigned(ulong arg1, int arg2); [DllImport("libzt", EntryPoint = "CSharp_zts_addr_get")] static extern int zts_addr_get(ulong arg1, int arg2, global::System.Runtime.InteropServices.HandleRef arg3); [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_addr_get_str")] static extern int zts_addr_get_str(ulong arg1, int arg2, IntPtr arg3, int arg4); [DllImport("libzt", EntryPoint = "CSharp_zts_addr_get_all")] static extern int zts_addr_get_all( ulong arg1, global::System.Runtime.InteropServices.HandleRef arg2, global::System.Runtime.InteropServices.HandleRef arg3); [DllImport("libzt", EntryPoint = "CSharp_zts_addr_compute_6plane")] static extern int zts_addr_compute_6plane(ulong arg1, ulong arg2, global::System.Runtime.InteropServices.HandleRef arg3); [DllImport("libzt", EntryPoint = "CSharp_zts_addr_compute_rfc4193")] static extern int zts_addr_compute_rfc4193(ulong arg1, ulong arg2, global::System.Runtime.InteropServices.HandleRef arg3); [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_addr_compute_rfc4193_str")] static extern int zts_addr_compute_rfc4193_str(ulong arg1, ulong arg2, string arg3, int arg4); [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_addr_compute_6plane_str")] static extern int zts_addr_compute_6plane_str(ulong arg1, ulong arg2, string arg3, int arg4); /* [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); */ // net [DllImport("libzt", EntryPoint = "CSharp_zts_net_compute_adhoc_id")] public static extern ulong zts_net_compute_adhoc_id(ushort arg1, ushort arg2); [DllImport("libzt", EntryPoint = "CSharp_zts_net_join")] static extern int zts_net_join(ulong arg1); [DllImport("libzt", EntryPoint = "CSharp_zts_net_leave")] static extern int zts_net_leave(ulong arg1); [DllImport("libzt", EntryPoint = "CSharp_zts_net_transport_is_ready")] static extern int zts_net_transport_is_ready(ulong arg1); [DllImport("libzt", EntryPoint = "CSharp_zts_net_get_mac")] public static extern ulong zts_net_get_mac(ulong arg1); [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_net_get_mac_str")] static extern int zts_net_get_mac_str(ulong arg1, string arg2, int arg3); [DllImport("libzt", EntryPoint = "CSharp_zts_net_get_broadcast")] static extern int zts_net_get_broadcast(ulong arg1); [DllImport("libzt", EntryPoint = "CSharp_zts_net_get_mtu")] static extern int zts_net_get_mtu(ulong arg1); [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_net_get_name")] static extern int zts_net_get_name(ulong arg1, string arg2, int arg3); [DllImport("libzt", EntryPoint = "CSharp_zts_net_get_status")] static extern int zts_net_get_status(ulong arg1); [DllImport("libzt", EntryPoint = "CSharp_zts_net_get_type")] static extern int zts_net_get_type(ulong arg1); // route [DllImport("libzt", EntryPoint = "CSharp_zts_route_is_assigned")] static extern int zts_route_is_assigned(ulong arg1, int arg2); // node [DllImport("libzt", EntryPoint = "CSharp_zts_node_start")] static extern int zts_node_start(); [DllImport("libzt", EntryPoint = "CSharp_zts_node_is_online")] static extern int zts_node_is_online(); [DllImport("libzt", EntryPoint = "CSharp_zts_node_get_id")] public static extern ulong zts_node_get_id(); [DllImport("libzt", CharSet = CharSet.Ansi, EntryPoint = "CSharp_zts_node_get_id_pair")] static extern int zts_node_get_id_pair(string arg1, global::System.Runtime.InteropServices.HandleRef arg2); [DllImport("libzt", EntryPoint = "CSharp_zts_node_get_port")] static extern int zts_node_get_port(); [DllImport("libzt", EntryPoint = "CSharp_zts_node_stop")] static extern int zts_node_stop(); [DllImport("libzt", EntryPoint = "CSharp_zts_node_free")] static extern int zts_node_free(); // moon [DllImport("libzt", EntryPoint = "CSharp_zts_moon_orbit")] static extern int zts_moon_orbit(ulong arg1, ulong arg2); [DllImport("libzt", EntryPoint = "CSharp_zts_moon_deorbit")] static extern int zts_moon_deorbit(ulong arg1); // util [DllImport("libzt", EntryPoint = "CSharp_zts_util_delay")] static extern void zts_util_delay(int arg1); [DllImport("libzt", EntryPoint = "CSharp_zts_errno_get")] static extern int zts_errno_get(); [StructLayout(LayoutKind.Sequential)] struct zts_node_info_t { public ulong node_id; public ushort primary_port; public ushort secondary_port; public ushort tertiary_port; public byte ver_major; public byte ver_minor; public byte ver_rev; } [StructLayout(LayoutKind.Sequential)] struct zts_net_info_t { public ulong net_id; public ulong mac; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] public byte[] name; public int status; public int type; public uint mtu; public int dhcp; public int bridge; public int broadcast_enabled; public int port_error; public ulong netconf_rev; // address, routes, and multicast subs are retrieved using zts_core_ API } [StructLayout(LayoutKind.Sequential)] struct zts_route_info_t { IntPtr target; IntPtr via; ushort flags; ushort metric; } [StructLayout(LayoutKind.Sequential)] struct zts_addr_info_t { ulong nwid; IntPtr addr; } [StructLayout(LayoutKind.Sequential)] struct zts_peer_info_t { public ulong address; public int ver_major; public int ver_minor; public int ver_rev; public int latency; public byte role; // TODO } [StructLayout(LayoutKind.Sequential)] struct zts_event_msg_t { public short event_code; public IntPtr node; public IntPtr network; public IntPtr netif; public IntPtr route; public IntPtr peer; public IntPtr addr; public IntPtr cache; public int len; } public static int ErrNo { get { return zts_errno_get(); } } } }