SafeDispatch/MotoRepeaterCore/LinkEstablishment.cs

2525 lines
119 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}