SafeDispatch/MotoRepeaterCore/LinkEstablishment.cs

2525 lines
119 KiB
C#
Raw Normal View History

2024-02-22 16:43:59 +00:00
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;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
}
/// <summary>
/// Set the slots that will be registered when the Wireline Registration
/// will be established
/// </summary>
/// <param name="slots">Required slots to register on</param>
public void SetRegisteredSlots(Wireline.SlotNumber slots)
{
Utils.WriteLine("Wireline Registration on " + slots, ConsoleColor.Cyan);
this.slots = slots;
}
/// <summary>
/// Get the slots on which the Wireline Registration needs to be established
/// </summary>
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<byte> responseList = new List<byte>();
/* 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<byte> responseList = new List<byte>();
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<byte> responseList = new List<byte>();
/* 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<byte> responseList = new List<byte>();
/* 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<byte> responseList = new List<byte>();
/* 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<byte> responseList = new List<byte>();
/* 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 peers 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<byte> responseList = new List<byte>();
/* 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<byte> responseList = new List<byte>();
/* 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<byte> responseList = new List<byte>();
/* 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<byte> responseList = new List<byte>();
/* 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<byte> responseList = new List<byte>();
/* 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<byte> responseList = new List<byte>();
/* 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
}
}