2using System.Collections.Generic;
5using System.Threading.Tasks;
15 private byte[] packetBuffer =
null;
17 private IPEndPoint remoteEndpoint;
20 private object stateObject =
null;
21 private int readState = 0;
22 private int packetSize = 0;
23 private ushort outgoingPacketNumber = 0;
24 private int offset = 0;
25 private int packetPos = 0;
26 private bool closed =
false;
27 private bool disposed =
false;
28 private readonly
bool encapsulatePackets;
31 bool EncapsulatePackets)
35 this.tcpConnection = TcpConnection;
36 this.encapsulatePackets = EncapsulatePackets;
38 this.tcpConnection.OnDisconnected += this.TcpConnection_OnDisconnected;
39 this.tcpConnection.OnError += this.TcpConnection_OnError;
40 this.tcpConnection.OnReceived += this.TcpConnection_OnReceived;
41 this.tcpConnection.OnSent += this.TcpConnection_OnSent;
44 private async Task TcpConnection_OnSent(
object Sender,
byte[] Buffer,
int Offset,
int Count)
46 this.lastTcpPacket = DateTime.Now;
53 await h(
this, Buffer, Offset, Count);
62 private async Task<bool> TcpConnection_OnReceived(
object Sender,
byte[] Buffer,
int Offset,
int Count)
66 this.lastTcpPacket = DateTime.Now;
67 this.resynchCallback =
null;
69 if (this.encapsulatePackets)
74 while (Count-- > 0 &&
Continue && !this.disposed)
76 switch (this.readState)
80 this.packetSize |= (b & 127) << this.offset;
84 this.packetBuffer =
new byte[this.packetSize];
91 NrLeft = Math.Min(Count, this.packetSize - this.packetPos);
92 Array.Copy(Buffer, Offset, this.packetBuffer, this.packetPos, NrLeft);
94 this.packetPos += NrLeft;
96 if (this.packetPos >= this.packetSize)
98 Continue = await this.OnPacketReceived();
103 this.packetBuffer =
null;
115 this.packetSize = Count;
116 this.packetBuffer =
new byte[Count];
117 Array.Copy(Buffer, Offset, this.packetBuffer, 0, Count);
118 Continue = await this.OnPacketReceived();
124 private async Task<bool> OnPacketReceived()
131 return await h(
this, this.packetBuffer, 0, this.packetSize);
142 private Task TcpConnection_OnError(
object _, Exception _2)
144 return this.Closed();
147 private Task TcpConnection_OnDisconnected(
object Sender, EventArgs e)
149 return this.Closed();
170 this.resynchCallback = ResynchCallback;
189 get => this.remoteEndpoint;
190 internal set => this.remoteEndpoint = value;
196 [Obsolete(
"Use DisposeAsync()")]
214 this.disposed =
true;
216 this.idleTimer?.Dispose();
217 this.idleTimer =
null;
220 this.tcpConnection =
null;
222 return this.Closed();
232 return this.
SendTcp(Packet,
null,
null);
242 public Task
SendTcp(
byte[] Packet, EventHandlerAsync<DeliveryEventArgs> Callback,
object State)
245 return Task.CompletedTask;
247 byte[] EncodedPacket = this.EncodePacket(Packet,
false);
248 return this.tcpConnection.
SendAsync(EncodedPacket, Callback, State);
251 private byte[] EncodePacket(
byte[] Packet,
bool IncludePacketNumber)
253 if (!this.encapsulatePackets)
257 int i = Packet.Length;
269 if (IncludePacketNumber)
274 byte[] Packet2 =
new byte[c + i];
275 Array.Copy(Packet, 0, Packet2, c, i);
288 if (IncludePacketNumber)
290 PacketNr = ++this.outgoingPacketNumber;
292 Packet2[j++] = (byte)PacketNr;
293 Packet2[j++] = (byte)(PacketNr >> 8);
308 public Task
SendUdp(
byte[] Packet,
int IncludeNrPreviousPackets)
310 byte[] EncodedPacket = this.EncodePacket(Packet,
true);
312 lock (this.historicPackets)
316 int c = EncodedPacket.Length;
318 if (IncludeNrPreviousPackets == 0)
319 ToSend = EncodedPacket;
322 foreach (
byte[] Packet2
in this.historicPackets)
326 if (i >= IncludeNrPreviousPackets)
330 ToSend =
new byte[c];
331 j = EncodedPacket.Length;
332 Array.Copy(EncodedPacket, 0, ToSend, 0, j);
335 foreach (
byte[] Packet2
in this.historicPackets)
337 Array.Copy(Packet2, 0, ToSend, j, Packet2.Length);
340 if (i >= IncludeNrPreviousPackets)
345 this.historicPackets.AddFirst(EncodedPacket);
347 if (this.nrHistoricPackets >= IncludeNrPreviousPackets)
348 this.historicPackets.RemoveLast();
350 this.nrHistoricPackets++;
352 return this.network.SendUdp(this.remoteEndpoint, ToSend);
356 private int nrHistoricPackets = 0;
357 private readonly LinkedList<byte[]> historicPackets =
new LinkedList<byte[]>();
382 private async Task Closed()
388 if (!(this.resynchCallback is
null))
390 await this.resynchCallback.Raise(
this, EventArgs.Empty,
false);
394 await this.RaiseOnClosed();
398 private Task RaiseOnClosed()
400 return this.
OnClosed.Raise(
this, EventArgs.Empty);
413 get => this.stateObject;
414 set => this.stateObject = value;
419 if (this.encapsulatePackets)
421 LinkedList<KeyValuePair<ushort, byte[]>> LostPackets =
null;
422 byte[] FirstPacket =
null;
423 ushort FirstPacketNr = 0;
426 byte[] Data = e.
Data;
427 int Len = Data.Length;
433 lock (this.udpReceiveLock)
438 PacketLen = (b & 127);
440 while (Pos < Len && (b & 128) != 0)
443 PacketLen |= (b & 127) << Offset;
450 PacketNr = Data[Pos++];
451 PacketNr |= (ushort)(Data[Pos++] << 8);
453 if (Pos + PacketLen > Len)
456 Packet =
new byte[PacketLen];
457 Array.Copy(Data, Pos, Packet, 0, PacketLen);
460 if ((
short)(PacketNr - this.lastReceivedPacket) > 0)
462 if (FirstPacket is
null)
464 FirstPacket = Packet;
465 FirstPacketNr = PacketNr;
469 if (LostPackets is
null)
470 LostPackets =
new LinkedList<KeyValuePair<ushort, byte[]>>();
472 LostPackets.AddFirst(
new KeyValuePair<ushort,
byte[]>(PacketNr, Packet));
477 if (!(FirstPacket is
null))
478 this.lastReceivedPacket = FirstPacketNr;
484 if (!(LostPackets is
null))
486 foreach (KeyValuePair<ushort,
byte[]> P
in LostPackets)
490 await h(
this, P.Value, 0, P.Value.Length);
499 if (!(FirstPacket is
null))
503 await h(
this, FirstPacket, 0, FirstPacket.Length);
514 byte[] Data = e.
Data;
515 int Len = Data.Length;
516 byte[] Packet =
new byte[Len];
518 Array.Copy(Data, 0, Packet, 0, Len);
525 await h(
this, Packet, 0, Packet.Length);
535 private ushort lastReceivedPacket = 0;
536 private readonly
object udpReceiveLock =
new object();
538 internal void StartIdleTimer()
540 this.idleTimer =
new Timer(this.IdleTimerCallback,
null, 5000, 5000);
543 private async
void IdleTimerCallback(
object P)
547 if ((DateTime.Now -
this.lastTcpPacket).TotalSeconds > 10)
551 await this.
SendTcp(
new byte[0]);
573 private Timer idleTimer =
null;
574 private DateTime lastTcpPacket = DateTime.Now;
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Implements a binary TCP Client, by encapsulating a TcpClient. It also makes the use of TcpClient safe...
Task< bool > SendAsync(byte[] Packet)
Sends a binary packet.
void Continue()
Continues reading from the socket, if paused in an event handler.
bool Paused
If the reading is paused.
virtual void Dispose()
Disposes of the object. The underlying TcpClient is either disposed directly, or when asynchronous op...
Maintains a peer connection
BinaryTcpClient Tcp
Underlying TCP connection
PeerToPeerNetwork Network
Peer-to-peer network.
object StateObject
State object that applications can use to attach information to a connection.
BinaryDataWrittenEventHandler OnSent
Event raised when a packet has been sent.
void Start(EventHandlerAsync ResynchCallback)
Starts receiving on the connection.
IPEndPoint RemoteEndpoint
Remote endpoint.
void Start()
Starts receiving on the connection.
void Continue()
Continues a paused connection.
Task DisposeAsync()
IDisposable.Dispose
bool Paused
If reading has been paused.
Task SendTcp(byte[] Packet)
Sends a packet to the peer at the other side of the TCP connection. Transmission is done asynchronous...
async void Dispose()
IDisposable.Dispose
Task SendTcp(byte[] Packet, EventHandlerAsync< DeliveryEventArgs > Callback, object State)
Sends a packet to the peer at the other side of the TCP connection. Transmission is done asynchronous...
BinaryDataReadEventHandler OnReceived
Event received when binary data has been received.
Task SendUdp(byte[] Packet, int IncludeNrPreviousPackets)
Sends a packet to a peer using UDP. Transmission is done asynchronously and is buffered if a sending ...
EventHandlerAsync OnClosed
Event raised when a connection has been closed for some reason.
Manages a peer-to-peer network that can receive connections from outside of a NAT-enabled firewall.
Event arguments for UDP Datagram events.
byte[] Data
Binary Datagram
delegate Task EventHandlerAsync(object Sender, EventArgs e)
Asynchronous version of EventArgs.
delegate Task BinaryDataWrittenEventHandler(object Sender, byte[] Buffer, int Offset, int Count)
Event handler for binary packet events.
delegate Task< bool > BinaryDataReadEventHandler(object Sender, byte[] Buffer, int Offset, int Count)
Event handler for binary packet events.