// Callback used internally to ferry events from the C++ layer static void OnZeroTierEvent(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.Core.Event newEvent = null; // Node events if (msg.eventCode == Constants.EVENT_NODE_UP) { newEvent = new ZeroTier.Core.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.Core.Event(msg.eventCode, "EVENT_NODE_ONLINE"); } if (msg.eventCode == Constants.EVENT_NODE_OFFLINE) { _isOnline = false; newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NODE_OFFLINE"); } if (msg.eventCode == Constants.EVENT_NODE_NORMAL_TERMINATION) { _isOnline = false; newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NODE_NORMAL_TERMINATION"); } if (msg.eventCode == Constants.EVENT_NODE_DOWN) { _isOnline = false; newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NODE_DOWN"); } if (msg.eventCode == Constants.EVENT_NODE_IDENTITY_COLLISION) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NODE_IDENTITY_COLLISION"); _isOnline = false; } if (msg.eventCode == Constants.EVENT_NODE_UNRECOVERABLE_ERROR) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NODE_UNRECOVERABLE_ERROR"); _isOnline = false; } // Network events if (msg.eventCode == Constants.EVENT_NETWORK_NOT_FOUND) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETWORK_NOT_FOUND"); } if (msg.eventCode == Constants.EVENT_NETWORK_REQ_CONFIG) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETWORK_REQ_CONFIG"); } if (msg.eventCode == Constants.EVENT_NETWORK_ACCESS_DENIED) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETWORK_ACCESS_DENIED"); } if (msg.eventCode == Constants.EVENT_NETWORK_READY_IP4) { _joinedAtLeastOneNetwork = true; newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETWORK_READY_IP4"); } if (msg.eventCode == Constants.EVENT_NETWORK_READY_IP6) { _joinedAtLeastOneNetwork = true; newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETWORK_READY_IP6"); } if (msg.eventCode == Constants.EVENT_NETWORK_DOWN) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETWORK_DOWN"); } if (msg.eventCode == Constants.EVENT_NETWORK_CLIENT_TOO_OLD) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETWORK_CLIENT_TOO_OLD"); } if (msg.eventCode == Constants.EVENT_NETWORK_REQ_CONFIG) { newEvent = new ZeroTier.Core.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.Core.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.Core.Event(msg.eventCode, "EVENT_NETWORK_ACCESS_DENIED"); } if (msg.eventCode == Constants.EVENT_NETWORK_READY_IP4_IP6) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETWORK_READY_IP4_IP6"); } if (msg.eventCode == Constants.EVENT_NETWORK_UPDATE) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETWORK_UPDATE"); } // Stack events if (msg.eventCode == Constants.EVENT_STACK_UP) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_STACK_UP"); } if (msg.eventCode == Constants.EVENT_STACK_DOWN) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_STACK_DOWN"); } // Address events if (msg.eventCode == Constants.EVENT_ADDR_ADDED_IP4) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_ADDR_ADDED_IP4"); } if (msg.eventCode == Constants.EVENT_ADDR_ADDED_IP6) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_ADDR_ADDED_IP6"); } if (msg.eventCode == Constants.EVENT_ADDR_REMOVED_IP4) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_ADDR_REMOVED_IP4"); } if (msg.eventCode == Constants.EVENT_ADDR_REMOVED_IP6) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_ADDR_REMOVED_IP6"); } // peer events if (msg.eventCode == Constants.EVENT_PEER_DIRECT) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_PEER_DIRECT"); } if (msg.eventCode == Constants.EVENT_PEER_RELAY) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_PEER_RELAY"); } // newEvent = new ZeroTier.Core.Event(msg.eventCode,"EVENT_PEER_UNREACHABLE"); if (msg.eventCode == Constants.EVENT_PEER_PATH_DISCOVERED) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_PEER_PATH_DISCOVERED"); } if (msg.eventCode == Constants.EVENT_PEER_PATH_DEAD) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_PEER_PATH_DEAD"); } // Route events if (msg.eventCode == Constants.EVENT_ROUTE_ADDED) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_ROUTE_ADDED"); } if (msg.eventCode == Constants.EVENT_ROUTE_REMOVED) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_ROUTE_REMOVED"); } // Netif events if (msg.eventCode == Constants.EVENT_NETIF_UP) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETIF_UP"); } if (msg.eventCode == Constants.EVENT_NETIF_DOWN) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETIF_DOWN"); } if (msg.eventCode == Constants.EVENT_NETIF_REMOVED) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETIF_REMOVED"); } if (msg.eventCode == Constants.EVENT_NETIF_LINK_UP) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETIF_LINK_UP"); } if (msg.eventCode == Constants.EVENT_NETIF_LINK_DOWN) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_NETIF_LINK_DOWN"); } if (msg.eventCode == Constants.EVENT_ADDR_REMOVED_IP6) { newEvent = new ZeroTier.Core.Event(msg.eventCode, "EVENT_ADDR_REMOVED_IP6"); } // Pass the converted Event to the managed callback (visible to user) if (newEvent != null) { _managedCallback(newEvent); } }
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.UTF8.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 <string, IPAddress> newAddrsDict = new ConcurrentDictionary <string, IPAddress>(); 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 <string, RouteInfo> newRoutesDict = new ConcurrentDictionary <string, RouteInfo>(); 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) { newEvent.Name = "PEER_ROLE_PLANET"; } 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); } }