WIP
parent
6e43e1daf9
commit
16b31d731b
|
@ -0,0 +1,165 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
namespace ln.types
|
||||
{
|
||||
|
||||
public class Argument
|
||||
{
|
||||
public char Short { get; }
|
||||
public String Long { get; }
|
||||
|
||||
public bool NeedsValue { get; }
|
||||
public bool HasValue => Value != null;
|
||||
|
||||
public String Value { get; set; }
|
||||
public int IntegerValue => int.Parse(Value);
|
||||
public double DoubleValue => double.Parse(Value);
|
||||
|
||||
public bool IsSet { get; set; }
|
||||
|
||||
public Argument(char shortName, string longName)
|
||||
{
|
||||
Short = shortName;
|
||||
Long = longName;
|
||||
|
||||
NeedsValue = false;
|
||||
}
|
||||
public Argument(char shortName, string longName, int defaultValue)
|
||||
: this(shortName, longName, defaultValue.ToString()) { }
|
||||
public Argument(char shortName, string longName, double defaultValue)
|
||||
: this(shortName, longName, defaultValue.ToString()) { }
|
||||
|
||||
public Argument(char shortName, string longName, string defaultValue)
|
||||
{
|
||||
Short = shortName;
|
||||
Long = longName;
|
||||
|
||||
NeedsValue = true;
|
||||
Value = defaultValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class ArgumentContainer
|
||||
{
|
||||
List<Argument> arguments;
|
||||
List<String> additionalArguments;
|
||||
|
||||
public ArgumentContainer()
|
||||
{
|
||||
arguments = new List<Argument>();
|
||||
additionalArguments = new List<string>();
|
||||
}
|
||||
public ArgumentContainer(IEnumerable<Argument> argumentDefinitions)
|
||||
: this()
|
||||
{
|
||||
arguments.AddRange(argumentDefinitions);
|
||||
}
|
||||
|
||||
public Argument this[string longName]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (longName == null)
|
||||
throw new ArgumentNullException(nameof(longName));
|
||||
|
||||
foreach (Argument argument in arguments)
|
||||
{
|
||||
if (longName.Equals(argument.Long))
|
||||
return argument;
|
||||
}
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
}
|
||||
public Argument this[char shortName]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (shortName == 0)
|
||||
throw new ArgumentNullException(nameof(shortName));
|
||||
|
||||
foreach (Argument argument in arguments)
|
||||
{
|
||||
if (shortName.Equals(argument.Short))
|
||||
return argument;
|
||||
}
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(string longName)
|
||||
{
|
||||
foreach (Argument argument in arguments)
|
||||
{
|
||||
if (longName.Equals(argument.Long))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public bool Contains(char shortName)
|
||||
{
|
||||
if (shortName == (char)0)
|
||||
return false;
|
||||
|
||||
foreach (Argument argument in arguments)
|
||||
{
|
||||
if (shortName.Equals(argument.Short))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public ArgumentContainer Add(Argument argument)
|
||||
{
|
||||
if (Contains(argument.Short) || Contains(argument.Long))
|
||||
throw new ArgumentException(nameof(argument),String.Format("0x{0:x} / {1}",(int)argument.Short,argument.Long));
|
||||
|
||||
arguments.Add(argument);
|
||||
return this;
|
||||
}
|
||||
public ArgumentContainer Add(char shortName) => Add(new Argument(shortName, null));
|
||||
public ArgumentContainer Add(string longName) => Add(new Argument((char)0, longName));
|
||||
public ArgumentContainer Add(char shortName, string longName) => Add(new Argument(shortName, longName));
|
||||
public ArgumentContainer Add(char shortName, string longName, string defaultValue) => Add(new Argument(shortName, longName, defaultValue));
|
||||
public ArgumentContainer Add(int shortName, string longName, string defaultValue) => Add(new Argument((char)shortName, longName, defaultValue));
|
||||
|
||||
public void Parse(IEnumerable<string> args)
|
||||
{
|
||||
Queue<string> q = new Queue<string>(args);
|
||||
while (q.Count > 0)
|
||||
{
|
||||
string currentOption = q.Dequeue();
|
||||
|
||||
if (currentOption[0].Equals('-'))
|
||||
{
|
||||
if (currentOption[1].Equals('-'))
|
||||
{
|
||||
String aname = currentOption.Substring(2);
|
||||
Argument argument = this[aname];
|
||||
argument.IsSet = true;
|
||||
if (argument.NeedsValue)
|
||||
argument.Value = q.Dequeue();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (char option in currentOption.Substring(1))
|
||||
{
|
||||
Argument argument = this[option];
|
||||
argument.IsSet = true;
|
||||
if (argument.NeedsValue)
|
||||
argument.Value = q.Dequeue();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
additionalArguments.Add(currentOption);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,16 @@ namespace ln.types
|
|||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static T[] Combine<T>(this T[] me,IEnumerable<T> other)
|
||||
public static T[] Concat<T>(this T[] me, T[] other)
|
||||
{
|
||||
T[] combined = new T[me.Length + other.Length];
|
||||
Array.Copy(me, 0, combined, 0, me.Length);
|
||||
Array.Copy(other, 0, combined, me.Length, combined.Length);
|
||||
return combined;
|
||||
}
|
||||
|
||||
|
||||
public static T[] Combine<T>(this T[] me, IEnumerable<T> other)
|
||||
{
|
||||
HashSet<T> elements = new HashSet<T>(me);
|
||||
foreach (T e in other)
|
||||
|
@ -104,6 +113,35 @@ namespace ln.types
|
|||
return BitConverter.ToUInt16(bytes, 0);
|
||||
}
|
||||
|
||||
public static void WriteLong(this Stream stream, long value, bool bigEndian = false)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
if (BitConverter.IsLittleEndian == bigEndian)
|
||||
Array.Reverse(bytes);
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
public static long ReadLong(this Stream stream, bool bigEndian = false)
|
||||
{
|
||||
byte[] bytes = stream.ReadBytes(8);
|
||||
if (BitConverter.IsLittleEndian == bigEndian)
|
||||
Array.Reverse(bytes);
|
||||
return BitConverter.ToInt64(bytes, 0);
|
||||
}
|
||||
|
||||
public static void WriteULong(this Stream stream, ulong value, bool bigEndian = false)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(value);
|
||||
if (BitConverter.IsLittleEndian == bigEndian)
|
||||
Array.Reverse(bytes);
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
public static ulong ReadULong(this Stream stream, bool bigEndian = false)
|
||||
{
|
||||
byte[] bytes = stream.ReadBytes(8);
|
||||
if (BitConverter.IsLittleEndian == bigEndian)
|
||||
Array.Reverse(bytes);
|
||||
return BitConverter.ToUInt64(bytes, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -135,6 +173,21 @@ namespace ln.types
|
|||
return BitConverter.ToUInt32(ib, 0);
|
||||
}
|
||||
|
||||
public static byte[] GetBytes(this short v, bool bigEndian = false)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(v);
|
||||
if (BitConverter.IsLittleEndian == bigEndian)
|
||||
Array.Reverse(bytes);
|
||||
return bytes;
|
||||
}
|
||||
public static byte[] GetBytes(this ushort v, bool bigEndian = false)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(v);
|
||||
if (BitConverter.IsLittleEndian == bigEndian)
|
||||
Array.Reverse(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static short GetShort(this byte[] bytes, bool bigEndian = false) => GetShort(bytes, 0, bigEndian);
|
||||
public static short GetShort(this byte[] bytes, int offset, bool bigEndian = false)
|
||||
{
|
||||
|
@ -148,6 +201,23 @@ namespace ln.types
|
|||
return BitConverter.ToUInt16(ib, 0);
|
||||
}
|
||||
|
||||
public static byte[] GetBytes(this long v, bool bigEndian = false)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(v);
|
||||
if (BitConverter.IsLittleEndian == bigEndian)
|
||||
Array.Reverse(bytes);
|
||||
return bytes;
|
||||
}
|
||||
public static byte[] GetBytes(this ulong v, bool bigEndian = false)
|
||||
{
|
||||
byte[] bytes = BitConverter.GetBytes(v);
|
||||
if (BitConverter.IsLittleEndian == bigEndian)
|
||||
Array.Reverse(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static T[] Slice<T>(this T[] me, int offset) => Slice(me, offset, me.Length - offset);
|
||||
public static T[] Slice<T>(this T[] me,int offset,int length)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
namespace ln.types.json.rpc
|
||||
{
|
||||
public class RPCError
|
||||
{
|
||||
public int Code { get; set; }
|
||||
public string Message { get; set; }
|
||||
|
||||
public object Data { get; set; }
|
||||
|
||||
public RPCError()
|
||||
{
|
||||
}
|
||||
public RPCError(Exception e)
|
||||
{
|
||||
Code = 500;
|
||||
Message = e.ToString();
|
||||
}
|
||||
public RPCError(int code,String message)
|
||||
{
|
||||
Code = code;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
namespace ln.types.json.rpc
|
||||
{
|
||||
public class RPCMessage
|
||||
{
|
||||
public String Version { get; set; }
|
||||
public String Method { get; set; }
|
||||
public object[] Parameters { get; set; }
|
||||
|
||||
public object Result { get; set; }
|
||||
public RPCError Error { get; set; }
|
||||
|
||||
public JToken Identifier { get; set; }
|
||||
|
||||
public RPCMessage()
|
||||
{
|
||||
Version = "2.0";
|
||||
Parameters = new object[0];
|
||||
}
|
||||
public RPCMessage(JObject source)
|
||||
{
|
||||
Version = source["jsonrpc"].ToObject<string>();
|
||||
if (source.ContainsKey("method"))
|
||||
Method = source["method"].ToObject<string>();
|
||||
if (source.ContainsKey("params"))
|
||||
Parameters = source["params"].ToObject<object[]>();
|
||||
|
||||
if (source.ContainsKey("result"))
|
||||
Result = source["result"];
|
||||
|
||||
if (source.ContainsKey("error"))
|
||||
|
||||
if (source.ContainsKey("id"))
|
||||
Identifier = source["id"];
|
||||
else
|
||||
Identifier = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -115,6 +115,15 @@
|
|||
<Compile Include="json\converter\JSONGuidConverter.cs" />
|
||||
<Compile Include="json\converter\JSONIPv4Converter.cs" />
|
||||
<Compile Include="json\converter\JSONNetwork4Converter.cs" />
|
||||
<Compile Include="net\tools\Ping.cs" />
|
||||
<Compile Include="net\IPv4Header.cs" />
|
||||
<Compile Include="net\ICMPPacket.cs" />
|
||||
<Compile Include="json\rpc\RPCMessage.cs" />
|
||||
<Compile Include="json\rpc\RPCError.cs" />
|
||||
<Compile Include="ArgumentContainer.cs" />
|
||||
<Compile Include="rpc\RPCContainer.cs" />
|
||||
<Compile Include="rpc\RPCCall.cs" />
|
||||
<Compile Include="rpc\RPCResult.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="sync\" />
|
||||
|
@ -132,6 +141,9 @@
|
|||
<Folder Include="odb\collections\" />
|
||||
<Folder Include="json\" />
|
||||
<Folder Include="json\converter\" />
|
||||
<Folder Include="net\tools\" />
|
||||
<Folder Include="json\rpc\" />
|
||||
<Folder Include="rpc\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ln.logging\ln.logging.csproj">
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using System.Security;
|
||||
namespace ln.types.net
|
||||
{
|
||||
public class ICMPHeader
|
||||
{
|
||||
public byte Type { get; set; }
|
||||
public byte Code { get; set; }
|
||||
public ushort Checksum { get; set; }
|
||||
public Int32 Rest { get; set; }
|
||||
|
||||
public int HeaderLength => 8 + Payload.Length;
|
||||
|
||||
public ushort Identifier
|
||||
{
|
||||
get => (ushort)(Rest & 0x0000FFFF);
|
||||
set
|
||||
{
|
||||
Rest = (int)(Rest & 0xFFFF0000) | (value & 0x0000FFFF);
|
||||
}
|
||||
}
|
||||
public ushort SequenceNumber
|
||||
{
|
||||
get => (ushort)((Rest & 0xFFFF0000) >> 16);
|
||||
set
|
||||
{
|
||||
Rest = (int)(Rest & 0x0000FFFF) | ((value << 16) & 0x0000FFFF);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Payload { get; set; } = new byte[0];
|
||||
|
||||
public ICMPHeader()
|
||||
{
|
||||
}
|
||||
|
||||
public ICMPHeader(byte[] buffer, int offset, int length)
|
||||
{
|
||||
if (buffer.Length < 8)
|
||||
throw new ArgumentOutOfRangeException(nameof(buffer));
|
||||
if (buffer.Length < (offset + 8))
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
if (buffer.Length < (offset + length))
|
||||
throw new ArgumentOutOfRangeException(nameof(length));
|
||||
|
||||
Type = buffer[offset];
|
||||
Code = buffer[offset + 1];
|
||||
Checksum = BitConverter.ToUInt16(buffer, offset + 2);
|
||||
Rest = BitConverter.ToInt32(buffer, offset + 4);
|
||||
Payload = buffer.Slice(offset + 8);
|
||||
}
|
||||
public void Write(byte[] buffer, int offset) => Write(buffer, offset, false);
|
||||
public void Write(byte[] buffer,int offset,bool performChecksum)
|
||||
{
|
||||
if (buffer.Length < HeaderLength)
|
||||
throw new ArgumentOutOfRangeException(nameof(buffer));
|
||||
if (buffer.Length < (offset + HeaderLength))
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
|
||||
if (performChecksum)
|
||||
Checksum = 0;
|
||||
|
||||
buffer[offset] = Type;
|
||||
buffer[offset + 1] = Code;
|
||||
Array.Copy(BitConverter.GetBytes(Checksum), 0, buffer, offset + 2, 2);
|
||||
Array.Copy(BitConverter.GetBytes(Rest), 0, buffer, offset + 4, 4);
|
||||
Array.Copy(Payload, 0, buffer, offset + 8, Payload.Length);
|
||||
|
||||
if (performChecksum)
|
||||
{
|
||||
Checksum = IPv4Header.PerformChecksum(buffer,offset,HeaderLength);
|
||||
Array.Copy(BitConverter.GetBytes(Checksum), 0, buffer, offset + 2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ToBytes(bool performChecksum)
|
||||
{
|
||||
byte[] packet = new byte[HeaderLength];
|
||||
Write(packet, 0, performChecksum);
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static ICMPHeader Parse(byte[] buffer, int offset, int length)
|
||||
{
|
||||
return new ICMPHeader(buffer, offset, length);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
using System;
|
||||
namespace ln.types.net
|
||||
{
|
||||
public class IPv4Header
|
||||
{
|
||||
public byte Version { get; set; }
|
||||
public byte IHL { get; set; }
|
||||
public byte TypeOfService { get; set; }
|
||||
|
||||
public ushort TotalLength { get; set; }
|
||||
public ushort Identification { get; set; }
|
||||
|
||||
public byte Flags { get; set; }
|
||||
public ushort FragmentOffset { get; set; }
|
||||
|
||||
public byte TimeToLive { get; set; }
|
||||
public byte Protocol { get; set; }
|
||||
public ushort HeaderChecksum { get; set; }
|
||||
|
||||
public IPv4 SourceAddress { get; set; }
|
||||
public IPv4 DestinationAddress { get; set; }
|
||||
|
||||
public byte[] Options { get; set; }
|
||||
|
||||
public IPv4Header()
|
||||
{
|
||||
}
|
||||
|
||||
public int HeaderLength => IHL << 2;
|
||||
public void Write(byte[] buffer, int offset) => Write(buffer, offset, false);
|
||||
public void Write(byte[] buffer,int offset,bool performChecksum)
|
||||
{
|
||||
if (buffer.Length < HeaderLength)
|
||||
throw new ArgumentOutOfRangeException(nameof(buffer));
|
||||
if (offset + HeaderLength < buffer.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
|
||||
if ((Options.Length % 4) != 0)
|
||||
throw new InvalidOperationException("IPv4Header.Options must be length multiple of 4");
|
||||
|
||||
if ((Options.Length + 20) != HeaderLength)
|
||||
throw new InvalidOperationException("IHL must match .Header and .Options length");
|
||||
|
||||
if (performChecksum)
|
||||
HeaderChecksum = 0;
|
||||
|
||||
int i = (Version) | (IHL << 4) | (TypeOfService << 8) | (TotalLength << 16);
|
||||
Array.Copy(BitConverter.GetBytes(i), 0, buffer, offset, 4);
|
||||
i = (Identification) | (Flags << 16) | (FragmentOffset << 19);
|
||||
Array.Copy(BitConverter.GetBytes(i), 0, buffer, offset + 4, 4);
|
||||
i = (TimeToLive) | (Protocol << 8) | (HeaderChecksum << 16);
|
||||
Array.Copy(BitConverter.GetBytes(i), 0, buffer, offset + 8, 4);
|
||||
|
||||
Array.Copy(SourceAddress.IPBytes, 0, buffer, offset + 12, 4);
|
||||
Array.Copy(SourceAddress.IPBytes, 0, buffer, offset + 16, 4);
|
||||
|
||||
Array.Copy(Options, 0, buffer, offset + 20, Options.Length);
|
||||
|
||||
if (performChecksum)
|
||||
{
|
||||
HeaderChecksum = PerformChecksum(buffer,offset,HeaderLength);
|
||||
Array.Copy(BitConverter.GetBytes(HeaderChecksum), 0, buffer, offset + 10, 4);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ToBytes() => ToBytes(false);
|
||||
public byte[] ToBytes(bool performChecksum)
|
||||
{
|
||||
byte[] packet = new byte[HeaderLength];
|
||||
Write(packet, 0, performChecksum);
|
||||
return packet;
|
||||
}
|
||||
public static ushort PerformChecksum(byte[] headerBytes) => PerformChecksum(headerBytes, 0, headerBytes.Length);
|
||||
public static ushort PerformChecksum(byte[] headerBytes,int offset,int length)
|
||||
{
|
||||
uint chksum = 0;
|
||||
|
||||
for (int n = 0; n < headerBytes.Length; n += 4)
|
||||
chksum += BitConverter.ToUInt16(headerBytes, n);
|
||||
|
||||
chksum += (chksum & 0xFFFF) + (chksum >> 16);
|
||||
if ((chksum & 0xFFFF0000)!=0)
|
||||
chksum += (chksum & 0xFFFF) + (chksum >> 16);
|
||||
|
||||
return (ushort)((~chksum) & 0xFFFF);
|
||||
}
|
||||
|
||||
public static IPv4Header Parse(byte[] packet,int offset,int length)
|
||||
{
|
||||
if (offset >= packet.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
if ((offset + length > packet.Length)|| (length < 20))
|
||||
throw new ArgumentOutOfRangeException(nameof(length));
|
||||
|
||||
IPv4Header header = new IPv4Header();
|
||||
|
||||
uint ui = BitConverter.ToUInt32(packet, offset);
|
||||
|
||||
header.Version = (byte)(ui & 0x0F);
|
||||
header.IHL = (byte)((ui & 0xF0) >> 4);
|
||||
header.TypeOfService = (byte)(ui >> 8);
|
||||
header.TotalLength = (ushort)(ui >> 16);
|
||||
|
||||
ui = BitConverter.ToUInt32(packet, offset + 4);
|
||||
header.Identification = (ushort)(ui & 0x0000FFFF);
|
||||
header.Flags = (byte)((ui & 0x00070000) >> 16);
|
||||
header.FragmentOffset = (ushort)((ui & 0xFFF80000) >> 19);
|
||||
|
||||
ui = BitConverter.ToUInt32(packet, offset + 4);
|
||||
header.TimeToLive = (byte)(ui & 0x000000FF);
|
||||
header.Protocol = (byte)((ui & 0x0000FF00) >> 8);
|
||||
header.HeaderChecksum = (ushort)((ui & 0xFFFF0000)>>16);
|
||||
|
||||
header.SourceAddress = new IPv4(packet, 12);
|
||||
header.DestinationAddress= new IPv4(packet, 16);
|
||||
|
||||
header.Options = packet.Slice(20,header.HeaderLength - 20);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using ln.logging;
|
||||
|
||||
namespace ln.types.net.tools
|
||||
{
|
||||
public class Ping
|
||||
{
|
||||
public Socket Socket { get; private set; }
|
||||
public IPEndPoint LocalEndpoint { get; private set; }
|
||||
|
||||
public Ping()
|
||||
{
|
||||
Socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
|
||||
LocalEndpoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
Socket.Bind(LocalEndpoint);
|
||||
}
|
||||
|
||||
public int TimeToLive
|
||||
{
|
||||
get => (int)Socket.GetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
|
||||
set => Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
|
||||
}
|
||||
|
||||
private void Listener()
|
||||
{
|
||||
byte[] rxBuffer = new byte[4096];
|
||||
EndPoint re = null;
|
||||
IPEndPoint remoteEndpoint;
|
||||
|
||||
while (true)
|
||||
{
|
||||
Socket.ReceiveFrom(rxBuffer, rxBuffer.Length, SocketFlags.None, ref re);
|
||||
remoteEndpoint = (IPEndPoint)re;
|
||||
}
|
||||
}
|
||||
|
||||
private void SendRequest(PingRequest pingRequest)
|
||||
{
|
||||
IPv4Header ipHeader = new IPv4Header();
|
||||
ICMPHeader icmpHeader = new ICMPHeader();
|
||||
|
||||
byte[] packet = new byte[ipHeader.HeaderLength + icmpHeader.HeaderLength];
|
||||
ipHeader.Write(packet, 0, true);
|
||||
icmpHeader.Write(packet, ipHeader.HeaderLength, true);
|
||||
|
||||
Logging.Log(LogLevel.DEBUG, "ICMP-Request: {0}", BitConverter.ToString(packet));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PingRequest
|
||||
{
|
||||
public PingReply PingReply { get; }
|
||||
public IPEndPoint RemoteEndpoint => PingReply.RemoteEndpoint;
|
||||
|
||||
|
||||
public int Sequence { get; private set; }
|
||||
public DateTime TimeStamp { get; set; }
|
||||
|
||||
public PingRequest(PingReply pingReply,int sequence)
|
||||
{
|
||||
PingReply = pingReply;
|
||||
Sequence = sequence;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => RemoteEndpoint.GetHashCode() ^ 0;
|
||||
|
||||
}
|
||||
|
||||
class PingReply
|
||||
{
|
||||
public IPEndPoint RemoteEndpoint { get; }
|
||||
|
||||
public int TimeOut { get; private set; }
|
||||
|
||||
public int PingsToSend { get; }
|
||||
public int PingsSent { get; private set; }
|
||||
public int Received { get; private set; }
|
||||
|
||||
public PingReply(IPEndPoint remoteEndpoint,int pingsToSend,int timeOut)
|
||||
{
|
||||
RemoteEndpoint = remoteEndpoint;
|
||||
PingsToSend = pingsToSend;
|
||||
TimeOut = timeOut;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json;
|
||||
namespace ln.types.rpc
|
||||
{
|
||||
public class RPCCall
|
||||
{
|
||||
public object Identifier { get; set; }
|
||||
|
||||
public String ModuleName { get; set; }
|
||||
public string MethodName { get; set; }
|
||||
|
||||
public object[] Parameters { get; set; }
|
||||
|
||||
public RPCCall()
|
||||
{
|
||||
Identifier = Guid.NewGuid();
|
||||
}
|
||||
public RPCCall(JObject json)
|
||||
{
|
||||
if (json.ContainsKey("id"))
|
||||
{
|
||||
switch (json["id"].Type)
|
||||
{
|
||||
case JTokenType.Integer:
|
||||
Identifier = json["id"].ToObject<int>();
|
||||
break;
|
||||
case JTokenType.Float:
|
||||
Identifier = json["id"].ToObject<float>();
|
||||
break;
|
||||
case JTokenType.String:
|
||||
Identifier = json["id"].ToObject<string>();
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(String.Format("JToken {0} is not supported as RPCCall.Identifier",json["id"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Identifier = Guid.NewGuid();
|
||||
}
|
||||
|
||||
if (json.ContainsKey("module"))
|
||||
ModuleName = json["module"].ToObject<string>();
|
||||
|
||||
if (json.ContainsKey("method"))
|
||||
MethodName = json["method"].ToObject<string>();
|
||||
|
||||
if (json.ContainsKey("parameters"))
|
||||
Parameters = json["parameters"].ToObject<object[]>();
|
||||
else
|
||||
Parameters = new object[0];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
namespace ln.types.rpc
|
||||
{
|
||||
public class PublishAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
public class RPCContainer
|
||||
{
|
||||
Dictionary<string, RPCModule> modules = new Dictionary<string, RPCModule>();
|
||||
|
||||
public RPCContainer()
|
||||
{
|
||||
}
|
||||
|
||||
public void Add(object moduleInstance) => Add(moduleInstance.GetType().Name, moduleInstance);
|
||||
public void Add(string moduleName,object moduleInstance)
|
||||
{
|
||||
if (modules.ContainsKey(moduleName))
|
||||
throw new ArgumentOutOfRangeException(nameof(moduleName), "Module with same name already added");
|
||||
|
||||
RPCModule rpcModule = new RPCModule(moduleName,moduleInstance);
|
||||
modules.Add(moduleName, rpcModule);
|
||||
}
|
||||
|
||||
public RPCResult Invoke(RPCCall call)
|
||||
{
|
||||
if ((call.ModuleName != null) && !modules.ContainsKey(call.ModuleName))
|
||||
throw new KeyNotFoundException(call.ModuleName);
|
||||
|
||||
RPCModule rpcModule = call.ModuleName != null ? modules[call.ModuleName] : modules[""];
|
||||
return rpcModule.Invoke(call);
|
||||
}
|
||||
|
||||
public class RPCModule
|
||||
{
|
||||
public String Name { get; }
|
||||
public object ModuleInstance { get; }
|
||||
|
||||
public Dictionary<string, MethodInfo> methodInfos = new Dictionary<string, MethodInfo>();
|
||||
|
||||
public RPCModule(string moduleName,object instance)
|
||||
{
|
||||
Name = moduleName;
|
||||
ModuleInstance = instance;
|
||||
|
||||
Initialize(ModuleInstance.GetType());
|
||||
}
|
||||
public RPCModule(string moduleName,Type type)
|
||||
{
|
||||
Name = moduleName;
|
||||
ModuleInstance = null;
|
||||
|
||||
Initialize(type);
|
||||
}
|
||||
|
||||
private void Initialize(Type type)
|
||||
{
|
||||
foreach (MethodInfo methodInfo in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance))
|
||||
{
|
||||
if (methodInfo.IsStatic || !Object.ReferenceEquals(ModuleInstance,null) )
|
||||
{
|
||||
if (methodInfo.IsPublic || (methodInfo.GetCustomAttribute<PublishAttribute>() != null))
|
||||
{
|
||||
methodInfos.Add(methodInfo.Name, methodInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RPCResult Invoke(RPCCall call)
|
||||
{
|
||||
if (!Name.Equals(call.ModuleName) && (call.ModuleName != null))
|
||||
throw new ArgumentOutOfRangeException(nameof(call.ModuleName), "RPC: Invoke called for wrong module");
|
||||
|
||||
try
|
||||
{
|
||||
if (!methodInfos.ContainsKey(call.MethodName))
|
||||
throw new KeyNotFoundException(call.MethodName);
|
||||
|
||||
MethodInfo methodInfo = methodInfos[call.MethodName];
|
||||
ParameterInfo[] paramterInfos = methodInfo.GetParameters();
|
||||
|
||||
object[] parameters = new object[paramterInfos.Length];
|
||||
for (int n=0;n<parameters.Length;n++)
|
||||
{
|
||||
parameters[n] = Convert.ChangeType(call.Parameters[n], paramterInfos[n].ParameterType);
|
||||
}
|
||||
|
||||
object result = methodInfo.Invoke(ModuleInstance, parameters);
|
||||
|
||||
return new RPCResult(call, result);
|
||||
} catch (Exception e)
|
||||
{
|
||||
return new RPCResult(call, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
namespace ln.types.rpc
|
||||
{
|
||||
public class RPCResult
|
||||
{
|
||||
public object Identifier { get; set; }
|
||||
|
||||
public object Result { get; set; }
|
||||
|
||||
public String ErrorText { get; set; }
|
||||
public Exception Exception { get; set; }
|
||||
|
||||
public RPCResult(RPCCall call)
|
||||
{
|
||||
Identifier = call.Identifier;
|
||||
}
|
||||
public RPCResult(RPCCall call,object result)
|
||||
{
|
||||
Identifier = call.Identifier;
|
||||
Result = result;
|
||||
}
|
||||
public RPCResult(RPCCall call,Exception e)
|
||||
{
|
||||
Identifier = call.Identifier;
|
||||
Exception = e;
|
||||
ErrorText = e.ToString();
|
||||
}
|
||||
|
||||
public JObject ToJSON()
|
||||
{
|
||||
JObject result = new JObject();
|
||||
result["id"] = JToken.FromObject(Identifier);
|
||||
|
||||
if (ErrorText != null)
|
||||
{
|
||||
result["error"] = new JObject();
|
||||
result["error"]["message"] = JToken.FromObject(ErrorText);
|
||||
result["error"]["exception"] = JToken.FromObject(Exception);
|
||||
}
|
||||
else
|
||||
{
|
||||
result["result"] = JToken.FromObject(Result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue