fixed compilation errors

This commit is contained in:
Timerix 2025-05-09 16:32:35 +05:00
parent acaf5fee14
commit bf4924c4d6
17 changed files with 179 additions and 78 deletions

View File

@ -1,15 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<Version>1.0.0</Version> <Version>0.0.1</Version>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Meum.Client\Meum.Client.csproj" /> <ProjectReference Include="..\Meum.Client\Meum.Client.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="DTLib" Version="1.6.0" />
</ItemGroup>
</Project> </Project>

View File

@ -4,11 +4,11 @@ global using System.Threading;
global using System.Threading.Tasks; global using System.Threading.Tasks;
global using Meum.Core; global using Meum.Core;
using System.Net; using System.Net;
using System.Net.Quic;
using System.Reflection; using System.Reflection;
using DTLib.Console; using DTLib.Console;
using DTLib.Demystifier; using DTLib.Demystifier;
using DTLib.Extensions; using DTLib.Extensions;
using DTLib.Logging;
namespace Meum.Client.CLI; namespace Meum.Client.CLI;
@ -34,15 +34,15 @@ class Program
{ {
Console.OutputEncoding = StringConverter.UTF8; Console.OutputEncoding = StringConverter.UTF8;
Console.InputEncoding = StringConverter.UTF8; Console.InputEncoding = StringConverter.UTF8;
ColoredConsole.ResetColor(); ColoredConsole.Clear();
var loggerRoot = new ConsoleLogger();
try try
{ {
var v = Assembly.GetExecutingAssembly().GetName().Version; var v = Assembly.GetExecutingAssembly().GetName().Version;
string title = $"Meum CLI v{v?.ToString(3) ?? "Null"}"; string title = $"Meum CLI v{v?.ToString(3) ?? "Null"}";
Console.Title = title; Console.Title = title;
if (!QuicConnection.IsSupported) Functions.InitMsQuic(loggerRoot);
throw new Exception("Quic is not supported, check for presence of libmsquic and openssl");
ColoredConsole.WriteTitle(title, '=', fg: ConsoleColor.Cyan); ColoredConsole.WriteTitle(title, '=', fg: ConsoleColor.Cyan);
ColoredConsole.WriteLine(greeting_art, fg: ConsoleColor.Magenta); ColoredConsole.WriteLine(greeting_art, fg: ConsoleColor.Magenta);
@ -57,17 +57,18 @@ class Program
{ {
if (userAddress == null) if (userAddress == null)
{ {
var addrstr = ColoredConsole.Write("enter user address (name@server.xyz): ", ConsoleColor.Blue);
ColoredConsole.ReadLine("enter user address (name@server.xyz)", ConsoleColor.Blue); var addrstr = ColoredConsole.ReadLine(ConsoleColor.Cyan);
if (string.IsNullOrEmpty(addrstr)) if (string.IsNullOrEmpty(addrstr))
continue; continue;
userAddress = new(addrstr); userAddress = new(addrstr);
} }
Client client = new(); Client client = new(loggerRoot);
if (serverEndPoint == null) if (serverEndPoint == null)
{ {
serverAddress = ColoredConsole.ReadLine("enter server address (server.xyz)", ConsoleColor.Blue); ColoredConsole.Write("enter server address (server.xyz): ", ConsoleColor.Blue);
serverAddress = ColoredConsole.ReadLine(ConsoleColor.Cyan);
if (string.IsNullOrEmpty(serverAddress)) if (string.IsNullOrEmpty(serverAddress))
{ {
ColoredConsole.WriteLine("null address", ConsoleColor.Red); ColoredConsole.WriteLine("null address", ConsoleColor.Red);
@ -82,7 +83,6 @@ class Program
var conn = await client.ConnectToServerAsync(serverEndPoint); var conn = await client.ConnectToServerAsync(serverEndPoint);
ColoredConsole.WriteLine("Connected to server", ConsoleColor.Green); ColoredConsole.WriteLine("Connected to server", ConsoleColor.Green);
await conn.PingAsync();
await Task.Delay(-1); await Task.Delay(-1);
} }
catch (Exception ex) catch (Exception ex)

View File

@ -1,5 +1,6 @@
global using System; global using System;
global using System.Collections.Generic; global using System.Collections.Generic;
global using System.Threading;
global using System.Threading.Tasks; global using System.Threading.Tasks;
global using Meum.Core; global using Meum.Core;
using System.Net; using System.Net;
@ -36,7 +37,7 @@ public class Client
return Task.CompletedTask; return Task.CompletedTask;
} }
public async Task<ServerConnection> ConnectToServerAsync(DnsEndPoint serverEndPoint) public async Task<ServerConnection> ConnectToServerAsync(DnsEndPoint serverEndPoint, CancellationToken ct = default)
{ {
var quicConn = await QuicConnection.ConnectAsync(new QuicClientConnectionOptions var quicConn = await QuicConnection.ConnectAsync(new QuicClientConnectionOptions
{ {
@ -49,8 +50,15 @@ public class Client
ApplicationProtocols = Constants.ApplicationProtocols, ApplicationProtocols = Constants.ApplicationProtocols,
TargetHost = serverEndPoint.Host TargetHost = serverEndPoint.Host
} }
}); }, ct);
var serv = new ServerConnection(quicConn, serverEndPoint, _logger);
var timeOutCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
timeOutCts.CancelAfter(Constants.ConnectionTimeout);
var serv = await ServerConnection.OpenAsync(quicConn,
serverEndPoint,
_logger,
timeOutCts.Token);
if(!_connectedServers.Add(serv)) if(!_connectedServers.Add(serv))
throw new Exception($"Is already connected to server '{serverEndPoint.Host}'"); throw new Exception($"Is already connected to server '{serverEndPoint.Host}'");
return serv; return serv;

View File

@ -2,17 +2,12 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Meum.Core\Meum.Core.csproj" /> <ProjectReference Include="..\Meum.Core\Meum.Core.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="DTLib" Version="1.6.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project> </Project>

View File

@ -1,7 +1,5 @@
using System.Net; using System.Net;
using System.Net.Quic; using System.Net.Quic;
using System.Net.Security;
using DTLib.Extensions;
using DTLib.Logging; using DTLib.Logging;
namespace Meum.Client; namespace Meum.Client;
@ -14,13 +12,24 @@ public class ServerConnection : IAsyncDisposable
public DnsEndPoint ServerEndPoint { get; } public DnsEndPoint ServerEndPoint { get; }
public ServerConnection(QuicConnection quicConnection, DnsEndPoint serverEndPoint, ILogger logger) private ServerConnection(QuicConnection quicConnection, DnsEndPoint serverEndPoint, ILogger logger)
{ {
ServerEndPoint = serverEndPoint; ServerEndPoint = serverEndPoint;
_quicConnection = quicConnection; _quicConnection = quicConnection;
_logger = logger; _logger = logger;
} }
public static async Task<ServerConnection> OpenAsync(QuicConnection quicConnection,
DnsEndPoint serverEndPoint,
ILogger logger,
CancellationToken ct)
{
var serverConnection = new ServerConnection(quicConnection, serverEndPoint, logger);
var systemStream = await quicConnection.OpenStreamAsync(QuicStreamType.Bidirectional, ct);
await systemStream.SendPingReceivePong();
return serverConnection;
}
public override int GetHashCode() public override int GetHashCode()
{ {

View File

@ -2,7 +2,6 @@
global using System.Collections.Generic; global using System.Collections.Generic;
global using System.Threading; global using System.Threading;
global using System.Threading.Tasks; global using System.Threading.Tasks;
using System.Net;
using System.Net.Security; using System.Net.Security;
namespace Meum.Core; namespace Meum.Core;
@ -17,4 +16,5 @@ public static class Constants
public const int ServerPortDefault = 9320; public const int ServerPortDefault = 9320;
public const long DefaultStreamErrorCode = 0xA; public const long DefaultStreamErrorCode = 0xA;
public const long DefaultCloseErrorCode = 0xB; public const long DefaultCloseErrorCode = 0xB;
public static readonly TimeSpan ConnectionTimeout = TimeSpan.FromSeconds(3);
} }

View File

@ -1,9 +1,25 @@
using System.Net; using System.Net;
using System.Net.Quic;
using DTLib.Logging;
using Unofficial.MsQuic;
namespace Meum.Core; namespace Meum.Core;
public static class Functions public static class Functions
{ {
public static void InitMsQuic(ILogger? logger)
{
if (logger != null)
{
HarmonyMsQuicLoadFix.Apply(msg => logger.LogInfo(nameof(HarmonyMsQuicLoadFix), msg));
using var netEventListener = new NetEventListener(logger);
}
else HarmonyMsQuicLoadFix.Apply();
if (!QuicConnection.IsSupported)
throw new Exception("Quic is not supported, check for presence of libmsquic and openssl");
}
public static bool IsValidDomainName(string name) public static bool IsValidDomainName(string name)
{ {
return Uri.CheckHostName(name) != UriHostNameType.Unknown; return Uri.CheckHostName(name) != UriHostNameType.Unknown;

View File

@ -1,9 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Unofficial.MsQuic" Version="2.4.6" /> <PackageReference Include="DTLib" Version="1.7.3" />
<PackageReference Include="Unofficial.MsQuic" Version="2.4.10" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,37 @@
using System.Diagnostics.Tracing;
using System.Linq;
using DTLib.Logging;
namespace Meum.Core;
internal class NetEventListener(ILogger _logger) : EventListener
{
protected override void OnEventSourceCreated(EventSource eventSource)
{
// Filter for NetEventSource
if (eventSource.Name.Contains("System.Net"))
{
EnableEvents(eventSource, EventLevel.LogAlways, EventKeywords.All);
}
}
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
LogSeverity severity = eventData.Level switch
{
EventLevel.LogAlways => LogSeverity.Info,
EventLevel.Critical => LogSeverity.Error,
EventLevel.Error => LogSeverity.Error,
EventLevel.Warning => LogSeverity.Warn,
EventLevel.Informational => LogSeverity.Info,
EventLevel.Verbose => LogSeverity.Debug,
_ => throw new ArgumentOutOfRangeException(eventData.Level.ToString())
};
IEnumerable<object?> payload = eventData.Payload ?? Enumerable.Empty<object?>();
var message = string.Join(", ", payload);
string context = eventData.EventSource.Name;
if (context.Contains("System.Net.Quic"))
context = "MsQuic";
_logger.Log(context, severity, message);
}
}

View File

@ -0,0 +1,24 @@
using System.Net.Quic;
namespace Meum.Core;
public static class QuicExtensions
{
public static async Task<QuicStreamWrapper> AcceptStreamAsync(this QuicConnection conn,
QuicStreamType streamType, CancellationToken ct = default)
{
var s = await conn.AcceptInboundStreamAsync(ct);
if (s.Type != streamType)
throw new Exception($"Accepted stream type is invalid: {s.Type} instead of {streamType}");
var w = new QuicStreamWrapper(s);
return w;
}
public static async Task<QuicStreamWrapper> OpenStreamAsync(this QuicConnection conn,
QuicStreamType streamType, CancellationToken ct = default)
{
var s = await conn.OpenOutboundStreamAsync(streamType, ct);
var w = new QuicStreamWrapper(s);
return w;
}
}

View File

@ -74,8 +74,23 @@ public class QuicStreamWrapper : IAsyncDisposable
return m; return m;
} }
//TODO
// public async ValueTask<> public async Task ReceivePingSendPong()
{
var messageCode = await ReadCodeMessageAsync();
if(messageCode != MessageTypeCode.Ping)
throw new Exception($"Failed to test application protocol: expected Ping, got {messageCode}");
await WriteCodeMessageAsync(MessageTypeCode.Pong);
}
public async Task SendPingReceivePong()
{
await WriteCodeMessageAsync(MessageTypeCode.Ping);
var messageCode = await ReadCodeMessageAsync();
if(messageCode != MessageTypeCode.Pong)
throw new Exception($"Failed to test application protocol: expected Pong, got {messageCode}");
}
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()
{ {

View File

@ -1,5 +1,4 @@
using System.IO; using System.Net.Quic;
using System.Net.Quic;
using DTLib.Logging; using DTLib.Logging;
using Meum.Core.Messages; using Meum.Core.Messages;
@ -8,52 +7,49 @@ namespace Meum.Server;
public class ClientConnection : IAsyncDisposable public class ClientConnection : IAsyncDisposable
{ {
private readonly QuicConnection _quicConnection; private readonly QuicConnection _quicConnection;
private QuicStreamWrapper? _systemStream; private QuicStreamWrapper _systemStream;
private ILogger _logger; private ILogger _logger;
public ClientConnection(QuicConnection quicConnection, ILogger logger) private ClientConnection(QuicConnection quicConnection, QuicStreamWrapper systemStream, ILogger logger)
{ {
_quicConnection = quicConnection; _quicConnection = quicConnection;
_systemStream = systemStream;
_logger = logger; _logger = logger;
} }
private async Task<QuicStreamWrapper> AcceptStreamAsync(QuicStreamType streamType, CancellationToken ct = default) public static async Task<ClientConnection> OpenAsync(
QuicConnection quicConnection,
ILogger logger,
CancellationToken ct)
{ {
var s = await _quicConnection.AcceptInboundStreamAsync(ct);
if (s.Type != streamType)
throw new Exception($"Accepted stream type is invalid: {s.Type} instead of {streamType}");
var w = new QuicStreamWrapper(s);
return w; var systemStream = await quicConnection.AcceptStreamAsync(QuicStreamType.Bidirectional, ct);
} await systemStream.ReceivePingSendPong();
var clientConnection = new ClientConnection(quicConnection, systemStream, logger);
public async void HandleClientRequestsAsync(CancellationToken ct = default) DataMessageHeader header = await systemStream.ReadDataMessageHeaderAsync(ct);
{
if(_systemStream != null)
throw new Exception("Already connected to client");
_systemStream = await AcceptStreamAsync(QuicStreamType.Bidirectional, ct);
// receive "Ping"
if(await _systemStream.ReadCodeMessageAsync(ct) != MessageTypeCode.Ping)
throw new Exception("Failed to test application protocol");
// send "Pong"
await _systemStream.WriteCodeMessageAsync(MessageTypeCode.Pong, ct);
DataMessageHeader header = await _systemStream.ReadDataMessageHeaderAsync(ct);
switch (header.type_code) switch (header.type_code)
{ {
case MessageTypeCode.RegistrationRequest: case MessageTypeCode.RegistrationRequest:
break; break;
case MessageTypeCode.AuthorizationRequest: case MessageTypeCode.AuthorizationRequest:
// if (authorized)
// clientConnection.HandleClientRequestsAsync()
break; break;
default: default:
throw new Exception($"New connection sent unexpected message: {header.type_code}"); throw new Exception($"New connection sent unexpected message: {header.type_code}");
} }
return clientConnection;
} }
// private async void HandleClientRequestsAsync(CancellationToken ct = default)
// {
//
// }
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()
{ {
await _quicConnection.DisposeAsync(); await _quicConnection.DisposeAsync();

View File

@ -1,15 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<Version>0.0.1</Version>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Meum.Core\Meum.Core.csproj" /> <ProjectReference Include="..\Meum.Core\Meum.Core.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="DTLib" Version="1.6.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project> </Project>

View File

@ -3,15 +3,8 @@ global using System.Collections.Generic;
global using System.Threading; global using System.Threading;
global using System.Threading.Tasks; global using System.Threading.Tasks;
global using Meum.Core; global using Meum.Core;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Quic;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using DTLib.Console; using DTLib.Console;
using DTLib.Demystifier; using DTLib.Demystifier;
using DTLib.Extensions;
using DTLib.Filesystem; using DTLib.Filesystem;
using DTLib.Logging; using DTLib.Logging;
@ -25,10 +18,10 @@ static class Program
{ {
try try
{ {
if (!QuicConnection.IsSupported)
throw new Exception("Quic is not supported, check for presence of libmsquic and openssl");
var config = ServerConfig.LoadOrCreate(config_path); var config = ServerConfig.LoadOrCreate(config_path);
var logger = new ConsoleLogger(); var logger = new ConsoleLogger();
Functions.InitMsQuic(logger);
var server = new Server(config, logger); var server = new Server(config, logger);
await server.ListenAsync(); await server.ListenAsync();
while (true) while (true)

View File

@ -1,4 +1,4 @@
## Create self-signed certificate ## Create self-signed certificate
```sh ```sh
dotnet dev-certs https -ep bin/Debug/net8.0/self-signed.pem --trust --format PEM --no-password dotnet dev-certs https -ep bin/Debug/net9.0/self-signed.pem --trust --format PEM --no-password
``` ```

View File

@ -54,8 +54,12 @@ public class Server
{ {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
var quicConnection = await _listener.AcceptConnectionAsync(ct); var quicConnection = await _listener.AcceptConnectionAsync(ct);
var clientConnection = new ClientConnection(quicConnection, _logger); var timeOutCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
await clientConnection.HandleClientRequestsAsync(ct); timeOutCts.CancelAfter(Constants.ConnectionTimeout);
var clientConnection = await ClientConnection.OpenAsync(
quicConnection,
_logger,
timeOutCts.Token);
return clientConnection; return clientConnection;
} }
} }

View File

@ -1,7 +1,5 @@
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization;
using DTLib.Filesystem; using DTLib.Filesystem;
using Newtonsoft.Json;
namespace Meum.Server; namespace Meum.Server;
@ -12,9 +10,14 @@ public class ServerConfig
public string certificate_path { get; set; } = "self-signed.pem"; public string certificate_path { get; set; } = "self-signed.pem";
public string? key_path { get; set; } = "self-signed.key"; public string? key_path { get; set; } = "self-signed.key";
private static JsonSerializerOptions _serializerOptions = new()
{
WriteIndented = true,
};
public void Save(IOPath file_path) public void Save(IOPath file_path)
{ {
string serialized = JsonConvert.SerializeObject(this); string serialized = JsonSerializer.Serialize(this, _serializerOptions);
if (string.IsNullOrEmpty(serialized)) if (string.IsNullOrEmpty(serialized))
throw new Exception("can't serialize config"); throw new Exception("can't serialize config");
File.WriteAllText(file_path, serialized); File.WriteAllText(file_path, serialized);
@ -25,7 +28,7 @@ public class ServerConfig
if(File.Exists(file_path)) if(File.Exists(file_path))
{ {
string serialized = File.ReadAllText(file_path); string serialized = File.ReadAllText(file_path);
return JsonConvert.DeserializeObject<ServerConfig>(serialized) return JsonSerializer.Deserialize<ServerConfig>(serialized)
?? throw new Exception("can't deserialize config"); ?? throw new Exception("can't deserialize config");
} }