diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 835b96d..86dc0fe 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1 +1,2 @@
+ko_fi: oliverbooth
custom: ['https://buymeacoffee.com/oliverbooth']
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 41cf44d..ae53f18 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -2,9 +2,13 @@ name: .NET
on:
push:
- branches: [ main, develop ]
+ branches:
+ - '*'
+ - '*/*'
pull_request:
- branches: [ main, develop ]
+ branches:
+ - '*'
+ - '*/*'
jobs:
build:
@@ -16,9 +20,9 @@ jobs:
uses: actions/checkout@v3
- name: Setup .NET
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v3
with:
- dotnet-version: 7.0.x
+ dotnet-version: 8.0.x
- name: Add NuGet source
run: dotnet nuget add source --username oliverbooth --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/oliverbooth/index.json"
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml
index ca5ca69..913a55b 100644
--- a/.github/workflows/nightly.yml
+++ b/.github/workflows/nightly.yml
@@ -3,7 +3,8 @@ name: Publish Nightly
on:
push:
branches:
- - develop
+ - main
+ workflow_dispatch:
jobs:
nightly:
@@ -15,9 +16,9 @@ jobs:
uses: actions/checkout@v3
- name: Setup .NET
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v3
with:
- dotnet-version: 7.0.x
+ dotnet-version: 8.0.x
- name: Add GitHub NuGet source
run: dotnet nuget add source --username oliverbooth --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/oliverbooth/index.json"
diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml
index 7f089d9..06245fd 100644
--- a/.github/workflows/prerelease.yml
+++ b/.github/workflows/prerelease.yml
@@ -15,9 +15,9 @@ jobs:
uses: actions/checkout@v3
- name: Setup .NET
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v3
with:
- dotnet-version: 7.0.x
+ dotnet-version: 8.0.x
- name: Add GitHub NuGet source
run: dotnet nuget add source --username oliverbooth --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/oliverbooth/index.json"
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b234990..910cb8d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -15,9 +15,9 @@ jobs:
uses: actions/checkout@v3
- name: Setup .NET
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v3
with:
- dotnet-version: 7.0.x
+ dotnet-version: 8.0.x
- name: Add GitHub NuGet source
run: dotnet nuget add source --username oliverbooth --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/oliverbooth/index.json"
diff --git a/README.md b/README.md
index c08825b..5a5c582 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
-
TcpDotNet
+
-
-
-
-
-
-
+
+
+
+
+
+
### About
-TcpDotNet is a .NET Standard 2.1 package that enables you to perform server/client communications over the TCP protocol.
+TcpDotNet is a .NET package that enables you to perform server/client communications over the TCP protocol.
This package is a work-in-progress and not deemed ready for production use. However, it is available on NuGet as a very crude and early development build. This package will be maintained as I see fit.
*(I'm also [dogfooding](https://www.pcmag.com/encyclopedia/term/dogfooding) this library, so there's that.)*
@@ -17,7 +17,7 @@ This package is a work-in-progress and not deemed ready for production use. Howe
## Installation
### NuGet installation
```ps
-Install-Package TcpDotNet -Version 0.1.0-nightly.1
+Install-Package TcpDotNet -Version 1.0.0
```
### Manual installation
diff --git a/TcpDotNet.ClientIntegrationTest/GoodbyePacket.cs b/TcpDotNet.ClientIntegrationTest/GoodbyePacket.cs
index d79d97c..9892853 100644
--- a/TcpDotNet.ClientIntegrationTest/GoodbyePacket.cs
+++ b/TcpDotNet.ClientIntegrationTest/GoodbyePacket.cs
@@ -1,4 +1,4 @@
-using TcpDotNet.Protocol;
+using TcpDotNet.Protocol;
namespace TcpDotNet.ClientIntegrationTest;
diff --git a/TcpDotNet.ClientIntegrationTest/HelloPacket.cs b/TcpDotNet.ClientIntegrationTest/HelloPacket.cs
index 0b4f357..0cc4e9f 100644
--- a/TcpDotNet.ClientIntegrationTest/HelloPacket.cs
+++ b/TcpDotNet.ClientIntegrationTest/HelloPacket.cs
@@ -1,4 +1,4 @@
-using TcpDotNet.Protocol;
+using TcpDotNet.Protocol;
namespace TcpDotNet.ClientIntegrationTest;
diff --git a/TcpDotNet.ClientIntegrationTest/PacketHandlers/GoodbyePacketHandler.cs b/TcpDotNet.ClientIntegrationTest/PacketHandlers/GoodbyePacketHandler.cs
index 243aa78..58fec4a 100644
--- a/TcpDotNet.ClientIntegrationTest/PacketHandlers/GoodbyePacketHandler.cs
+++ b/TcpDotNet.ClientIntegrationTest/PacketHandlers/GoodbyePacketHandler.cs
@@ -1,10 +1,10 @@
-using TcpDotNet.Protocol;
+using TcpDotNet.Protocol;
namespace TcpDotNet.ClientIntegrationTest.PacketHandlers;
internal sealed class GoodbyePacketHandler : PacketHandler
{
- public override Task HandleAsync(BaseClientNode recipient, GoodbyePacket packet, CancellationToken cancellationToken = default)
+ public override Task HandleAsync(ClientNode recipient, GoodbyePacket packet, CancellationToken cancellationToken = default)
{
Console.WriteLine($"Server sent {packet.Message}");
return Task.CompletedTask;
diff --git a/TcpDotNet.ClientIntegrationTest/Program.cs b/TcpDotNet.ClientIntegrationTest/Program.cs
index ada9729..0ecd968 100644
--- a/TcpDotNet.ClientIntegrationTest/Program.cs
+++ b/TcpDotNet.ClientIntegrationTest/Program.cs
@@ -1,4 +1,4 @@
-using System.Net;
+using System.Net;
using TcpDotNet;
using TcpDotNet.ClientIntegrationTest;
using TcpDotNet.ClientIntegrationTest.PacketHandlers;
@@ -17,7 +17,7 @@ Console.WriteLine($"Connected to {client.RemoteEndPoint}. My session is {client.
var ping = new PingPacket();
Console.WriteLine($"Sending ping packet with payload: {BitConverter.ToString(ping.Payload)}");
-var pong = await client.SendAndReceiveAsync(ping);
+var pong = await client.SendAndReceiveAsync(ping);
Console.WriteLine($"Received pong packet with payload: {BitConverter.ToString(pong.Payload)}");
Console.WriteLine(pong.Payload.SequenceEqual(ping.Payload) ? "Payload matches!" : "Payload does not match!");
diff --git a/TcpDotNet.ClientIntegrationTest/TcpDotNet.ClientIntegrationTest.csproj b/TcpDotNet.ClientIntegrationTest/TcpDotNet.ClientIntegrationTest.csproj
index ed854e8..8532d3c 100644
--- a/TcpDotNet.ClientIntegrationTest/TcpDotNet.ClientIntegrationTest.csproj
+++ b/TcpDotNet.ClientIntegrationTest/TcpDotNet.ClientIntegrationTest.csproj
@@ -2,7 +2,7 @@
Exe
- net7.0
+ net8.0
enable
enable
diff --git a/TcpDotNet.ListenerIntegrationTest/GoodbyePacket.cs b/TcpDotNet.ListenerIntegrationTest/GoodbyePacket.cs
index 02baa10..40e03c1 100644
--- a/TcpDotNet.ListenerIntegrationTest/GoodbyePacket.cs
+++ b/TcpDotNet.ListenerIntegrationTest/GoodbyePacket.cs
@@ -1,4 +1,4 @@
-using TcpDotNet.Protocol;
+using TcpDotNet.Protocol;
namespace TcpDotNet.ListenerIntegrationTest;
diff --git a/TcpDotNet.ListenerIntegrationTest/HelloPacket.cs b/TcpDotNet.ListenerIntegrationTest/HelloPacket.cs
index 80a958b..6adb687 100644
--- a/TcpDotNet.ListenerIntegrationTest/HelloPacket.cs
+++ b/TcpDotNet.ListenerIntegrationTest/HelloPacket.cs
@@ -1,4 +1,4 @@
-using TcpDotNet.Protocol;
+using TcpDotNet.Protocol;
namespace TcpDotNet.ListenerIntegrationTest;
diff --git a/TcpDotNet.ListenerIntegrationTest/PacketHandlers/HelloPacketHandler.cs b/TcpDotNet.ListenerIntegrationTest/PacketHandlers/HelloPacketHandler.cs
index f181fea..f138f55 100644
--- a/TcpDotNet.ListenerIntegrationTest/PacketHandlers/HelloPacketHandler.cs
+++ b/TcpDotNet.ListenerIntegrationTest/PacketHandlers/HelloPacketHandler.cs
@@ -1,10 +1,10 @@
-using TcpDotNet.Protocol;
+using TcpDotNet.Protocol;
namespace TcpDotNet.ListenerIntegrationTest.PacketHandlers;
internal sealed class HelloPacketHandler : PacketHandler
{
- public override Task HandleAsync(BaseClientNode recipient, HelloPacket packet, CancellationToken cancellationToken = default)
+ public override Task HandleAsync(ClientNode recipient, HelloPacket packet, CancellationToken cancellationToken = default)
{
Console.WriteLine($"Client sent {packet.Message}");
return recipient.SendPacketAsync(new GoodbyePacket {Message = "Goodbye!"}, cancellationToken);
diff --git a/TcpDotNet.ListenerIntegrationTest/Program.cs b/TcpDotNet.ListenerIntegrationTest/Program.cs
index 8f88848..611cae2 100644
--- a/TcpDotNet.ListenerIntegrationTest/Program.cs
+++ b/TcpDotNet.ListenerIntegrationTest/Program.cs
@@ -1,4 +1,4 @@
-using TcpDotNet;
+using TcpDotNet;
using TcpDotNet.ListenerIntegrationTest.PacketHandlers;
using TcpDotNet.Protocol;
using TcpDotNet.Protocol.Packets.ClientBound;
@@ -16,7 +16,7 @@ await Task.Delay(-1);
internal sealed class PingPacketHandler : PacketHandler
{
- public override async Task HandleAsync(BaseClientNode recipient, PingPacket packet, CancellationToken cancellationToken = default)
+ public override async Task HandleAsync(ClientNode recipient, PingPacket packet, CancellationToken cancellationToken = default)
{
Console.WriteLine($"Client {recipient.SessionId} sent ping with payload {BitConverter.ToString(packet.Payload)}");
var pong = new PongPacket(packet.CallbackId, packet.Payload);
diff --git a/TcpDotNet.ListenerIntegrationTest/TcpDotNet.ListenerIntegrationTest.csproj b/TcpDotNet.ListenerIntegrationTest/TcpDotNet.ListenerIntegrationTest.csproj
index ed854e8..8532d3c 100644
--- a/TcpDotNet.ListenerIntegrationTest/TcpDotNet.ListenerIntegrationTest.csproj
+++ b/TcpDotNet.ListenerIntegrationTest/TcpDotNet.ListenerIntegrationTest.csproj
@@ -2,7 +2,7 @@
Exe
- net7.0
+ net8.0
enable
enable
diff --git a/TcpDotNet.sln b/TcpDotNet.sln
index 1a518a6..dd1fca7 100644
--- a/TcpDotNet.sln
+++ b/TcpDotNet.sln
@@ -6,6 +6,23 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TcpDotNet.ListenerIntegrati
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TcpDotNet.ClientIntegrationTest", "TcpDotNet.ClientIntegrationTest\TcpDotNet.ClientIntegrationTest.csproj", "{ED9C812F-9835-4268-9AFC-57CFAAC16162}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D55FB87A-1066-489D-B0CC-F2C09B611751}"
+ ProjectSection(SolutionItems) = preProject
+ .gitignore = .gitignore
+ LICENSE.md = LICENSE.md
+ README.md = README.md
+ branding_Banner.png = branding_Banner.png
+ branding_Icon.png = branding_Icon.png
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Workflows", "Workflows", "{0FAB77D5-AAE4-4722-A5F4-88A239858D65}"
+ ProjectSection(SolutionItems) = preProject
+ .github\workflows\dotnet.yml = .github\workflows\dotnet.yml
+ .github\workflows\nightly.yml = .github\workflows\nightly.yml
+ .github\workflows\prerelease.yml = .github\workflows\prerelease.yml
+ .github\workflows\release.yml = .github\workflows\release.yml
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
diff --git a/TcpDotNet/Assembly.cs b/TcpDotNet/Assembly.cs
index f547610..c0d560e 100644
--- a/TcpDotNet/Assembly.cs
+++ b/TcpDotNet/Assembly.cs
@@ -1 +1 @@
-[assembly: CLSCompliant(true)]
+[assembly: CLSCompliant(true)]
diff --git a/TcpDotNet/BaseClientNode.cs b/TcpDotNet/ClientNode.cs
similarity index 79%
rename from TcpDotNet/BaseClientNode.cs
rename to TcpDotNet/ClientNode.cs
index 9670bb0..bc8ebd9 100644
--- a/TcpDotNet/BaseClientNode.cs
+++ b/TcpDotNet/ClientNode.cs
@@ -1,8 +1,7 @@
-using System.Collections.Concurrent;
+using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
-using System.Runtime.Serialization;
using Chilkat;
using TcpDotNet.Protocol;
using Stream = System.IO.Stream;
@@ -13,16 +12,16 @@ namespace TcpDotNet;
///
/// Represents a client node.
///
-public abstract class BaseClientNode : Node
+public abstract class ClientNode : Node
{
- private readonly ObjectIDGenerator _callbackIdGenerator = new();
private readonly ConcurrentDictionary>> _packetCompletionSources = new();
+ private readonly ConcurrentDictionary> _callbackCompletionSources = new();
private EndPoint? _remoteEP;
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- protected BaseClientNode()
+ protected ClientNode()
{
}
@@ -148,7 +147,7 @@ public abstract class BaseClientNode : Node
if (constructor is null)
return null;
- var packet = (Packet) constructor.Invoke(null);
+ var packet = (Packet)constructor.Invoke(null);
packet.Deserialize(bufferReader);
await targetStream.DisposeAsync();
@@ -198,7 +197,7 @@ public abstract class BaseClientNode : Node
buffer.Position = 0;
}
- var length = (int) buffer.Length;
+ var length = (int)buffer.Length;
networkWriter.Write(length);
try
@@ -219,53 +218,29 @@ public abstract class BaseClientNode : Node
///
/// Sends a packet, and waits for a specific packet to be received.
///
- /// The packet to send.
- /// A cancellation token that can be used to cancel the asynchronous operation.
- /// The type of the packet to send.
+ /// The packet to send.
+ ///
+ /// A cancellation token that can be used to cancel the asynchronous operation.
+ ///
/// The type of the packet to return.
/// The received packet.
///
- /// This method will consume all incoming packets, raising their associated handlers if such packets are recognised.
+ /// This method will consume all incoming packets, raising their associated handlers if such packets are
+ /// recognised.
///
- public async Task SendAndReceiveAsync(TSend packetToSend,
+ /// is .
+ public async Task SendAndReceiveAsync(RequestPacket packet,
CancellationToken cancellationToken = default)
- where TSend : Packet
- where TReceive : Packet
+ where TReceive : ResponsePacket
{
- var attribute = typeof(TReceive).GetCustomAttribute();
- if (attribute is null)
- throw new ArgumentException($"The packet type {typeof(TReceive).Name} is not a valid packet.");
+ if (packet is null) throw new ArgumentNullException(nameof(packet));
- var requestPacket = packetToSend as RequestPacket;
- if (requestPacket is not null)
- requestPacket.CallbackId = _callbackIdGenerator.GetId(packetToSend, out _);
+ var completionSource = new TaskCompletionSource();
+ if (!_callbackCompletionSources.TryAdd(packet.CallbackId, completionSource))
+ throw new InvalidOperationException("Duplicate packet sent");
- var completionSource = new TaskCompletionSource();
- if (!_packetCompletionSources.TryGetValue(attribute.Id, out List>? completionSources))
- {
- completionSources = new List>();
- _packetCompletionSources.TryAdd(attribute.Id, completionSources);
- }
-
- lock (completionSources)
- {
- if (!completionSources.Contains(completionSource))
- completionSources.Add(completionSource);
- }
-
- await SendPacketAsync(packetToSend, cancellationToken);
- TReceive response;
- do
- {
- response = await WaitForPacketAsync(completionSource, cancellationToken);
- if (requestPacket is null)
- break;
-
- if (response is ResponsePacket responsePacket && responsePacket.CallbackId == requestPacket.CallbackId)
- break;
- } while (true);
-
- return response;
+ await SendPacketAsync(packet, cancellationToken);
+ return (TReceive)await completionSource.Task;
}
///
@@ -284,17 +259,16 @@ public abstract class BaseClientNode : Node
return WaitForPacketAsync(completionSource, cancellationToken);
}
- private async Task WaitForPacketAsync(
- TaskCompletionSource completionSource,
- CancellationToken cancellationToken = default
- )
+ private async Task WaitForPacketAsync(TaskCompletionSource completionSource,
+ CancellationToken cancellationToken = default)
where TPacket : Packet
{
var attribute = typeof(TPacket).GetCustomAttribute();
if (attribute is null)
throw new ArgumentException($"The packet type {typeof(TPacket).Name} is not a valid packet.");
- if (!_packetCompletionSources.TryGetValue(attribute.Id, out List>? completionSources))
+ if (!_packetCompletionSources.TryGetValue(attribute.Id,
+ out List>? completionSources))
{
completionSources = new List>();
_packetCompletionSources.TryAdd(attribute.Id, completionSources);
@@ -328,7 +302,7 @@ public abstract class BaseClientNode : Node
completionSource.SetCanceled();
}, cancellationToken);
- var packet = (TPacket) await Task.Run(() => completionSource.Task, cancellationToken);
+ var packet = (TPacket)await Task.Run(() => completionSource.Task, cancellationToken);
if (_packetCompletionSources.TryGetValue(attribute.Id, out completionSources))
{
lock (completionSources)
diff --git a/TcpDotNet/ClientState.cs b/TcpDotNet/ClientState.cs
index 01532ba..fec2980 100644
--- a/TcpDotNet/ClientState.cs
+++ b/TcpDotNet/ClientState.cs
@@ -1,7 +1,7 @@
-namespace TcpDotNet;
+namespace TcpDotNet;
///
-/// An enumeration of states for a to be in.
+/// An enumeration of states for a to be in.
///
public enum ClientState
{
diff --git a/TcpDotNet/CryptographyUtils.cs b/TcpDotNet/CryptographyUtils.cs
index 2907bb9..f1b287a 100644
--- a/TcpDotNet/CryptographyUtils.cs
+++ b/TcpDotNet/CryptographyUtils.cs
@@ -1,4 +1,4 @@
-using Chilkat;
+using Chilkat;
namespace TcpDotNet;
diff --git a/TcpDotNet/Node.cs b/TcpDotNet/Node.cs
index bdcf759..7af3a01 100644
--- a/TcpDotNet/Node.cs
+++ b/TcpDotNet/Node.cs
@@ -1,4 +1,4 @@
-using System.Collections.Concurrent;
+using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using System.Net.Sockets;
using System.Reflection;
@@ -38,7 +38,8 @@ public abstract class Node : IDisposable
/// The registered packets.
public IReadOnlyDictionary> RegisteredPacketHandlers =>
new ReadOnlyDictionary>(
- _registeredPacketHandlers.ToDictionary(p => p.Key, p => (IReadOnlyCollection) p.Value.AsReadOnly()));
+ _registeredPacketHandlers.ToDictionary(p => p.Key,
+ p => (IReadOnlyCollection)p.Value.AsReadOnly()));
///
/// Closes the base socket connection and releases all associated resources.
@@ -124,7 +125,8 @@ public abstract class Node : IDisposable
var attribute = packetType.GetCustomAttribute();
if (attribute is null) throw new ArgumentException($"{packetType.Name} is not a valid packet.");
if (_registeredPackets.TryGetValue(attribute.Id, out Type? registeredPacket))
- throw new ArgumentException($"The packet type {attribute.Id:X8} is already registered to {registeredPacket.Name}.");
+ throw new ArgumentException(
+ $"The packet type {attribute.Id:X8} is already registered to {registeredPacket.Name}.");
_registeredPackets.TryAdd(attribute.Id, packetType);
}
diff --git a/TcpDotNet/Protocol/HandshakeResponse.cs b/TcpDotNet/Protocol/HandshakeResponse.cs
index a0a5a30..4534962 100644
--- a/TcpDotNet/Protocol/HandshakeResponse.cs
+++ b/TcpDotNet/Protocol/HandshakeResponse.cs
@@ -1,4 +1,4 @@
-namespace TcpDotNet.Protocol;
+namespace TcpDotNet.Protocol;
///
/// An enumeration of handshake responses.
diff --git a/TcpDotNet/Protocol/Packet.cs b/TcpDotNet/Protocol/Packet.cs
index e984dbc..c1c79ce 100644
--- a/TcpDotNet/Protocol/Packet.cs
+++ b/TcpDotNet/Protocol/Packet.cs
@@ -1,4 +1,4 @@
-using System.Reflection;
+using System.Reflection;
namespace TcpDotNet.Protocol;
diff --git a/TcpDotNet/Protocol/PacketAttribute.cs b/TcpDotNet/Protocol/PacketAttribute.cs
index 8bda278..a613d81 100644
--- a/TcpDotNet/Protocol/PacketAttribute.cs
+++ b/TcpDotNet/Protocol/PacketAttribute.cs
@@ -1,4 +1,4 @@
-namespace TcpDotNet.Protocol;
+namespace TcpDotNet.Protocol;
///
/// Specifies metadata for a .
diff --git a/TcpDotNet/Protocol/PacketHandler.cs b/TcpDotNet/Protocol/PacketHandler.cs
index c303e27..9431b8a 100644
--- a/TcpDotNet/Protocol/PacketHandler.cs
+++ b/TcpDotNet/Protocol/PacketHandler.cs
@@ -1,4 +1,4 @@
-namespace TcpDotNet.Protocol;
+namespace TcpDotNet.Protocol;
///
/// Represents the base class for a packet handler.
@@ -12,7 +12,7 @@ public abstract class PacketHandler
/// The recipient of the packet.
/// The packet to handle.
/// A cancellation token that can be used to cancel the asynchronous operation.
- public abstract Task HandleAsync(BaseClientNode recipient, Packet packet, CancellationToken cancellationToken = default);
+ public abstract Task HandleAsync(ClientNode recipient, Packet packet, CancellationToken cancellationToken = default);
}
///
@@ -27,7 +27,7 @@ public abstract class PacketHandler : PacketHandler
public static readonly PacketHandler Empty = new NullPacketHandler();
///
- public override Task HandleAsync(BaseClientNode recipient, Packet packet, CancellationToken cancellationToken = default)
+ public override Task HandleAsync(ClientNode recipient, Packet packet, CancellationToken cancellationToken = default)
{
if (packet is T actual) return HandleAsync(recipient, actual, cancellationToken);
return Task.CompletedTask;
@@ -39,7 +39,7 @@ public abstract class PacketHandler : PacketHandler
/// The recipient of the packet.
/// The packet to handle.
/// A cancellation token that can be used to cancel the asynchronous operation.
- public abstract Task HandleAsync(BaseClientNode recipient, T packet, CancellationToken cancellationToken = default);
+ public abstract Task HandleAsync(ClientNode recipient, T packet, CancellationToken cancellationToken = default);
}
///
@@ -50,7 +50,7 @@ internal sealed class NullPacketHandler : PacketHandler
where T : Packet
{
///
- public override Task HandleAsync(BaseClientNode recipient, T packet, CancellationToken cancellationToken = default)
+ public override Task HandleAsync(ClientNode recipient, T packet, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
diff --git a/TcpDotNet/Protocol/PacketHandlers/DisconnectPacketHandler.cs b/TcpDotNet/Protocol/PacketHandlers/DisconnectPacketHandler.cs
index 0107ba9..b36f755 100644
--- a/TcpDotNet/Protocol/PacketHandlers/DisconnectPacketHandler.cs
+++ b/TcpDotNet/Protocol/PacketHandlers/DisconnectPacketHandler.cs
@@ -1,4 +1,4 @@
-using TcpDotNet.Protocol.Packets.ClientBound;
+using TcpDotNet.Protocol.Packets.ClientBound;
namespace TcpDotNet.Protocol.PacketHandlers;
@@ -6,7 +6,7 @@ internal sealed class DisconnectPacketHandler : PacketHandler
{
///
public override Task HandleAsync(
- BaseClientNode recipient,
+ ClientNode recipient,
DisconnectPacket packet,
CancellationToken cancellationToken = default
)
diff --git a/TcpDotNet/Protocol/PacketHandlers/EncryptionResponsePacketHandler.cs b/TcpDotNet/Protocol/PacketHandlers/EncryptionResponsePacketHandler.cs
index c79914a..16dc115 100644
--- a/TcpDotNet/Protocol/PacketHandlers/EncryptionResponsePacketHandler.cs
+++ b/TcpDotNet/Protocol/PacketHandlers/EncryptionResponsePacketHandler.cs
@@ -1,4 +1,4 @@
-using System.Security.Cryptography;
+using System.Security.Cryptography;
using TcpDotNet.Protocol.Packets.ClientBound;
using TcpDotNet.Protocol.Packets.ServerBound;
@@ -11,7 +11,7 @@ internal sealed class EncryptionResponsePacketHandler : PacketHandler
public override async Task HandleAsync(
- BaseClientNode recipient,
+ ClientNode recipient,
EncryptionResponsePacket packet,
CancellationToken cancellationToken = default
)
diff --git a/TcpDotNet/Protocol/PacketHandlers/HandshakeRequestPacketHandler.cs b/TcpDotNet/Protocol/PacketHandlers/HandshakeRequestPacketHandler.cs
index 2df88d0..217f411 100644
--- a/TcpDotNet/Protocol/PacketHandlers/HandshakeRequestPacketHandler.cs
+++ b/TcpDotNet/Protocol/PacketHandlers/HandshakeRequestPacketHandler.cs
@@ -1,4 +1,4 @@
-using TcpDotNet.Protocol.Packets.ClientBound;
+using TcpDotNet.Protocol.Packets.ClientBound;
using TcpDotNet.Protocol.Packets.ServerBound;
namespace TcpDotNet.Protocol.PacketHandlers;
@@ -10,7 +10,7 @@ internal sealed class HandshakeRequestPacketHandler : PacketHandler
public override async Task HandleAsync(
- BaseClientNode recipient,
+ ClientNode recipient,
HandshakeRequestPacket packet,
CancellationToken cancellationToken = default
)
@@ -22,13 +22,14 @@ internal sealed class HandshakeRequestPacketHandler : PacketHandler
protected internal override void Deserialize(ProtocolReader reader)
{
- Reason = (DisconnectReason) reader.ReadByte();
+ Reason = (DisconnectReason)reader.ReadByte();
}
///
protected internal override void Serialize(ProtocolWriter writer)
{
- writer.Write((byte) Reason);
+ writer.Write((byte)Reason);
}
}
diff --git a/TcpDotNet/Protocol/Packets/ClientBound/EncryptionRequestPacket.cs b/TcpDotNet/Protocol/Packets/ClientBound/EncryptionRequestPacket.cs
index c3960f5..cbbef56 100644
--- a/TcpDotNet/Protocol/Packets/ClientBound/EncryptionRequestPacket.cs
+++ b/TcpDotNet/Protocol/Packets/ClientBound/EncryptionRequestPacket.cs
@@ -1,4 +1,4 @@
-using System.Security.Cryptography;
+using System.Security.Cryptography;
namespace TcpDotNet.Protocol.Packets.ClientBound;
diff --git a/TcpDotNet/Protocol/Packets/ClientBound/HandshakeResponsePacket.cs b/TcpDotNet/Protocol/Packets/ClientBound/HandshakeResponsePacket.cs
index 0cc020e..b0eb8e2 100644
--- a/TcpDotNet/Protocol/Packets/ClientBound/HandshakeResponsePacket.cs
+++ b/TcpDotNet/Protocol/Packets/ClientBound/HandshakeResponsePacket.cs
@@ -1,4 +1,4 @@
-using TcpDotNet.Protocol.Packets.ServerBound;
+using TcpDotNet.Protocol.Packets.ServerBound;
namespace TcpDotNet.Protocol.Packets.ClientBound;
@@ -6,14 +6,16 @@ namespace TcpDotNet.Protocol.Packets.ClientBound;
/// Represents a packet which responds to a .
///
[Packet(0x7FFFFFE1)]
-internal sealed class HandshakeResponsePacket : Packet
+internal sealed class HandshakeResponsePacket : ResponsePacket
{
///
/// Initializes a new instance of the class.
///
+ /// The callback ID.
/// The requested protocol version.
/// The handshake response.
- public HandshakeResponsePacket(int protocolVersion, HandshakeResponse handshakeResponse)
+ public HandshakeResponsePacket(long callbackId, int protocolVersion, HandshakeResponse handshakeResponse)
+ : base(callbackId)
{
ProtocolVersion = protocolVersion;
HandshakeResponse = handshakeResponse;
@@ -38,14 +40,14 @@ internal sealed class HandshakeResponsePacket : Packet
///
protected internal override void Deserialize(ProtocolReader reader)
{
- HandshakeResponse = (HandshakeResponse) reader.ReadByte();
+ HandshakeResponse = (HandshakeResponse)reader.ReadByte();
ProtocolVersion = reader.ReadInt32();
}
///
protected internal override void Serialize(ProtocolWriter writer)
{
- writer.Write((byte) HandshakeResponse);
+ writer.Write((byte)HandshakeResponse);
writer.Write(ProtocolVersion);
}
}
diff --git a/TcpDotNet/Protocol/Packets/ClientBound/PongPacket.cs b/TcpDotNet/Protocol/Packets/ClientBound/PongPacket.cs
index 7952016..7bc7a60 100644
--- a/TcpDotNet/Protocol/Packets/ClientBound/PongPacket.cs
+++ b/TcpDotNet/Protocol/Packets/ClientBound/PongPacket.cs
@@ -1,4 +1,4 @@
-namespace TcpDotNet.Protocol.Packets.ClientBound;
+namespace TcpDotNet.Protocol.Packets.ClientBound;
///
/// Represents a packet which performs a heartbeat response.
diff --git a/TcpDotNet/Protocol/Packets/ClientBound/SessionExchangePacket.cs b/TcpDotNet/Protocol/Packets/ClientBound/SessionExchangePacket.cs
index e7679ac..3301b50 100644
--- a/TcpDotNet/Protocol/Packets/ClientBound/SessionExchangePacket.cs
+++ b/TcpDotNet/Protocol/Packets/ClientBound/SessionExchangePacket.cs
@@ -1,4 +1,4 @@
-namespace TcpDotNet.Protocol.Packets.ClientBound;
+namespace TcpDotNet.Protocol.Packets.ClientBound;
[Packet(0x7FFFFFE4)]
internal sealed class SessionExchangePacket : Packet
diff --git a/TcpDotNet/Protocol/Packets/ServerBound/EncryptionResponsePacket.cs b/TcpDotNet/Protocol/Packets/ServerBound/EncryptionResponsePacket.cs
index 935cca6..4107174 100644
--- a/TcpDotNet/Protocol/Packets/ServerBound/EncryptionResponsePacket.cs
+++ b/TcpDotNet/Protocol/Packets/ServerBound/EncryptionResponsePacket.cs
@@ -1,4 +1,4 @@
-using TcpDotNet.Protocol.Packets.ClientBound;
+using TcpDotNet.Protocol.Packets.ClientBound;
namespace TcpDotNet.Protocol.Packets.ServerBound;
diff --git a/TcpDotNet/Protocol/Packets/ServerBound/HandshakeRequestPacket.cs b/TcpDotNet/Protocol/Packets/ServerBound/HandshakeRequestPacket.cs
index 82e4ef3..afe4102 100644
--- a/TcpDotNet/Protocol/Packets/ServerBound/HandshakeRequestPacket.cs
+++ b/TcpDotNet/Protocol/Packets/ServerBound/HandshakeRequestPacket.cs
@@ -1,10 +1,10 @@
-namespace TcpDotNet.Protocol.Packets.ServerBound;
+namespace TcpDotNet.Protocol.Packets.ServerBound;
///
/// Represents a packet which requests a handshake with a .
///
[Packet(0x7FFFFFE0)]
-internal sealed class HandshakeRequestPacket : Packet
+internal sealed class HandshakeRequestPacket : RequestPacket
{
///
/// Initializes a new instance of the class.
diff --git a/TcpDotNet/Protocol/Packets/ServerBound/PingPacket.cs b/TcpDotNet/Protocol/Packets/ServerBound/PingPacket.cs
index 06eb33c..1ce5e8e 100644
--- a/TcpDotNet/Protocol/Packets/ServerBound/PingPacket.cs
+++ b/TcpDotNet/Protocol/Packets/ServerBound/PingPacket.cs
@@ -1,4 +1,4 @@
-using System.Security.Cryptography;
+using System.Security.Cryptography;
namespace TcpDotNet.Protocol.Packets.ServerBound;
diff --git a/TcpDotNet/Protocol/ProtocolReader.cs b/TcpDotNet/Protocol/ProtocolReader.cs
index 810613d..e9b5e53 100644
--- a/TcpDotNet/Protocol/ProtocolReader.cs
+++ b/TcpDotNet/Protocol/ProtocolReader.cs
@@ -1,4 +1,4 @@
-using System.Net;
+using System.Net;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
@@ -66,7 +66,7 @@ public sealed class ProtocolReader : BinaryReader
result |= (byteReadJustNow & 0x7Fu) << shift;
if (byteReadJustNow <= 0x7Fu)
- return (int) result; // early exit
+ return (int)result; // early exit
}
// Read the 5th byte. Since we already read 28 bits,
@@ -77,8 +77,8 @@ public sealed class ProtocolReader : BinaryReader
if (byteReadJustNow > 0b_1111u)
throw new FormatException();
- result |= (uint) byteReadJustNow << (maxBytesWithoutOverflow * 7);
- return (int) result;
+ result |= (uint)byteReadJustNow << (maxBytesWithoutOverflow * 7);
+ return (int)result;
}
///
@@ -107,7 +107,7 @@ public sealed class ProtocolReader : BinaryReader
result |= (byteReadJustNow & 0x7Ful) << shift;
if (byteReadJustNow <= 0x7Fu)
- return (long) result; // early exit
+ return (long)result; // early exit
}
// Read the 10th byte. Since we already read 63 bits,
@@ -118,8 +118,8 @@ public sealed class ProtocolReader : BinaryReader
if (byteReadJustNow > 0b_1u)
throw new FormatException();
- result |= (ulong) byteReadJustNow << (maxBytesWithoutOverflow * 7);
- return (long) result;
+ result |= (ulong)byteReadJustNow << (maxBytesWithoutOverflow * 7);
+ return (long)result;
}
///
@@ -196,21 +196,21 @@ public sealed class ProtocolReader : BinaryReader
[CLSCompliant(false)]
public override ushort ReadUInt16()
{
- return (ushort) IPAddress.NetworkToHostOrder((short) base.ReadUInt16());
+ return (ushort)IPAddress.NetworkToHostOrder((short)base.ReadUInt16());
}
///
[CLSCompliant(false)]
public override uint ReadUInt32()
{
- return (uint) IPAddress.NetworkToHostOrder((int) base.ReadUInt32());
+ return (uint)IPAddress.NetworkToHostOrder((int)base.ReadUInt32());
}
///
[CLSCompliant(false)]
public override ulong ReadUInt64()
{
- return (ulong) IPAddress.NetworkToHostOrder((long) base.ReadUInt64());
+ return (ulong)IPAddress.NetworkToHostOrder((long)base.ReadUInt64());
}
///
diff --git a/TcpDotNet/Protocol/ProtocolWriter.cs b/TcpDotNet/Protocol/ProtocolWriter.cs
index 76280fe..920b867 100644
--- a/TcpDotNet/Protocol/ProtocolWriter.cs
+++ b/TcpDotNet/Protocol/ProtocolWriter.cs
@@ -1,4 +1,4 @@
-using System.Net;
+using System.Net;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
@@ -38,7 +38,11 @@ public sealed class ProtocolWriter : BinaryWriter
public override void Write(double value)
{
Span buffer = stackalloc byte[8];
+#if NET8_0_OR_GREATER
+ MemoryMarshal.TryWrite(buffer, in value);
+#else
MemoryMarshal.TryWrite(buffer, ref value);
+#endif
if (BitConverter.IsLittleEndian) buffer.Reverse();
Write(buffer);
@@ -89,7 +93,11 @@ public sealed class ProtocolWriter : BinaryWriter
public override void Write(float value)
{
Span buffer = stackalloc byte[4];
+#if NET8_0_OR_GREATER
+ MemoryMarshal.TryWrite(buffer, in value);
+#else
MemoryMarshal.TryWrite(buffer, ref value);
+#endif
if (BitConverter.IsLittleEndian) buffer.Reverse();
Write(buffer);
@@ -99,21 +107,21 @@ public sealed class ProtocolWriter : BinaryWriter
[CLSCompliant(false)]
public override void Write(ushort value)
{
- base.Write((ushort) IPAddress.HostToNetworkOrder((short) value));
+ base.Write((ushort)IPAddress.HostToNetworkOrder((short)value));
}
///
[CLSCompliant(false)]
public override void Write(uint value)
{
- base.Write((uint) IPAddress.HostToNetworkOrder((int) value));
+ base.Write((uint)IPAddress.HostToNetworkOrder((int)value));
}
///
[CLSCompliant(false)]
public override void Write(ulong value)
{
- base.Write((ulong) IPAddress.HostToNetworkOrder((long) value));
+ base.Write((ulong)IPAddress.HostToNetworkOrder((long)value));
}
///
@@ -155,7 +163,7 @@ public sealed class ProtocolWriter : BinaryWriter
/// The 32-bit integer to be written.
public void Write7BitEncodedInt32(int value)
{
- var uValue = (uint) value;
+ var uValue = (uint)value;
// Write out an int 7 bits at a time. The high bit of the byte,
// when on, tells reader to continue reading more bytes.
@@ -165,11 +173,11 @@ public sealed class ProtocolWriter : BinaryWriter
while (uValue > 0x7Fu)
{
- Write((byte) (uValue | ~0x7Fu));
+ Write((byte)(uValue | ~0x7Fu));
uValue >>= 7;
}
- Write((byte) uValue);
+ Write((byte)uValue);
}
///
@@ -178,7 +186,7 @@ public sealed class ProtocolWriter : BinaryWriter
/// The 64-bit integer to be written.
public void Write7BitEncodedInt64(long value)
{
- var uValue = (ulong) value;
+ var uValue = (ulong)value;
// Write out an int 7 bits at a time. The high bit of the byte,
// when on, tells reader to continue reading more bytes.
@@ -188,10 +196,10 @@ public sealed class ProtocolWriter : BinaryWriter
while (uValue > 0x7Fu)
{
- Write((byte) ((uint) uValue | ~0x7Fu));
+ Write((byte)((uint)uValue | ~0x7Fu));
uValue >>= 7;
}
- Write((byte) uValue);
+ Write((byte)uValue);
}
}
diff --git a/TcpDotNet/Protocol/RequestPacket.cs b/TcpDotNet/Protocol/RequestPacket.cs
index 42f3bcf..21037d9 100644
--- a/TcpDotNet/Protocol/RequestPacket.cs
+++ b/TcpDotNet/Protocol/RequestPacket.cs
@@ -1,15 +1,28 @@
-namespace TcpDotNet.Protocol;
+using System.Buffers.Binary;
+using System.Security.Cryptography;
+
+namespace TcpDotNet.Protocol;
///
/// Represents a request packet, which forms a request/response packet pair.
///
public abstract class RequestPacket : Packet
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ protected RequestPacket()
+ {
+ Span buffer = stackalloc byte[8];
+ RandomNumberGenerator.Fill(buffer);
+ CallbackId = BinaryPrimitives.ReadInt64BigEndian(buffer);
+ }
+
///
/// Gets the request identifier.
///
/// The request identifier.
- public long CallbackId { get; internal set; }
+ public long CallbackId { get; private set; }
///
protected internal override void Deserialize(ProtocolReader reader)
diff --git a/TcpDotNet/Protocol/ResponsePacket.cs b/TcpDotNet/Protocol/ResponsePacket.cs
index 7aade8b..f162c92 100644
--- a/TcpDotNet/Protocol/ResponsePacket.cs
+++ b/TcpDotNet/Protocol/ResponsePacket.cs
@@ -1,4 +1,4 @@
-namespace TcpDotNet.Protocol;
+namespace TcpDotNet.Protocol;
///
/// Represents a response packet, which forms a request/response packet pair.
@@ -14,6 +14,10 @@ public abstract class ResponsePacket : Packet
CallbackId = callbackId;
}
+ internal ResponsePacket()
+ {
+ }
+
///
/// Gets the response identifier.
///
diff --git a/TcpDotNet/ProtocolClient.cs b/TcpDotNet/ProtocolClient.cs
index 1294eb8..de0bb89 100644
--- a/TcpDotNet/ProtocolClient.cs
+++ b/TcpDotNet/ProtocolClient.cs
@@ -1,4 +1,4 @@
-using System.Net;
+using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using TcpDotNet.EventData;
@@ -14,7 +14,7 @@ namespace TcpDotNet;
///
/// Represents a client on the TcpDotNet protocol.
///
-public sealed class ProtocolClient : BaseClientNode
+public sealed class ProtocolClient : ClientNode
{
///
/// Initializes a new instance of the class.
@@ -82,7 +82,7 @@ public sealed class ProtocolClient : BaseClientNode
BaseSocket = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
- await Task.Run(() => BaseSocket.ConnectAsync(remoteEP), cancellationToken);
+ await BaseSocket.ConnectAsync(remoteEP, cancellationToken);
}
catch
{
@@ -95,15 +95,15 @@ public sealed class ProtocolClient : BaseClientNode
State = ClientState.Handshaking;
var handshakeRequest = new HandshakeRequestPacket(ProtocolVersion);
- var handshakeResponse =
- await SendAndReceiveAsync(handshakeRequest, cancellationToken);
+ var handshakeResponse = await SendAndReceiveAsync(handshakeRequest, cancellationToken);
if (handshakeResponse.HandshakeResponse != HandshakeResponse.Success)
{
Close();
IsConnected = false;
- throw new InvalidOperationException("Handshake failed. " +
- $"Server responded with {handshakeResponse.HandshakeResponse:D}");
+
+ var message = $"Handshake failed. Server responded with {handshakeResponse.HandshakeResponse:D}";
+ throw new InvalidOperationException(message);
}
State = ClientState.Encrypting;
@@ -113,8 +113,7 @@ public sealed class ProtocolClient : BaseClientNode
byte[] encryptedPayload = rsa.Encrypt(encryptionRequest.Payload, true);
var key = new byte[128];
- using var rng = new RNGCryptoServiceProvider();
- rng.GetBytes(key);
+ RandomNumberGenerator.Fill(key);
Aes = CryptographyUtils.GenerateAes(key);
byte[] aesKey = rsa.Encrypt(key, true);
diff --git a/TcpDotNet/ProtocolListener.Client.cs b/TcpDotNet/ProtocolListener.Client.cs
index 2755a31..2364d1b 100644
--- a/TcpDotNet/ProtocolListener.Client.cs
+++ b/TcpDotNet/ProtocolListener.Client.cs
@@ -8,7 +8,7 @@ public sealed partial class ProtocolListener
///
/// Represents a client that is connected to a .
///
- public sealed class Client : BaseClientNode
+ public sealed class Client : ClientNode
{
internal Client(ProtocolListener listener, Socket socket)
{
@@ -35,7 +35,8 @@ public sealed partial class ProtocolListener
foreach (Type packetType in ParentListener.RegisteredPackets.Values)
RegisterPacket(packetType);
- foreach ((Type packetType, IReadOnlyCollection? handlers) in ParentListener.RegisteredPacketHandlers)
+ foreach ((Type packetType, IReadOnlyCollection? handlers) in ParentListener
+ .RegisteredPacketHandlers)
foreach (PacketHandler handler in handlers)
RegisterPacketHandler(packetType, handler);
diff --git a/TcpDotNet/ProtocolListener.cs b/TcpDotNet/ProtocolListener.cs
index 335d313..4787449 100644
--- a/TcpDotNet/ProtocolListener.cs
+++ b/TcpDotNet/ProtocolListener.cs
@@ -1,4 +1,4 @@
-using System.Net;
+using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using TcpDotNet.EventData;
diff --git a/TcpDotNet/TcpDotNet.csproj b/TcpDotNet/TcpDotNet.csproj
index 3e8b637..515cbd5 100644
--- a/TcpDotNet/TcpDotNet.csproj
+++ b/TcpDotNet/TcpDotNet.csproj
@@ -1,7 +1,7 @@
- netstandard2.1;net6.0;net7.0
+ net6.0;net7.0;net8.0
enable
enable
10
@@ -12,6 +12,7 @@
git
A TCP library for .NET with support for AES encryption.
LICENSE.md
+ branding_Icon.png
dotnet networking encryption tcp
0.1.0
true
@@ -40,10 +41,18 @@
+
+ True
+
+
True
+
+ True
+
+
diff --git a/branding_Banner.png b/branding_Banner.png
new file mode 100644
index 0000000..50ae366
Binary files /dev/null and b/branding_Banner.png differ
diff --git a/branding_Icon.png b/branding_Icon.png
new file mode 100644
index 0000000..781d411
Binary files /dev/null and b/branding_Icon.png differ
diff --git a/global.json b/global.json
new file mode 100644
index 0000000..b5b37b6
--- /dev/null
+++ b/global.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "8.0.0",
+ "rollForward": "latestMajor",
+ "allowPrerelease": false
+ }
+}
\ No newline at end of file