UDP
namespace Ppp.Net.Udp
{
using System;
using System.Net;
using System.Net.Sockets;
using Ppp.Core;
using Ppp.Net.IP;
public class UdpFrame : EventArgs
{
public virtual IPEndPoint Source { get; set; }
public virtual IPEndPoint Destination { get; set; }
public virtual AddressFamily AddressFamily { get; }
public virtual BufferSegment Payload { get; }
public virtual int Ttl { get; set; }
public UdpFrame(IPEndPoint source, IPEndPoint destination, BufferSegment payload)
{
this.Ttl = IPFrame.DefaultTtl;
this.Source = source ?? throw new ArgumentNullException(nameof(source));
this.Destination = destination ?? throw new ArgumentNullException(nameof(Destination));
this.AddressFamily = destination.AddressFamily;
if (source.AddressFamily != destination.AddressFamily)
{
throw new ArgumentOutOfRangeException("The original address is inconsistent with the target address protocol.");
}
this.Payload = payload ?? throw new ArgumentNullException(nameof(payload));
}
public virtual UdpFrame Depth()
{
return new UdpFrame(this.Source, this.Destination, this.Payload.Depth())
{
Ttl = this.Ttl
};
}
public override string ToString()
{
return string.Format($"{Source} -> {Destination}");
}
}
}
namespace Ppp.Net.Udp
{
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using Ppp.Core;
using Ppp.Net.Entry;
using Ppp.Net.IP;
public unsafe class UdpLayer
{
public virtual ILayerLocator Locator { get; }
public UdpLayer(ILayerLocator locator)
{
this.Locator = locator ?? throw new ArgumentNullException(nameof(locator));
}
public virtual void Input(UdpFrame frame)
{
Output(new UdpFrame(frame.Destination, frame.Source, frame.Payload) { Ttl = frame.Ttl });
}
public static IPFrame ToIPFrame(UdpFrame frame)
{
if (frame == null)
{
throw new ArgumentNullException(nameof(frame));
}
if (frame.AddressFamily != AddressFamily.InterNetwork)
{
throw new ArgumentNullException("UDP frames of this address family type are not supported.");
}
int payload_offset = sizeof(udp_hdr);
int payload_size = frame.Payload.Length;
byte[] message = new byte[payload_offset + payload_size];
fixed (byte* pinned = message)
{
udp_hdr* udphdr = (udp_hdr*)pinned;
udphdr->src = CheckSum.htons((ushort)frame.Source.Port);
udphdr->dest = CheckSum.htons((ushort)frame.Destination.Port);
udphdr->len = CheckSum.htons((ushort)message.Length);
udphdr->chksum = 0;
Buffer.BlockCopy(frame.Payload.Buffer,
frame.Payload.Offset,
message,
payload_offset,
payload_size);
ushort pseudo_checksum = CheckSum.inet_chksum_pseudo(pinned,
(uint)ProtocolType.Udp,
(uint)message.Length,
IPFrame.GetAddressV4(frame.Source.Address),
IPFrame.GetAddressV4(frame.Destination.Address));
if (pseudo_checksum == 0)
{
pseudo_checksum = 0xffff;
}
udphdr->chksum = pseudo_checksum;
}
return new IPFrame(ProtocolType.Udp,
frame.Source.Address,
frame.Destination.Address,
new BufferSegment(message))
{
Ttl = frame.Ttl,
Tos = 0x04,
Flags = 0x00,
};
}
public virtual void Output(UdpFrame frame)
{
IPFrame ip = ToIPFrame(frame);
if (ip != null)
{
Locator.IPv4.Output(ip);
}
}
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 8)]
private struct udp_hdr
{
[FieldOffset(0)]
public ushort src;
[FieldOffset(2)]
public ushort dest; /* src/dest UDP ports */
[FieldOffset(4)]
public ushort len;
[FieldOffset(6)]
public ushort chksum;
}
public virtual UdpFrame Parse(IPFrame ip) => ParseFrame(ip);
public static UdpFrame ParseFrame(IPFrame ip, bool checksum = true)
{
if (ip == null)
{
return null;
}
UdpFrame frame = null;
BufferSegment messages = ip.Payload;
messages.UnsafeAddrOfPinnedArrayElement((p) =>
{
udp_hdr* udphdr = (udp_hdr*)p;
if (udphdr == null)
{
return;
}
if (messages.Length != CheckSum.ntohs(udphdr->len)) // 错误的数据报
{
return;
}
int offset = sizeof(udp_hdr);
int len = messages.Length - offset;
if (len <= 0)
{
return;
}
if (checksum && udphdr->chksum != 0)
{
uint pseudo_checksum = CheckSum.inet_chksum_pseudo((byte*)p.ToPointer(),
(uint)ProtocolType.Udp,
(uint)messages.Length,
ip.SourceAddressV4,
ip.DestinationAddressV4);
if (pseudo_checksum != 0)
{
return;
}
}
BufferSegment message = new BufferSegment(messages.Buffer, messages.Offset + offset, len);
frame = new UdpFrame(
new IPEndPoint(ip.Source, CheckSum.ntohs(udphdr->src)),
new IPEndPoint(ip.Destination, CheckSum.ntohs(udphdr->dest)), message)
{
Ttl = ip.Ttl,
};
});
return frame;
}
}
}
TCP
namespace Ppp.Net.Tcp
{
using System.Net;
using Ppp.Core;
using Ppp.Net.Udp;
public enum TcpFlags
{
TCP_FIN = 0x01,
TCP_SYN = 0x02,
TCP_RST = 0x04,
TCP_PSH = 0x08,
TCP_ACK = 0x10,
TCP_UGR = 0x20,
TCP_ECE = 0x40,
TCP_CWR = 0x80,
TCP_FLAGS = 0x3f
}
public class TcpFrame : UdpFrame
{
public new static readonly BufferSegment Empty = new BufferSegment(BufferSegment.Empty);
public virtual TcpFlags Flags { get; set; }
public virtual uint SequenceNo { get; set; }
public virtual uint AcknowledgeNo { get; set; }
public virtual ushort WindowSize { get; set; }
public virtual BufferSegment Options { get; set; }
public virtual ushort UrgentPointer { get; set; }
public TcpFrame(IPEndPoint source, IPEndPoint destination, BufferSegment payload) : base(source, destination, payload)
{
}
}
}
namespace Ppp.Net.Tcp
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using Ppp.Core;
using Ppp.Net.Entry;
using Ppp.Net.IP;
#if NET40
using System.Collections.Concurrent;
#endif
class SegmentsContext
{
public uint AcknowledgeNo;
public uint SequenceNo;
public TcpFlags Flags;
public uint Length;
public int Retransmission;
public int Counter;
public Stopwatch Stopwatch;
public TcpPcb Pcb;
public bool Timeout;
public BufferSegment Payload = TcpFrame.Empty;
public TcpFrame CreateFrame(TcpPcb pcb)
{
return new TcpFrame(pcb.Destination, pcb.Source, this.Payload)
{
AcknowledgeNo = this.AcknowledgeNo,
SequenceNo = this.SequenceNo,
Flags = this.Flags,
Ttl = pcb.Ttl,
WindowSize = (ushort)pcb.ReceiveBufferSize,
};
}
}
public unsafe class TcpLayer
{
private IDictionary<string, TcpPcb> pcbTable =
#if NET40
new ConcurrentDictionary<string, TcpPcb>();
#else
new Dictionary<string, TcpPcb>();
#endif
private bool disposed = false;
/*
* typedef struct _tcp_hdr
* {
* unsigned short src_port; //源端口号
* unsigned short dst_port; //目的端口号
* unsigned int seq_no; //序列号
* unsigned int ack_no; //确认号
* #if LITTLE_ENDIAN
* unsigned char reserved_1:4; //保留6位中的4位首部长度
* unsigned char thl:4; //tcp头部长度
* unsigned char flag:6; //6位标志
* unsigned char reseverd_2:2; //保留6位中的2位
* #else
* unsigned char thl:4; //tcp头部长度
* unsigned char reserved_1:4; //保留6位中的4位首部长度
* unsigned char reseverd_2:2; //保留6位中的2位
* unsigned char flag:6; //6位标志
* #endif
* unsigned short wnd_size; //16位窗口大小
* unsigned short chk_sum; //16位TCP检验和
* unsigned short urgt_p; //16为紧急指针
* }tcp_hdr;
*/
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct tcp_hdr
{
public ushort src;
public ushort dest;
public uint seqno;
public uint ackno;
public ushort _hdrlen_rsvd_flags;
public ushort wnd;
public ushort chksum;
public ushort urgp; // 应用层不可能出现“URGP/UGR or OPT”的协议;这类紧急协议数据报文直接RST链接即可。
}
private const int TCP_HLEN = 20;
private static ushort TCPH_HDRLEN(tcp_hdr* phdr)
{
return ((ushort)(CheckSum.ntohs((phdr)->_hdrlen_rsvd_flags) >> 12));
}
private static byte TCPH_HDRLEN_BYTES(tcp_hdr* phdr)
{
return ((byte)(TCPH_HDRLEN(phdr) << 2));
}
private static byte TCPH_FLAGS(tcp_hdr* phdr)
{
return ((byte)((CheckSum.ntohs((phdr)->_hdrlen_rsvd_flags) & (byte)TcpFlags.TCP_FLAGS)));
}
private static ushort TCPH_HDRLEN_SET(tcp_hdr* phdr, int len)
{
var u = ((len) << 12) | TCPH_FLAGS(phdr);
return (phdr)->_hdrlen_rsvd_flags = CheckSum.htons((ushort)u);
}
private static ushort PP_HTONS(int x)
{
return ((ushort)((((x) & (ushort)0x00ffU) << 8) | (((x) & (ushort)0xff00U) >> 8)));
}
private static ushort TCPH_FLAGS_SET(tcp_hdr* phdr, int flags)
{
return (phdr)->_hdrlen_rsvd_flags = (ushort)(((phdr)->_hdrlen_rsvd_flags &
PP_HTONS(~(ushort)TcpFlags.TCP_FLAGS)) | CheckSum.htons((ushort)flags));
}
public virtual ILayerLocator Locator { get; }
public TcpLayer(ILayerLocator locator)
{
this.Locator = locator ?? throw new ArgumentNullException(nameof(locator));
new Thread(WorkThread) { IsBackground = true, Priority = ThreadPriority.Lowest }.Start();
}
private void WorkThread(object state)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while (!this.disposed)
{
if (stopwatch.ElapsedTicks < TcpPcb.MIN_RTO)
{
Thread.Sleep(1);
continue;
}
else
{
stopwatch.Reset();
stopwatch.Start();
}
lock (this.pcbTable)
{
foreach (var pair in pcbTable.ToList())
{
TcpPcb pcb = pair.Value;
if (pcb == null)
{
continue;
}
SortedDictionary<long, SegmentsContext> segments = pcb.SegmentsContexts;
if (segments == null)
{
continue;
}
lock (segments)
{
var remove_segments_keys = new List<long>();
foreach (var segments_pair in segments)
{
SegmentsContext segments_context = segments_pair.Value;
if (segments_context == null)
{
continue;
}
double rto_radix = Math.Pow(1.5, Math.Min(segments_context.Retransmission, (1 + segments_context.Counter)));
if (segments_context.Stopwatch.ElapsedMilliseconds >= (Math.Max(pcb.RTO, TcpPcb.MIN_RTO)
* rto_radix))
{
if (segments_context.Counter++ < segments_context.Retransmission)
{
segments_context.Stopwatch.Reset();
segments_context.Stopwatch.Start();
this.Output(segments_context.CreateFrame(pcb));
}
else
{
remove_segments_keys.Add(segments_pair.Key);
}
}
}
foreach (var segments_key in remove_segments_keys)
{
pcb.SegmentsContexts.Remove(segments_key, out SegmentsContext segments_x);
}
}
}
}
}
}
private void ClosePCB(TcpPcb pcb, TcpState state)
{
if (pcb == null)
{
return;
}
string pcbKey = GetPcbKey(pcb.Source, pcb.Destination);
lock (pcbTable)
{
pcbTable.Remove(pcbKey, out TcpPcb pcbx);
}
lock (pcb)
{
pcb.State = state;
if (!pcb.Aborted)
{
pcb.Aborted = true;
pcb.OnAbort(EventArgs.Empty);
}
}
}
private static string GetPcbKey(IPEndPoint source, IPEndPoint destination)
{
string key = $"{source} <-> {destination}";
return key;
}
private void RST(TcpPcb pcb, TcpFrame frame)
{
uint seqno = frame.AcknowledgeNo;
uint ackno = frame.SequenceNo + 1;
pcb.State = TcpState.LAST_ACK;
pcb.Post(TcpFlags.TCP_RST, ackno, seqno);
ClosePCB(pcb, TcpState.CLOSED);
}
public virtual void Input(TcpFrame frame)
{
string pcbKey = GetPcbKey(frame.Source, frame.Destination);
TcpPcb pcb = null;
lock (pcbTable)
{
pcbTable.TryGetValue(pcbKey, out pcb);
if (pcb == null)
{
pcb = new TcpPcb(frame, this.Locator)
{
State = TcpState.SYN_RCVD
};
if (0 == (frame.Flags & TcpFlags.TCP_SYN) || // 不接受此套接字则积极拒绝
!this.Locator.Sockets.BeginAccept(pcb))
{
RST(pcb, frame);
return;
}
pcbTable.TryAdd(pcbKey, pcb);
pcb.Open += (sender, e) =>
{
if (!pcb.Estableshed)
{
pcb.Estableshed = true;
var socket = this.Locator.Sockets.EndAccept(pcb);
if (socket == null)
{
pcb.Close();
}
else
{
pcb.OnOpen(e);
}
}
};
pcb.Abort += (sender, e) => ClosePCB(sender as TcpPcb, TcpState.CLOSED);
}
}
lock (pcb)
{
if (0 != (frame.Flags & TcpFlags.TCP_SYN))
{
uint seqno = pcb.AcknowledgeNo++;
uint ackno = ++pcb.SequenceNo;
pcb.Post(TcpFlags.TCP_SYN | TcpFlags.TCP_ACK, ackno, seqno, 1, 3);
}
else if (0 != (frame.Flags & TcpFlags.TCP_RST) ||
0 != (frame.Flags & (TcpFlags.TCP_CWR | TcpFlags.TCP_ECE | TcpFlags.TCP_UGR)))
{
RST(pcb, frame);
}
else
{
pcb.SendBufferSize = frame.WindowSize;
if (0 != (frame.Flags & TcpFlags.TCP_ACK))
{
pcb.Ack(frame.AcknowledgeNo);
}
if (0 != (frame.Flags & TcpFlags.TCP_PSH))
{
uint pylen = (uint)frame.Payload.Length;
uint seqno = frame.AcknowledgeNo;
uint ackno = frame.SequenceNo + pylen;
if (ackno >= pcb.SequenceNo)
{
pcb.InputStream.Input(frame);
}
else
{
pcb.Post(TcpFlags.TCP_ACK, ackno, seqno, 0);
}
}
else if (0 != (frame.Flags & TcpFlags.TCP_FIN))
{
uint seqno = frame.AcknowledgeNo;
uint ackno = frame.SequenceNo + 1;
pcb.Post(TcpFlags.TCP_ACK, ackno, seqno, 0);
ClosePCB(pcb, TcpState.CLOSED);
}
}
}
}
public virtual void Output(TcpFrame frame)
{
IPFrame ip = ToIPFrame(frame);
if (ip != null)
{
Locator.IPv4.Output(ip);
}
}
public static IPFrame ToIPFrame(TcpFrame frame)
{
if (frame == null)
{
throw new ArgumentNullException(nameof(frame));
}
if (frame.AddressFamily != AddressFamily.InterNetwork)
{
throw new ArgumentNullException("TCP frames of this address family type are not supported.");
}
BufferSegment options_data = frame.Options;
int options_size = options_data?.Length ?? 0;
int payload_offset = sizeof(tcp_hdr) + options_size;
int payload_size = frame.Payload?.Length ?? 0;
byte[] message = new byte[payload_offset + payload_size];
fixed (byte* pinned = message)
{
tcp_hdr* tcphdr = (tcp_hdr*)pinned;
tcphdr->dest = CheckSum.htons((ushort)frame.Destination.Port);
tcphdr->src = CheckSum.htons((ushort)frame.Source.Port);
tcphdr->seqno = CheckSum.htonl(frame.SequenceNo);
tcphdr->ackno = CheckSum.htonl(frame.AcknowledgeNo);
tcphdr->urgp = CheckSum.htons(frame.UrgentPointer);
tcphdr->wnd = CheckSum.htons(frame.WindowSize);
TCPH_HDRLEN_SET(tcphdr, payload_offset >> 2);
TCPH_FLAGS_SET(tcphdr, (int)frame.Flags);
if (options_size > 0)
{
IntPtr destination_options = (IntPtr)(pinned + sizeof(tcp_hdr));
Marshal.Copy(options_data.Buffer, options_data.Offset, destination_options, options_size);
}
if (payload_size > 0)
{
using (MemoryStream ms = new MemoryStream(message, payload_offset, payload_size))
{
ms.Write(frame.Payload.Buffer, frame.Payload.Offset, payload_size);
}
}
ushort pseudo_checksum = CheckSum.inet_chksum_pseudo(pinned, (uint)ProtocolType.Tcp, (uint)message.Length,
IPFrame.GetAddressV4(frame.Source.Address),
IPFrame.GetAddressV4(frame.Destination.Address));
if (pseudo_checksum == 0)
{
pseudo_checksum = 0xffff;
}
tcphdr->chksum = pseudo_checksum;
}
return new IPFrame(ProtocolType.Tcp, frame.Source.Address, frame.Destination.Address, new BufferSegment(message))
{
Ttl = frame.Ttl,
};
}
public static TcpFrame ParseFrame(IPFrame ip, bool checksum = true)
{
if (ip == null)
{
return null;
}
TcpFrame frame = null;
BufferSegment packet = ip.Payload;
packet.UnsafeAddrOfPinnedArrayElement((p) =>
{
tcp_hdr* tcphdr = (tcp_hdr*)p;
if (tcphdr == null)
{
return;
}
int hdrlen_bytes = TCPH_HDRLEN_BYTES(tcphdr);
if (hdrlen_bytes < TCP_HLEN || hdrlen_bytes > packet.Length) // 错误的数据报
{
return;
}
int len = packet.Length - hdrlen_bytes;
if (len < 0)
{
return;
}
TcpFlags flags = (TcpFlags)TCPH_FLAGS(tcphdr);
if (checksum && tcphdr->chksum != 0)
{
uint pseudo_checksum = CheckSum.inet_chksum_pseudo((byte*)p.ToPointer(),
(uint)ProtocolType.Tcp,
(uint)packet.Length,
ip.SourceAddressV4,
ip.DestinationAddressV4);
if (pseudo_checksum != 0)
{
return;
}
}
long payload_offset = 0;
fixed (byte* stream = packet.Buffer)
{
payload_offset = ((byte*)p + hdrlen_bytes) - stream;
}
BufferSegment message_data = new BufferSegment(packet.Buffer, unchecked((int)payload_offset), len);
BufferSegment options_data = null;
int options_size = hdrlen_bytes - sizeof(tcp_hdr);
if (options_size <= 0)
{
options_data = new BufferSegment(BufferSegment.Empty);
}
else
{
options_data = new BufferSegment(packet.Buffer,
packet.Offset + sizeof(tcp_hdr), options_size);
}
frame = new TcpFrame(new IPEndPoint(ip.Source, CheckSum.ntohs(tcphdr->src)), new IPEndPoint(ip.Destination, CheckSum.ntohs(tcphdr->dest)), message_data)
{
Ttl = ip.Ttl,
AcknowledgeNo = CheckSum.ntohl(tcphdr->ackno),
SequenceNo = CheckSum.ntohl(tcphdr->seqno),
WindowSize = CheckSum.ntohs(tcphdr->wnd),
Flags = flags,
Options = options_data,
UrgentPointer = CheckSum.ntohs(tcphdr->urgp)
};
});
return frame;
}
public virtual TcpFrame Parse(IPFrame ip) => ParseFrame(ip);
}
}
namespace Ppp.Net.Tcp
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using Ppp.Core;
using Ppp.Net;
using Ppp.Net.Entry;
public enum TcpState : byte
{
CLOSED = 0,
LISTEN = 1,
SYN_SENT = 2,
SYN_RCVD = 3,
ESTABLISHED = 4,
FIN_WAIT_1 = 5,
FIN_WAIT_2 = 6,
CLOSE_WAIT = 7,
CLOSING = 8,
LAST_ACK = 9,
TIME_WAIT = 10
}
class TcpInputStream
{
public readonly LinkedList<TcpFrame> Frames = new LinkedList<TcpFrame>();
public event EventHandler<TcpFrame> Receive;
public readonly TcpPcb Pcb;
public TcpInputStream(TcpPcb pcb)
{
this.Pcb = pcb ?? throw new ArgumentNullException(nameof(pcb));
}
public virtual void Input(TcpFrame frame)
{
if (frame == null || frame.Payload == null)
{
return;
}
if (frame.Payload.Length <= 0)
{
return;
}
lock (this.Frames)
{
if (frame.SequenceNo == this.Pcb.SequenceNo)
{
this.Pcb.SequenceNo = frame.SequenceNo + (uint)frame.Payload.Length;
OnReceive(frame);
var node = this.Frames.First;
while (node != null)
{
TcpFrame f = node.Value;
var current = node;
node = current.Next;
if (f.SequenceNo == this.Pcb.SequenceNo)
{
this.Frames.Remove(current);
this.Pcb.SequenceNo = f.SequenceNo + (uint)f.Payload.Length;
OnReceive(f);
}
}
}
else if (this.Frames.Count <= 0)
{
this.Frames.AddLast(frame);
}
else
{
var node = this.Frames.Last;
if (frame.SequenceNo == node.Value.SequenceNo)
{
return;
}
else if (frame.SequenceNo > node.Value.SequenceNo)
{
this.Frames.AddLast(frame);
}
else
{
node = this.Frames.Last;
while (node != null)
{
TcpFrame f = node.Value;
if (f.SequenceNo == frame.SequenceNo)
{
return;
}
if (f.SequenceNo < frame.SequenceNo)
{
this.Frames.AddAfter(node, frame);
break;
}
node = node.Previous;
}
if (node == null)
{
this.Frames.AddFirst(frame);
}
}
}
}
}
protected virtual void OnReceive(TcpFrame frame)
{
this.Receive?.Invoke(this, frame);
}
}
class TcpPcb : IPcb
{
public ILayerLocator Locator;
public TcpState State;
public uint SequenceNo;
public uint AcknowledgeNo;
public uint SendBufferSize;
public uint ReceiveBufferSize;
public IPEndPoint Source;
public IPEndPoint Destination;
public int Ttl;
public bool Estableshed;
public bool Aborted;
public double RTT;
public double SRTT;
public double RTO;
public double RTTVAL;
public override EndPoint LocalEndPoint => this.Source;
public override EndPoint RemoteEndPoint => this.Destination;
public override AddressFamily AddressFamily { get; }
public const int MIN_RTO = 200;
public SortedDictionary<long, SegmentsContext> SegmentsContexts = new SortedDictionary<long, SegmentsContext>();
public TcpInputStream InputStream;
public TcpPcb(TcpFrame frame, ILayerLocator locator)
{
if (frame == null)
{
throw new ArgumentNullException(nameof(frame));
}
this.Locator = locator ?? throw new ArgumentNullException(nameof(locator));
this.AcknowledgeNo = frame.AcknowledgeNo;
this.SequenceNo = frame.SequenceNo;
this.AddressFamily = frame.AddressFamily;
this.Destination = frame.Destination;
this.Source = frame.Source;
this.Ttl = frame.Ttl;
this.Aborted = false;
this.Estableshed = false;
this.SendBufferSize = frame.WindowSize;
this.ReceiveBufferSize = frame.WindowSize;
this.InputStream = new TcpInputStream(this);
this.InputStream.Receive += (sender, e) =>
{
uint ackNo = Convert.ToUInt32(e.SequenceNo + e.Payload.Length);
uint seqNo = e.AcknowledgeNo;
this.SequenceNo = ackNo;
{
this.Post(TcpFlags.TCP_ACK, ackNo, seqNo, 0);
}
this.OnMessage(e.Payload);
};
}
internal virtual void Post(TcpFlags flags, uint ackno, uint seqno, uint length = 0, int retransmission = 0, bool timeout = false)
{
SegmentsContext segments = null;
lock (this)
{
lock (this.SegmentsContexts)
{
segments = new SegmentsContext()
{
AcknowledgeNo = ackno,
SequenceNo = seqno,
Flags = flags,
Length = length,
Stopwatch = new Stopwatch(),
Retransmission = retransmission,
Pcb = this,
Timeout = timeout,
};
if (retransmission > 0)
{
long nackNo = segments.SequenceNo + segments.Length;
if (this.SegmentsContexts.TryAdd(nackNo, segments))
{
segments.Stopwatch.Start();
}
}
}
}
TcpFrame frame = segments.CreateFrame(this);
this.Locator.Tcp.Output(frame);
}
internal virtual bool Ack(long ackno)
{
bool ack = false;
SegmentsContext segments = null;
lock (this.SegmentsContexts)
{
ack = this.SegmentsContexts.Remove(ackno, out segments);
if (ack)
{
segments.Stopwatch.Stop();
UpdateAckTime(segments.Stopwatch.ElapsedMilliseconds);
if (this.State == TcpState.SYN_RCVD)
{
this.State = TcpState.ESTABLISHED;
this.OnOpen(EventArgs.Empty);
}
}
if (this.SegmentsContexts.Count > 0 && ackno <= this.AcknowledgeNo)
{
var rapids = new List<long>();
foreach (var key in this.SegmentsContexts.Keys)
{
if (key > ackno)
{
break;
}
rapids.Add(key);
}
foreach (var key in rapids)
{
this.SegmentsContexts.Remove(key, out segments);
}
}
}
return ack;
}
private void UpdateAckTime(long rtt)
{
RTT = Convert.ToInt64(rtt);
if (0 == SRTT)
{
SRTT = RTT;
RTTVAL = RTT / 2;
}
else
{
RTTVAL = ((RTTVAL * 3) + Math.Abs(RTT - SRTT)) / 4;
SRTT = (7 * SRTT + RTT) / 8;
SRTT = SRTT <= 0 ? 1 : SRTT;
}
RTO = SRTT + Math.Min(1, RTTVAL * 4);
if (RTO < MIN_RTO)
{
RTO = MIN_RTO;
}
}
public override string ToString()
{
return $"{this.Source} <-> {this.Destination}";
}
public override bool Send(BufferSegment payload)
{
if (payload == null || payload.Length <= 0)
{
return false;
}
bool sendto(BufferSegment buffer)
{
if (buffer == null || buffer.Length <= 0)
{
return false;
}
SegmentsContext segments = null;
lock (this)
{
lock (this.SegmentsContexts)
{
segments = new SegmentsContext()
{
AcknowledgeNo = this.SequenceNo,
SequenceNo = this.AcknowledgeNo,
Flags = TcpFlags.TCP_PSH | TcpFlags.TCP_ACK,
Length = (uint)buffer.Length,
Stopwatch = new Stopwatch(),
Pcb = this,
Retransmission = 5,
Payload = payload,
};
var ackNo = segments.SequenceNo + segments.Length;
if (this.SegmentsContexts.TryAdd(ackNo, segments))
{
segments.Stopwatch.Start();
this.AcknowledgeNo += segments.Length;
}
}
}
TcpFrame frame = segments.CreateFrame(this);
this.Locator.Tcp.Output(frame);
return true;
}
foreach (BufferSegment buffer in Slices(payload))
{
if (!sendto(buffer))
{
return false;
}
}
return true;
}
private void CloseOrTimeout(bool timeout = false)
{
var pcb = this;
lock (this)
{
if (!this.Aborted)
{
uint seqno = pcb.AcknowledgeNo++;
uint ackno = pcb.SequenceNo;
if (timeout)
{
pcb.Post(TcpFlags.TCP_FIN | TcpFlags.TCP_ACK, ackno, seqno);
}
else
{
pcb.Post(TcpFlags.TCP_FIN | TcpFlags.TCP_ACK, ackno, seqno, 1, 3);
}
this.Aborted = false;
this.OnAbort(EventArgs.Empty);
}
}
}
public virtual void Timeout()
{
CloseOrTimeout(true);
}
public override void Close()
{
CloseOrTimeout();
}
}
}
ICMP
namespace Ppp.Net.Icmp
{
using System;
using System.Net;
using System.Net.Sockets;
using Ppp.Core;
using Ppp.Net.IP;
public enum IcmpType : byte
{
ICMP_ER = 0, /* echo reply */
ICMP_DUR = 3, /* destination unreachable */
ICMP_SQ = 4, /* source quench */
ICMP_RD = 5, /* redirect */
ICMP_ECHO = 8, /* echo */
ICMP_TE = 11, /* time exceeded */
ICMP_PP = 12, /* parameter problem */
ICMP_TS = 13, /* timestamp */
ICMP_TSR = 14, /* timestamp reply */
ICMP_IRQ = 15, /* information request */
ICMP_IR = 16, /* information reply */
ICMP_AM = 17, /* address mask request */
ICMP_AMR = 18, /* address mask reply */
}
public class IcmpFrame
{
public virtual IcmpType Type { get; set; }
public virtual byte Code { get; set; }
public virtual ushort Identification { get; set; }
public virtual ushort Sequence { get; set; }
public virtual IPAddress Source { get; }
public virtual IPAddress Destination { get; }
public virtual int Ttl { get; set; }
public virtual AddressFamily AddressFamily { get; }
public virtual BufferSegment Payload { get; set; }
public IcmpFrame(IPAddress source, IPAddress destination, BufferSegment payload)
{
this.Ttl = IPFrame.DefaultTtl;
this.Payload = payload ?? new BufferSegment(BufferSegment.Empty);
this.Source = source ?? throw new ArgumentNullException(nameof(source));
this.Destination = destination ?? throw new ArgumentNullException(nameof(Destination));
this.AddressFamily = destination.AddressFamily;
}
public override string ToString()
{
return string.Format($"{Source} -> {Destination}");
}
}
}
namespace Ppp.Net.Icmp
{
using System;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using Ppp.Core;
using Ppp.Net.Entry;
using Ppp.Net.IP;
public unsafe class IcmpLayer
{
[StructLayout(LayoutKind.Sequential, Pack = 1)] // RFC 792(http://www.faqs.org/rfcs/rfc792.html)
struct icmp_hdr
{
public byte icmp_type; // icmp service type, 8 echo request, 0 echo reply
public byte icmp_code; // icmp header code
public ushort icmp_chksum; // icmp header chksum
public ushort icmp_id; // icmp packet identification
public ushort icmp_seq; // icmp packet sequent
}
public virtual ILayerLocator Locator { get; }
public IcmpLayer(ILayerLocator locator)
{
this.Locator = locator ?? throw new ArgumentNullException(nameof(locator));
}
public virtual void Input(IcmpFrame frame)
{
}
public virtual void Output(IcmpFrame frame)
{
IPFrame ip = ToIPFrame(frame);
if (ip != null)
{
Locator.IPv4.Output(ip);
}
}
public static IPFrame ToIPFrame(IcmpFrame frame)
{
if (frame == null)
{
throw new ArgumentNullException(nameof(frame));
}
if (frame.AddressFamily != AddressFamily.InterNetwork)
{
throw new ArgumentNullException("ICMP frames of this address family type are not supported.");
}
BufferSegment payload = frame.Payload;
byte[] buffer = new byte[sizeof(icmp_hdr) + payload?.Length ?? 0];
fixed (byte* pinned = buffer)
{
icmp_hdr* icmp = (icmp_hdr*)pinned;
icmp->icmp_type = (byte)frame.Type;
icmp->icmp_code = frame.Code;
icmp->icmp_id = CheckSum.ntohs(frame.Identification);
icmp->icmp_seq = CheckSum.ntohs(frame.Sequence);
icmp->icmp_chksum = 0;
if (payload != null)
{
Marshal.Copy(payload.Buffer, payload.Offset, (IntPtr)(pinned + sizeof(icmp_hdr)), payload.Length);
}
icmp->icmp_chksum = CheckSum.inet_chksum(icmp, buffer.Length);
if (icmp->icmp_chksum == 0)
{
icmp->icmp_chksum = 0xffff;
}
}
return new IPFrame(ProtocolType.Icmp, frame.Source, frame.Destination, new BufferSegment(buffer))
{
Ttl = frame.Ttl,
};
}
public static IcmpFrame ParseFrame(IPFrame ip, bool checksum = true)
{
if (ip == null)
{
return null;
}
IcmpFrame frame = null;
BufferSegment segment = ip.Payload;
segment.UnsafeAddrOfPinnedArrayElement(p =>
{
icmp_hdr* icmp = (icmp_hdr*)p;
if (checksum && icmp->icmp_chksum != 0)
{
ushort cksum = CheckSum.inet_chksum(icmp, segment.Length);
if (cksum != 0)
{
return;
}
}
int payload_size = segment.Length - sizeof(icmp_hdr);
if (payload_size < 0)
{
return;
}
frame = new IcmpFrame(ip.Source, ip.Destination, new BufferSegment(segment.Buffer, segment.Offset + sizeof(icmp_hdr), payload_size))
{
Type = (IcmpType)icmp->icmp_type,
Code = icmp->icmp_code,
Identification = CheckSum.ntohs(icmp->icmp_id),
Sequence = CheckSum.ntohs(icmp->icmp_seq),
Ttl = ip.Ttl,
};
});
return frame;
}
public virtual IcmpFrame Parse(IPFrame ip) => ParseFrame(ip);
}
}
IPv4
namespace Ppp.Net.IP
{
using System;
using System.Net;
using System.Net.Sockets;
using Ppp.Core;
public enum IPFlags : ushort
{
IP_RF = 0x8000, /* reserved fragment flag */
IP_DF = 0x4000, /* dont fragment flag */
IP_MF = 0x2000, /* more fragments flag */
IP_OFFMASK = 0x1fff, /* mask for fragmenting bits */
}
public unsafe class IPFrame : EventArgs
{
public const int DefaultTtl = 64;
public IPFrame(ProtocolType protocolType, IPAddress source, IPAddress destination, BufferSegment payload)
{
this.Destination = destination ?? throw new ArgumentNullException(nameof(destination));
this.Source = source ?? throw new ArgumentNullException(nameof(source));
this.AddressFamily = destination.AddressFamily;
if (source.AddressFamily != destination.AddressFamily)
{
throw new ArgumentOutOfRangeException("The original address is inconsistent with the target address protocol.");
}
this.Ttl = DefaultTtl;
this.Tos = IPv4Layer.TOS_ROUTIN_MODE;
this.Flags = IPFlags.IP_DF;
this.ProtocolType = protocolType;
this.Payload = payload ?? throw new ArgumentNullException(nameof(payload));
}
public virtual AddressFamily AddressFamily { get; }
public virtual ushort Id { get; set; }
public virtual IPFlags Flags { get; set; }
public virtual int FragmentOffset
{
get
{
int offset = (ushort)this.Flags;
offset = ((ushort)(offset << 3)) >> 3;
offset <<= 3;
return offset;
}
set
{
int flags = (int)this.Flags >> 13;
flags = flags << 13 | value >> 3;
this.Flags = (IPFlags)flags;
}
}
public virtual IPAddress Source { get; set; }
public virtual IPAddress Destination { get; set; }
public static uint GetAddressV4(IPAddress address)
{
if (address == null || address.AddressFamily != AddressFamily.InterNetwork)
{
return 0;
}
byte[] addressBytes = address.GetAddressBytes();
fixed (byte* p = addressBytes)
{
if (p == null)
{
return 0;
}
return *(uint*)p;
}
}
public virtual uint SourceAddressV4
{
get
{
return GetAddressV4(this.Source);
}
}
public virtual uint DestinationAddressV4
{
get
{
return GetAddressV4(this.Destination);
}
}
public virtual BufferSegment Payload { get; }
public virtual BufferSegment Options { get; set; }
public virtual int Ttl { get; set; }
public virtual byte Tos { get; set; }
public virtual ProtocolType ProtocolType { get; }
public virtual bool HasFlag(IPFlags flags)
{
ushort v = CheckSum.ntohs((ushort)this.Flags);
return (v & CheckSum.ntohs((ushort)(flags))) != 0;
}
public override string ToString()
{
return string.Format($"{this.Source} -> {this.Destination}");
}
}
}
namespace Ppp.Net.IP
{
using Ppp.Core;
using Ppp.Net.Icmp;
using Ppp.Net.Tcp;
using Ppp.Net.Udp;
public interface IPLayer
{
TcpLayer Tcp { get; }
UdpLayer Udp { get; }
IcmpLayer Icmp { get; }
void Output(IPFrame frame);
void Input(IPFrame frame);
IPFrame Parse(BufferSegment buffer);
}
}
namespace Ppp.Net.IP
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using Ppp.Core;
using Ppp.Net.Entry;
using Ppp.Net.Icmp;
using Ppp.Net.Tcp;
using Ppp.Net.Udp;
public unsafe class IPv4Layer : IPLayer
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private static volatile int _locationId = Environment.TickCount;
public const byte TOS_ROUTIN_MODE = 0x00;
public virtual TcpLayer Tcp { get; }
public virtual UdpLayer Udp { get; }
public virtual IcmpLayer Icmp { get; }
public virtual ILayerLocator Locator { get; }
public IPv4Layer(ILayerLocator locator)
{
this.Locator = locator ?? throw new ArgumentNullException(nameof(locator));
this.Tcp = locator.Tcp;
this.Udp = locator.Udp;
this.Icmp = locator.Icmp;
}
public virtual void Output(IPFrame frame)
{
var packet = ToArray(frame);
if (packet != null)
{
Locator.Netif.Output(packet);
}
}
public virtual void Input(IPFrame frame)
{
if (frame.ProtocolType == ProtocolType.Tcp)
{
var f = Tcp.Parse(frame);
if (f != null)
{
Tcp.Input(f);
}
}
else if (frame.ProtocolType == ProtocolType.Udp)
{
var f = Udp.Parse(frame);
if (f != null)
{
Udp.Input(f);
}
}
else if (frame.ProtocolType == ProtocolType.Icmp)
{
var f = Icmp.Parse(frame);
if (f != null)
{
Icmp.Input(f);
}
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 20)]
private struct ip_hdr
{
#pragma warning disable 0649
/* version / header length / type of service */
public byte _v_hl;
/* type of service */
public byte _tos;
/* total length */
public ushort _len;
/* identification */
public ushort _id;
/* fragment offset field */
public ushort _flags;
/* time to live */
public byte _ttl;
/* protocol */
public byte _proto;
/* checksum */
public ushort _chksum;
/* source and destination IP addresses */
public uint src;
public uint dest;
#pragma warning restore 0649
public static int IPH_V(ip_hdr* hdr)
{
return ((hdr)->_v_hl >> 4);
}
public static int IPH_HL(ip_hdr* hdr)
{
return ((hdr)->_v_hl & 0x0f);
}
public static int IPH_PROTO(ip_hdr* hdr)
{
return ((hdr)->_proto & 0xff);
}
public static int IPH_OFFSET(ip_hdr* hdr)
{
return (hdr)->_flags;
}
public static int IPH_TTL(ip_hdr* hdr)
{
return ((hdr)->_ttl & 0xff);
}
}
private const uint IP_ADDR_ANY_VALUE = 0x00000000;
private const uint IP_ADDR_BROADCAST_VALUE = 0xffffffff;
private static bool ip_addr_isbroadcast(uint addr)
{
/* all ones (broadcast) or all zeroes (old skool broadcast) */
if ((~addr == IP_ADDR_ANY_VALUE) ||
(addr == IP_ADDR_ANY_VALUE))
return true;
return false;
}
public const int IP_PROTO_ICMP = 1;
public const int IP_PROTO_UDP = 17;
public const int IP_PROTO_TCP = 6;
public const int IP_PROTO_IGMP = 2;
public const int IP_PROTO_GRE = 47;
private const int IP_HLEN = 20;
public virtual IPFrame Parse(BufferSegment buffer) => ParseFrame(buffer);
public static IPFrame ParseFrame(BufferSegment packet, bool checksum = true)
{
if (packet == null)
{
return null;
}
IPFrame frame = null;
packet.UnsafeAddrOfPinnedArrayElement((payload) =>
{
ip_hdr* iphdr = (ip_hdr*)payload;
if (iphdr == null)
{
return;
}
if (ip_hdr.IPH_V(iphdr) != 4)
{
return;
}
int iphdr_hlen = ip_hdr.IPH_HL(iphdr) << 2;
if (iphdr_hlen > packet.Length)
{
return;
}
if (iphdr_hlen < IP_HLEN)
{
return;
}
int ttl = ip_hdr.IPH_TTL(iphdr);
if (ttl <= 0)
{
return;
}
if (checksum && iphdr->_chksum != 0)
{
int cksum = CheckSum.inet_chksum(iphdr, iphdr_hlen);
if (cksum != 0)
{
return;
}
}
if (ip_addr_isbroadcast(iphdr->src) || ip_addr_isbroadcast(iphdr->dest))
{
return;
}
if ((ip_hdr.IPH_OFFSET(iphdr) & CheckSum.ntohs((ushort)(IPFlags.IP_OFFMASK | IPFlags.IP_MF))) != 0) // 不允许IP分片(NAT不太容易处理好分片)
{
return;
}
ProtocolType protocolType = (ProtocolType)ip_hdr.IPH_PROTO(iphdr);
if (protocolType == (ProtocolType)IP_PROTO_UDP ||
protocolType == (ProtocolType)IP_PROTO_TCP ||
protocolType == (ProtocolType)IP_PROTO_ICMP ||
protocolType == (ProtocolType)IP_PROTO_GRE)
{
BufferSegment message_data = new BufferSegment(packet.Buffer,
packet.Offset + iphdr_hlen,
packet.Length - iphdr_hlen);
BufferSegment options_data = null;
int options_size = (iphdr_hlen - sizeof(ip_hdr));
if (options_size <= 0)
{
options_data = new BufferSegment(BufferSegment.Empty);
}
else
{
options_data = new BufferSegment(packet.Buffer,
packet.Offset + sizeof(ip_hdr), options_size);
}
frame = new IPFrame(protocolType,
new IPAddress(iphdr->src),
new IPAddress(iphdr->dest),
message_data)
{
Id = CheckSum.ntohs(iphdr->_id),
Ttl = ttl,
Tos = iphdr->_tos,
Options = options_data,
Flags = (IPFlags)CheckSum.ntohs(iphdr->_flags),
};
}
});
return frame;
}
public static ushort NewId() => (ushort)Interlocked.Increment(ref _locationId);
public static IList<IPFrame> Subpackages(IPFrame frame)
{
if (frame == null)
{
throw new ArgumentNullException(nameof(frame));
}
List<IPFrame> subpackages = new List<IPFrame>();
if (0 != (frame.Flags & IPFlags.IP_MF))
{
subpackages.Add(frame);
return subpackages;
}
BufferSegment messages = frame.Payload;
BufferSegment options = frame.Options;
if (messages == null)
{
subpackages.Add(frame);
return subpackages;
}
int max = Tap.MTU - sizeof(ip_hdr);
if (options != null)
{
max -= options.Length;
}
max = unchecked((max >> 3) << 3);
int szz = messages.Length;
int ofs = 0;
IPFrame fragment = null;
while (szz > max)
{
fragment = new IPFrame(frame.ProtocolType,
frame.Source,
frame.Destination,
new BufferSegment(messages.Buffer, messages.Offset + ofs, max))
{
Flags = IPFlags.IP_MF,
Id = frame.Id,
Options = frame.Options,
Ttl = frame.Ttl,
Tos = frame.Tos,
FragmentOffset = ofs,
};
ofs += max;
szz -= max;
subpackages.Add(fragment);
}
fragment = new IPFrame(frame.ProtocolType,
frame.Source,
frame.Destination,
new BufferSegment(messages.Buffer, messages.Offset + ofs, szz))
{
Flags = subpackages.Count <= 0 ? frame.Flags : 0,
Id = frame.Id,
Options = frame.Options,
Ttl = frame.Ttl,
Tos = frame.Tos,
FragmentOffset = ofs,
};
subpackages.Add(fragment);
return subpackages;
}
public static BufferSegment ToArray(IPFrame frame)
{
if (frame == null)
{
throw new ArgumentNullException(nameof(frame));
}
BufferSegment payload_segment = frame.Payload;
BufferSegment options_segment = frame.Options;
int options_size = 0;
if (options_segment != null)
{
options_size = options_segment.Length;
}
int payload_offset = sizeof(ip_hdr) + options_size;
int payload_size = 0;
if (payload_segment != null)
{
payload_size = payload_segment.Length;
}
byte[] message_data = new byte[payload_offset + payload_size];
fixed (byte* pinned = message_data)
{
ip_hdr* iphdr = (ip_hdr*)pinned;
iphdr->dest = frame.DestinationAddressV4;
iphdr->src = frame.SourceAddressV4;
iphdr->_ttl = (byte)frame.Ttl;
iphdr->_proto = (byte)frame.ProtocolType;
iphdr->_v_hl = (byte)(4 << 4 | payload_offset >> 2);
iphdr->_tos = frame.Tos; // Routine Mode
iphdr->_len = CheckSum.htons((ushort)message_data.Length);
iphdr->_id = CheckSum.htons(frame.Id);
iphdr->_flags = CheckSum.ntohs((ushort)(frame.Flags == 0 ? IPFlags.IP_DF : frame.Flags));
iphdr->_chksum = 0;
if (options_size > 0)
{
IntPtr destination_options = (IntPtr)(pinned + sizeof(ip_hdr));
Marshal.Copy(options_segment.Buffer, options_segment.Offset, destination_options, options_size);
}
if (payload_size > 0)
{
Buffer.BlockCopy(payload_segment.Buffer, payload_segment.Offset, message_data, payload_offset, payload_size);
}
iphdr->_chksum = CheckSum.inet_chksum(pinned, payload_offset);
if (iphdr->_chksum == 0)
{
iphdr->_chksum = 0xffff;
}
}
return new BufferSegment(message_data);
}
}
}
CheckSum
namespace Ppp.Core
{
public unsafe static class CheckSum
{
public static ushort ip_standard_chksum(void* dataptr, int len)
{
uint acc;
ushort src;
byte* octetptr;
acc = 0;
/* dataptr may be at odd or even addresses */
octetptr = (byte*)dataptr;
while (len > 1)
{
/* declare first octet as most significant
thus assume network order, ignoring host order */
src = (ushort)((*octetptr) << 8);
octetptr++;
/* declare second octet as least significant */
src |= (*octetptr);
octetptr++;
acc += src;
len -= 2;
}
if (len > 0)
{
/* accumulate remaining octet */
src = (ushort)((*octetptr) << 8);
acc += src;
}
/* add deferred carry bits */
acc = (uint)((acc >> 16) + (acc & 0x0000ffffUL));
if ((acc & 0xffff0000UL) != 0)
{
acc = (uint)((acc >> 16) + (acc & 0x0000ffffUL));
}
/* This maybe a little confusing: reorder sum using htons()
instead of ntohs() since it has a little less call overhead.
The caller must invert bits for Internet sum ! */
return ntohs((ushort)acc);
}
public static ushort inet_chksum(void* dataptr, int len)
{
return (ushort)~ip_standard_chksum(dataptr, len);
}
private static uint FOLD_U32T(uint u)
{
return ((uint)(((u) >> 16) + ((u) & 0x0000ffffUL)));
}
private static uint SWAP_BYTES_IN_WORD(uint w)
{
return (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8);
}
public static ushort ntohs(ushort n)
{
ushort r = 0;
byte* p1 = (byte*)&n;
byte* p2 = (byte*)&r;
p2[0] = p1[1];
p2[1] = p1[0];
return r;
}
public static uint ntohl(uint n)
{
uint r = 0;
byte* p1 = (byte*)&n;
byte* p2 = (byte*)&r;
p2[0] = p1[3];
p2[1] = p1[2];
p2[2] = p1[1];
p2[3] = p1[0];
return r;
}
public static uint htonl(uint n)
{
return ntohl(n);
}
public static ushort htons(ushort n)
{
return ntohs(n);
}
public static ushort inet_cksum_pseudo_base(byte* payload, uint proto, uint proto_len, uint acc)
{
bool swapped = false;
acc += ip_standard_chksum(payload, (int)proto_len);
acc = FOLD_U32T(acc);
if (proto_len % 2 != 0)
{
swapped = !swapped;
acc = SWAP_BYTES_IN_WORD(acc);
}
if (swapped)
{
acc = SWAP_BYTES_IN_WORD(acc);
}
acc += htons((ushort)proto);
acc += htons((ushort)proto_len);
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
return (ushort)~(acc & 0xffffUL);
}
public static ushort inet_chksum_pseudo(byte* payload, uint proto, uint proto_len, uint src, uint dest)
{
uint acc;
uint addr;
addr = src;
acc = (addr & 0xffff);
acc = (acc + ((addr >> 16) & 0xffff));
addr = dest;
acc = (acc + (addr & 0xffff));
acc = (acc + ((addr >> 16) & 0xffff));
/* fold down to 16 bits */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
return inet_cksum_pseudo_base(payload, proto, proto_len, acc);
}
}
}
BufferSegment
namespace Ppp.Core
{
using System;
using System.IO;
using System.Text;
using System.Collections;
using System.Linq;
using System.Collections.Generic;
#if NET40
using System.Collections.Concurrent;
#endif
public unsafe class BufferSegment : EventArgs, IEnumerable<byte>
{
public new static readonly byte[] Empty = new byte[0];
public static readonly IntPtr Null = IntPtr.Zero;
public virtual byte[] Buffer { get; private set; }
public virtual int Offset { get; private set; }
public virtual int Length { get; private set; }
public BufferSegment(byte[] buffer) : this(buffer, buffer?.Length ?? 0)
{
}
public BufferSegment(byte[] buffer, int length) : this(buffer, 0, length)
{
}
public BufferSegment(byte[] buffer, int offset, int length)
{
if (offset < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
if (length < 0)
{
throw new ArgumentOutOfRangeException(nameof(length));
}
this.Buffer = buffer ?? Empty;
if ((offset + length) > buffer.Length)
{
throw new ArgumentOutOfRangeException("The offset and length overflow the size of the buffer.");
}
this.Offset = offset;
this.Length = length;
}
~BufferSegment()
{
this.Buffer = null;
this.Offset = 0;
this.Length = 0;
GC.SuppressFinalize(this);
}
public virtual BufferSegment Depth()
{
byte[] b = null;
int length = this.Length;
if (length <= 0)
{
b = BufferSegment.Empty;
}
else
{
b = new byte[length];
}
BufferSegment s = new BufferSegment(b);
if (b.Length > 0)
{
this.CopyTo(s.Buffer);
}
return s;
}
public static implicit operator BufferSegment(byte[] b)
{
if (b == null)
{
return new BufferSegment(Empty);
}
return new BufferSegment(b);
}
public virtual ArraySegment<byte> ToArraySegment()
{
return new ArraySegment<byte>(this.Buffer, this.Offset, this.Length);
}
public virtual byte[] ToArray()
{
return ToArraySegment().ToArray();
}
public void CopyTo(byte[] destination)
{
ToArraySegment().CopyTo(destination, 0);
}
public virtual void CopyTo(byte[] destination, int destinationIndex)
{
ToArraySegment().CopyTo(destination, destinationIndex);
}
public virtual void CopyTo(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}
stream.Write(this.Buffer, this.Offset, this.Length);
}
public IntPtr UnsafeAddrOfPinnedArrayElement()
{
return UnsafeAddrOfPinnedArrayElement(null);
}
public virtual IntPtr UnsafeAddrOfPinnedArrayElement(Action<IntPtr> callback)
{
IntPtr ptr = IntPtr.Zero;
var buffer = this.Buffer;
fixed (byte* pinned = buffer)
{
if (pinned != null)
{
int num = (this.Offset + this.Length);
if (buffer.Length >= num)
{
ptr = (IntPtr)(pinned + this.Offset);
}
}
callback?.Invoke(ptr);
}
return ptr;
}
public override string ToString()
{
string s = string.Empty;
UnsafeAddrOfPinnedArrayElement((p) =>
{
if (p == null)
s = null;
else
s = new string((sbyte*)p, 0, this.Length, Encoding.Default);
});
return s;
}
public virtual IEnumerator GetEnumerator()
{
IEnumerable<byte> enumerator = this;
return enumerator.GetEnumerator();
}
IEnumerator<byte> IEnumerable<byte>.GetEnumerator()
{
var offset = this.Offset;
var size = this.Length;
var pinned = this.Buffer;
if (offset > 0 && size > 0)
{
for (int i = offset; i < size; i++)
{
yield return pinned[i];
}
}
}
}
public unsafe static class Extension
{
public static int IndexOf(ref int[] next, byte* src, int src_len, byte* sub, int sub_len)
{
int i = 0;
int j = 0;
FindNext(ref next, sub, sub_len);
while (i < src_len && j < sub_len)
{
if (j == -1 || src[i] == sub[j])
{
i++;
j++;
}
else
{
j = next[j];
}
}
if (j >= sub_len)
{
return i - sub_len;
}
else
{
return -1;
}
}
private static void FindNext(ref int[] next, byte* sub, int sub_len)
{
int l = sub_len - 1;
int i = 0;
int j = -1;
next[0] = -1;
while (i < l)
{
if (j == -1 || sub[i] == sub[j])
{
j++;
i++;
if (sub[i] == sub[j])
{
next[i] = next[j];
}
else
{
next[i] = j;
}
}
else
{
j = next[j];
}
}
}
#if !NETCOREAPP2_0
public static T[] ToArray<T>(this ArraySegment<T> segment)
{
T[] s = null;
if (segment != null)
{
s = new T[segment.Count];
CopyTo(segment, s, 0);
}
return s;
}
public static void CopyTo<T>(this ArraySegment<T> segment, T[] destination, int destinationIndex)
{
if (segment != null && destination != null && destinationIndex >= 0)
{
Buffer.BlockCopy(segment.Array, segment.Offset, destination, destinationIndex, segment.Count);
}
}
public static bool Remove<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, out TValue value)
{
value = default(TValue);
if (dictionary == null)
{
return false;
}
lock (dictionary)
{
if (!dictionary.TryGetValue(key, out value))
{
return false;
}
return dictionary.Remove(key);
}
}
#if !NET40
private static IEnumerable<TResult> ZipIterator<TFirst, TSecond, TResult>(IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
{
using (IEnumerator<TFirst> e3 = first.GetEnumerator())
{
using (IEnumerator<TSecond> e2 = second.GetEnumerator())
{
while (e3.MoveNext() && e2.MoveNext())
{
yield return resultSelector(e3.Current, e2.Current);
}
}
}
}
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
{
if (first == null)
{
throw new ArgumentNullException(nameof(first));
}
if (second == null)
{
throw new ArgumentNullException(nameof(second));
}
if (resultSelector == null)
{
throw new ArgumentNullException(nameof(resultSelector));
}
return ZipIterator(first, second, resultSelector);
}
#endif
public static IEnumerable<KeyValuePair<TKey, TValue>> ToList<TKey, TValue>(this IDictionary<TKey, TValue> d)
{
#if NET40
if (d is ConcurrentDictionary<TKey, TValue>)
{
return d;
}
#endif
if (d is global::Ppp.Collections.ConcurrentDictionary<TKey, TValue>)
{
return d;
}
return Enumerable.ToList(d);
}
public static bool TryAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
if (dictionary == null)
{
return false;
}
lock (dictionary)
{
if (dictionary.ContainsKey(key))
{
return false;
}
dictionary.Add(key, value);
}
return true;
}
#endif
}
}