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,
bool ConstantBuffer,
byte[] Buffer,
int Offset,
int Count)
46 this.lastTcpPacket = DateTime.Now;
53 await h(
this, ConstantBuffer, Buffer, Offset, Count);
62 private async Task<bool> TcpConnection_OnReceived(
object Sender,
bool ConstantBuffer,
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 System.Buffer.BlockCopy(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 System.Buffer.BlockCopy(Buffer, Offset, this.packetBuffer, 0, Count);
118 Continue = await this.OnPacketReceived();
124 private async Task<bool> OnPacketReceived()
131 return await h(
this,
false, 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()")]
207 this.disposed =
true;
209 this.idleTimer?.Dispose();
210 this.idleTimer =
null;
212 if (!(this.tcpConnection is
null))
215 this.tcpConnection =
null;
226 [Obsolete(
"Use an overload with a ConstantBuffer argument. This increases performance, as the buffer will not be unnecessarily cloned if queued.")]
229 return this.
SendTcp(
false, Packet);
239 public Task
SendTcp(
bool ConstantBuffer,
byte[] Packet)
241 return this.
SendTcp(ConstantBuffer, Packet,
null,
null);
251 [Obsolete(
"Use an overload with a ConstantBuffer argument. This increases performance, as the buffer will not be unnecessarily cloned if queued.")]
252 public Task
SendTcp(
byte[] Packet, EventHandlerAsync<DeliveryEventArgs> Callback,
object State)
254 return this.
SendTcp(
false, Packet, Callback, State);
266 public Task
SendTcp(
bool ConstantBuffer,
byte[] Packet, EventHandlerAsync<DeliveryEventArgs> Callback,
object State)
269 return Task.CompletedTask;
271 byte[] EncodedPacket = this.EncodePacket(Packet,
false, out
bool ConstantBuffer2);
272 return this.tcpConnection.
SendAsync(ConstantBuffer || ConstantBuffer2, EncodedPacket, Callback, State);
275 private byte[] EncodePacket(
byte[] Packet,
bool IncludePacketNumber, out
bool ConstantBuffer)
277 if (!this.encapsulatePackets)
279 ConstantBuffer =
false;
284 int i = Packet.Length;
296 if (IncludePacketNumber)
301 byte[] Packet2 =
new byte[c + i];
302 Buffer.BlockCopy(Packet, 0, Packet2, c, i);
303 ConstantBuffer =
true;
316 if (IncludePacketNumber)
318 PacketNr = ++this.outgoingPacketNumber;
320 Packet2[j++] = (byte)PacketNr;
321 Packet2[j++] = (byte)(PacketNr >> 8);
336 public Task
SendUdp(
byte[] Packet,
int IncludeNrPreviousPackets)
338 byte[] EncodedPacket = this.EncodePacket(Packet,
true, out
bool _);
340 lock (this.historicPackets)
344 int c = EncodedPacket.Length;
346 if (IncludeNrPreviousPackets == 0)
347 ToSend = EncodedPacket;
350 foreach (
byte[] Packet2
in this.historicPackets)
354 if (i >= IncludeNrPreviousPackets)
358 ToSend =
new byte[c];
359 j = EncodedPacket.Length;
360 Buffer.BlockCopy(EncodedPacket, 0, ToSend, 0, j);
363 foreach (
byte[] Packet2
in this.historicPackets)
365 Buffer.BlockCopy(Packet2, 0, ToSend, j, Packet2.Length);
368 if (i >= IncludeNrPreviousPackets)
373 this.historicPackets.AddFirst(EncodedPacket);
375 if (this.nrHistoricPackets >= IncludeNrPreviousPackets)
376 this.historicPackets.RemoveLast();
378 this.nrHistoricPackets++;
380 return this.network.SendUdp(this.remoteEndpoint, ToSend);
384 private int nrHistoricPackets = 0;
385 private readonly LinkedList<byte[]> historicPackets =
new LinkedList<byte[]>();
410 private async Task Closed()
416 if (!(this.resynchCallback is
null))
418 await this.resynchCallback.Raise(
this, EventArgs.Empty,
false);
422 await this.RaiseOnClosed();
426 private Task RaiseOnClosed()
428 return this.
OnClosed.Raise(
this, EventArgs.Empty);
441 get => this.stateObject;
442 set => this.stateObject = value;
447 if (this.encapsulatePackets)
449 LinkedList<KeyValuePair<ushort, byte[]>> LostPackets =
null;
450 byte[] FirstPacket =
null;
451 ushort FirstPacketNr = 0;
454 byte[] Data = e.
Data;
455 int Len = Data.Length;
461 lock (this.udpReceiveLock)
466 PacketLen = (b & 127);
468 while (Pos < Len && (b & 128) != 0)
471 PacketLen |= (b & 127) << Offset;
478 PacketNr = Data[Pos++];
479 PacketNr |= (ushort)(Data[Pos++] << 8);
481 if (Pos + PacketLen > Len)
484 Packet =
new byte[PacketLen];
485 Buffer.BlockCopy(Data, Pos, Packet, 0, PacketLen);
488 if ((
short)(PacketNr - this.lastReceivedPacket) > 0)
490 if (FirstPacket is
null)
492 FirstPacket = Packet;
493 FirstPacketNr = PacketNr;
497 LostPackets ??=
new LinkedList<KeyValuePair<ushort, byte[]>>();
498 LostPackets.AddFirst(
new KeyValuePair<ushort,
byte[]>(PacketNr, Packet));
503 if (!(FirstPacket is
null))
504 this.lastReceivedPacket = FirstPacketNr;
510 if (!(LostPackets is
null))
512 foreach (KeyValuePair<ushort,
byte[]> P
in LostPackets)
516 await h(
this,
true, P.Value, 0, P.Value.Length);
525 if (!(FirstPacket is
null))
529 await h(
this,
true, FirstPacket, 0, FirstPacket.Length);
540 byte[] Data = e.
Data;
541 int Len = Data.Length;
542 byte[] Packet =
new byte[Len];
544 Buffer.BlockCopy(Data, 0, Packet, 0, Len);
551 await h(
this,
true, Packet, 0, Packet.Length);
561 private ushort lastReceivedPacket = 0;
562 private readonly
object udpReceiveLock =
new object();
564 internal void StartIdleTimer()
566 this.idleTimer =
new Timer(this.IdleTimerCallback,
null, 5000, 5000);
569 private async
void IdleTimerCallback(
object P)
573 if ((DateTime.Now -
this.lastTcpPacket).TotalSeconds > 10)
577 await this.
SendTcp(
true, Array.Empty<
byte>());
599 private Timer idleTimer =
null;
600 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 Task DisposeAsync()
Disposes of the object asynchronously. The underlying TcpClient is either disposed directly,...
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.
Task SendTcp(bool ConstantBuffer, byte[] Packet)
Sends a packet to the peer at the other side of the TCP connection. Transmission is done asynchronous...
void Start()
Starts receiving on the connection.
void Continue()
Continues a paused connection.
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...
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...
async Task DisposeAsync()
IDisposable.Dispose
BinaryDataReadEventHandler OnReceived
Event received when binary data has been received.
Task SendTcp(bool ConstantBuffer, 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...
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
Interface for asynchronously disposable objects.
delegate Task EventHandlerAsync(object Sender, EventArgs e)
Asynchronous version of EventArgs.
delegate Task< bool > BinaryDataReadEventHandler(object Sender, bool ConstantBuffer, byte[] Buffer, int Offset, int Count)
Event handler for binary packet events.
delegate Task BinaryDataWrittenEventHandler(object Sender, bool ConstantBuffer, byte[] Buffer, int Offset, int Count)
Event handler for binary packet events.