SafeDispatch/MotoTrbo_GW/SMSReceiveThread.cs
2024-02-22 18:43:59 +02:00

359 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using SafeMobileLib;
using System.Threading;
using MotoTRBO_GW;
namespace MotoTrbo_GW
{
class SMSReceiveThread
{
private string radioIP;
public Int32 smsPort;
private byte[] data = new byte[1024];
private UdpMulticast udpMulticast;
private UdpClient udpClient;
private String mIP;
private Int32 mPort;
public SMSReceiveThread(string radioIP, Int32 port, String multicastID, String multicastPort, UdpClient capPlusUDP = null)
{
this.radioIP = radioIP;
smsPort = port;
mIP = multicastID;
mPort = Int32.Parse(multicastPort);
//for cap plus
udpClient = capPlusUDP;
}
public void handleConnection()
{
SafeMobileLib.Utils.WriteLine("SMSReceive Thread started on port " + smsPort, ConsoleColor.Cyan, ConsoleType.SMS);
try
{
if (!Main.capacityPlus)
{
udpClient = null;
udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
string localIP = RadioStuff.GetInterface(radioIP);
udpClient.Client.Bind(new IPEndPoint(IPAddress.Parse(localIP), smsPort));
}
else
{
SafeMobileLib.Utils.WriteLine("SMS in cap+ MODE!!", ConsoleType.SMS);
}
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("SMSReceiveThread handleConnection exception: " + ex.ToString(), ConsoleColor.Red, ConsoleType.SMS);
}
try
{
udpMulticast = new UdpMulticast(mIP, mPort);
SafeMobileLib.Utils.WriteLine("SMSReceiveThread successfully registered to multicast group", ConsoleType.SMS);
}
catch (Exception ex)
{
SafeMobileLib.Utils.WriteLine("SMSReceiveThread exception while joining the multicast group: " + ex.ToString(), ConsoleColor.Red, ConsoleType.SMS);
}
IPEndPoint remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
SafeMobileLib.Utils.WriteLine("Waiting for SMS on port " + smsPort, ConsoleType.SMS);
while (Program.isRunning)
{
try
{
// Blocks until a message returns on this socket from a remote host.
Byte[] receivedBytes = udpClient.Receive(ref remoteIpEndPoint);
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]);
//EndPoint p= udpClient.Client.LocalEndPoint;
string suid = radioID.ToString();
SafeMobileLib.Utils.WriteLine("SMSReceiveThread received data from radio " + radioID + ": ", ConsoleType.SMS);
Utils.printBytesArray(receivedBytes, ConsoleType.SMS);
SafeMobileLib.Utils.WriteLine("\n\n", ConsoleType.SMS);
//register route
if (!Main.capacityPlus)
{
//SafeMobileLib.Utils.WriteLine("RadioGW received a sms from field unit with ID " + suid + " on gateway radio with IP " + radioIP + " \n\r Adding route to route table if route not present.");
if (RouteManager.NetworkIDs_Hash.ContainsKey(radioIP))
{
RoutingUtils.addRoute_withBuffer(suid.ToString(), radioIP, RouteManager.NetworkIDs_Hash[radioIP].ToString());
}
else
{
//SafeMobileLib.Utils.WriteLine("RouteManager.NetworkIDs_Hash does not contain a key for " + radioIP, ConsoleColor.Red);
}
}
header_T hret = DecodePacket(receivedBytes);
if (hret.ack)
{
SafeMobileLib.Utils.WriteLine("ACK received", ConsoleType.SMS);
Thread.Sleep(1000);
// The client needs an ACK
byte extension_header = 0;
if (hret.seq_no > 0x1F)
extension_header = 1;
Byte[] sendBytes = new Byte[5 + extension_header];
sendBytes[0] = 0x00; // len (2B)
sendBytes[1] = (byte)(3 + extension_header);
sendBytes[2] = 0xBF; // first header (req)
sendBytes[3] = 0x00; // addr len
sendBytes[4] = (byte)(hret.seq_no & 0x1F); // 2nd header (opt)
if (extension_header == 1)
{
sendBytes[4] += 0x80; //added the extension header info
sendBytes[5] = (byte)(hret.seq_no & 0x60);
}
//SafeMobileLib.Utils.WriteLine("SMSReceiveThread ACK sent: " + Utils.Byte2String(sendBytes, 0, sendBytes[1] + 2));
udpClient.Send(sendBytes, sendBytes[1] + 2, remoteIpEndPoint);
}
SafeMobileLib.Utils.WriteLine("", ConsoleType.SMS);
if (hret.header != 0x0BF) //regular message received
{
SafeMobileLib.Utils.WriteLine("REGULAR MESSAGE RECEIVED ", ConsoleType.SMS);
// decode the message received
SafeMobileLib.MessageDecoders.SMSdecoder dec2 = new SafeMobileLib.MessageDecoders.SMSdecoder(false);
dec2.DecodePacket(receivedBytes);
// check if the message has text
if (dec2.messBody != "")
{
SafeMobileLib.Utils.WriteLine("msg body " + dec2.messBody, ConsoleType.SMS);
// convert the string inyo byte array
List<byte> bytes = new List<byte>();
foreach (char c in dec2.messBody.ToCharArray())
bytes.Add((byte)c);
// add the hyt flag to the message to announce that is already parsed
bytes.Add((byte)'#');
bytes.Add((byte)'h');
bytes.Add((byte)'y');
bytes.Add((byte)'t');
#if LINXB
// Check if message is for a Linx (text msg of call request)
// Text messages for LINX : LINX(linxID).(text) - ex: Linx100.Hello
// Call request message for LINX: Linx(linxID).. - ex: Linx100..
string message = dec2.messBody;
bool isMessageForLinx = false;
int linxID = -1;
string txtForLinx = "";
if (message.IndexOf("linx", 0, StringComparison.InvariantCultureIgnoreCase) == 0)
{
// message starts with linx
int indexOfFirstPoint;
if ((indexOfFirstPoint = message.IndexOf('.', 4)) != -1)
{
// There is a point in the text
string linxIDstring = message.Substring(4, indexOfFirstPoint - 4);
if (int.TryParse(linxIDstring, out linxID))
{
// Message for a linx ID
// Determine if is an sms or call request
txtForLinx = message.Substring(indexOfFirstPoint + 1);
if (txtForLinx == ".")
{
// Call request for LINX
PrivateCallRequestForLinxReceived?.Invoke(int.Parse(suid), linxID);
// Don't send cmd on mbus
continue;
}
else
{
// text message for LINX
isMessageForLinx = true;
}
}
}
}
#endif
//put information on message bus
string sequenceID;
Byte[] toSendMulticast = Utils.createMulticastMessage(132, suid, bytes.ToArray(), out sequenceID);
udpMulticast.Send(toSendMulticast, toSendMulticast.Length);
#if LINXB
if (isMessageForLinx)
SmsForLixReceived?.Invoke(sequenceID, int.Parse(suid), linxID, txtForLinx);
#endif
#if DEBUG
SafeMobileLib.Utils.WriteLine("SMSReceiveThread Received SMS", ConsoleType.SMS);
SafeMobileLib.Utils.WriteLine("SMSReceiveThread sent data to message bus", ConsoleType.SMS);
#endif
}
}
else //ack received
{
SafeMobileLib.Utils.WriteLine("ACK Received", ConsoleType.SMS);
string seq_no = "0.0";
if (Main.smsConfirmForUnits.ContainsKey((Int32)radioID))
seq_no = Main.smsConfirmForUnits[(Int32)radioID].getFromConfirmationQueue(hret.seq_no);
#if DEBUG
SafeMobileLib.Utils.WriteLine("Received ACK with header:" + hret.header + " with seq_id :" + hret.seq_no, ConsoleColor.Cyan, ConsoleType.SMS);
SafeMobileLib.Utils.WriteLine("SMSConfirm.getFromConfirmationQueue(hret.seq_no)=" + seq_no, ConsoleColor.Cyan, ConsoleType.SMS);
#endif
System.Text.Encoding enc = System.Text.Encoding.ASCII;
byte[] buf = enc.GetBytes(GetAck4MessagebusForSequence(seq_no));
//send SMS ack to message bus
udpMulticast.Send(buf, buf.Length);
// add message to the acknowledged ones
SMSSendThread.acknowledgedMessagesSeqNo.Add(seq_no);
}
Thread.Sleep(100);
}
catch (Exception e)
{
SafeMobileLib.Utils.WriteLine("##### SMSReceiveThread Exception #########\n" + e.ToString(), ConsoleColor.Red, ConsoleType.SMS);
}
}
}
/// <summary>
/// Create a confirmation message that needs to be broadcasted over the message bus.
/// The message requires the sequence number for which the ack is done
/// </summary>
/// <param name="seqNo">Message sequence number that will be ack</param>
/// <returns>A string that will be sent over the message bus</returns>
public static string GetAck4MessagebusForSequence(string seqNo)
{
string test = "#242#1#";
String cmdok = "#" + seqNo + test;
Int32 tmp = cmdok.Length + 1;
tmp += tmp.ToString().Length;
cmdok = "#" + tmp.ToString() + cmdok;
return cmdok;
}
header_T DecodePacket(Byte[] data)
{
SafeMobileLib.Utils.WriteLine("Decode Packet length " + data.Length, ConsoleType.SMS);
header_T hret = new header_T();
int i, j, pdata;
pdata = (int)data[0];
pdata <<= 8;
pdata |= (int)data[1];
// parse header
int header = data[2];
hret.header = data[2];
if ((header & 0x80) != 0)
hret.ext = true;
else hret.ext = false;
if ((header & 0x40) != 0)
hret.ack = true;
else hret.ack = false;
if ((header & 0x10) != 0)
hret.cntl = true;
else hret.cntl = false; // txt message
hret.pdu_type = (byte)(header & 0x0f);
SafeMobileLib.Utils.WriteLine("Decode 3 " + data[3], ConsoleType.SMS);
// parse address
int addrsize = data[3];
i = 4;
//Console.Write("Address: ");
for (j = 0; j < addrsize; j++)
{
//Console.Write(data[i + j].ToString("X"));
}
i += j;
// parse rest of headers
if (hret.ext)
{
byte h2 = data[i];
if ((h2 & 0x80) != 0)
hret.ext2 = true;
else hret.ext2 = false;
hret.seq_no = (byte)(h2 & 0x1F);
i++;
SafeMobileLib.Utils.WriteLine("seq no " + hret.seq_no, ConsoleType.SMS);
if (hret.ext2)
{ // parse third header
byte seqNr_MSB = (byte)(data[i] & 0x60);
hret.seq_no += seqNr_MSB;
hret.encoding = (byte)(data[i] & 0x0f);
i++;
}
}
SafeMobileLib.Utils.WriteLine("crc" + data[3], ConsoleType.SMS);
int crc = 0;
if ((!hret.cntl) && (hret.pdu_type == 0))
{ // the rest is the txt message
Char[] cs = new Char[100];
int k;
for (j = i, k = 0; j < pdata + 2; j++)
{
//Console.Write(" 0x" + data[j].ToString("X"));
if (data[j] != 0)
{
cs[k++] = (Char)data[j];
crc |= (Char)data[j];
}
}
SafeMobileLib.Utils.WriteLine("after msg parsing", ConsoleType.SMS);
// save message in inbox ht
string s = new string(cs, 0, k);
s.Replace("\r\n", "");
s = s.Replace(System.Environment.NewLine, string.Empty);
SafeMobileLib.Utils.WriteLine("Message [" + s + "]", ConsoleType.SMS);
}
return hret;
}
#if LINXB
#region Events fro LINX
public delegate void SmsForLixReceivedDel(string seqID, int remoteRadioID, int linxRadioID, string text);
public event SmsForLixReceivedDel SmsForLixReceived;
public delegate void PrivateCallRequestForLinxReceivedDel(int remoteRadioID, int linxRadioID);
public event PrivateCallRequestForLinxReceivedDel PrivateCallRequestForLinxReceived;
#endregion
#endif
}
}