using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Net; using System.Net.Sockets; using System.Collections; using SafeMobileLib; namespace MotoRepeater { public class LinkEstablishment { #region ENUMS public enum Operations { LE_MASTER_PEER_REGISTRATION_REQUEST = 0x90, LE_MASTER_PEER_REGISTRATION_RESPONSE = 0x91, LE_NOTIFICATION_MAP_REQUEST = 0x92, LE_NOTIFICATION_MAP_BROADCAST = 0x93, LE_PEER_REGISTRATION_REQUEST = 0x94, LE_PEER_REGISTRATION_RESPONSE = 0x95, LE_MASTER_PEER_KEEP_ALIVE_REQUEST = 0x96, LE_MASTER_PEER_KEEP_ALIVE_RESPONSE = 0x97, LE_PEER_KEEP_ALIVE_REQUEST = 0x98, LE_PEER_KEEP_ALIVE_RESPONSE = 0x99, LE_DEREGISTRATION_REQUEST = 0x9A, LE_DEREGISTRATION_RESPONSE = 0x9B, LE_DIGITALVOTING_MAP_BROADCAST = 0x33 }; public enum SystemReleaseNumber { R22, R23, R23A, R23B, R24A, R24B, R25 }; public enum SystemType { IP_SITE_CONNECT, CAPACITY_PLUS, LINKED_CAPACITY_PLUS }; public static byte RESERVED = 0x00; public enum MapType { SystemWideMap = 0x00, MasterPeerProgrammingMap = 0x02, VolterMap = 0x04, MapContinuationIndicator = 0x07 }; /* This field contains two bits to indicate whether a peer is currently disabled or enabled. * When a peer is disabled, it only supports Link Establishment and some peer services * (i.e. RDAC and other XCMP/XNL services). It does not support voice, data, or CSBK * calls when disabled */ public enum PeerStatus { Disabled = 0, Enabled = 1, KnockedDown = 2, Locked = 3 } /* This field will contain two bits to indicate the current RF signaling mode information * pertaining to the Analog or Digital modes of operation. A peer can also indicate that it * has no RF support */ public enum SignalingMode { NoRFSupport = 0, Analog = 1, Digital = 2, RESERVED = 3 }; /* This field will contain two bits to indicate the slot assignment information regarding use * for IP Site Connect call support, local site call support only, or no call support on this * peer (i.e. an RDAC peer) */ public enum SlotAssignment { NoCallSupport = 0, LocalSiteCallSupportOnly = 1, IPSiteConnectCallSupport = 2, RESERVED = 3, // for LCP LCPTrunkedChannel = 1, LCPLocalAreaDataRevertChannel = 2, LCPWideAreaDataRevertChannel = 3 }; #endregion /* Variables for LE_MASTER_PEER_REGISTRATION_REQUEST && LE_MASTER_PEER_REGISTRATION_RESPONSE */ // ########## IMPORTANT ############## // the bytes are LSB to MSB , eg. peerID is 0x00000003 /* List of known peers, Master and Myself */ public Peer masterPeer = new Peer(); public Peer myselfPeer = new Peer(); private Hashtable peersHashTable = new Hashtable(); public int numPeers = 0; public int mapType = 0; // for Map Request & Response private bool registrationResent = false; /* System variables */ private Thread linkEstablishmentHandlerThread; private Thread keepAliveThread; private Thread registeringThread; private Thread peersKeepAliveThread; public UdpClient udpClient; public SystemType systemType = SystemType.IP_SITE_CONNECT; public SystemReleaseNumber releaseNumber = SystemReleaseNumber.R23A; public int leProtocolVersion = 3; private bool isMaster = false; private bool isRegistered = false; private bool isRunning = true; private DateTime lastKeepAliveRequestTime; private DateTime lastKeepAliveResponseTime; private Int16 keepAliveSecondsInterval = 15; private Int16 peerKeepAliveSecondsInterval = 5; // the slots on which the wireline registration will be made private Wireline.SlotNumber slots = Wireline.SlotNumber.BothSlots; public LinkEstablishment(String masterIP, int masterUDPPort, Int64 peerID, int peerPort, SystemReleaseNumber releaseNumber, SystemType systemType) { masterPeer.ipAddress = masterIP; masterPeer.port = masterUDPPort; this.releaseNumber = releaseNumber; myselfPeer.peerID = peerID; //BitConverter.ToUInt32(new byte[] { 0x0B, 0xCF, 0x17, 0x00 }, 0); myselfPeer.slot1ID = 0xCCCCCC; myselfPeer.slot2ID = 0xDDDDDD; myselfPeer.port = peerPort; myselfPeer.SetPeerMode(systemType, systemType == SystemType.LINKED_CAPACITY_PLUS ? 0x4000 : ( systemType == SystemType.IP_SITE_CONNECT ? 0x4A : 0x65)); // 0x40 - should make me enabled myselfPeer.SetPeerServices(systemType, systemType == SystemType.LINKED_CAPACITY_PLUS ? 0x00062004 : 0x2020); // for RMC - 0x6020 //myselfPeer.peerServices = new byte[] { 0x24, 0x0, 0x80, 0x4D }; //myselfPeer.peerServices = BitConverter.GetBytes(0x2400804D); //0x6a000d00 //myselfPeer.peerServices = new byte[] { 0x3C, 0x30, 0xA0, 0xCD }; // create evnet handler for when the Master Peer is Registered this.OnRegistrationResponseReceived += new RegistrationResponseDEl(LinkEstablishment_OnRegistrationResponseReceived); this.OnMasterRegistrationRequestReceived += new MasterRegistrationRequestDEl(LinkEstablishment_OnMasterRegistrationRequestReceived); this.OnMasterKeepAliveRequestReceived += new MasterKeepAliveRequestDEl(LinkEstablishment_OnMasterKeepAliveRequestReceived); this.OnMapRequestReceived += new MapRequestDEl(LinkEstablishment_OnMapRequestReceived); // create event handler for when a peer sends a registration request and a ping pong request this.OnPeerRegistrationRequestReceived += new PeerRegistrationRequestDEl(LinkEstablishment_OnPeerRegistrationRequestReceived); this.OnPeerKeepAliveRequestReceived += new PeerKeepAliveRequestDEl(LinkEstablishment_OnPeerKeepAliveRequestReceived); this.OnPeerKeepAliveResponseReceived += new PeerKeepAliveResponseDEl(LinkEstablishment_OnPeerKeepAliveResponseReceived); } /* Set the system Type and LinkEstablishment Protocol Version based * on the system type and system realease number */ public void SetSystemType(SystemType systemType) { this.systemType = systemType; Utils.WriteLine("System type is " + systemType.ToString(), ConsoleColor.Cyan, ConsoleType.LE); myselfPeer?.SetPeerMode(systemType, systemType == SystemType.LINKED_CAPACITY_PLUS ? 0x4000 : (systemType == SystemType.IP_SITE_CONNECT ? 0x4A : 0x65)); // 0x40 - should make me enabled myselfPeer?.SetPeerServices(systemType, systemType == SystemType.LINKED_CAPACITY_PLUS ? 0x00062004 : (systemType == SystemType.IP_SITE_CONNECT ? 0x2020 : 0x2020)); // for RMC - 0x6020 // SMART PTT - 0xE56C switch (releaseNumber) { case SystemReleaseNumber.R24A: case SystemReleaseNumber.R24B: case SystemReleaseNumber.R25: { if (systemType == SystemType.LINKED_CAPACITY_PLUS) leProtocolVersion = 7; else leProtocolVersion = 6; break; } case SystemReleaseNumber.R23A: case SystemReleaseNumber.R23B: { leProtocolVersion = 6; break; } case SystemReleaseNumber.R23: { leProtocolVersion = 5; break; } case SystemReleaseNumber.R22: { if (systemType == SystemType.CAPACITY_PLUS) leProtocolVersion = 3; else leProtocolVersion = 4; break; } default: { leProtocolVersion = 6; break; } } SetCurrentAndOldestLinkProtocolVersion(); } /* Set the IP of the master peer */ public void SetMasterPeerIP(string masterIP) { masterPeer.ipAddress = masterIP; } /* Set the udp port that will be used to communicate with the master peer */ public void SetMasterPeerPort(Int32 masterUdpPort) { masterPeer.port = masterUdpPort; } /* Set the udp port that will be used by others to communicate with me */ public void SetMyselfPeerPort(Int32 myselfUdpPort) { myselfPeer.port = myselfUdpPort; } /* For this section see page 97 from devspec_link_establishment_0102 * 4.9.9 Link Protocol Version Bit Field (Link Protocol Version) * This field is used to exchange link protocol version information for the accepted, current, * and oldest supported versions. The link protocol version has two components: system * ID and version information, which are used to determine the message structure and * procedure in the multi-software-version system interactions. Each PDU is defined to * support a specific system ID and protocol in section 4.8. * The overall field size is 16 bits that is broken into the 10-bit version information field and * 6-bit system ID field. * * A bit mask of 0xFC00 can be used to derive the System ID from the Link Protocol * Version field. A bit mask of 0x03FF can be used to derive the version information value * from the Link Protocol Version field. * * ┌───────────────┬───────────────┬──────────────────────────────────────┐ * │ Link Protocol │ Link Protocol │ Description │ * │ Version Bits │ Version Name │ │ * ├───────────────┼───────────────┼──────────────────────────────────────┤ * │ │ │ 0b 00 0000 0011 = R19(LCP), R22(CPC) │ * │ 0-9 │ Protocol Vers │ 0b 00 0000 0100 = R22(LCP, IPSC) │ * │ │ │ 0b 00 0000 0101 = R23(LCP,IPCS,CPC) │ * ├───────────────┼───────────────┼──────────────────────────────────────┤ * │ │ │ 0b 0000 01 = IPSC, Analog, Sg. Site │ * │ 10-15 │ System ID │ 0b 0000 10 = Capacity Plus │ * │ │ │ 0b 0001 00 = LCP │ * └───────────────┴───────────────┴──────────────────────────────────────┘ * */ public void SetCurrentAndOldestLinkProtocolVersion() { // clear previous values myselfPeer.currentLinkProtocolVersion[0] = 0x00; myselfPeer.currentLinkProtocolVersion[1] = 0x00; myselfPeer.oldestLinkProtocolVersion[0] = 0x00; myselfPeer.oldestLinkProtocolVersion[1] = 0x00; // create two 'bit' arrays for System ID and Protocol Version bool[] systemID = new bool[6]; bool[] protocolVers = new bool[10]; bool[] oldestProtocolVers = new bool[10]; switch (systemType) { case SystemType.IP_SITE_CONNECT: { systemID = new bool[] { false, false, false, false, false, true }; break; } case SystemType.CAPACITY_PLUS: { systemID = new bool[] { false, false, false, false, true, false }; break; } case SystemType.LINKED_CAPACITY_PLUS: { systemID = new bool[] { false, false, false, true, false, false }; break; } } switch (releaseNumber) { case SystemReleaseNumber.R23A: case SystemReleaseNumber.R23B: { protocolVers = new bool[] { false, false, false, false, false, false, false, true, true, false }; break; } case SystemReleaseNumber.R23: { protocolVers = new bool[] { false, false, false, false, false, false, false, true, false, true }; break; } case SystemReleaseNumber.R22: { if (systemType == SystemType.CAPACITY_PLUS) protocolVers = new bool[] { false, false, false, false, false, false, false, true, false, false }; else protocolVers = new bool[] { false, false, false, false, false, false, false, false, true, true }; break; } default: { protocolVers = new bool[] { false, false, false, false, false, false, false, true, true, false }; break; } } // create current Link Protocol Version bytes from systemID and protocolVers bool[] linkProtocolBits = new bool[systemID.Length + protocolVers.Length]; systemID.CopyTo(linkProtocolBits, 0); protocolVers.CopyTo(linkProtocolBits, systemID.Length); string base2Value = ""; // create a string that will be in base 2 for (int i = 0; i < linkProtocolBits.Length; i++ ) { base2Value += (linkProtocolBits[i] ? "1" : "0"); } myselfPeer.currentLinkProtocolVersion = BitConverter.GetBytes(Convert.ToInt32(base2Value, 2)); //TODO find a way to set this programmatically // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // READ MORE IN DOC ABOUT OLDEST VERSION // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! myselfPeer.oldestLinkProtocolVersion[1] = 0x04; myselfPeer.oldestLinkProtocolVersion[0] = 0x03; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } /// /// Set the slots that will be registered when the Wireline Registration /// will be established /// /// Required slots to register on public void SetRegisteredSlots(Wireline.SlotNumber slots) { Utils.WriteLine("Wireline Registration on " + slots, ConsoleColor.Cyan); this.slots = slots; } /// /// Get the slots on which the Wireline Registration needs to be established /// public Wireline.SlotNumber GetRegisteredSlots() { return slots; } // start all the threads which are in charge with the Link Establishment public void StartLinkEstablishment() { linkEstablishmentHandlerThread = new Thread(new ThreadStart(linkEstablishmentHandler)); linkEstablishmentHandlerThread.Start(); // create Threads that will handle Keep Alive Requests and Responses keepAliveThread = new Thread(new ThreadStart(MasterKeepAliveHandler)); peersKeepAliveThread = new Thread(new ThreadStart(PeersKeepAliveHandler)); registeringThread = new Thread(new ThreadStart(RegisteringThreadHandler)); // start LE registration only if not master if(!isMaster) registeringThread.Start(); } // stop all the threads which are in charge with the Link Establishment public void StopLinkEstablishment() { isRunning = false; try { udpClient.Close(); udpClient = null; } catch (Exception) { udpClient = null; } } #region THREAD CALLBACKS // Creates the UDP Client and receive bytes which are then decoded private void linkEstablishmentHandler() { Utils.WriteLine("Link Establishment Thread - Initialized on port " + myselfPeer.port, ConsoleColor.Cyan, ConsoleType.LE); try { udpClient = new UdpClient(); udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, myselfPeer.port)); udpClient.Client.ReceiveTimeout = 1000 * 200000; } catch (SocketException ex) { //Utils.ConsWrite(DebugMSG_Type.DB, "Link Establishment Thread handleConnection exception while creating udpClient: " + ex.ToString()); } IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); while (isRunning) { while (udpClient != null && isRunning) { try { // Blocks until a message returns on this socket from a remote host. Byte[] receivedBytes = udpClient.Receive(ref remoteIpEndPoint); // do not parse message if not opCode and PeerID in it //if (receivedBytes.Length <= 5) // continue; char[] separator = { '.' }; string[] su = remoteIpEndPoint.Address.ToString().Split(separator); uint radioID = (Convert.ToUInt32(su[1])) * 256 * 256 + (Convert.ToUInt32(su[2])) * 256 + Convert.ToUInt32(su[3]); string suid = radioID.ToString(); string senderPeerIP = su[0] + "." + su[1] + "." + su[2] + "." + su[3]; //Utils.WriteLine("Received bytes from " + senderPeerIP, ConsoleColor.Red); // decode the received message decode(receivedBytes, senderPeerIP, masterPeer.port); } catch (Exception) { //Utils.ConsWrite(DebugMSG_Type.DB, "##### Link Establishment Exception #########\n" + e.ToString()); } } try { // here the udpClient should be null so I have to recreate it udpClient = new UdpClient(); udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, masterPeer.port)); udpClient.Client.ReceiveTimeout = 1000 * 200000; } catch (SocketException ex) { //Utils.ConsWrite(DebugMSG_Type.DB, "Link Establishment Thread handleConnection exception while creating udpClient: " + ex.ToString()); } } //Utils.ConsWrite(DebugMSG_Type.DB, "##### Link Establishment Thread ENDED #########\n"); } /* Method will keep a 'ping-pong' communication with the master peer */ private void MasterKeepAliveHandler() { Utils.WriteLine("♥♥♥ Keep Alive Thread started"); while (isRegistered && isRunning) { TimeSpan span = lastKeepAliveRequestTime.Subtract(lastKeepAliveResponseTime); if (span.TotalSeconds >= keepAliveSecondsInterval * 3) { // Keep Alive Expired isRegistered = false; Thread.Sleep(600); // start register thread if (!registeringThread.IsAlive) { registeringThread = new Thread(new ThreadStart(RegisteringThreadHandler)); registeringThread.Start(); } } // it's time to send a new Keep Alive message to the Master Peer span = DateTime.Now.Subtract(lastKeepAliveRequestTime); if (span.TotalSeconds >= keepAliveSecondsInterval) { SendLEMessage(createLEMessage(Operations.LE_MASTER_PEER_KEEP_ALIVE_REQUEST)); lastKeepAliveRequestTime = DateTime.Now; } Thread.Sleep(500); } Utils.WriteLine("Keep Alive Thread ended ♥♥♥"); } /* Method will keep a 'ping-pong' communication with all the peers */ private void PeersKeepAliveHandler() { Utils.WriteLine("♥♥♥ Peers Keep Alive Thread started"); while (isRegistered && isRunning) { Thread.Sleep(200); lock (peersHashTable.SyncRoot) { foreach (DictionaryEntry entry in peersHashTable) { Peer peer = (Peer)entry.Value; TimeSpan span = peer.lastKeepAliveRequestTime.Subtract(peer.lastKeepAliveResponseTime); /* // remove from hash if 3 interval without response if (span.TotalSeconds >= 3 * peerKeepAliveSecondsInterval) { peersHashTable.Remove(entry.Key); continue; } */ // if last Keep Alive message is older than the Timeout I should resend the Keep Alive Request if (span.TotalSeconds >= peerKeepAliveSecondsInterval) { SendLEMessage(createLEMessage(Operations.LE_MASTER_PEER_KEEP_ALIVE_REQUEST), peer.ipAddress, peer.port); peer.lastKeepAliveRequestTime = DateTime.Now; } } } } Utils.WriteLine("Peers Keep Alive Thread ended ♥♥♥"); } /* Method that will send the registering message and */ private void RegisteringThreadHandler() { Utils.WriteLine("♥♥♥ Registering Thread started"); int count = 0; while (!isRegistered && isRunning) { // resend the message one at 5 seconds if(count % 10 == 0) SendLEMessage(createLEMessage(Operations.LE_MASTER_PEER_REGISTRATION_REQUEST)); // count that a new registration message was sent count++; Thread.Sleep(500); // trigger event in order for a message to be displayed that the // registration could not be completed if (count == 30 && !isRegistered) OnRegistrationResponseReceived(false); } Utils.WriteLine("Registering Thread ended ♥♥♥"); } #endregion /* Send a message Link Establishment message to the desired peer */ public void SendLEMessage(byte[] message, String peerIP, Int32 peerUDPPort) { if (message.Length < 1) return; try { if (udpClient != null) { udpClient.Client.SendTo(message, new IPEndPoint(IPAddress.Parse(peerIP), peerUDPPort)); PrintMessage(message, peerIP, peerUDPPort, false); } } catch (Exception ex) { Utils.WriteLine("Link Establishment Thread Send exception: " + ex.ToString(), ConsoleType.LE); } } /* Send a Link Establishment message to the current Master Peer */ public void SendLEMessage(byte[] message) { SendLEMessage(message, masterPeer.ipAddress, masterPeer.port); } // Create a Link Establishment Response/Request Message based on the Operation type private byte[] createLEMessage(Operations operation) { byte[] response = {}; switch (operation) { #region LE_MASTER_PEER_REGISTRATION_REQUEST /** * This message is used to register with the Master Peer. * A peer sends out an LE_MASTER_PEER_REGISTRATION_REQUEST in one of the * following situations: * 1) When the peer first powers up * 2) When a peer stops receiving keep alive data from another peer * 3) When a peer stops receiving keep alive data from the Master Peer * 4) When the Master Peer fails to respond to a LE_MASTER_PEER_REGISTRATION_REQUEST * * This process stops when one of the following conditions is met: * 1) The peer receives three consecutive LE_MASTER_PEER_REGISTRATION_RESPONSE * messages with link protocol version of zero. The peer uses the IPSC message * with link protocol version of zero to communicate with the Master Peer. * 2) The peer receives a LE_MASTER_PEER_REGISTRATION_RESPONSE message with * link protocol version field. The peer uses the IPSC message with * link protocol version of acceptedLinkProtocolVersion in the * LE_MASTER_PEER_REGISTRATION_RESPONSE to communicate with the Master Peer. * * See page 60-62 from adk_link_establishment_spec_0101 or devspec_link_establishment_0102 */ case Operations.LE_MASTER_PEER_REGISTRATION_REQUEST: { List responseList = new List(); /* 0 - opCode */ responseList.Add((byte) Operations.LE_MASTER_PEER_REGISTRATION_REQUEST); /* 1 - peerID */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); /* 2 - peerID */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); /* 3 - peerID */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); /* 4 - peerID */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); /* 5 - peerMode */ if (systemType != SystemType.LINKED_CAPACITY_PLUS) responseList.Add((byte) myselfPeer.peerMode[0]); else { /* 5 - peerMode */ responseList.Add((byte)myselfPeer.peerMode[1]); /* 6 - peerMode */ responseList.Add((byte)myselfPeer.peerMode[0]); } if (leProtocolVersion == 0) { /* 6 - peerServ */ responseList.Add(myselfPeer.peerServices[1]); /* 7 - peerServ */ responseList.Add(myselfPeer.peerServices[0]); } else { /* IPSC & CPC Vers 1 LCPC */ /* 6 - peerServ */ responseList.Add(myselfPeer.peerServices[3]); /* 7 - peerServ */ /* 7 - peerServ */ responseList.Add(myselfPeer.peerServices[2]); /* 8 - peerServ */ /* 8 - peerServ */ responseList.Add(myselfPeer.peerServices[1]); /* 9 - peerServ */ /* 9 - peerServ */ responseList.Add(myselfPeer.peerServices[0]); /* 10 - peerServ */ } /* LCPC Vers 3 */ /* 11 - leadingChID */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) responseList.Add((byte)myselfPeer.leadingChannelID); if (leProtocolVersion != 0) { /* IPSC & CPC Vers 1 LCPC */ /* 10 - currentVers */ responseList.Add((byte)myselfPeer.currentLinkProtocolVersion[1]); /* 12 - currentVers */ /* 11 - currentVers */ responseList.Add((byte)myselfPeer.currentLinkProtocolVersion[0]); /* 13 - currentVers */ /* 12 - oldestVers */ responseList.Add((byte)myselfPeer.oldestLinkProtocolVersion[1]); /* 14 - oldestVers */ /* 13 - oldestVers */ responseList.Add((byte)myselfPeer.oldestLinkProtocolVersion[0]); /* 15 - oldestVers */ } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion #region LE_MASTER_PEER_REGISTRATION_RESPONSE case Operations.LE_MASTER_PEER_REGISTRATION_RESPONSE: { List responseList = new List(); responseList.Add((byte)Operations.LE_MASTER_PEER_REGISTRATION_RESPONSE); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); if (systemType != SystemType.LINKED_CAPACITY_PLUS) responseList.Add((byte)myselfPeer.peerMode[0]); else { responseList.Add((byte)myselfPeer.peerMode[1]); responseList.Add((byte)myselfPeer.peerMode[0]); } if (leProtocolVersion == 0) { responseList.Add(myselfPeer.peerServices[1]); responseList.Add(myselfPeer.peerServices[0]); } else { responseList.Add(myselfPeer.peerServices[3]); responseList.Add(myselfPeer.peerServices[2]); responseList.Add(myselfPeer.peerServices[1]); responseList.Add(myselfPeer.peerServices[0]); } if (systemType == SystemType.LINKED_CAPACITY_PLUS) responseList.Add((byte)myselfPeer.leadingChannelID); responseList.Add(BitConverter.GetBytes(peersHashTable.Count)[1]); responseList.Add(BitConverter.GetBytes(peersHashTable.Count)[0]); if (leProtocolVersion != 0) { responseList.Add((byte)myselfPeer.currentLinkProtocolVersion[1]); responseList.Add((byte)myselfPeer.currentLinkProtocolVersion[0]); responseList.Add((byte)myselfPeer.oldestLinkProtocolVersion[1]); responseList.Add((byte)myselfPeer.oldestLinkProtocolVersion[0]); } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion #region LE_MASTER_PEER_KEEP_ALIVE_RESPONSE case Operations.LE_MASTER_PEER_KEEP_ALIVE_RESPONSE: { List responseList = new List(); /* opCode */ responseList.Add((byte)Operations.LE_MASTER_PEER_KEEP_ALIVE_RESPONSE); /* ID of the sending peer */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); /* current operating modes of the sending peer */ if (systemType != SystemType.LINKED_CAPACITY_PLUS) responseList.Add((byte)myselfPeer.peerMode[0]); else { responseList.Add((byte)myselfPeer.peerMode[1]); responseList.Add((byte)myselfPeer.peerMode[0]); } /* services supports of the sending peer */ if (leProtocolVersion == 0) { responseList.Add(myselfPeer.peerServices[1]); responseList.Add(myselfPeer.peerServices[0]); } else { responseList.Add(myselfPeer.peerServices[3]); responseList.Add(myselfPeer.peerServices[2]); responseList.Add(myselfPeer.peerServices[1]); responseList.Add(myselfPeer.peerServices[0]); } /* channel ID for slot 1 on trunked and data revert repeaters */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) responseList.Add((byte)myselfPeer.leadingChannelID); /* system type is IPSC or CPC with version 1 , or LCP wit version 3 */ if (leProtocolVersion >= 1) { responseList.Add(myselfPeer.currentLinkProtocolVersion[1]); responseList.Add(myselfPeer.currentLinkProtocolVersion[0]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[1]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[0]); } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion #region LE_MASTER_PEER_KEEP_ALIVE_REQUEST /** * This message is used to request the keep alive with the Master Peer. * A peer sends out this message in one of the following situations: * 1) Upon receiving an LE_NOTIFICATION_MAP_BROADCAST from the Master Peer * 2) Upon receiving an LE_MASTER_PEER_REGISTRATION_RESPONSE from the * Master Peer when the number of linked peers is less than one * 3) Upon receiving an LE_MASTER_PEER_KEEP_ALIVE_RESPONSE from the Master Peer. * 4) Upon the MasterPeer KeepAlive Timer times out. * The LE_MASTER_PEER_KEEP_ALIVE_REQUEST is only sent from a peer to the * Master Peer. However, the LE_MASTER_PEER_KEEP_ALIVE_REQUEST is not * immediately sent following the above messages. Instead, the peer waits a * predetermined amount of time (typical 15s) before proceeding to send the Keep Alive * Request. * The LE_MASTER_PEER_KEEP_ALIVE_REQUEST also contains the peer mode and * peer services fields. The Master Peer uses this information to rebuild the peer map * when it encounters a fault and resets. A peer can also use this information to re-register * with the Master Peer after the fault occurs. * When a peer encounters a fault scenario and resets at the same time as the Master * Peer, it shall attempt to re-register with the Master Peer after resetting. The same is true * for the case when the peer changes its peer mode and/or peer service bits at the same * time as the Master Peer encounters a fault scenario and resets. * After the peer joins the IP Site Connect system, it starts the MasterPeerKeepAlive Timer. * * When the MasterPeerKeepAlive Timer times out, the peer sends * LE_MASTER_PEER_KEEP_ALIVE_REQUEST to the Master Peer. After the peer does * not receive the LE_MASTER_PEER_KEEP_ALIVE_RESPONSE for 3 times * continuously from the Master Peer, the peer considers the link is down and starts the * registration process by sending the LE_MASTER_PEER_REGISTRATION_REQUEST * to the Master Peer. * * There is no limit on the setting of the MasterPeerKeepAlive Timer. The MOTOTRBO * repeaters use 15 seconds for this timer. */ case Operations.LE_MASTER_PEER_KEEP_ALIVE_REQUEST: { List responseList = new List(); /* opCode */ responseList.Add((byte)Operations.LE_MASTER_PEER_KEEP_ALIVE_REQUEST); /* ID of the sending peer */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); /* current operating modes of the sending peer */ if (systemType != SystemType.LINKED_CAPACITY_PLUS) responseList.Add((byte)myselfPeer.peerMode[0]); else { responseList.Add((byte)myselfPeer.peerMode[1]); responseList.Add((byte)myselfPeer.peerMode[0]); } /* services supports of the sending peer */ if (leProtocolVersion == 0) { responseList.Add(myselfPeer.peerServices[1]); responseList.Add(myselfPeer.peerServices[0]); } else { responseList.Add(myselfPeer.peerServices[3]); responseList.Add(myselfPeer.peerServices[2]); responseList.Add(myselfPeer.peerServices[1]); responseList.Add(myselfPeer.peerServices[0]); } /* channel ID for slot 1 on trunked and data revert repeaters */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) responseList.Add((byte)myselfPeer.leadingChannelID); /* system type is IPSC or CPC with version 1 , or LCP wit version 3 */ if (leProtocolVersion >= 1) { responseList.Add(myselfPeer.currentLinkProtocolVersion[1]); responseList.Add(myselfPeer.currentLinkProtocolVersion[0]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[1]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[0]); } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion #region LE_NOTIFICATION_MAP_REQUEST /** * This message is used to request the IP Site Connect System Map, Satellite Map or Vote * Map information. * A peer sends out an LE_NOTIFICATION_MAP_REQUEST in the following situation: * 1) When it receives an LE_MASTER_PEER_REGISTRATION_RESPONSE where * the number of linked peers value is greater than zero. * 2) When it is 3rd Party RDAC Application and established a connection with the * Mast Peer. * For normal Peer, The LE_NOTIFICATION_MAP_REQUEST is sent from a peer to the * Master Peer. The request normally follows an LE_MASTER_PEER_REGISTRATION_ * RESPONSE when there are one or more linked peers in the system. Otherwise, when * the linking peer is the first peer in the system, then notification of the current peer map * is not requested. * The peer map is only requested when updated information about the state of the linked * peers is needed. For example, when a peer stops receiving keep alive data from * another peer for a predetermined amount of time (typical 60s) it sends * LE_MASTER_PEER_REGISTRATION_REQUEST and gets a new peer map to decide * whether this peer has actually become disconnected from the network or simply * changed its IP address or port number. * * See page 66-67 from devspec_link_establishment_0102 */ case Operations.LE_NOTIFICATION_MAP_REQUEST: { List responseList = new List(); /* 0 - opCode */ responseList.Add((byte)Operations.LE_NOTIFICATION_MAP_REQUEST); /* 1-4 : peerID */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); if (systemType == SystemType.LINKED_CAPACITY_PLUS) { responseList.Add((byte)mapType); responseList.Add(myselfPeer.acceptedLinkProtocolVersion[1]); responseList.Add(myselfPeer.acceptedLinkProtocolVersion[0]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[1]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[0]); } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion #region LE_NOTIFICATION_MAP_BROADCAST case Operations.LE_NOTIFICATION_MAP_BROADCAST: { List responseList = new List(); /* 0 - opCode */ responseList.Add((byte)Operations.LE_NOTIFICATION_MAP_BROADCAST); /* 1-4 : peerID */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); if(systemType == SystemType.LINKED_CAPACITY_PLUS) responseList.Add((byte)mapType); // add map length responseList.Add(BitConverter.GetBytes(peersHashTable.Count)[1]); responseList.Add(BitConverter.GetBytes(peersHashTable.Count)[0]); if (peersHashTable.Count > 0) { // later } if (systemType == SystemType.LINKED_CAPACITY_PLUS) { responseList.Add(myselfPeer.acceptedLinkProtocolVersion[1]); responseList.Add(myselfPeer.acceptedLinkProtocolVersion[0]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[1]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[0]); } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion #region LE_PEER_REGISTRATION_REQUEST /** * This message is used to register with another peer. * A peer sends out an LE_PEER_REGISTRATION_REQUEST to another peer in the * following situation: * 1) Upon receiving an LE_NOTIFICATION_MAP_BROADCAST identifying new or updated peers * The LE_PEER_REGISTRATION_REQUEST is only sent from one peer to another * peer, but not to the Master Peer. When a new peer map from the Master Peer identifies * a newly linked peer or a peer with new IP address or port number, it shall attempt to * establish a link based on the latest information. After the peer sends * LE_PEER_REGISTRATION_REQUEST, it starts the PeerRegister Timer. If another peer fails * to respond the LE_PEER_REGISTRATION_REQUEST before timeout, the peer will resend * the LE_PEER_REGISTRATION_REQUEST. * * If the peer’s current link protocol version is higher than zero and supports the link * protocol version of zero, when it receives LE_PEER_REGISTRATION_REQUEST * without link protocol version field, it shall take the following actions: * 1) Send the LE_PEER_REGISTRATION_RESP without link protocol version field * 2) Stop the current PeerRegister Timer for the LE_PEER_REGISTRATION_REQUEST with * link protocol version field * 3) Send the LE_PEER_REGISTRATION_REQUEST without link protocol version field. * 4) Start the PeerRegister Timer * There is no limit on the setting of the PeerRegister Timer. The MOTOTRBO repeaters * use 1 second for this timer. * * See page 72-73 from devspec_link_establishment_0102 */ case Operations.LE_PEER_REGISTRATION_REQUEST: { List responseList = new List(); /* 0 - opCode */ responseList.Add((byte)Operations.LE_PEER_REGISTRATION_REQUEST); /* 1-4 : peerID */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); /* system type is IPSC or CPC with version 1 , or LCP wit version 3 */ if (leProtocolVersion >= 1) { responseList.Add(myselfPeer.currentLinkProtocolVersion[1]); responseList.Add(myselfPeer.currentLinkProtocolVersion[0]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[1]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[0]); } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion #region LE_PEER_REGISTRATION_RESPONSE case Operations.LE_PEER_REGISTRATION_RESPONSE: { List responseList = new List(); /* opCode */ responseList.Add((byte)Operations.LE_PEER_REGISTRATION_RESPONSE); /* ID of the sending peer */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); /* system type is IPSC or CPC with version 1 , or LCP wit version 3 */ if (leProtocolVersion >= 1) { /* responseList.Add(0x04); responseList.Add(0x06); responseList.Add(0x04); responseList.Add(0x04); */ responseList.Add(myselfPeer.acceptedLinkProtocolVersion[1]); responseList.Add(myselfPeer.acceptedLinkProtocolVersion[0]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[1]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[0]); } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion #region LE_PEER_KEEP_ALIVE_REQUEST case Operations.LE_PEER_KEEP_ALIVE_REQUEST: { List responseList = new List(); /* opCode */ responseList.Add((byte)Operations.LE_PEER_KEEP_ALIVE_REQUEST); /* ID of the sending peer */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); /* current operating modes of the sending peer */ if (systemType != SystemType.LINKED_CAPACITY_PLUS) responseList.Add((byte)myselfPeer.peerMode[0]); else { responseList.Add((byte)myselfPeer.peerMode[0]); responseList.Add((byte)myselfPeer.peerMode[1]); } /* services supports of the sending peer */ if (leProtocolVersion == 0) //|| systemType != SystemType.LINKED_CAPACITY_PLUS) { responseList.Add(myselfPeer.peerServices[1]); responseList.Add(myselfPeer.peerServices[0]); } else { responseList.Add(myselfPeer.peerServices[3]); responseList.Add(myselfPeer.peerServices[2]); responseList.Add(myselfPeer.peerServices[1]); responseList.Add(myselfPeer.peerServices[0]); } /* system type is IPSC */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) { responseList.Add(myselfPeer.currentLinkProtocolVersion[1]); responseList.Add(myselfPeer.currentLinkProtocolVersion[0]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[1]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[0]); } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion #region LE_PEER_KEEP_ALIVE_RESPONSE case Operations.LE_PEER_KEEP_ALIVE_RESPONSE: { List responseList = new List(); /* opCode */ responseList.Add((byte)Operations.LE_PEER_KEEP_ALIVE_RESPONSE); /* ID of the sending peer */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); /* current operating modes of the sending peer */ if (systemType != SystemType.LINKED_CAPACITY_PLUS) responseList.Add((byte)myselfPeer.peerMode[0]); else { responseList.Add((byte)myselfPeer.peerMode[0]); responseList.Add((byte)myselfPeer.peerMode[1]); } /* services supports of the sending peer */ if (leProtocolVersion == 0) //|| systemType != SystemType.LINKED_CAPACITY_PLUS) { responseList.Add(myselfPeer.peerServices[1]); responseList.Add(myselfPeer.peerServices[0]); } else { responseList.Add(myselfPeer.peerServices[3]); responseList.Add(myselfPeer.peerServices[2]); responseList.Add(myselfPeer.peerServices[1]); responseList.Add(myselfPeer.peerServices[0]); } /* system type is IPSC */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) { responseList.Add(myselfPeer.currentLinkProtocolVersion[1]); responseList.Add(myselfPeer.currentLinkProtocolVersion[0]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[1]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[0]); } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion #region LE_DEREGISTRATION_REQUEST case Operations.LE_DEREGISTRATION_REQUEST: { List responseList = new List(); /* opCode */ responseList.Add((byte)Operations.LE_PEER_KEEP_ALIVE_REQUEST); /* ID of the sending peer */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); /* system type is IPSC */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) { responseList.Add(myselfPeer.currentLinkProtocolVersion[1]); responseList.Add(myselfPeer.currentLinkProtocolVersion[0]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[1]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[0]); } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion #region LE_DEREGISTRATION_RESPONSE case Operations.LE_DEREGISTRATION_RESPONSE: { List responseList = new List(); /* opCode */ responseList.Add((byte)Operations.LE_PEER_KEEP_ALIVE_RESPONSE); /* ID of the sending peer */ responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[3]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[2]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[1]); responseList.Add(BitConverter.GetBytes(myselfPeer.peerID)[0]); /* system type is IPSC */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) { responseList.Add(myselfPeer.currentLinkProtocolVersion[1]); responseList.Add(myselfPeer.currentLinkProtocolVersion[0]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[1]); responseList.Add(myselfPeer.oldestLinkProtocolVersion[0]); } // convert the list of bytes to a byte array response = new byte[responseList.Count]; for (int i = 0; i < responseList.Count; i++) response[i] = responseList[i]; break; } #endregion } return response; } // Decore a message received from a peer public void decode(byte[] toDecode, string peerIP, Int32 peerPort) { int crtPosition = 0; byte opCode = toDecode[crtPosition++]; /* get sender peerID */ byte[] senderPeerID = new byte[4]; senderPeerID[3] = toDecode[crtPosition++]; senderPeerID[2] = toDecode[crtPosition++]; senderPeerID[1] = toDecode[crtPosition++]; senderPeerID[0] = toDecode[crtPosition++]; peerPort = GetPeerPortFromID(BitConverter.ToInt32(senderPeerID, 0)); // print the message in the Console PrintMessage(toDecode, peerIP, peerPort, true); switch (opCode) { // received a wireline message case 0xB2: OnWirelineMessageReceived(toDecode, peerIP, peerPort); break; #region LE_MASTER_PEER_REGISTRATION_REQUEST case (byte)Operations.LE_MASTER_PEER_REGISTRATION_REQUEST: { byte[] peerID = { 0x00, 0x00, 0x00, 0x00 }; // Valid range 0x000001 to 0x0x00FFFCDF byte[] peerMode = { 0x00, 0x00 }; /* get peerID */ peerID[3] = senderPeerID[3]; peerID[2] = senderPeerID[2]; peerID[1] = senderPeerID[1]; peerID[0] = senderPeerID[0]; /* Utils.WriteLine("Peer ID: " + masterPeer.peerID + " [" + BitConverter.ToString(masterPeerID.Reverse().ToArray(), 0) + "]"); */ /* get peerMode */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) { peerMode[1] = toDecode[crtPosition++]; peerMode[0] = toDecode[crtPosition++]; } else { peerMode[1] = 0x00; peerMode[0] = toDecode[crtPosition++]; } /* get peer Service */ if (leProtocolVersion == 0) { masterPeer.peerServices[3] = (byte)0x00; masterPeer.peerServices[2] = (byte)0x00; masterPeer.peerServices[1] = toDecode[crtPosition++]; masterPeer.peerServices[0] = toDecode[crtPosition++]; } else { masterPeer.peerServices[3] = toDecode[crtPosition++]; masterPeer.peerServices[2] = toDecode[crtPosition++]; masterPeer.peerServices[1] = toDecode[crtPosition++]; masterPeer.peerServices[0] = toDecode[crtPosition++]; } /* Utils.WriteLine("Peer Services: " + BitConverter.ToString(masterPeer.peerServices.Reverse().ToArray(), 0)); */ /* The channel ID for slot 1 on trunked and data revert repeaters */ if (leProtocolVersion >= 3 && systemType == SystemType.LINKED_CAPACITY_PLUS) { int leadingChannelID = toDecode[crtPosition++]; } /* Field that represents the common protocol version accepted for messaging between peers */ byte[] acceptedLinkProtocolVersion = new byte[2]; byte[] oldestLinkProtocolVersion = new byte[2]; if (leProtocolVersion != 0) { acceptedLinkProtocolVersion[1] = toDecode[crtPosition++]; acceptedLinkProtocolVersion[0] = toDecode[crtPosition++]; } /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ if (leProtocolVersion != 0) { oldestLinkProtocolVersion[1] = toDecode[crtPosition++]; oldestLinkProtocolVersion[0] = toDecode[crtPosition++]; } OnMasterRegistrationRequestReceived(peerID, peerIP, peerPort); break; } #endregion #region LE_MASTER_PEER_REGISTRATION_RESPONSE case (byte)Operations.LE_MASTER_PEER_REGISTRATION_RESPONSE: { byte[] masterPeerID = { 0x00, 0x00, 0x00, 0x00 }; // Valid range 0x000001 to 0x0x00FFFCDF byte[] masterPeerMode = { 0x00, 0x00 }; /* get peerID */ masterPeerID[3] = senderPeerID[3]; masterPeerID[2] = senderPeerID[2]; masterPeerID[1] = senderPeerID[1]; masterPeerID[0] = senderPeerID[0]; masterPeer.peerID = BitConverter.ToUInt32(masterPeerID, 0); // update the protocol version SetCurrentAndOldestLinkProtocolVersion(); /* Utils.WriteLine("Peer ID: " + masterPeer.peerID + " [" + BitConverter.ToString(masterPeerID.Reverse().ToArray(), 0) + "]"); */ /* get peerMode */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) { masterPeer.SetPeerMode(systemType, toDecode[crtPosition++] * 256 + toDecode[crtPosition++]); } else { masterPeer.SetPeerMode(systemType, toDecode[crtPosition++]); } /* get peer Service */ if (leProtocolVersion == 0) { masterPeer.peerServices[3] = (byte)0x00; masterPeer.peerServices[2] = (byte)0x00; masterPeer.peerServices[1] = toDecode[crtPosition++]; masterPeer.peerServices[0] = toDecode[crtPosition++]; } else { masterPeer.peerServices[3] = toDecode[crtPosition++]; masterPeer.peerServices[2] = toDecode[crtPosition++]; masterPeer.peerServices[1] = toDecode[crtPosition++]; masterPeer.peerServices[0] = toDecode[crtPosition++]; } /* Utils.WriteLine("Peer Services: " + BitConverter.ToString(masterPeer.peerServices.Reverse().ToArray(), 0)); */ /* The channel ID for slot 1 on trunked and data revert repeaters */ if(leProtocolVersion >= 3 && systemType == SystemType.LINKED_CAPACITY_PLUS) masterPeer.leadingChannelID = toDecode[crtPosition++]; /* Number of peers that have established links with the Master Peer */ numPeers = toDecode[crtPosition++] * 256 + toDecode[crtPosition++]; //Utils.WriteLine("Master Peer number of peers is " + numPeers); /* Field that represents the common protocol version accepted for messaging between peers */ if (leProtocolVersion != 0) { masterPeer.acceptedLinkProtocolVersion[1] = toDecode[crtPosition++]; masterPeer.acceptedLinkProtocolVersion[0] = toDecode[crtPosition++]; // I will accept the same link protocol version as the master peer myselfPeer.acceptedLinkProtocolVersion[1] = masterPeer.acceptedLinkProtocolVersion[1]; myselfPeer.acceptedLinkProtocolVersion[0] = masterPeer.acceptedLinkProtocolVersion[0]; /* Utils.WriteLine("Accepted Link Protocol Version: " + BitConverter.ToString(masterPeer.acceptedLinkProtocolVersion.Reverse().ToArray(), 0)); */ } /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ if (leProtocolVersion != 0) { masterPeer.oldestLinkProtocolVersion[1] = toDecode[crtPosition++]; masterPeer.oldestLinkProtocolVersion[0] = toDecode[crtPosition++]; /* Utils.WriteLine("Oldest Link Protocol Version: " + BitConverter.ToString(masterPeer.oldestLinkProtocolVersion.Reverse().ToArray(), 0)); */ } Utils.WriteLine(String.Format("\tMaster Peer ID: {0}", masterPeer.peerID)); Utils.WriteLine(String.Format("\tNumber of peers: {0}", numPeers)); //if (masterPeer.oldestLinkProtocolVersion[0] == 0 && !registrationResent) { /* // resend with new accepter Link Protocol Version Thread.Sleep(1200); registrationResent = true; myselfPeer.SetPeerMode(SystemType.IP_SITE_CONNECT, 0x40); myselfPeer.SetPeerServices(SystemType.IP_SITE_CONNECT, 0x6020); myselfPeer.oldestLinkProtocolVersion[1] = 0x4; myselfPeer.oldestLinkProtocolVersion[0] = 0x3; //SendLEMessage(createLEMessage(Operations.LE_MASTER_PEER_REGISTRATION_REQUEST)); */ // flag that this connection is Alive by faking a KeepAlive response lastKeepAliveResponseTime = DateTime.Now; lastKeepAliveRequestTime = DateTime.Now; // flag that the peer is not registered with the master peer isRegistered = true; // start Keep Alive Threads if (!keepAliveThread.IsAlive) { keepAliveThread = new Thread(new ThreadStart(MasterKeepAliveHandler)); keepAliveThread.Start(); } //peersKeepAliveThread.Start(); OnRegistrationResponseReceived(true); } /* else OnRegistrationResponseReceived(false); */ break; } #endregion #region LE_MASTER_PEER_KEEP_ALIVE_REQUEST case (byte)Operations.LE_MASTER_PEER_KEEP_ALIVE_REQUEST: { /* get peerID */ byte[] remotePeerID = new byte[4]; remotePeerID[3] = senderPeerID[3]; remotePeerID[2] = senderPeerID[2]; remotePeerID[1] = senderPeerID[1]; remotePeerID[0] = senderPeerID[0]; /* get peerMode */ byte[] peerMode = new byte[2]; if (systemType == SystemType.LINKED_CAPACITY_PLUS) { peerMode[1] = toDecode[crtPosition++]; peerMode[0] = toDecode[crtPosition++]; } else { peerMode[1] = (byte)0x00; peerMode[0] = toDecode[crtPosition++]; } /* get peer Service */ byte[] peerServices = new byte[4]; if (leProtocolVersion == 0) { peerServices[3] = (byte)0x00; peerServices[2] = (byte)0x00; peerServices[1] = toDecode[crtPosition++]; peerServices[0] = toDecode[crtPosition++]; } else { peerServices[3] = toDecode[crtPosition++]; peerServices[2] = toDecode[crtPosition++]; peerServices[1] = toDecode[crtPosition++]; peerServices[0] = toDecode[crtPosition++]; } /* The channel ID for slot 1 on trunked and data revert repeaters */ int leadingChannelID = 0; if (systemType == SystemType.LINKED_CAPACITY_PLUS) leadingChannelID = toDecode[crtPosition++]; /* Field that represents the common protocol version accepted for messaging between peers */ byte[] acceptedLinkProtocolVersion = new byte[2]; byte[] currentLinkProtocolVersion = new byte[2]; if (leProtocolVersion != 0) { if (systemType != SystemType.IP_SITE_CONNECT) { acceptedLinkProtocolVersion[1] = toDecode[crtPosition++]; acceptedLinkProtocolVersion[0] = toDecode[crtPosition++]; } else { currentLinkProtocolVersion[1] = toDecode[crtPosition++]; currentLinkProtocolVersion[0] = toDecode[crtPosition++]; } } /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ byte[] oldestLinkProtocolVersion = new byte[2]; if (leProtocolVersion != 0) { oldestLinkProtocolVersion[1] = toDecode[crtPosition++]; oldestLinkProtocolVersion[0] = toDecode[crtPosition++]; } // trigger event for Master Keep Alive Request Received OnMasterKeepAliveRequestReceived(remotePeerID, peerIP, peerPort); break; } #endregion #region LE_MASTER_PEER_KEEP_ALIVE_RESPONSE case (byte)Operations.LE_MASTER_PEER_KEEP_ALIVE_RESPONSE: { // update last Keep Alive Response Time lastKeepAliveResponseTime = DateTime.Now; /* get peerID */ byte[] remotePeerID = new byte[4]; remotePeerID[3] = senderPeerID[3]; remotePeerID[2] = senderPeerID[2]; remotePeerID[1] = senderPeerID[1]; remotePeerID[0] = senderPeerID[0]; /* get peerMode */ byte[] peerMode = new byte[2]; if (systemType == SystemType.LINKED_CAPACITY_PLUS) { peerMode[1] = toDecode[crtPosition++]; peerMode[0] = toDecode[crtPosition++]; } else { peerMode[1] = (byte)0x00; peerMode[0] = toDecode[crtPosition++]; } /* get peer Service */ byte[] peerServices = new byte[4]; if (leProtocolVersion == 0) { peerServices[3] = (byte)0x00; peerServices[2] = (byte)0x00; peerServices[1] = toDecode[crtPosition++]; peerServices[0] = toDecode[crtPosition++]; } else { peerServices[3] = toDecode[crtPosition++]; peerServices[2] = toDecode[crtPosition++]; peerServices[1] = toDecode[crtPosition++]; peerServices[0] = toDecode[crtPosition++]; } /* The channel ID for slot 1 on trunked and data revert repeaters */ int leadingChannelID = 0; if (systemType == SystemType.LINKED_CAPACITY_PLUS) leadingChannelID = toDecode[crtPosition++]; /* Field that represents the common protocol version accepted for messaging between peers */ byte[] acceptedLinkProtocolVersion = new byte[2]; byte[] currentLinkProtocolVersion = new byte[2]; if (leProtocolVersion != 0) { if (systemType != SystemType.IP_SITE_CONNECT) { acceptedLinkProtocolVersion[1] = toDecode[crtPosition++]; acceptedLinkProtocolVersion[0] = toDecode[crtPosition++]; } else { currentLinkProtocolVersion[1] = toDecode[crtPosition++]; currentLinkProtocolVersion[0] = toDecode[crtPosition++]; } } /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ byte[] oldestLinkProtocolVersion = new byte[2]; if (leProtocolVersion != 0) { oldestLinkProtocolVersion[1] = toDecode[crtPosition++]; oldestLinkProtocolVersion[0] = toDecode[crtPosition++]; } break; } #endregion #region LE_NOTIFICATION_MAP_REQUEST case (byte)Operations.LE_NOTIFICATION_MAP_REQUEST: { /* get peerID */ byte[] remotePeerID = new byte[4]; remotePeerID[3] = senderPeerID[3]; remotePeerID[2] = senderPeerID[2]; remotePeerID[1] = senderPeerID[1]; remotePeerID[0] = senderPeerID[0]; /* map Type */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) mapType = toDecode[crtPosition++]; /* Field that represents the common protocol version accepted for messaging between peers */ byte[] acceptedLinkProtocolVersion = new byte[2]; acceptedLinkProtocolVersion[1] = toDecode[crtPosition++]; acceptedLinkProtocolVersion[0] = toDecode[crtPosition++]; /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ byte[] oldestLinkProtocolVersion = new byte[2]; oldestLinkProtocolVersion[1] = toDecode[crtPosition++]; oldestLinkProtocolVersion[0] = toDecode[crtPosition++]; // trigger event for map request received OnMapRequestReceived(remotePeerID, peerIP, peerPort); break; } #endregion #region LE_NOTIFICATION_MAP_BROADCAST /** * Warnings * The master peer in the LCP system always sends two * LE_NOTIFICATION_MAP_BROADCAST messages: one for the system wide map, and * the other for the master peer programming map. */ case (byte)Operations.LE_NOTIFICATION_MAP_BROADCAST: { /* get peerID */ byte[] masterPeerID = new byte[4]; masterPeerID[3] = senderPeerID[3]; masterPeerID[2] = senderPeerID[2]; masterPeerID[1] = senderPeerID[1]; masterPeerID[0] = senderPeerID[0]; /* map Type */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) mapType = toDecode[crtPosition++]; /* map Length */ int mapLength = toDecode[crtPosition++] * 256 + toDecode[crtPosition++]; if (leProtocolVersion >= 0 && systemType != SystemType.LINKED_CAPACITY_PLUS) { while (crtPosition < toDecode.Length) { try { Peer peer = new Peer(); // ID of the peer that established a link to the Master Peer peer.peerID = toDecode[crtPosition++] * 256 * 256 * 256 + toDecode[crtPosition++] * 256 * 256 + toDecode[crtPosition++] * 256 + toDecode[crtPosition++]; // IP address of this peer as seen to the public internet (i.e. router address) peer.ipAddress = toDecode[crtPosition++] + "." + toDecode[crtPosition++] + "." + toDecode[crtPosition++] + "." + toDecode[crtPosition++]; // port address of this peer as seen to the public internet (i.e. router port) peer.port = toDecode[crtPosition++] * 256 + toDecode[crtPosition++]; // represents the current operating modes of the peer peer.SetPeerMode(systemType, toDecode[crtPosition++]); //Utils.WriteLine(peer.ToString()); // do not add myself to the list if (peer.peerID == myselfPeer.peerID) continue; // add or update the peer if (!peersHashTable.ContainsKey(peer.peerID)) peersHashTable.Add(peer.peerID, peer); else { // update the peer peersHashTable[peer.peerID] = peer; } } catch (Exception ex) { //Utils.WriteLine("LE_NOTIFICATION_MAP_BROADCAST Exception: " + ex.ToString()); } } } // Linked Capacity Plus else if (leProtocolVersion == 3) { while (crtPosition <= mapLength + 7) { try { Peer peer = new Peer(); // ID of the peer that established a link to the Master Peer peer.peerID = toDecode[crtPosition++] * 256 * 256 * 256 + toDecode[crtPosition++] * 256 * 256 + toDecode[crtPosition++] * 256 + toDecode[crtPosition++]; // IP address of this peer as seen to the public internet (i.e. router address) peer.ipAddress = toDecode[crtPosition++] + "." + toDecode[crtPosition++] + "." + toDecode[crtPosition++] + "." + toDecode[crtPosition++]; // port address of this peer as seen to the public internet (i.e. router port) peer.port = toDecode[crtPosition++] * 256 + toDecode[crtPosition++]; // represents the current operating modes of the peer peer.SetPeerMode(systemType, toDecode[crtPosition++] * 256 + toDecode[crtPosition++]); //The channel ID for slot 1 on trunked and data revert repeaters peer.leadingChannelID = toDecode[crtPosition++]; // do not add myself to the list if (peer.peerID == myselfPeer.peerID) continue; // add or update the peer if (!peersHashTable.ContainsKey(peer.peerID)) peersHashTable.Add(peer.peerID, peer); else { // update the peer peersHashTable[peer.peerID] = peer; } } catch (Exception ex) { //Utils.WriteLine("LE_NOTIFICATION_MAP_BROADCAST Exception: " + ex.ToString()); } } /* Field that represents the common protocol version accepted for messaging between peers */ byte[] acceptedLinkProtocolVersion = new byte[2]; acceptedLinkProtocolVersion[1] = toDecode[crtPosition++]; acceptedLinkProtocolVersion[0] = toDecode[crtPosition++]; /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ byte[] oldestLinkProtocolVersion = new byte[2]; oldestLinkProtocolVersion[1] = toDecode[crtPosition++]; oldestLinkProtocolVersion[0] = toDecode[crtPosition++]; } break; } #endregion #region LE_PEER_REGISTRATION_REQUEST case (byte)Operations.LE_PEER_REGISTRATION_REQUEST: { Peer peer = new Peer(); peer.ipAddress = peerIP; peer.port = peerPort; /* get peerID */ byte[] remotePeerID = new byte[4]; remotePeerID[3] = senderPeerID[3]; remotePeerID[2] = senderPeerID[2]; remotePeerID[1] = senderPeerID[1]; remotePeerID[0] = senderPeerID[0]; peer.peerID = BitConverter.ToUInt32(remotePeerID, 0); /* Field that represents the common protocol version accepted for messaging between peers */ byte[] currentLinkProtocolVersion = new byte[2]; if (leProtocolVersion != 0) { currentLinkProtocolVersion[1] = toDecode[crtPosition++]; currentLinkProtocolVersion[0] = toDecode[crtPosition++]; /* Utils.WriteLine("Peer's Current Link Protocol Version: " + BitConverter.ToString(currentLinkProtocolVersion.Reverse().ToArray(), 0)); */ } /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ byte[] oldestLinkProtocolVersion = new byte[2]; if (leProtocolVersion != 0) { oldestLinkProtocolVersion[1] = toDecode[crtPosition++]; oldestLinkProtocolVersion[0] = toDecode[crtPosition++]; /* Utils.WriteLine("Peer's Oldest Link Protocol Version: " + BitConverter.ToString(oldestLinkProtocolVersion.Reverse().ToArray(), 0)); */ } peer.oldestLinkProtocolVersion = oldestLinkProtocolVersion; peer.currentLinkProtocolVersion = currentLinkProtocolVersion; // add or update the peer if (!peersHashTable.ContainsKey(peer.peerID)) peersHashTable.Add(peer.peerID, peer); else { // update the peer Peer hashPeer = (Peer)peersHashTable[peer.peerID]; hashPeer.currentLinkProtocolVersion = peer.currentLinkProtocolVersion; hashPeer.oldestLinkProtocolVersion = oldestLinkProtocolVersion; } try { OnPeerRegistrationRequestReceived(remotePeerID, peerIP, peerPort); } // no listener was added catch (NullReferenceException) { } break; } #endregion #region LE_PEER_REGISTRATION_RESPONSE case (byte)Operations.LE_PEER_REGISTRATION_RESPONSE: { Peer peer = new Peer(); peer.ipAddress = peerIP; peer.port = peerPort; /* get peerID */ byte[] remotePeerID = new byte[4]; remotePeerID[3] = senderPeerID[3]; remotePeerID[2] = senderPeerID[2]; remotePeerID[1] = senderPeerID[1]; remotePeerID[0] = senderPeerID[0]; peer.peerID = BitConverter.ToUInt32(remotePeerID, 0); /* Field that represents the common protocol version accepted for messaging between peers */ byte[] currentLinkProtocolVersion = new byte[2]; if (leProtocolVersion != 0) { currentLinkProtocolVersion[1] = toDecode[crtPosition++]; currentLinkProtocolVersion[0] = toDecode[crtPosition++]; } /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ byte[] acceptedLinkProtocolVersion = new byte[2]; if (leProtocolVersion != 0) { acceptedLinkProtocolVersion[1] = toDecode[crtPosition++]; acceptedLinkProtocolVersion[0] = toDecode[crtPosition++]; } peer.acceptedLinkProtocolVersion = acceptedLinkProtocolVersion; peer.currentLinkProtocolVersion = currentLinkProtocolVersion; // add or update the peer if (!peersHashTable.ContainsKey(peer.peerID)) peersHashTable.Add(peer.peerID, peer); else { // update the peer Peer hashPeer = (Peer)peersHashTable[peer.peerID]; hashPeer.currentLinkProtocolVersion = peer.currentLinkProtocolVersion; hashPeer.acceptedLinkProtocolVersion = peer.acceptedLinkProtocolVersion; } // send keep alive message //SendLEMessage(createLEMessage(Operations.LE_PEER_KEEP_ALIVE_REQUEST), peerIP, peerPort); break; } #endregion #region LE_PEER_KEEP_ALIVE_REQUEST case (byte)Operations.LE_PEER_KEEP_ALIVE_REQUEST: { Peer peer = new Peer(); peer.ipAddress = peerIP; peer.port = peerPort; /* get peerID */ byte[] remotePeerID = new byte[4]; remotePeerID[3] = senderPeerID[3]; remotePeerID[2] = senderPeerID[2]; remotePeerID[1] = senderPeerID[1]; remotePeerID[0] = senderPeerID[0]; peer.peerID = BitConverter.ToUInt32(remotePeerID, 0); /* get peerMode */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) { peer.peerMode[1] = toDecode[crtPosition++]; peer.peerMode[0] = toDecode[crtPosition++]; } else { peer.peerMode[1] = (byte)0x00; peer.peerMode[0] = toDecode[crtPosition++]; } /* get peer Service */ if (leProtocolVersion == 0) { peer.peerServices[3] = (byte)0x00; peer.peerServices[2] = (byte)0x00; peer.peerServices[1] = toDecode[crtPosition++]; peer.peerServices[0] = toDecode[crtPosition++]; } else { peer.peerServices[3] = toDecode[crtPosition++]; peer.peerServices[2] = toDecode[crtPosition++]; peer.peerServices[1] = toDecode[crtPosition++]; peer.peerServices[0] = toDecode[crtPosition++]; } /* Field that represents the common protocol version accepted for messaging between peers */ byte[] currentLinkProtocolVersion = new byte[2]; if (systemType == SystemType.LINKED_CAPACITY_PLUS) { currentLinkProtocolVersion[1] = toDecode[crtPosition++]; currentLinkProtocolVersion[0] = toDecode[crtPosition++]; } /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ byte[] oldestLinkProtocolVersion = new byte[2]; if (systemType == SystemType.LINKED_CAPACITY_PLUS) { oldestLinkProtocolVersion[1] = toDecode[crtPosition++]; oldestLinkProtocolVersion[0] = toDecode[crtPosition++]; } peer.oldestLinkProtocolVersion = oldestLinkProtocolVersion; peer.currentLinkProtocolVersion = currentLinkProtocolVersion; // trigger event OnPeerKeepAliveRequestReceived(remotePeerID, peer.ipAddress, peer.port); break; } #endregion #region LE_PEER_KEEP_ALIVE_RESPONSE case (byte)Operations.LE_PEER_KEEP_ALIVE_RESPONSE: { Peer peer = new Peer(); peer.ipAddress = peerIP; peer.port = peerPort; /* get peerID */ byte[] remotePeerID = new byte[4]; remotePeerID[3] = senderPeerID[3]; remotePeerID[2] = senderPeerID[2]; remotePeerID[1] = senderPeerID[1]; remotePeerID[0] = senderPeerID[0]; peer.peerID = BitConverter.ToUInt32(remotePeerID, 0); /* get peerMode */ if (systemType == SystemType.LINKED_CAPACITY_PLUS) { peer.peerMode[1] = toDecode[crtPosition++]; peer.peerMode[0] = toDecode[crtPosition++]; } else { peer.peerMode[1] = (byte)0x00; peer.peerMode[0] = toDecode[crtPosition++]; } /* get peer Service */ if (leProtocolVersion == 0) { peer.peerServices[3] = (byte)0x00; peer.peerServices[2] = (byte)0x00; peer.peerServices[1] = toDecode[crtPosition++]; peer.peerServices[0] = toDecode[crtPosition++]; } else { peer.peerServices[3] = toDecode[crtPosition++]; peer.peerServices[2] = toDecode[crtPosition++]; peer.peerServices[1] = toDecode[crtPosition++]; peer.peerServices[0] = toDecode[crtPosition++]; } /* Field that represents the common protocol version accepted for messaging between peers */ byte[] currentLinkProtocolVersion = new byte[2]; if (systemType == SystemType.LINKED_CAPACITY_PLUS) { currentLinkProtocolVersion[1] = toDecode[crtPosition++]; currentLinkProtocolVersion[0] = toDecode[crtPosition++]; } /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ byte[] oldestLinkProtocolVersion = new byte[2]; if (systemType == SystemType.LINKED_CAPACITY_PLUS) { oldestLinkProtocolVersion[1] = toDecode[crtPosition++]; oldestLinkProtocolVersion[0] = toDecode[crtPosition++]; } peer.oldestLinkProtocolVersion = oldestLinkProtocolVersion; peer.currentLinkProtocolVersion = currentLinkProtocolVersion; // trigger event OnPeerKeepAliveResponseReceived(remotePeerID, peer.ipAddress, peer.port); break; } #endregion #region LE_DEREGISTRATION_REQUEST case (byte)Operations.LE_DEREGISTRATION_REQUEST: { Peer peer = new Peer(); peer.ipAddress = peerIP; peer.port = peerPort; /* get peerID */ byte[] remotePeerID = new byte[4]; remotePeerID[3] = senderPeerID[3]; remotePeerID[2] = senderPeerID[2]; remotePeerID[1] = senderPeerID[1]; remotePeerID[0] = senderPeerID[0]; peer.peerID = BitConverter.ToUInt32(remotePeerID, 0); /* Field that represents the common protocol version accepted for messaging between peers */ byte[] currentLinkProtocolVersion = new byte[2]; if (systemType == SystemType.LINKED_CAPACITY_PLUS) { currentLinkProtocolVersion[1] = toDecode[crtPosition++]; currentLinkProtocolVersion[0] = toDecode[crtPosition++]; } /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ byte[] oldestLinkProtocolVersion = new byte[2]; if (systemType == SystemType.LINKED_CAPACITY_PLUS) { oldestLinkProtocolVersion[1] = toDecode[crtPosition++]; oldestLinkProtocolVersion[0] = toDecode[crtPosition++]; } peer.oldestLinkProtocolVersion = oldestLinkProtocolVersion; peer.currentLinkProtocolVersion = currentLinkProtocolVersion; break; } #endregion #region LE_DEREGISTRATION_RESPONSE case (byte)Operations.LE_DEREGISTRATION_RESPONSE: { Peer peer = new Peer(); peer.ipAddress = peerIP; peer.port = peerPort; /* get peerID */ byte[] remotePeerID = new byte[4]; remotePeerID[3] = senderPeerID[3]; remotePeerID[2] = senderPeerID[2]; remotePeerID[1] = senderPeerID[1]; remotePeerID[0] = senderPeerID[0]; peer.peerID = BitConverter.ToUInt32(remotePeerID, 0); /* Field that represents the common protocol version accepted for messaging between peers */ byte[] currentLinkProtocolVersion = new byte[2]; if (systemType == SystemType.LINKED_CAPACITY_PLUS) { currentLinkProtocolVersion[1] = toDecode[crtPosition++]; currentLinkProtocolVersion[0] = toDecode[crtPosition++]; } /* Field that represents the oldest working protocol version that the peer can support exchanging with another peer */ byte[] oldestLinkProtocolVersion = new byte[2]; if (systemType == SystemType.LINKED_CAPACITY_PLUS) { oldestLinkProtocolVersion[1] = toDecode[crtPosition++]; oldestLinkProtocolVersion[0] = toDecode[crtPosition++]; } peer.oldestLinkProtocolVersion = oldestLinkProtocolVersion; peer.currentLinkProtocolVersion = currentLinkProtocolVersion; break; } #endregion } } private Int32 GetPeerPortFromID(Int32 peerID) { // get sender port from peers list based on it's ID lock (peersHashTable.SyncRoot) { foreach (DictionaryEntry entry in peersHashTable) { Peer peer = (Peer)entry.Value; if (peer.peerID == peerID) return peer.port; } } return masterPeer.port; } // Get a string that represents the Message Type based on the opCode private string GetMessageType(byte opCode) { switch (opCode) { case (byte)Operations.LE_DEREGISTRATION_REQUEST: return Operations.LE_DEREGISTRATION_REQUEST.ToString(); case (byte)Operations.LE_DEREGISTRATION_RESPONSE: return Operations.LE_DEREGISTRATION_RESPONSE.ToString(); case (byte)Operations.LE_DIGITALVOTING_MAP_BROADCAST: return Operations.LE_DIGITALVOTING_MAP_BROADCAST.ToString(); case (byte)Operations.LE_MASTER_PEER_KEEP_ALIVE_REQUEST: return Operations.LE_MASTER_PEER_KEEP_ALIVE_REQUEST.ToString(); case (byte)Operations.LE_MASTER_PEER_KEEP_ALIVE_RESPONSE: return Operations.LE_MASTER_PEER_KEEP_ALIVE_RESPONSE.ToString(); case (byte)Operations.LE_MASTER_PEER_REGISTRATION_REQUEST: return Operations.LE_MASTER_PEER_REGISTRATION_REQUEST.ToString(); case (byte)Operations.LE_MASTER_PEER_REGISTRATION_RESPONSE: return Operations.LE_MASTER_PEER_REGISTRATION_RESPONSE.ToString(); case (byte)Operations.LE_NOTIFICATION_MAP_BROADCAST: return Operations.LE_NOTIFICATION_MAP_BROADCAST.ToString(); case (byte)Operations.LE_NOTIFICATION_MAP_REQUEST: return Operations.LE_NOTIFICATION_MAP_REQUEST.ToString(); case (byte)Operations.LE_PEER_KEEP_ALIVE_REQUEST: return Operations.LE_PEER_KEEP_ALIVE_REQUEST.ToString(); case (byte)Operations.LE_PEER_KEEP_ALIVE_RESPONSE: return Operations.LE_PEER_KEEP_ALIVE_RESPONSE.ToString(); case (byte)Operations.LE_PEER_REGISTRATION_REQUEST: return Operations.LE_PEER_REGISTRATION_REQUEST.ToString(); case (byte)Operations.LE_PEER_REGISTRATION_RESPONSE: return Operations.LE_PEER_REGISTRATION_RESPONSE.ToString(); default: return opCode.ToString(); } } private void PrintMessage(byte[] receivedBytes, string peerIP, Int32 peerPort, bool isReceived) { Utils.WriteLine(Utils.PrintBytesArray(receivedBytes), ConsoleType.LE); byte opCode = receivedBytes[0]; switch (opCode) { case (byte)Operations.LE_MASTER_PEER_KEEP_ALIVE_REQUEST: case (byte)Operations.LE_MASTER_PEER_KEEP_ALIVE_RESPONSE: case (byte)Operations.LE_PEER_KEEP_ALIVE_REQUEST: case (byte)Operations.LE_PEER_KEEP_ALIVE_RESPONSE: case (byte)Operations.LE_DEREGISTRATION_REQUEST: case (byte)Operations.LE_DEREGISTRATION_RESPONSE: case (byte)Operations.LE_DIGITALVOTING_MAP_BROADCAST: case (byte)Operations.LE_MASTER_PEER_REGISTRATION_REQUEST: case (byte)Operations.LE_MASTER_PEER_REGISTRATION_RESPONSE: case (byte)Operations.LE_NOTIFICATION_MAP_BROADCAST: case (byte)Operations.LE_NOTIFICATION_MAP_REQUEST: case (byte)Operations.LE_PEER_REGISTRATION_REQUEST: case (byte)Operations.LE_PEER_REGISTRATION_RESPONSE: { if (isReceived) Utils.WriteLine(String.Format("»»» {0,-34} [{1}:{2}]", GetMessageType(receivedBytes[0]), peerIP, peerPort), ConsoleType.LE); else Utils.WriteLine(String.Format("««« {0,-34} [{1}:{2}]", GetMessageType(receivedBytes[0]), peerIP, peerPort), ConsoleType.LE); // + ":" + peerUDPPort); //Utils.WriteLine(ConsoleType.LE, Utils.printBytesArray(receivedBytes)); break; } default: { // do not print if the message if a Wireline one if (receivedBytes[0] == 0xB2) break; // do not print this message because it isn't in the docs //if (receivedBytes[0] == 0x52) // break; if(isReceived) Utils.WriteLine(String.Format("»»» Link Establishment 0x{0:X} [{1}]", receivedBytes[0], peerIP), ConsoleType.LE); else Utils.WriteLine(String.Format("««« Link Establishment 0x{0:X} [{1}]", receivedBytes[0], peerIP), ConsoleType.LE); // + ":" + peerUDPPort); Utils.WriteLine(Utils.PrintBytesArray(receivedBytes), ConsoleType.LE); break; } } } public static string GetSystemTypeForConfig(string systemType) { switch (systemType) { case "Single/IP Site Connect": return GetSystemTypeForConfig(SystemType.IP_SITE_CONNECT); case "Capacity Plus": return GetSystemTypeForConfig(SystemType.CAPACITY_PLUS); default: return GetSystemTypeForConfig(SystemType.LINKED_CAPACITY_PLUS); } } public static string GetSystemTypeForConfig(SystemType systemType) { switch (systemType) { case SystemType.CAPACITY_PLUS: return "CPP"; case SystemType.IP_SITE_CONNECT: return "IPSC"; default: return "LCP"; } } public static SystemType GetSystemType(string systemType) { switch (systemType) { case "CPP": case "Capacity Plus": return SystemType.CAPACITY_PLUS; case "IPSC": case "Single/IP Site Connect": return SystemType.IP_SITE_CONNECT; case "LCP": case "Linked Capacity Plus": return SystemType.LINKED_CAPACITY_PLUS; default: return SystemType.IP_SITE_CONNECT; } } public static String GetStringSystemType(SystemType systemType) { switch (systemType) { case SystemType.CAPACITY_PLUS: return "Capacity Plus"; case SystemType.IP_SITE_CONNECT: return "Single/IP Site Connect"; default: return "Linked Capacity Plus"; } } public static string GetSystemTypeFromConfig(string systemType) { switch (systemType) { case "CPP": return "Capacity Plus"; case "IPSC": return "Single/IP Site Connect"; case "LCP": return "Linked Capacity Plus"; default: return "Linked Capacity Plus"; } } #region EVENT HANDLERS // triggered each time when a peer request a registration void LinkEstablishment_OnPeerRegistrationRequestReceived(byte[] peerID, string peerIP, int peerPort) { SendLEMessage(createLEMessage(Operations.LE_PEER_REGISTRATION_RESPONSE), peerIP, peerPort); } /* Method that will response to any master register request */ void LinkEstablishment_OnMasterRegistrationRequestReceived(byte[] peerID, string peerIP, int peerPort) { SendLEMessage(createLEMessage(Operations.LE_MASTER_PEER_REGISTRATION_RESPONSE), peerIP, peerPort); } // Master Keep Alive Request message sent by a remote peer void LinkEstablishment_OnMasterKeepAliveRequestReceived(byte[] peerID, string peerIP, int peerPort) { SendLEMessage(createLEMessage(Operations.LE_MASTER_PEER_KEEP_ALIVE_RESPONSE), peerIP, peerPort); } // Map Request void LinkEstablishment_OnMapRequestReceived(byte[] peerID, string peerIP, int peerPort) { SendLEMessage(createLEMessage(Operations.LE_NOTIFICATION_MAP_BROADCAST), peerIP, peerPort); } // Keep Alive Request message sent by a remote peer void LinkEstablishment_OnPeerKeepAliveRequestReceived(byte[] peerID, string peerIP, int peerPort) { // update keep alive time lock (peersHashTable.SyncRoot) { foreach (DictionaryEntry entry in peersHashTable) { Peer peer = (Peer)entry.Value; if (peer.ipAddress == peerIP && peer.port == peerPort) { peer.lastKeepAliveRequestTime = DateTime.Now; SendLEMessage(createLEMessage(Operations.LE_PEER_KEEP_ALIVE_RESPONSE), peerIP, peerPort); // send a peer Keep Alive Request SendLEMessage(createLEMessage(Operations.LE_PEER_KEEP_ALIVE_REQUEST), peerIP, peerPort); break; } } } } // Response to a Keep Alive message sent by a remote peer void LinkEstablishment_OnPeerKeepAliveResponseReceived(byte[] peerID, string peerIP, int peerPort) { // update keep alive time lock (peersHashTable.SyncRoot) { foreach (DictionaryEntry entry in peersHashTable) { Peer peer = (Peer)entry.Value; if (peer.ipAddress == peerIP && peer.port == peerPort) { peer.lastKeepAliveResponseTime = DateTime.Now; break; } } } } // Event that is triggered once the registration with the Master Peer is done void LinkEstablishment_OnRegistrationResponseReceived(bool isValid) { if (isValid) { //SendLEMessage(createLEMessage(Operations.LE_NOTIFICATION_MAP_REQUEST)); //Thread.Sleep(300); SendLEMessage(createLEMessage(Operations.LE_MASTER_PEER_KEEP_ALIVE_REQUEST)); } } #endregion #region EVENT DELEGATES public delegate void RegistrationResponseDEl(Boolean isValid); public event RegistrationResponseDEl OnRegistrationResponseReceived; public delegate void MasterRegistrationRequestDEl(byte[] peerID, string peerIP, int peerPort); public event MasterRegistrationRequestDEl OnMasterRegistrationRequestReceived; public delegate void PeerRegistrationRequestDEl(byte[] peerID, string peerIP, Int32 peerPort); public event PeerRegistrationRequestDEl OnPeerRegistrationRequestReceived; public delegate void MapRequestDEl(byte[] peerID, string peerIP, Int32 peerPort); public event MapRequestDEl OnMapRequestReceived; public delegate void MasterKeepAliveRequestDEl(byte[] peerID, string peerIP, Int32 peerPort); public event MasterKeepAliveRequestDEl OnMasterKeepAliveRequestReceived; public delegate void PeerKeepAliveRequestDEl(byte[] peerID, string peerIP, Int32 peerPort); public event PeerKeepAliveRequestDEl OnPeerKeepAliveRequestReceived; public delegate void PeerKeepAliveResponseDEl(byte[] peerID, string peerIP, Int32 peerPort); public event PeerKeepAliveResponseDEl OnPeerKeepAliveResponseReceived; public delegate void WirelineMessageReceivedDEl(byte[] received, string peerIP, Int32 peerPort); public event WirelineMessageReceivedDEl OnWirelineMessageReceived; #endregion /* Class for holding a peer object */ public class Peer { public Int64 peerID; public Int64 slot1ID = 0xCCCCCC; public Int64 slot2ID = 0xDDDDDD; public String ipAddress; public Int32 port; private Int32 mode; public Int16 leadingChannelID; public byte[] currentLinkProtocolVersion = { 0x00, 0x00 }; public byte[] oldestLinkProtocolVersion = { 0x00, 0x00 }; public byte[] acceptedLinkProtocolVersion = { 0x00, 0x00 }; public byte[] peerMode = { 0x00, 0x00 }; public byte[] peerServices = { 0x00, 0x00, 0x00, 0x00 }; public DateTime lastKeepAliveRequestTime = DateTime.Now; public DateTime lastKeepAliveResponseTime = DateTime.Now; // this values are received by bitwise operations with the mode field // see page 93-96 from devspec_link_establishment_0102.pdf public PeerStatus peerStatus = PeerStatus.Disabled; public SlotAssignment slot1Assignment = SlotAssignment.NoCallSupport; public SlotAssignment slot2Assignment = SlotAssignment.NoCallSupport; public SignalingMode signalingMode = SignalingMode.NoRFSupport; public Peer() { peerID = 0; ipAddress = ""; port = 0; mode = 0; leadingChannelID = 0; } override public string ToString() { return String.Format("Peer ID {0,-8} [{1,-15}:{2,5}] \n\t {3} {4} {5} {6}", peerID, ipAddress, port, peerStatus, slot1Assignment, slot2Assignment, signalingMode); //return "Peer: " + peerID + " [" + ipAddress + ":" + port + "]" + " [" + String.Format("0x{0:X2}",mode) + "]"; } public void SetPeerMode(SystemType systemType, Int32 peerMode) { this.mode = peerMode; this.peerMode = BitConverter.GetBytes(peerMode); int pStatus = 0; int slot1Assign = 0; int slot2Assign = 0; int signMode = 0; if (systemType == SystemType.LINKED_CAPACITY_PLUS) { // get PeerStatus Type for LCP pStatus = (int)((mode & 0x30) >> 4); slot1Assign = (int)((mode & 0x02) >> 2); slot2Assign = (int)((mode & 0x03)); } else { // get PeerStatus Type for IPSC, CPC pStatus = (int)((mode & 0xC0) >> 6); signMode = (int)((mode & 0x30) >> 4); slot1Assign = (int)((mode & 0x0C) >> 2); slot2Assign = (int)((mode & 0x03)); } // set enum values peerStatus = GetPeerStatus(pStatus); signalingMode = GetSignalingMode(signMode); slot1Assignment = GetSlotAssignment(systemType, slot1Assign); slot2Assignment = GetSlotAssignment(systemType, slot2Assign); } public void SetPeerServices(SystemType systemType, Int64 peerServices) { this.peerServices = BitConverter.GetBytes(peerServices); } private string GetHexPeerID(Int64 peerID) { String peerHexID = ""; bool uselessBytes = true; byte[] bytes = BitConverter.GetBytes(peerID); foreach (byte by in bytes.Reverse().ToArray()) { if (uselessBytes && by == 0) continue; peerHexID += String.Format("{0:X2}-", by); uselessBytes = false; } //remove last - return peerHexID.Remove(peerHexID.Length - 1); } } #region Static Enum Correspondece public static PeerStatus GetPeerStatus(int status) { switch (status) { case 0: return PeerStatus.Disabled; case 1: return PeerStatus.Enabled; case 2: return PeerStatus.KnockedDown; case 3: return PeerStatus.Locked; default: return PeerStatus.Disabled; } } public static SignalingMode GetSignalingMode(int signalingMode) { switch (signalingMode) { case 0: return SignalingMode.NoRFSupport; case 1: return SignalingMode.Analog; case 2: return SignalingMode.Digital; case 3: return SignalingMode.RESERVED; default: return SignalingMode.NoRFSupport; } } public static SlotAssignment GetSlotAssignment(SystemType systemType, int value) { if(systemType == SystemType.LINKED_CAPACITY_PLUS) switch (value) { case 0: return SlotAssignment.NoCallSupport; case 1: return SlotAssignment.LCPTrunkedChannel; case 2: return SlotAssignment.LCPLocalAreaDataRevertChannel; case 3: return SlotAssignment.LCPWideAreaDataRevertChannel; default: return SlotAssignment.NoCallSupport; } else switch (value) { case 0: return SlotAssignment.NoCallSupport; case 1: return SlotAssignment.LocalSiteCallSupportOnly; case 2: return SlotAssignment.IPSiteConnectCallSupport; case 3: return SlotAssignment.RESERVED; default: return SlotAssignment.NoCallSupport; } } #endregion } }