using Edge.Core.Parser.BinaryParser.Util; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using PetroChinaOnlineWatchPlugin.MessageEntity.Outgoing; using System; using System.Diagnostics; using System.Net; using System.Net.Sockets; namespace PetroChinaOnlineWatchPlugin { internal class HeartBeatUdpProxy { public event EventHandler OnDataReceived; public static HeartBeatUdpProxy Default => instance; private static readonly HeartBeatUdpProxy instance = new HeartBeatUdpProxy(); private int heartBeatUdpPortNumber = 0; private UdpClient heartBeatUdpClient; private ILogger logger = NullLogger.Instance; private string localIpAddresses = string.Empty; private string broadcastIpAddresses = string.Empty; private AppConfigV1 appConfig; public bool Start(AppConfigV1 appConfig, ILogger logger) { this.appConfig = appConfig; this.logger = logger; heartBeatUdpPortNumber = appConfig.HeartBeatPortNumber; // setup heartBeat UdpClient heartBeatUdpClient = new UdpClient(new IPEndPoint(IPAddress.Any, heartBeatUdpPortNumber)) { EnableBroadcast = true }; heartBeatUdpClient.BeginReceive(Udp_DataReceived, null); GetLocalIp(); return true; } public void Udp_SendData() { try { var outHeartBeat = new HeartBeatOut() { IpAddress = localIpAddresses, Port = ConnectionController.Default.TcpListenPort, Subnet = appConfig.LocalSubnet, Node = appConfig.LocalNode }; byte[] heartBeatRawDataToSend = Parser.Default.Serialize(outHeartBeat); logger.LogTrace($"Udp Outgoing--->: 0x{heartBeatRawDataToSend.ToHexLogString()}"); heartBeatUdpClient.Send(heartBeatRawDataToSend, heartBeatRawDataToSend.Length, broadcastIpAddresses, heartBeatUdpPortNumber); } catch (Exception ex) { logger.LogError($"Exception in Udp_SendData(...):\r\n{ex}"); } } private void Udp_DataReceived(IAsyncResult ar) { try { // IFSF always have 10 bytes heartbeat: ip0.ip1.ip2,ip3,port(2 bytes),4 ifsf standard bytes var broadcastHeartBeatReceiveEP = new IPEndPoint(IPAddress.Any, 0); byte[] heartBeatBytes = heartBeatUdpClient.EndReceive(ar, ref broadcastHeartBeatReceiveEP); logger.LogTrace($"Udp Incoming--->: 0x{heartBeatBytes.ToHexLogString()}"); dynamic heartBeat = Parser.Default.Deserialize(heartBeatBytes); logger.LogTrace($"HeartBeatIncoming--->: {heartBeat.ToString()}"); if (heartBeat.Subnet == appConfig.RemoteSubnet && heartBeat.Node == appConfig.RemoteNode) { logger.LogTrace($"Received heart beat from IpAddress:Port, {heartBeat.ToString()}"); if (!ConnectionController.Default.TcpClientInstance.Connected) OnDataReceived?.Invoke(this, new UdpDataEventArgs() { IpAddress = heartBeat.IpAddress, Port = heartBeat.Port }); } } catch (Exception ex) { logger.LogError($"Exception in Udp_DataReceived(...):\r\n{ex}"); } finally { heartBeatUdpClient.BeginReceive(Udp_DataReceived, null); } } private void GetLocalIp() { try { //var localIpAddresses = NetworkInterface.GetAllNetworkInterfaces() // .Where(i => i.SupportsMulticast && i.Supports(NetworkInterfaceComponent.IPv4)) // .SelectMany(i => i.GetIPProperties().UnicastAddresses) // .Select(ad => ad.Address) // .Where(ad => ad.AddressFamily == AddressFamily.InterNetwork); //logger.LogInformation("Local ip addresses are: " + localIpAddresses.Select(i => i.ToString()) // .Aggregate((acc, n) => acc + ", " + n)); var cmd = new Process(); cmd.StartInfo.FileName = "ipconfig.exe"; cmd.StartInfo.RedirectStandardOutput = true; cmd.StartInfo.RedirectStandardInput = true; cmd.StartInfo.UseShellExecute = false; cmd.StartInfo.CreateNoWindow = true; cmd.Start(); string info = cmd.StandardOutput.ReadToEnd(); cmd.WaitForExit(); cmd.Close(); info = info.Substring(info.IndexOf(appConfig.NetworkConnections)); string ipFlag = "IPv4 Address. . . . . . . . . . . : "; int index = info.IndexOf(ipFlag); if (index > 0) { info = info?.Substring(index + ipFlag.Length); } else { ipFlag = "IPv4 地址 . . . . . . . . . . . . : "; info = info?.Substring(info.IndexOf(ipFlag) + ipFlag.Length); } localIpAddresses = info?.Split("\r\n")[0]; logger.LogInformation($"Local ip addresses is: {localIpAddresses}"); ipFlag = "Subnet Mask . . . . . . . . . . . : "; index = info.IndexOf(ipFlag); if (index > 0) { info = info?.Substring(index + ipFlag.Length); } else { ipFlag = "子网掩码 . . . . . . . . . . . . : "; info = info?.Substring(info.IndexOf(ipFlag) + ipFlag.Length); } string subnetMask = info?.Split("\r\n")[0]; logger.LogInformation($"Local subnet mask is: {subnetMask}"); broadcastIpAddresses = GetBroadcastIpAddresses(localIpAddresses, subnetMask); logger.LogInformation($"Broadcast ip addresses is: {broadcastIpAddresses}"); } catch (Exception ex) { logger.LogError($"Exception in GetLocalIp(...):\r\n{ex}"); } } private string GetBroadcastIpAddresses(string ipAddress, string subnetMask) { byte[] ipBuffer = IpAddress2Bytes(ipAddress); byte[] smBuffer = IpAddress2Bytes(subnetMask); return $"{ipBuffer[0] | Negate(smBuffer[0])}.{ipBuffer[1] | Negate(smBuffer[1])}." + $"{ipBuffer[2] | Negate(smBuffer[2])}.{ipBuffer[3] | Negate(smBuffer[3])}"; } private byte Negate(byte value) { int first = value >> 7; if (first == 1) { value = (byte)(value & 0x7F); value = (byte)(~value & 0x7F); } else { value = (byte)(~value); } return value; } private byte[] IpAddress2Bytes(string ipAddress) { byte[] buffer = new byte[4]; int i = 0; foreach (string item in ipAddress.Split('.')) { buffer[i++] = byte.Parse(item); } return buffer; } } public class UdpDataEventArgs : EventArgs { public string IpAddress { get; set; } public int Port { get; set; } } }