2525 lines
119 KiB
C#
2525 lines
119 KiB
C#
|
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 peer’s current link protocol version is higher than zero and supports the link
|
|||
|
* protocol version of zero, when it receives LE_PEER_REGISTRATION_REQUEST
|
|||
|
* without link protocol version field, it shall take the following actions:
|
|||
|
* 1) Send the LE_PEER_REGISTRATION_RESP without link protocol version field
|
|||
|
* 2) Stop the current PeerRegister Timer for the LE_PEER_REGISTRATION_REQUEST with
|
|||
|
* link protocol version field
|
|||
|
* 3) Send the LE_PEER_REGISTRATION_REQUEST without link protocol version field.
|
|||
|
* 4) Start the PeerRegister Timer
|
|||
|
* There is no limit on the setting of the PeerRegister Timer. The MOTOTRBO repeaters
|
|||
|
* use 1 second for this timer.
|
|||
|
*
|
|||
|
* See page 72-73 from devspec_link_establishment_0102
|
|||
|
*/
|
|||
|
case Operations.LE_PEER_REGISTRATION_REQUEST:
|
|||
|
{
|
|||
|
List<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
|
|||
|
}
|
|||
|
}
|