using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using DTS.DASLib.Command.Classes; using DTS.Common.Utilities.Logging; using DTS.Common.Interface.DASFactory; using DTS.Common.Enums.DASFactory; namespace DTS.DASLib.Command.SLICE.MulticastCommands { /// /// 10558 Auto-discovery to add cmd/res support for MAC table /// public class MulticastDiscoverSlice6 : MulticastCommandBase { #region constants and enums private const int COMMAND_PAYLOAD_SIZE = 80; private const int DEVICE_CLASS_OFFSET = 36; private const int NUMBER_OF_RECORDS_OFFSET = 40; private const int RESERVED_OFFSET = 42; private const int START_OF_MAC_TABLE = 48; private const int SIZE_OF_MAC_RECORD = 12;//bytes private const int PORT_OFFSET = 2; private const int FILTER_OFFSET = 4; private const int MAC_OFFSET = 6; #endregion #region private properties protected override Commands Command => Commands.GetMACTable; protected override bool StopAfterFirstMessage => false; private uint _deviceClass; private byte _responseOption; private IPAddress _address; private const string RX_MULTICAST_ADDRESS = "239.4.5.6"; private void SetMulticastConfig() { IPAddress.TryParse(RX_MULTICAST_ADDRESS, out _address); } #endregion #region public properties public DeviceClasses DeviceClass { set { _deviceClass = (uint)value; command.SetParameter(36, (int)_deviceClass); } } public ResponseOptions ResponseOption { set { _responseOption = (byte)value; command.SetParameter(40, _responseOption); } } public uint DesiredPort { set => command.SetParameter(41, value); } public byte[] MACFilter { set => command.SetParameter(45, value); } public TextLogger Logger { get; set; } public Dictionary MACAddressToDevice { get; set; } private readonly List _connectedDevices = new List(); public DiscoveredConnectedSlice[] ConnectedDevices => _connectedDevices.ToArray(); #endregion #region constructors and initializers public MulticastDiscoverSlice6(DeviceClasses deviceClass, string hostMac) : base(null) { command.Parameter = new byte[COMMAND_PAYLOAD_SIZE]; HostMac = hostMac; DeviceClass = deviceClass; ResponseOption = ResponseOptions.AlwaysRespond; SetMulticastConfig(); DesiredPort = 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3; MACFilter = new[] { Convert.ToByte(0x00), Convert.ToByte(0x19), Convert.ToByte(0x9b), byte.MaxValue, byte.MaxValue, byte.MaxValue }; } public MulticastDiscoverSlice6(string hostMac, int timeoutMillisec) : base(null, timeoutMillisec) { command.Parameter = new byte[COMMAND_PAYLOAD_SIZE]; HostMac = hostMac; DeviceClass = DeviceClasses.Any; ResponseOption = ResponseOptions.AlwaysRespond; SetMulticastConfig(); DesiredPort = 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3;//ports 1-4 MACFilter = new[] { Convert.ToByte(0x00), Convert.ToByte(0x19), Convert.ToByte(0x9b), byte.MaxValue, byte.MaxValue, byte.MaxValue }; } #endregion #region methods protected override CommandReceiveAction WholePackage() { if (response.Status != DFConstantsAndEnums.CommandStatus.StatusNoError) return CommandReceiveAction.StopReceiving; response.GetParameter(HOST_MAC_ADDRESS_OFFSET, out ResponseHostMac); if (null == ResponseHostMac || !HostMac.Equals(ResponseHostMac)) { response.Status = DFConstantsAndEnums.CommandStatus.StatusInvalidPacket; return CommandReceiveAction.StopReceiving; } response.GetParameter(CLIENT_MAC_ADDRESS_OFFSET, out ResponseClientMac); response.GetParameter(DEVICE_CLASS_OFFSET, out _deviceClass); ushort numberOfEntries; response.GetParameter(NUMBER_OF_RECORDS_OFFSET, out numberOfEntries); var list = new List(); for (var i = 0; i < numberOfEntries; i++) { try { response.GetParameter(START_OF_MAC_TABLE + i * SIZE_OF_MAC_RECORD, out ushort age); response.GetParameter(START_OF_MAC_TABLE + i * SIZE_OF_MAC_RECORD + PORT_OFFSET, out ushort port); response.GetParameter(START_OF_MAC_TABLE + i * SIZE_OF_MAC_RECORD + FILTER_OFFSET, out ushort filter); var mac = new byte[6]; for (var b = 0; b < mac.Length; b++) { response.GetParameter(START_OF_MAC_TABLE + i * SIZE_OF_MAC_RECORD + MAC_OFFSET + b, out byte thisByte); mac[b] = thisByte; } list.Add(new MACTableEntry(age, port, filter, mac)); } catch (Exception ex) { APILogger.Log($"MulticastDiscoverSlice6 failed to get entry - ignoring entry", ex.Message); } } _connectedDevices.Add(new DiscoveredConnectedSlice(ResponseClientMac, list.ToArray())); var responseMac = ResponseClientMac.Replace('-', ':').ToUpper(); var serialNumber = "N/A"; if (null != MACAddressToDevice && MACAddressToDevice.ContainsKey(responseMac)) { serialNumber = MACAddressToDevice[responseMac].Serial; } Log(ResponseHostMac, ResponseClientMac, list.ToArray(), serialNumber); //Log(response.Parameter); return CommandReceiveAction.StopReceiving; } private static string ByteToHex(byte b) { return $"{b:x2}"; } private void Log(IReadOnlyList parameter) { var sb = new StringBuilder(); sb.Append("msg: "); foreach (var b in parameter) { sb.Append(ByteToHex(b)); } sb.AppendLine(); //var bytes = new List(parameter); sb.Append("header: "); for (var i = 0; i < START_OF_MAC_TABLE; i++) { sb.Append(ByteToHex(parameter[i])); } sb.AppendLine(); for (var i = START_OF_MAC_TABLE; i < parameter.Count; i += SIZE_OF_MAC_RECORD) { sb.Append("Record: "); for (var idx = 0; idx < SIZE_OF_MAC_RECORD; idx++) { sb.Append(ByteToHex(parameter[i + idx])); } sb.AppendLine(); } Log(sb.ToString()); } private void Log(string responseHostMac, string responseClientMac, MACTableEntry[] entries, string serialNumber) { var sb = new StringBuilder(); sb.AppendFormat("Host: {0}, Client: {1}, SerialNumber: {2}", responseHostMac, responseClientMac, serialNumber); sb.AppendLine(); sb.AppendLine("Age\tFilter\tMAC\t\t\tPort"); foreach (var entry in entries) { sb.AppendFormat("{0}\t{1}\t{2}\t{3}", entry.Age, entry.Filter, MACAddressToString(entry.MAC), entry.Port); sb.AppendLine(); } Log(sb.ToString()); } public static string MACAddressToString(IEnumerable mac) { var list = mac.Select(b => $"{b:x2}").ToList(); return string.Join(":", list.ToArray()).ToUpper(); } public override void CommandToString(ref List> lines) { base.CommandToString(ref lines); lines.Add(new List { $"AutoDiscover: [{HostMac}]" }); } private void Log(string msg) { if (null == Logger) { return; } Logger.LogMessage($"====={DateTime.Now.ToShortDateString()} {DateTime.Now.ToShortTimeString()}=====\r\n"); Logger.LogMessage(msg); } #endregion } }