Made a lot of changes. Enhanced memory usage.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using Models.Model.Backend;
|
||||
namespace Models.Experimental;
|
||||
public class CustomPing
|
||||
{
|
||||
public static IPStatus SendIcmpEchoRequestOverRawSocket(IPAddress address, int timeout)
|
||||
{
|
||||
SocketConfig socketConfig = new SocketConfig(new IPEndPoint(address, 0), timeout, (CustomProtocolType) 1, RawSocket.CreateSendMessageBuffer(new() {Type = 8}));
|
||||
using Socket rawSocket = RawSocket.GetRawSocket(socketConfig);
|
||||
int ipHeaderLength = 20;
|
||||
|
||||
try
|
||||
{
|
||||
rawSocket.SendTo(socketConfig.SendBuffer, 0, socketConfig.SendBuffer.Length, SocketFlags.None, socketConfig.EndPoint);
|
||||
byte[] numArray = new byte[136];
|
||||
long timestamp = Stopwatch.GetTimestamp();
|
||||
|
||||
// TODO: WTF ???
|
||||
EndPoint lol = socketConfig.EndPoint;
|
||||
|
||||
while (Stopwatch.GetElapsedTime(timestamp).TotalMilliseconds < timeout)
|
||||
{
|
||||
int from = rawSocket.ReceiveFrom(numArray, SocketFlags.None, ref lol);
|
||||
|
||||
IPStatus status;
|
||||
if (from - ipHeaderLength >= 8 && RawSocket.TryGetPingReply(numArray, from, ref ipHeaderLength, out status))
|
||||
return status;
|
||||
}
|
||||
}
|
||||
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut)
|
||||
{
|
||||
}
|
||||
|
||||
return IPStatus.TimedOut;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System.Net.NetworkInformation;
|
||||
namespace Models.Experimental;
|
||||
public struct MessageConstant
|
||||
{
|
||||
public static IPStatus MapV4TypeToIpStatus(int type, int code)
|
||||
{
|
||||
IPStatus ipStatus1;
|
||||
switch ((IcmpV4MessageType) type)
|
||||
{
|
||||
case IcmpV4MessageType.EchoReply:
|
||||
ipStatus1 = IPStatus.Success;
|
||||
break;
|
||||
case IcmpV4MessageType.DestinationUnreachable:
|
||||
IPStatus ipStatus2;
|
||||
switch ((byte) code)
|
||||
{
|
||||
case 0:
|
||||
ipStatus2 = IPStatus.DestinationNetworkUnreachable;
|
||||
break;
|
||||
case 1:
|
||||
ipStatus2 = IPStatus.DestinationHostUnreachable;
|
||||
break;
|
||||
case 2:
|
||||
ipStatus2 = IPStatus.DestinationProtocolUnreachable;
|
||||
break;
|
||||
case 3:
|
||||
ipStatus2 = IPStatus.DestinationPortUnreachable;
|
||||
break;
|
||||
default:
|
||||
ipStatus2 = IPStatus.DestinationUnreachable;
|
||||
break;
|
||||
}
|
||||
ipStatus1 = ipStatus2;
|
||||
break;
|
||||
case IcmpV4MessageType.SourceQuench:
|
||||
ipStatus1 = IPStatus.SourceQuench;
|
||||
break;
|
||||
case IcmpV4MessageType.TimeExceeded:
|
||||
ipStatus1 = IPStatus.TtlExpired;
|
||||
break;
|
||||
case IcmpV4MessageType.ParameterProblemBadIpHeader:
|
||||
ipStatus1 = IPStatus.BadHeader;
|
||||
break;
|
||||
default:
|
||||
ipStatus1 = IPStatus.Unknown;
|
||||
break;
|
||||
}
|
||||
return ipStatus1;
|
||||
}
|
||||
}
|
||||
|
||||
internal enum IcmpV4MessageType : byte
|
||||
{
|
||||
EchoReply = 0,
|
||||
DestinationUnreachable = 3,
|
||||
SourceQuench = 4,
|
||||
TimeExceeded = 11, // 0x0B
|
||||
ParameterProblemBadIpHeader = 12, // 0x0C
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Models.Model.Backend;
|
||||
|
||||
namespace Models.Experimental;
|
||||
|
||||
public class RawSocket
|
||||
{
|
||||
public static unsafe Socket GetRawSocket(SocketConfig socketConfig)
|
||||
{
|
||||
Socket rawSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, (ProtocolType)socketConfig.ProtocolType);
|
||||
rawSocket.ReceiveTimeout = socketConfig.Timeout;
|
||||
rawSocket.SendTimeout = socketConfig.Timeout;
|
||||
rawSocket.Connect(socketConfig.EndPoint);
|
||||
int num = 1;
|
||||
rawSocket.SetRawSocketOption(0, 11, new ReadOnlySpan<byte>((void*) &num, 4));
|
||||
return rawSocket;
|
||||
}
|
||||
|
||||
public static bool TryGetPingReply(byte[] receiveBuffer, int bytesReceived, ref int ipHeaderLength, out IPStatus reply)
|
||||
{
|
||||
byte num = (byte) (receiveBuffer[0] & 15U);
|
||||
ipHeaderLength = 4 * num;
|
||||
|
||||
int start = ipHeaderLength;
|
||||
int srcOffset = ipHeaderLength + 8;
|
||||
|
||||
IcmpHeader icmpHeader = Unsafe.ReadUnaligned<IcmpHeader>(ref MemoryMarshal.GetReference<byte>(receiveBuffer.AsSpan<byte>(start)));
|
||||
byte[] numArray = new byte[bytesReceived - srcOffset];
|
||||
Buffer.BlockCopy(receiveBuffer, srcOffset, numArray, 0, numArray.Length);
|
||||
reply = MessageConstant.MapV4TypeToIpStatus(icmpHeader.Type, icmpHeader.Code);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static unsafe byte[] CreateSendMessageBuffer(IcmpHeader icmpHeader)
|
||||
{
|
||||
int length = sizeof (IcmpHeader);
|
||||
byte[] sendMessageBuffer = new byte[length];
|
||||
new Span<byte>((void*) &icmpHeader, length).CopyTo(new Span<byte>(sendMessageBuffer, 0, length));
|
||||
ushort bufferChecksum = ComputeBufferChecksum(sendMessageBuffer.AsSpan<byte>(0));
|
||||
sendMessageBuffer[2] = (byte) ((uint) bufferChecksum >> 8);
|
||||
sendMessageBuffer[3] = (byte) (bufferChecksum & byte.MaxValue);
|
||||
return sendMessageBuffer;
|
||||
}
|
||||
|
||||
private static ushort ComputeBufferChecksum(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
uint num1 = 0;
|
||||
for (int index = 0; index < buffer.Length; index += 2)
|
||||
{
|
||||
ushort num2 = (ushort) ((ushort) (buffer[index] << 8 & 65280) | (index + 1 < buffer.Length ? (ushort) (buffer[index + 1] & (uint) byte.MaxValue) : 0));
|
||||
num1 += num2;
|
||||
}
|
||||
while (num1 >> 16 != 0U)
|
||||
num1 = (num1 & ushort.MaxValue) + (num1 >> 16);
|
||||
return (ushort) ~num1;
|
||||
}
|
||||
}
|
||||
|
||||
public class SocketConfig
|
||||
{
|
||||
public EndPoint EndPoint;
|
||||
public readonly int Timeout;
|
||||
public readonly CustomProtocolType ProtocolType;
|
||||
public readonly byte[] SendBuffer;
|
||||
|
||||
public SocketConfig(
|
||||
EndPoint endPoint,
|
||||
int timeout,
|
||||
CustomProtocolType protocolType,
|
||||
byte[] sendBuffer)
|
||||
{
|
||||
EndPoint = endPoint;
|
||||
Timeout = timeout;
|
||||
ProtocolType = protocolType;
|
||||
SendBuffer = sendBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct IcmpHeader
|
||||
{
|
||||
public byte Type;
|
||||
public byte Code;
|
||||
public ushort HeaderChecksum;
|
||||
public ushort Identifier;
|
||||
public ushort SequenceNumber;
|
||||
}
|
||||
Reference in New Issue
Block a user