mirror of
https://github.com/oliverbooth/TcpDotNet
synced 2024-11-10 04:55:41 +00:00
Merge 45111aae72
into 87cb461872
This commit is contained in:
commit
0db6fd2976
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@ -1 +1,2 @@
|
||||
ko_fi: oliverbooth
|
||||
custom: ['https://buymeacoffee.com/oliverbooth']
|
||||
|
12
.github/workflows/dotnet.yml
vendored
12
.github/workflows/dotnet.yml
vendored
@ -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"
|
||||
|
7
.github/workflows/nightly.yml
vendored
7
.github/workflows/nightly.yml
vendored
@ -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"
|
||||
|
4
.github/workflows/prerelease.yml
vendored
4
.github/workflows/prerelease.yml
vendored
@ -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"
|
||||
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -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"
|
||||
|
18
README.md
18
README.md
@ -1,15 +1,15 @@
|
||||
<h1 align="center">TcpDotNet</h1>
|
||||
<h1 align="center"><img src="branding_Banner.png" alt="TCP.NET"></h1>
|
||||
<p align="center">
|
||||
<a href="https://github.com/oliverbooth/TcpDotNet/actions/workflows/dotnet.yml"><img src="https://img.shields.io/github/actions/workflow/status/oliverbooth/TcpDotNet/dotnet.yml?branch=main" alt="GitHub Workflow Status" title="GitHub Workflow Status"></a>
|
||||
<a href="https://github.com/oliverbooth/TcpDotNet/issues"><img src="https://img.shields.io/github/issues/oliverbooth/TcpDotNet" alt="GitHub Issues" title="GitHub Issues"></a>
|
||||
<a href="https://www.nuget.org/packages/TcpDotNet/"><img src="https://img.shields.io/nuget/dt/TcpDotNet" alt="NuGet Downloads" title="NuGet Downloads"></a>
|
||||
<a href="https://www.nuget.org/packages/TcpDotNet/"><img src="https://img.shields.io/nuget/v/TcpDotNet?label=stable" alt="Stable Version" title="Stable Version"></a>
|
||||
<a href="https://www.nuget.org/packages/TcpDotNet/"><img src="https://img.shields.io/nuget/vpre/TcpDotNet?label=nightly" alt="Nightly Version" title="Nightly Version"></a>
|
||||
<a href="https://github.com/oliverbooth/TcpDotNet/blob/master/LICENSE.md"><img src="https://img.shields.io/github/license/oliverbooth/TcpDotNet" alt="MIT License" title="MIT License"></a>
|
||||
<a href="https://github.com/oliverbooth/TcpDotNet/actions/workflows/dotnet.yml"><img src="https://img.shields.io/github/actions/workflow/status/oliverbooth/TcpDotNet/dotnet.yml?branch=main&style=flat-square" alt="GitHub Workflow Status" title="GitHub Workflow Status"></a>
|
||||
<a href="https://github.com/oliverbooth/TcpDotNet/issues"><img src="https://img.shields.io/github/issues/oliverbooth/TcpDotNet?style=flat-square" alt="GitHub Issues" title="GitHub Issues"></a>
|
||||
<a href="https://www.nuget.org/packages/TcpDotNet/"><img src="https://img.shields.io/nuget/dt/TcpDotNet?style=flat-square" alt="NuGet Downloads" title="NuGet Downloads"></a>
|
||||
<a href="https://www.nuget.org/packages/TcpDotNet/"><img src="https://img.shields.io/nuget/v/TcpDotNet?label=stable&style=flat-square" alt="Stable Version" title="Stable Version"></a>
|
||||
<a href="https://www.nuget.org/packages/TcpDotNet/"><img src="https://img.shields.io/nuget/vpre/TcpDotNet?label=nightly&style=flat-square" alt="Nightly Version" title="Nightly Version"></a>
|
||||
<a href="https://github.com/oliverbooth/TcpDotNet/blob/master/LICENSE.md"><img src="https://img.shields.io/github/license/oliverbooth/TcpDotNet?style=flat-square" alt="MIT License" title="MIT License"></a>
|
||||
</p>
|
||||
|
||||
### 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
using TcpDotNet.Protocol;
|
||||
using TcpDotNet.Protocol;
|
||||
|
||||
namespace TcpDotNet.ClientIntegrationTest;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
using TcpDotNet.Protocol;
|
||||
using TcpDotNet.Protocol;
|
||||
|
||||
namespace TcpDotNet.ClientIntegrationTest;
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
using TcpDotNet.Protocol;
|
||||
using TcpDotNet.Protocol;
|
||||
|
||||
namespace TcpDotNet.ClientIntegrationTest.PacketHandlers;
|
||||
|
||||
internal sealed class GoodbyePacketHandler : PacketHandler<GoodbyePacket>
|
||||
{
|
||||
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;
|
||||
|
@ -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<PingPacket, PongPacket>(ping);
|
||||
var pong = await client.SendAndReceiveAsync<PongPacket>(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!");
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -1,4 +1,4 @@
|
||||
using TcpDotNet.Protocol;
|
||||
using TcpDotNet.Protocol;
|
||||
|
||||
namespace TcpDotNet.ListenerIntegrationTest;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
using TcpDotNet.Protocol;
|
||||
using TcpDotNet.Protocol;
|
||||
|
||||
namespace TcpDotNet.ListenerIntegrationTest;
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
using TcpDotNet.Protocol;
|
||||
using TcpDotNet.Protocol;
|
||||
|
||||
namespace TcpDotNet.ListenerIntegrationTest.PacketHandlers;
|
||||
|
||||
internal sealed class HelloPacketHandler : PacketHandler<HelloPacket>
|
||||
{
|
||||
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);
|
||||
|
@ -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<PingPacket>
|
||||
{
|
||||
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);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
@ -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
|
||||
|
@ -1 +1 @@
|
||||
[assembly: CLSCompliant(true)]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
@ -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;
|
||||
/// <summary>
|
||||
/// Represents a client node.
|
||||
/// </summary>
|
||||
public abstract class BaseClientNode : Node
|
||||
public abstract class ClientNode : Node
|
||||
{
|
||||
private readonly ObjectIDGenerator _callbackIdGenerator = new();
|
||||
private readonly ConcurrentDictionary<int, List<TaskCompletionSource<Packet>>> _packetCompletionSources = new();
|
||||
private readonly ConcurrentDictionary<long, TaskCompletionSource<ResponsePacket>> _callbackCompletionSources = new();
|
||||
private EndPoint? _remoteEP;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseClientNode" /> class.
|
||||
/// Initializes a new instance of the <see cref="ClientNode" /> class.
|
||||
/// </summary>
|
||||
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
|
||||
/// <summary>
|
||||
/// Sends a packet, and waits for a specific packet to be received.
|
||||
/// </summary>
|
||||
/// <param name="packetToSend">The packet to send.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
|
||||
/// <typeparam name="TSend">The type of the packet to send.</typeparam>
|
||||
/// <param name="packet">The packet to send.</param>
|
||||
/// <param name="cancellationToken">
|
||||
/// A cancellation token that can be used to cancel the asynchronous operation.
|
||||
/// </param>
|
||||
/// <typeparam name="TReceive">The type of the packet to return.</typeparam>
|
||||
/// <returns>The received packet.</returns>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
public async Task<TReceive> SendAndReceiveAsync<TSend, TReceive>(TSend packetToSend,
|
||||
/// <exception cref="ArgumentNullException"><paramref name="packet" /> is <see langword="null" />.</exception>
|
||||
public async Task<TReceive> SendAndReceiveAsync<TReceive>(RequestPacket packet,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TSend : Packet
|
||||
where TReceive : Packet
|
||||
where TReceive : ResponsePacket
|
||||
{
|
||||
var attribute = typeof(TReceive).GetCustomAttribute<PacketAttribute>();
|
||||
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<ResponsePacket>();
|
||||
if (!_callbackCompletionSources.TryAdd(packet.CallbackId, completionSource))
|
||||
throw new InvalidOperationException("Duplicate packet sent");
|
||||
|
||||
var completionSource = new TaskCompletionSource<Packet>();
|
||||
if (!_packetCompletionSources.TryGetValue(attribute.Id, out List<TaskCompletionSource<Packet>>? completionSources))
|
||||
{
|
||||
completionSources = new List<TaskCompletionSource<Packet>>();
|
||||
_packetCompletionSources.TryAdd(attribute.Id, completionSources);
|
||||
}
|
||||
|
||||
lock (completionSources)
|
||||
{
|
||||
if (!completionSources.Contains(completionSource))
|
||||
completionSources.Add(completionSource);
|
||||
}
|
||||
|
||||
await SendPacketAsync(packetToSend, cancellationToken);
|
||||
TReceive response;
|
||||
do
|
||||
{
|
||||
response = await WaitForPacketAsync<TReceive>(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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -284,17 +259,16 @@ public abstract class BaseClientNode : Node
|
||||
return WaitForPacketAsync<TPacket>(completionSource, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<TPacket> WaitForPacketAsync<TPacket>(
|
||||
TaskCompletionSource<Packet> completionSource,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
private async Task<TPacket> WaitForPacketAsync<TPacket>(TaskCompletionSource<Packet> completionSource,
|
||||
CancellationToken cancellationToken = default)
|
||||
where TPacket : Packet
|
||||
{
|
||||
var attribute = typeof(TPacket).GetCustomAttribute<PacketAttribute>();
|
||||
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<TaskCompletionSource<Packet>>? completionSources))
|
||||
if (!_packetCompletionSources.TryGetValue(attribute.Id,
|
||||
out List<TaskCompletionSource<Packet>>? completionSources))
|
||||
{
|
||||
completionSources = new List<TaskCompletionSource<Packet>>();
|
||||
_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)
|
@ -1,7 +1,7 @@
|
||||
namespace TcpDotNet;
|
||||
namespace TcpDotNet;
|
||||
|
||||
/// <summary>
|
||||
/// An enumeration of states for a <see cref="BaseClientNode" /> to be in.
|
||||
/// An enumeration of states for a <see cref="ClientNode" /> to be in.
|
||||
/// </summary>
|
||||
public enum ClientState
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Chilkat;
|
||||
using Chilkat;
|
||||
|
||||
namespace TcpDotNet;
|
||||
|
||||
|
@ -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
|
||||
/// <value>The registered packets.</value>
|
||||
public IReadOnlyDictionary<Type, IReadOnlyCollection<PacketHandler>> RegisteredPacketHandlers =>
|
||||
new ReadOnlyDictionary<Type, IReadOnlyCollection<PacketHandler>>(
|
||||
_registeredPacketHandlers.ToDictionary(p => p.Key, p => (IReadOnlyCollection<PacketHandler>) p.Value.AsReadOnly()));
|
||||
_registeredPacketHandlers.ToDictionary(p => p.Key,
|
||||
p => (IReadOnlyCollection<PacketHandler>)p.Value.AsReadOnly()));
|
||||
|
||||
/// <summary>
|
||||
/// Closes the base socket connection and releases all associated resources.
|
||||
@ -124,7 +125,8 @@ public abstract class Node : IDisposable
|
||||
var attribute = packetType.GetCustomAttribute<PacketAttribute>();
|
||||
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);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace TcpDotNet.Protocol;
|
||||
namespace TcpDotNet.Protocol;
|
||||
|
||||
/// <summary>
|
||||
/// An enumeration of handshake responses.
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Reflection;
|
||||
using System.Reflection;
|
||||
|
||||
namespace TcpDotNet.Protocol;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace TcpDotNet.Protocol;
|
||||
namespace TcpDotNet.Protocol;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies metadata for a <see cref="Packet" />.
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace TcpDotNet.Protocol;
|
||||
namespace TcpDotNet.Protocol;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the base class for a packet handler.
|
||||
@ -12,7 +12,7 @@ public abstract class PacketHandler
|
||||
/// <param name="recipient">The recipient of the packet.</param>
|
||||
/// <param name="packet">The packet to handle.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
|
||||
public abstract Task HandleAsync(BaseClientNode recipient, Packet packet, CancellationToken cancellationToken = default);
|
||||
public abstract Task HandleAsync(ClientNode recipient, Packet packet, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -27,7 +27,7 @@ public abstract class PacketHandler<T> : PacketHandler
|
||||
public static readonly PacketHandler<T> Empty = new NullPacketHandler<T>();
|
||||
|
||||
/// <inheritdoc />
|
||||
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<T> : PacketHandler
|
||||
/// <param name="recipient">The recipient of the packet.</param>
|
||||
/// <param name="packet">The packet to handle.</param>
|
||||
/// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
|
||||
public abstract Task HandleAsync(BaseClientNode recipient, T packet, CancellationToken cancellationToken = default);
|
||||
public abstract Task HandleAsync(ClientNode recipient, T packet, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -50,7 +50,7 @@ internal sealed class NullPacketHandler<T> : PacketHandler<T>
|
||||
where T : Packet
|
||||
{
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
|
@ -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<DisconnectPacket>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override Task HandleAsync(
|
||||
BaseClientNode recipient,
|
||||
ClientNode recipient,
|
||||
DisconnectPacket packet,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
|
@ -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<Encryption
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override async Task HandleAsync(
|
||||
BaseClientNode recipient,
|
||||
ClientNode recipient,
|
||||
EncryptionResponsePacket packet,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
|
@ -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<HandshakeReq
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override async Task HandleAsync(
|
||||
BaseClientNode recipient,
|
||||
ClientNode recipient,
|
||||
HandshakeRequestPacket packet,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
@ -22,13 +22,14 @@ internal sealed class HandshakeRequestPacketHandler : PacketHandler<HandshakeReq
|
||||
|
||||
if (packet.ProtocolVersion != Node.ProtocolVersion)
|
||||
{
|
||||
response = new HandshakeResponsePacket(packet.ProtocolVersion, HandshakeResponse.UnsupportedProtocolVersion);
|
||||
const HandshakeResponse responseCode = HandshakeResponse.UnsupportedProtocolVersion;
|
||||
response = new HandshakeResponsePacket(packet.CallbackId, packet.ProtocolVersion, responseCode);
|
||||
await client.SendPacketAsync(response, cancellationToken);
|
||||
client.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
response = new HandshakeResponsePacket(packet.ProtocolVersion, HandshakeResponse.Success);
|
||||
response = new HandshakeResponsePacket(packet.CallbackId, packet.ProtocolVersion, HandshakeResponse.Success);
|
||||
await client.SendPacketAsync(response, cancellationToken);
|
||||
|
||||
client.State = ClientState.Encrypting;
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace TcpDotNet.Protocol.Packets.ClientBound;
|
||||
namespace TcpDotNet.Protocol.Packets.ClientBound;
|
||||
|
||||
[Packet(0x7FFFFFFF)]
|
||||
internal sealed class DisconnectPacket : Packet
|
||||
@ -24,12 +24,12 @@ internal sealed class DisconnectPacket : Packet
|
||||
/// <inheritdoc />
|
||||
protected internal override void Deserialize(ProtocolReader reader)
|
||||
{
|
||||
Reason = (DisconnectReason) reader.ReadByte();
|
||||
Reason = (DisconnectReason)reader.ReadByte();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected internal override void Serialize(ProtocolWriter writer)
|
||||
{
|
||||
writer.Write((byte) Reason);
|
||||
writer.Write((byte)Reason);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace TcpDotNet.Protocol.Packets.ClientBound;
|
||||
|
||||
|
@ -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 <see cref="HandshakeRequestPacket" />.
|
||||
/// </summary>
|
||||
[Packet(0x7FFFFFE1)]
|
||||
internal sealed class HandshakeResponsePacket : Packet
|
||||
internal sealed class HandshakeResponsePacket : ResponsePacket
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HandshakeResponsePacket" /> class.
|
||||
/// </summary>
|
||||
/// <param name="callbackId">The callback ID.</param>
|
||||
/// <param name="protocolVersion">The requested protocol version.</param>
|
||||
/// <param name="handshakeResponse">The handshake response.</param>
|
||||
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
|
||||
/// <inheritdoc />
|
||||
protected internal override void Deserialize(ProtocolReader reader)
|
||||
{
|
||||
HandshakeResponse = (HandshakeResponse) reader.ReadByte();
|
||||
HandshakeResponse = (HandshakeResponse)reader.ReadByte();
|
||||
ProtocolVersion = reader.ReadInt32();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected internal override void Serialize(ProtocolWriter writer)
|
||||
{
|
||||
writer.Write((byte) HandshakeResponse);
|
||||
writer.Write((byte)HandshakeResponse);
|
||||
writer.Write(ProtocolVersion);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace TcpDotNet.Protocol.Packets.ClientBound;
|
||||
namespace TcpDotNet.Protocol.Packets.ClientBound;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a packet which performs a heartbeat response.
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace TcpDotNet.Protocol.Packets.ClientBound;
|
||||
namespace TcpDotNet.Protocol.Packets.ClientBound;
|
||||
|
||||
[Packet(0x7FFFFFE4)]
|
||||
internal sealed class SessionExchangePacket : Packet
|
||||
|
@ -1,4 +1,4 @@
|
||||
using TcpDotNet.Protocol.Packets.ClientBound;
|
||||
using TcpDotNet.Protocol.Packets.ClientBound;
|
||||
|
||||
namespace TcpDotNet.Protocol.Packets.ServerBound;
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
namespace TcpDotNet.Protocol.Packets.ServerBound;
|
||||
namespace TcpDotNet.Protocol.Packets.ServerBound;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a packet which requests a handshake with a <see cref="ProtocolListener" />.
|
||||
/// </summary>
|
||||
[Packet(0x7FFFFFE0)]
|
||||
internal sealed class HandshakeRequestPacket : Packet
|
||||
internal sealed class HandshakeRequestPacket : RequestPacket
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HandshakeRequestPacket" /> class.
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace TcpDotNet.Protocol.Packets.ServerBound;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -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());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[CLSCompliant(false)]
|
||||
public override uint ReadUInt32()
|
||||
{
|
||||
return (uint) IPAddress.NetworkToHostOrder((int) base.ReadUInt32());
|
||||
return (uint)IPAddress.NetworkToHostOrder((int)base.ReadUInt32());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[CLSCompliant(false)]
|
||||
public override ulong ReadUInt64()
|
||||
{
|
||||
return (ulong) IPAddress.NetworkToHostOrder((long) base.ReadUInt64());
|
||||
return (ulong)IPAddress.NetworkToHostOrder((long)base.ReadUInt64());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -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<byte> 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<byte> 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));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[CLSCompliant(false)]
|
||||
public override void Write(uint value)
|
||||
{
|
||||
base.Write((uint) IPAddress.HostToNetworkOrder((int) value));
|
||||
base.Write((uint)IPAddress.HostToNetworkOrder((int)value));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[CLSCompliant(false)]
|
||||
public override void Write(ulong value)
|
||||
{
|
||||
base.Write((ulong) IPAddress.HostToNetworkOrder((long) value));
|
||||
base.Write((ulong)IPAddress.HostToNetworkOrder((long)value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -155,7 +163,7 @@ public sealed class ProtocolWriter : BinaryWriter
|
||||
/// <param name="value">The 32-bit integer to be written.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -178,7 +186,7 @@ public sealed class ProtocolWriter : BinaryWriter
|
||||
/// <param name="value">The 64-bit integer to be written.</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,28 @@
|
||||
namespace TcpDotNet.Protocol;
|
||||
using System.Buffers.Binary;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace TcpDotNet.Protocol;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a request packet, which forms a request/response packet pair.
|
||||
/// </summary>
|
||||
public abstract class RequestPacket : Packet
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestPacket" /> class.
|
||||
/// </summary>
|
||||
protected RequestPacket()
|
||||
{
|
||||
Span<byte> buffer = stackalloc byte[8];
|
||||
RandomNumberGenerator.Fill(buffer);
|
||||
CallbackId = BinaryPrimitives.ReadInt64BigEndian(buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the request identifier.
|
||||
/// </summary>
|
||||
/// <value>The request identifier.</value>
|
||||
public long CallbackId { get; internal set; }
|
||||
public long CallbackId { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected internal override void Deserialize(ProtocolReader reader)
|
||||
|
@ -1,4 +1,4 @@
|
||||
namespace TcpDotNet.Protocol;
|
||||
namespace TcpDotNet.Protocol;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a response packet, which forms a request/response packet pair.
|
||||
@ -14,6 +14,10 @@ public abstract class ResponsePacket : Packet
|
||||
CallbackId = callbackId;
|
||||
}
|
||||
|
||||
internal ResponsePacket()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the response identifier.
|
||||
/// </summary>
|
||||
|
@ -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;
|
||||
/// <summary>
|
||||
/// Represents a client on the TcpDotNet protocol.
|
||||
/// </summary>
|
||||
public sealed class ProtocolClient : BaseClientNode
|
||||
public sealed class ProtocolClient : ClientNode
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProtocolClient" /> 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<HandshakeRequestPacket, HandshakeResponsePacket>(handshakeRequest, cancellationToken);
|
||||
var handshakeResponse = await SendAndReceiveAsync<HandshakeResponsePacket>(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);
|
||||
|
@ -8,7 +8,7 @@ public sealed partial class ProtocolListener
|
||||
/// <summary>
|
||||
/// Represents a client that is connected to a <see cref="ProtocolListener" />.
|
||||
/// </summary>
|
||||
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<PacketHandler>? handlers) in ParentListener.RegisteredPacketHandlers)
|
||||
foreach ((Type packetType, IReadOnlyCollection<PacketHandler>? handlers) in ParentListener
|
||||
.RegisteredPacketHandlers)
|
||||
foreach (PacketHandler handler in handlers)
|
||||
RegisterPacketHandler(packetType, handler);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System.Net;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Security.Cryptography;
|
||||
using TcpDotNet.EventData;
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.1;net6.0;net7.0</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>10</LangVersion>
|
||||
@ -12,6 +12,7 @@
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<Description>A TCP library for .NET with support for AES encryption.</Description>
|
||||
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
|
||||
<PackageIcon>branding_Icon.png</PackageIcon>
|
||||
<PackageTags>dotnet networking encryption tcp</PackageTags>
|
||||
<VersionPrefix>0.1.0</VersionPrefix>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
@ -40,10 +41,18 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\branding_Icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath/>
|
||||
</None>
|
||||
<None Include="..\LICENSE.md">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath/>
|
||||
</None>
|
||||
<None Include="..\README.md">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath/>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
BIN
branding_Banner.png
Normal file
BIN
branding_Banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
branding_Icon.png
Normal file
BIN
branding_Icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
7
global.json
Normal file
7
global.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "8.0.0",
|
||||
"rollForward": "latestMajor",
|
||||
"allowPrerelease": false
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user