diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 1510ed02..e18a47db 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -42,7 +42,11 @@ jobs:
echo "~/.dotnet/tools" >> $GITHUB_PATH
- name: Build docs
- run: docfx docfx.json
+ run: |
+ dotnet --version
+ whereis docfx
+ docfx --version
+ docfx docfx.json
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
diff --git a/Directory.Build.targets b/Directory.Build.targets
index b191f782..7cc09f18 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -1,14 +1,4 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/NearShare.slnx b/NearShare.slnx
index 5980d523..19f555d4 100644
--- a/NearShare.slnx
+++ b/NearShare.slnx
@@ -15,6 +15,7 @@
+
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/Messages/FetchDataResponse.cs b/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/Messages/FetchDataResponse.cs
index e03b1270..ae578d6f 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/Messages/FetchDataResponse.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/Messages/FetchDataResponse.cs
@@ -1,47 +1,48 @@
-using ShortDev.Microsoft.ConnectedDevices.Serialization;
+using ShortDev.IO.Bond;
+using ShortDev.Microsoft.ConnectedDevices.Serialization;
namespace ShortDev.Microsoft.ConnectedDevices.NearShare.Messages;
internal static class FetchDataResponse
{
- public static void Write(EndianWriter writer, uint contentId, ulong start, int length, out Span blob)
+ public static void Write(ref TWriter writer, uint contentId, ulong start, int length, out Span blob) where TWriter : struct, IEndianWriter, allows ref struct
{
- CompactBinaryBondWriter bondWriter = new(writer.Buffer);
+ CompactBinaryWriter bondWriter = new(ref writer);
- bondWriter.WriteFieldBegin(Bond.BondDataType.BT_MAP, 1);
- bondWriter.WriteContainerBegin(count: 4, Bond.BondDataType.BT_WSTRING, Bond.BondDataType.BT_STRUCT);
+ bondWriter.WriteFieldBegin(BondDataType.BT_MAP, 1);
+ bondWriter.WriteContainerBegin(count: 4, BondDataType.BT_WSTRING, BondDataType.BT_STRUCT);
WritePropertyBegin(ref bondWriter, "ControlMessage", PropertyType.PropertyType_UInt32);
- bondWriter.WriteFieldBegin(Bond.BondDataType.BT_UINT32, 104);
+ bondWriter.WriteFieldBegin(BondDataType.BT_UINT32, 104);
bondWriter.WriteUInt32((uint)NearShareControlMsgType.FetchDataResponse);
bondWriter.WriteStructEnd();
WritePropertyBegin(ref bondWriter, "ContentId", PropertyType.PropertyType_UInt32);
- bondWriter.WriteFieldBegin(Bond.BondDataType.BT_UINT32, 104);
+ bondWriter.WriteFieldBegin(BondDataType.BT_UINT32, 104);
bondWriter.WriteUInt32(contentId);
bondWriter.WriteStructEnd();
WritePropertyBegin(ref bondWriter, "BlobPosition", PropertyType.PropertyType_UInt64);
- bondWriter.WriteFieldBegin(Bond.BondDataType.BT_UINT64, 106);
+ bondWriter.WriteFieldBegin(BondDataType.BT_UINT64, 106);
bondWriter.WriteUInt64(start);
bondWriter.WriteStructEnd();
WritePropertyBegin(ref bondWriter, "DataBlob", PropertyType.PropertyType_UInt8Array);
- bondWriter.WriteFieldBegin(Bond.BondDataType.BT_LIST, 200);
- bondWriter.WriteContainerBegin(length, Bond.BondDataType.BT_UINT8);
+ bondWriter.WriteFieldBegin(BondDataType.BT_LIST, 200);
+ bondWriter.WriteContainerBegin(length, BondDataType.BT_UINT8);
- blob = writer.Buffer.GetSpan(length)[..length];
- writer.Buffer.Advance(length);
+ blob = writer.GetSpan(length)[..length];
+ writer.Advance(length);
bondWriter.WriteStructEnd();
bondWriter.WriteStructEnd();
}
- static void WritePropertyBegin(ref CompactBinaryBondWriter writer, string name, PropertyType type)
+ static void WritePropertyBegin(ref CompactBinaryWriter writer, string name, PropertyType type) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.WriteWString(name);
- writer.WriteFieldBegin(Bond.BondDataType.BT_INT32, 0);
+ writer.WriteFieldBegin(BondDataType.BT_INT32, 0);
writer.WriteInt32((int)type);
}
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/NearShareSender.cs b/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/NearShareSender.cs
index c1c8f5fc..2eff8012 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/NearShareSender.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/NearShareSender.cs
@@ -1,4 +1,5 @@
-using ShortDev.Microsoft.ConnectedDevices.Exceptions;
+using ShortDev.IO.ValueStream;
+using ShortDev.Microsoft.ConnectedDevices.Exceptions;
using ShortDev.Microsoft.ConnectedDevices.Messages;
using ShortDev.Microsoft.ConnectedDevices.Messages.Session;
using ShortDev.Microsoft.ConnectedDevices.NearShare.Apps;
@@ -186,9 +187,9 @@ void HandleDataRequest(BinaryMsgHeader header, ValueSet payload)
var length = payload.Get("BlobSize");
var fileProvider = _files?[(int)contentId] ?? throw new NullReferenceException("Could not access files to transfer");
- Channel.SendBinaryMessage(writer =>
+ Channel.SendBinaryMessage((ref EndianWriter writer) =>
{
- FetchDataResponse.Write(writer, contentId, start, (int)length, out var blob);
+ FetchDataResponse.Write(ref writer, contentId, start, (int)length, out var blob);
Debug.Assert(blob.Length == length);
fileProvider.ReadBlob(start, blob);
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/ShortDev.Microsoft.ConnectedDevices.NearShare.csproj b/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/ShortDev.Microsoft.ConnectedDevices.NearShare.csproj
index 3a3bb996..85561d53 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/ShortDev.Microsoft.ConnectedDevices.NearShare.csproj
+++ b/lib/ShortDev.Microsoft.ConnectedDevices.NearShare/ShortDev.Microsoft.ConnectedDevices.NearShare.csproj
@@ -8,4 +8,10 @@
+
+
+
+
+
+
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/CdpChannel.cs b/lib/ShortDev.Microsoft.ConnectedDevices/CdpChannel.cs
index 1a80f6a9..6ff5856d 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/CdpChannel.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/CdpChannel.cs
@@ -3,6 +3,7 @@
using ShortDev.Microsoft.ConnectedDevices.Messages.Session;
using ShortDev.Microsoft.ConnectedDevices.Session.Channels;
using ShortDev.Microsoft.ConnectedDevices.Transports;
+using System.Buffers;
namespace ShortDev.Microsoft.ConnectedDevices;
@@ -49,7 +50,7 @@ private CdpChannel(ChannelHandler handler, ulong channelId, CdpSocket socket, Cd
///
public ulong ChannelId { get; }
- public void SendBinaryMessage(BodyCallback bodyCallback, uint msgId, List? headers = null)
+ public void SendBinaryMessage(BodyCallback bodyCallback, uint msgId)
{
CommonHeader header = new()
{
@@ -57,17 +58,22 @@ public void SendBinaryMessage(BodyCallback bodyCallback, uint msgId, List ConnectClientAsync(ConnectedDevicesPlatfo
#endregion
#region SendMessage
- public void SendMessage(CdpSocket socket, CommonHeader header, EndianWriter payloadWriter, bool supplyRequestId = false)
- => SendMessage(socket, header, payloadWriter.Buffer.AsSpan(), supplyRequestId);
-
uint _sequenceNumber = 0;
ulong _requestId = 0;
internal CdpCryptor? Cryptor { get; set; }
+
+ public void SendMessage(
+ CdpSocket socket,
+ CommonHeader header, in TMessageHeader messageHeader, in TMessage message,
+ bool supplyRequestId = false
+ ) where TMessageHeader : IBinaryWritable where TMessage : IBinaryWritable
+ {
+ SendMessage(socket, ref header, messageHeader, message, supplyRequestId: supplyRequestId);
+ }
+
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public void SendMessage(
+ CdpSocket socket,
+ ref CommonHeader header, in TMessageHeader messageHeader, in TMessage message,
+ bool supplyRequestId = false
+ ) where TMessageHeader : IBinaryWritable where TMessage : IBinaryWritable
+ {
+ var bufferSize = EndianWriter.CalcBinarySize(messageHeader) + EndianWriter.CalcBinarySize(message);
+ var writer = EndianWriter.Create(Endianness.BigEndian, ConnectedDevicesPlatform.MemoryPool, initialCapacity: (int)bufferSize);
+ try
+ {
+ messageHeader.Write(ref writer);
+ message.Write(ref writer);
+ SendMessage(socket, header, writer.Stream.WrittenSpan, supplyRequestId);
+ }
+ finally
+ {
+ writer.Dispose();
+ }
+ }
+
public void SendMessage(CdpSocket socket, CommonHeader header, ReadOnlySpan payload, bool supplyRequestId = false)
{
if (header.Type == MessageType.Session && Cryptor == null)
@@ -121,11 +150,11 @@ public void SendMessage(CdpSocket socket, CommonHeader header, ReadOnlySpan _msgRegistry = new();
- void HandleSession(CommonHeader header, ref EndianReader reader)
+ void HandleSession(CommonHeader header, ref HeapEndianReader reader)
{
CdpMessage msg = _msgRegistry.GetOrAdd(header.SequenceNumber, id => new(header));
- msg.AddFragment(reader.ReadToEnd()); // ToDo: Reduce allocations
+ msg.AddFragment(reader.Stream.ReadSlice((int)(reader.Stream.Length - reader.Stream.Position)));
if (msg.IsComplete)
{
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/ConnectedDevicesPlatform.MessageLoop.cs b/lib/ShortDev.Microsoft.ConnectedDevices/ConnectedDevicesPlatform.MessageLoop.cs
index 79e2f8ed..34aa9dad 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/ConnectedDevicesPlatform.MessageLoop.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/ConnectedDevicesPlatform.MessageLoop.cs
@@ -1,26 +1,26 @@
-using ShortDev.Microsoft.ConnectedDevices.Messages;
+using ShortDev.IO.Buffers;
+using ShortDev.IO.ValueStream;
+using ShortDev.Microsoft.ConnectedDevices.Messages;
using ShortDev.Microsoft.ConnectedDevices.Transports;
-using System.Buffers;
namespace ShortDev.Microsoft.ConnectedDevices;
partial class ConnectedDevicesPlatform
{
- static readonly ArrayPool _messagePool = ArrayPool.Create();
private void ReceiveLoop(CdpSocket socket)
{
RegisterKnownSocket(socket);
- Task.Run(() =>
+ Task.Factory.StartNew(() =>
{
- EndianReader streamReader = new(Endianness.BigEndian, socket.InputStream);
+ var streamReader = EndianReader.FromStream(Endianness.BigEndian, socket.InputStream);
using (socket)
{
ReceiveLoop(socket, ref streamReader);
}
- });
+ }, TaskCreationOptions.LongRunning);
}
- void ReceiveLoop(CdpSocket socket, ref EndianReader streamReader)
+ void ReceiveLoop(CdpSocket socket, ref EndianReader streamReader)
{
do
{
@@ -38,13 +38,13 @@ void ReceiveLoop(CdpSocket socket, ref EndianReader streamReader)
header
);
- using var payload = _messagePool.RentToken(header.PayloadSize);
+ using var payload = MemoryPool.RentMemory(header.PayloadSize);
streamReader.ReadBytes(payload.Span);
if (socket.IsClosed)
return;
- EndianReader reader = new(Endianness.BigEndian, payload.Span);
+ var reader = EndianReader.FromMemory(Endianness.BigEndian, payload);
session.HandleMessage(socket, header, ref reader);
}
catch (IOException)
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/ConnectedDevicesPlatform.Utils.cs b/lib/ShortDev.Microsoft.ConnectedDevices/ConnectedDevicesPlatform.Utils.cs
index b85a3e6f..c6c8038d 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/ConnectedDevicesPlatform.Utils.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/ConnectedDevicesPlatform.Utils.cs
@@ -1,4 +1,5 @@
using ShortDev.Microsoft.ConnectedDevices.Encryption;
+using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
@@ -13,4 +14,6 @@ public static X509Certificate2 CreateDeviceCertificate([NotNull] CdpEncryptionPa
CertificateRequest certRequest = new("CN=Ms-Cdp", key, HashAlgorithmName.SHA256);
return certRequest.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5));
}
+
+ public static ArrayPool MemoryPool { get; } = ArrayPool.Create();
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/DeviceIdHash.cs b/lib/ShortDev.Microsoft.ConnectedDevices/DeviceIdHash.cs
new file mode 100644
index 00000000..b1e70971
--- /dev/null
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/DeviceIdHash.cs
@@ -0,0 +1,19 @@
+using System.Runtime.CompilerServices;
+
+namespace ShortDev.Microsoft.ConnectedDevices;
+
+[InlineArray(32)]
+public struct DeviceIdHash : IBinaryWritable, IBinaryParsable
+{
+ public byte _element0;
+
+ public readonly void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
+ => writer.Write((ReadOnlySpan)this);
+
+ public static DeviceIdHash Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
+ {
+ DeviceIdHash result = default;
+ reader.ReadBytes(result);
+ return result;
+ }
+}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Encryption/CdpCryptor.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Encryption/CdpCryptor.cs
index e581840d..9e73419a 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Encryption/CdpCryptor.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Encryption/CdpCryptor.cs
@@ -1,8 +1,11 @@
-using ShortDev.Microsoft.ConnectedDevices.Exceptions;
+using ShortDev.IO.Buffers;
+using ShortDev.IO.ValueStream;
+using ShortDev.Microsoft.ConnectedDevices.Exceptions;
using ShortDev.Microsoft.ConnectedDevices.Messages;
using ShortDev.Microsoft.ConnectedDevices.Transports;
using System.Buffers.Binary;
using System.Diagnostics;
+using System.Runtime.CompilerServices;
using System.Security.Cryptography;
namespace ShortDev.Microsoft.ConnectedDevices.Encryption;
@@ -25,6 +28,8 @@ public CdpCryptor(byte[] sharedSecret)
_hmac = sharedSecret.AsMemory()[^32..^0];
}
+ [SkipLocalsInit]
+ [MethodImpl(MethodImplOptions.AggressiveOptimization)]
void GenerateIV(CommonHeader header, Span destination)
{
Debug.Assert(destination.Length == Constants.IVSize);
@@ -49,17 +54,20 @@ void ComputeHmac(ReadOnlySpan buffer, Span destination)
Debug.Assert(bytesWritten == destination.Length);
}
- public ReadOnlyMemory DecryptMessage(CommonHeader header, ReadOnlySpan payload, ReadOnlySpan hmac)
+ public PooledMemory DecryptMessage(CommonHeader header, ReadOnlySpan payload, ReadOnlySpan hmac)
{
VerifyHMac(header, payload, hmac);
Span iv = stackalloc byte[Constants.IVSize];
GenerateIV(header, iv);
- byte[] decryptedPayload = _aes.DecryptCbc(payload, iv, PaddingMode.None);
+ var decryptedBufferSize = _aes.GetCiphertextLengthCbc(payload.Length, PaddingMode.None);
- var payloadSize = BinaryPrimitives.ReadUInt32BigEndian(decryptedPayload.AsSpan()[..sizeof(uint)]);
- return decryptedPayload.AsMemory(sizeof(uint), (int)payloadSize);
+ var decryptedPayload = ConnectedDevicesPlatform.MemoryPool.RentMemory(decryptedBufferSize);
+ _aes.DecryptCbc(payload, iv, decryptedPayload.Span, PaddingMode.None);
+
+ var payloadSize = BinaryPrimitives.ReadUInt32BigEndian(decryptedPayload.Span[..sizeof(uint)]);
+ return decryptedPayload.Slice(sizeof(uint), (int)payloadSize);
}
void VerifyHMac(CommonHeader header, ReadOnlySpan payload, ReadOnlySpan hmac)
@@ -67,75 +75,85 @@ void VerifyHMac(CommonHeader header, ReadOnlySpan payload, ReadOnlySpan expectedHMac = stackalloc byte[Constants.HMacSize];
- ComputeHmac(buffer, expectedHMac);
- if (!hmac.SequenceEqual(expectedHMac))
- throw new CdpSecurityException("Invalid hmac!");
+ Span expectedHMac = stackalloc byte[Constants.HMacSize];
+ ComputeHmac(buffer, expectedHMac);
+ if (!hmac.SequenceEqual(expectedHMac))
+ throw new CdpSecurityException("Invalid hmac!");
+ }
+ finally
+ {
+ writer.Dispose();
+ }
}
public void EncryptMessage(IFragmentSender sender, CommonHeader header, ReadOnlySpan payloadBuffer)
{
- // Prepend payload with length
- ReadOnlySpan finalPayload;
+ var msgWriter = EndianWriter.Create(Endianness.BigEndian, ConnectedDevicesPlatform.MemoryPool);
+ try
{
- EndianWriter payloadWriter = new(Endianness.BigEndian);
- payloadWriter.Write((uint)payloadBuffer.Length);
- payloadWriter.Write(payloadBuffer);
-
- finalPayload = payloadWriter.Buffer.AsSpan();
+ using (var payloadWriter = EndianWriter.Create(Endianness.BigEndian, ConnectedDevicesPlatform.MemoryPool, payloadBuffer.Length + sizeof(uint)))
+ {
+ // Prepend payload with length
+ payloadWriter.Write((uint)payloadBuffer.Length);
+ payloadWriter.Write(payloadBuffer);
+
+ // Encrypt
+ Encrypt(ref msgWriter, header, payloadWriter.Stream.WrittenSpan);
+ }
+
+ // HMAC
+ {
+ var msgBuffer = msgWriter.Stream.WrittenSpan;
+ Span hmac = stackalloc byte[Constants.HMacSize];
+ ComputeHmac(msgBuffer, hmac);
+ CommonHeader.ModifyMessageLength(msgBuffer.AsSpanUnsafe(), +Constants.HMacSize);
+ msgWriter.Write(hmac);
+ }
+
+ sender.SendFragment(msgWriter.Stream.WrittenSpan);
}
-
- // Encrypt
- var msgWriter = Encrypt(header, finalPayload);
-
- // HMAC
+ finally
{
- var msgBuffer = msgWriter.Buffer.AsWriteableSpan();
- Span hmac = stackalloc byte[Constants.HMacSize];
- ComputeHmac(msgBuffer, hmac);
- CommonHeader.ModifyMessageLength(msgBuffer, +Constants.HMacSize);
- msgWriter.Write(hmac);
+ msgWriter.Dispose();
}
-
- sender.SendFragment(msgWriter.Buffer.AsSpan());
}
- EndianWriter Encrypt(CommonHeader header, ReadOnlySpan buffer)
+ [SkipLocalsInit]
+ void Encrypt(ref TWriter writer, CommonHeader header, ReadOnlySpan buffer) where TWriter : struct, IEndianWriter, allows ref struct
{
// If payload size is an exact multiple of block length (16 bytes) no padding is applied
PaddingMode paddingMode = buffer.Length % 16 == 0 ? PaddingMode.None : PaddingMode.PKCS7;
var encryptedPayloadLength = _aes.GetCiphertextLengthCbc(buffer.Length, paddingMode);
// Write header
- EndianWriter writer = new(Endianness.BigEndian);
header.Flags |= MessageFlags.SessionEncrypted | MessageFlags.HasHMAC;
header.SetPayloadLength(encryptedPayloadLength);
- header.Write(writer);
+ header.Write(ref writer);
Span iv = stackalloc byte[Constants.IVSize];
GenerateIV(header, iv);
// Encrypt and write to msgWriter
- _aes.EncryptCbc(buffer, iv, writer.Buffer.GetSpan(encryptedPayloadLength), paddingMode);
- writer.Buffer.Advance(encryptedPayloadLength);
-
- return writer;
+ _aes.EncryptCbc(buffer, iv, writer.GetSpan(encryptedPayloadLength), paddingMode);
+ writer.Advance(encryptedPayloadLength);
}
- public void Read(ref EndianReader reader, CommonHeader header)
+ public DisposeToken Read(ref HeapEndianReader reader, CommonHeader header)
{
if (!header.HasFlag(MessageFlags.SessionEncrypted))
- return;
+ return default;
int payloadSize = header.PayloadSize;
if (header.HasFlag(MessageFlags.HasHMAC))
@@ -143,7 +161,7 @@ public void Read(ref EndianReader reader, CommonHeader header)
payloadSize -= Constants.HMacSize;
}
- var encryptedPayload = reader.ReadBytes(payloadSize);
+ var encryptedPayload = reader.Stream.ReadSlice(payloadSize);
scoped Span hmac = [];
if (header.HasFlag(MessageFlags.HasHMAC))
@@ -153,7 +171,9 @@ public void Read(ref EndianReader reader, CommonHeader header)
}
var decryptedPayload = DecryptMessage(header, encryptedPayload, hmac);
- reader = new(Endianness.BigEndian, decryptedPayload.Span);
+ reader = EndianReader.FromMemory(Endianness.BigEndian, decryptedPayload);
+
+ return decryptedPayload;
}
public void Dispose()
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Encryption/CdpEncryptionInfo.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Encryption/CdpEncryptionInfo.cs
index 297f4416..f83797b5 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Encryption/CdpEncryptionInfo.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Encryption/CdpEncryptionInfo.cs
@@ -19,15 +19,15 @@ public static CdpEncryptionInfo Create(CdpEncryptionParams encryptionParams)
EncryptionParams = encryptionParams
};
- public static CdpEncryptionInfo FromRemote(byte[] publicX, byte[] publicY, CdpNonce nonce, CdpEncryptionParams encryptionParams)
+ public static CdpEncryptionInfo FromRemote(ReadOnlyMemory publicX, ReadOnlyMemory publicY, CdpNonce nonce, CdpEncryptionParams encryptionParams)
{
var diffieHellman = ECDiffieHellman.Create(new ECParameters()
{
Curve = encryptionParams.Curve,
Q = new ECPoint()
{
- X = publicX,
- Y = publicY
+ X = publicX.ToArray(),
+ Y = publicY.ToArray()
}
});
return new()
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Extensions.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Extensions.cs
index 6d6be3dc..12d4261f 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Extensions.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Extensions.cs
@@ -1,6 +1,10 @@
-using System.Buffers;
+using ShortDev.IO.Buffers;
+using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Net.NetworkInformation;
+using System.Runtime.CompilerServices;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
namespace ShortDev.Microsoft.ConnectedDevices;
public static class Extensions
@@ -63,21 +67,40 @@ public static void DisposeAll([NotNull] this IEnumerable disposables) wher
throw new AggregateException(exceptions);
}
- public readonly struct ArrayPoolToken(ArrayPool pool, int capacity) : IDisposable
+ public static ReadOnlyMemory ReadBytesWithLength(this ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
{
- private readonly ArrayPool? _pool = pool;
- private readonly int _capacity = capacity;
- private readonly T[] _array = pool.Rent(capacity);
+ var length = reader.ReadUInt16();
+ byte[] buffer = new byte[length];
+ reader.ReadBytes(buffer);
+ return buffer;
+ }
- public T[] ArrayUnsafe => _array;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static X509Certificate2 ReadCert(this ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
+ {
+ var length = reader.ReadUInt16();
- public Memory Memory => _array.AsMemory()[0.._capacity];
- public Span Span => Memory.Span;
+ using var buffer = ArrayPool.Shared.RentMemory(length);
+ reader.ReadBytes(buffer.Span);
- public void Dispose()
- => _pool?.Return(_array);
+ return X509CertificateLoader.LoadCertificate(buffer.Span);
}
- public static ArrayPoolToken RentToken(this ArrayPool pool, int capacity)
- => new(pool, capacity);
+ [SkipLocalsInit]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static PhysicalAddress ReadPhysicalAddress(this ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
+ {
+ byte[] buffer = new byte[6];
+ reader.ReadBytes(buffer);
+ buffer.AsSpan().Reverse();
+ return new PhysicalAddress(buffer);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Write(this ref TWriter writer, PhysicalAddress address) where TWriter : struct, IEndianWriter, allows ref struct
+ {
+ var bytes = address.GetAddressBytes();
+ bytes.AsSpan().Reverse();
+ writer.Write(bytes);
+ }
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/GlobalUsings.cs b/lib/ShortDev.Microsoft.ConnectedDevices/GlobalUsings.cs
new file mode 100644
index 00000000..2952b7e4
--- /dev/null
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/GlobalUsings.cs
@@ -0,0 +1 @@
+global using HeapEndianReader = ShortDev.IO.Input.EndianReader;
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/AdditionalHeader.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/AdditionalHeader.cs
index 45d1987a..37117696 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/AdditionalHeader.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/AdditionalHeader.cs
@@ -10,7 +10,7 @@ namespace ShortDev.Microsoft.ConnectedDevices.Messages;
///
///
///
-public record AdditionalHeader(AdditionalHeaderType Type, ReadOnlyMemory Value)
+public readonly record struct AdditionalHeader(AdditionalHeaderType Type, ReadOnlyMemory Value)
{
public static AdditionalHeader CreateCorrelationHeader()
=> FromCorrelationVector(new CorrelationVectorV1());
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/BodyCallback.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/BodyCallback.cs
index d4af1540..94fb2b6b 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/BodyCallback.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/BodyCallback.cs
@@ -1,3 +1,5 @@
-namespace ShortDev.Microsoft.ConnectedDevices.Messages;
+using ShortDev.IO.ValueStream;
-public delegate void BodyCallback(EndianWriter writer);
+namespace ShortDev.Microsoft.ConnectedDevices.Messages;
+
+public delegate void BodyCallback(ref EndianWriter writer);
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/CdpMessage.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/CdpMessage.cs
index e8cf9de4..d70d03bb 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/CdpMessage.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/CdpMessage.cs
@@ -1,27 +1,21 @@
-using ShortDev.Microsoft.ConnectedDevices.Messages.Session;
+using ShortDev.IO.ValueStream;
+using ShortDev.Microsoft.ConnectedDevices.Messages.Session;
using ShortDev.Microsoft.ConnectedDevices.Serialization;
using ShortDev.Microsoft.ConnectedDevices.Transports;
namespace ShortDev.Microsoft.ConnectedDevices.Messages;
-public sealed class CdpMessage
+public sealed class CdpMessage(CommonHeader header)
{
- readonly EndianBuffer _buffer;
-
- public CdpMessage(CommonHeader header)
+ readonly HeapOutputStream _buffer = new()
{
- Header = header;
- _buffer = new(header.FragmentCount * MessageFragmenter.DefaultMessageFragmentSize);
- }
-
- public CdpMessage(CommonHeader header, byte[] payload)
- {
- Header = header;
- _buffer = new(payload);
- _receivedFragmentCount = header.FragmentCount;
- }
+ Writer = new()
+ {
+ Capacity = header.FragmentCount * MessageFragmenter.DefaultMessageFragmentSize
+ }
+ };
- public CommonHeader Header { get; }
+ public CommonHeader Header { get; } = header;
public uint Id
=> Header.SequenceNumber;
@@ -41,14 +35,14 @@ public void AddFragment(ReadOnlySpan fragment)
}
#endregion
- public void Read(out EndianReader reader)
+ public void Read(out HeapEndianReader reader)
{
ThrowIfNotCompleted();
- reader = new(Endianness.BigEndian, _buffer.AsSpan());
+ reader = EndianReader.FromMemory(Endianness.BigEndian, _buffer.WrittenMemory);
}
- public void ReadBinary(out EndianReader reader, out BinaryMsgHeader header)
+ public void ReadBinary(out HeapEndianReader reader, out BinaryMsgHeader header)
{
ThrowIfNotCompleted();
@@ -60,7 +54,7 @@ public void ReadBinary(out ValueSet payload, out BinaryMsgHeader header)
{
ThrowIfNotCompleted();
- ReadBinary(out EndianReader reader, out header);
+ ReadBinary(out HeapEndianReader reader, out header);
payload = ValueSet.Parse(ref reader);
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/CommonHeaders.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/CommonHeaders.cs
index 948c0a6a..8b77db49 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/CommonHeaders.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/CommonHeaders.cs
@@ -7,16 +7,16 @@ namespace ShortDev.Microsoft.ConnectedDevices.Messages;
///
/// The is common for all Messages.
///
-public sealed class CommonHeader : ICdpHeader
+public sealed class CommonHeader : IBinaryWritable, IBinaryParsable
{
- public static CommonHeader Parse(ref EndianReader reader)
+ public static CommonHeader Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
{
if (!TryParse(ref reader, out var result, out var ex))
throw ex;
return result;
}
- public static bool TryParse(ref EndianReader reader, [MaybeNullWhen(false)] out CommonHeader result, [MaybeNullWhen(true)] out Exception ex)
+ public static bool TryParse(ref TReader reader, [MaybeNullWhen(false)] out CommonHeader result, [MaybeNullWhen(true)] out Exception ex) where TReader : IEndianReader, allows ref struct
{
result = new();
var sig = reader.ReadUInt16();
@@ -27,14 +27,14 @@ public static bool TryParse(ref EndianReader reader, [MaybeNullWhen(false)] out
}
result.MessageLength = reader.ReadUInt16();
- result.Version = reader.ReadByte();
+ result.Version = reader.ReadUInt8();
if (result.Version != Constants.ProtocolVersion)
{
ex = new InvalidDataException($"Wrong version. Got \"{result.Version}\", expected \"{Constants.ProtocolVersion}\"");
return false;
}
- result.Type = (MessageType)reader.ReadByte();
+ result.Type = (MessageType)reader.ReadUInt8();
result.Flags = (MessageFlags)reader.ReadInt16();
result.SequenceNumber = reader.ReadUInt32();
result.RequestID = reader.ReadUInt64();
@@ -48,14 +48,15 @@ public static bool TryParse(ref EndianReader reader, [MaybeNullWhen(false)] out
List additionalHeaders = [];
while (true)
{
- nextHeaderType = (AdditionalHeaderType)reader.ReadByte();
- nextHeaderSize = reader.ReadByte();
+ nextHeaderType = (AdditionalHeaderType)reader.ReadUInt8();
+ nextHeaderSize = reader.ReadUInt8();
if (nextHeaderType == AdditionalHeaderType.None)
break;
- var value = reader.ReadBytes(nextHeaderSize);
- additionalHeaders.Add(new(nextHeaderType, value.ToArray()));
+ byte[] value = new byte[nextHeaderSize];
+ reader.ReadBytes(value);
+ additionalHeaders.Add(new(nextHeaderType, value));
}
if (nextHeaderSize != 0)
@@ -70,7 +71,8 @@ public static bool TryParse(ref EndianReader reader, [MaybeNullWhen(false)] out
return true;
}
- public void Write(EndianWriter writer)
+
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write(Constants.Signature);
writer.Write(MessageLength);
@@ -245,6 +247,6 @@ public void SetReplyToId(ulong requestId)
if (header == null)
return null;
- return BinaryPrimitives.ReadUInt64LittleEndian(header.Value.Span);
+ return BinaryPrimitives.ReadUInt64LittleEndian(header.Value.Value.Span);
}
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/Authentication/AuthenticationPayload.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/Authentication/AuthenticationPayload.cs
index a239512b..b9b167cc 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/Authentication/AuthenticationPayload.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/Authentication/AuthenticationPayload.cs
@@ -1,4 +1,5 @@
-using ShortDev.Microsoft.ConnectedDevices.Encryption;
+using ShortDev.IO.ValueStream;
+using ShortDev.Microsoft.ConnectedDevices.Encryption;
using ShortDev.Microsoft.ConnectedDevices.Exceptions;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
@@ -8,15 +9,13 @@ namespace ShortDev.Microsoft.ConnectedDevices.Messages.Connection.Authentication
///
/// For all authentication, devices send their device / user certificate, which is self-signed.
///
-public sealed class AuthenticationPayload : ICdpPayload
+public readonly record struct AuthenticationPayload : IBinaryWritable, IBinaryParsable
{
- private AuthenticationPayload() { }
-
- public static AuthenticationPayload Parse(ref EndianReader reader)
+ public static AuthenticationPayload Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
- Certificate = X509CertificateLoader.LoadCertificate(reader.ReadBytesWithLength()),
- SignedThumbprint = reader.ReadBytesWithLength().ToArray()
+ Certificate = reader.ReadCert(),
+ SignedThumbprint = reader.ReadBytesWithLength()
};
///
@@ -40,12 +39,12 @@ public static AuthenticationPayload Create(X509Certificate2 cert, CdpNonce hostN
///
/// A signed Device Cert Thumbprint.
///
- public required byte[] SignedThumbprint { get; init; }
+ public required ReadOnlyMemory SignedThumbprint { get; init; }
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.WriteWithLength(Certificate.Export(X509ContentType.Cert));
- writer.WriteWithLength(SignedThumbprint);
+ writer.WriteWithLength(SignedThumbprint.Span);
}
///
@@ -59,29 +58,33 @@ public bool VerifyThumbprint(CdpNonce hostNonce, CdpNonce clientNonce)
{
var publicKey = Certificate.GetECDsaPublicKey() ?? throw new CdpSecurityException("Invalid certificate!");
- var merged = MergeNoncesWithCertificate(Certificate, hostNonce, clientNonce).Span;
- return publicKey.VerifyData(merged, SignedThumbprint, thumbprintHashType);
+ // Use little-endian here!
+ using var nonceWriter = EndianWriter.Create(Endianness.LittleEndian, ConnectedDevicesPlatform.MemoryPool);
+ MergeNoncesWithCertificate(nonceWriter, Certificate, hostNonce, clientNonce);
+
+ return publicKey.VerifyData(nonceWriter.Stream.WrittenSpan, SignedThumbprint.Span, thumbprintHashType);
}
#region Thumbprint Api
static readonly HashAlgorithmName thumbprintHashType = HashAlgorithmName.SHA256;
- static ReadOnlyMemory MergeNoncesWithCertificate(X509Certificate2 cert, CdpNonce hostNonce, CdpNonce clientNonce)
+ static void MergeNoncesWithCertificate(EndianWriter writer, X509Certificate2 cert, CdpNonce hostNonce, CdpNonce clientNonce)
{
byte[] certData = cert.Export(X509ContentType.Cert);
- EndianWriter writer = new(Endianness.LittleEndian); // Use little-endian here!
writer.Write(hostNonce.Value);
writer.Write(clientNonce.Value);
writer.Write(certData);
- return writer.Buffer.AsMemory();
}
static byte[] CreateSignedThumbprint(X509Certificate2 cert, CdpNonce hostNonce, CdpNonce clientNonce)
{
- var data = MergeNoncesWithCertificate(cert, hostNonce, clientNonce);
+ // Use little-endian here!
+ using var nonceWriter = EndianWriter.Create(Endianness.LittleEndian, ConnectedDevicesPlatform.MemoryPool);
+ MergeNoncesWithCertificate(nonceWriter, cert, hostNonce, clientNonce);
+
var privateKey = cert.GetECDsaPrivateKey() ?? throw new ArgumentException("No ECDsa private key!", nameof(cert));
- return privateKey.SignData(data.Span, thumbprintHashType);
+ return privateKey.SignData(nonceWriter.Stream.WrittenSpan, thumbprintHashType);
}
#endregion
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionHeader.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionHeader.cs
index ab946750..b32ad5bc 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionHeader.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionHeader.cs
@@ -3,28 +3,28 @@
///
/// The is common for all Connection Messages.
///
-public sealed class ConnectionHeader : ICdpHeader
+public readonly record struct ConnectionHeader : IBinaryWritable, IBinaryParsable
{
///
/// Indicates the current connection type.
///
- public required ConnectionType MessageType { get; set; }
+ public required ConnectionType MessageType { get; init; }
///
/// Displays the types of available connections.
///
- public required ConnectionMode ConnectionMode { get; set; }
+ public required ConnectionMode ConnectionMode { get; init; }
- public static ConnectionHeader Parse(ref EndianReader reader)
+ public static ConnectionHeader Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
{
return new()
{
ConnectionMode = (ConnectionMode)reader.ReadInt16(),
- MessageType = (ConnectionType)reader.ReadByte()
+ MessageType = (ConnectionType)reader.ReadUInt8()
};
}
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((short)ConnectionMode);
writer.Write((byte)MessageType);
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionRequest.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionRequest.cs
index fffa2af7..0af53905 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionRequest.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionRequest.cs
@@ -6,50 +6,50 @@ namespace ShortDev.Microsoft.ConnectedDevices.Messages.Connection;
///
/// Client initiates a connection request with a host device.
///
-public sealed class ConnectionRequest : ICdpPayload
+public readonly record struct ConnectionRequest : IBinaryWritable, IBinaryParsable
{
///
/// The type of elliptical curve used.
///
- public required CurveType CurveType { get; set; }
+ public required CurveType CurveType { get; init; }
///
/// The expected size of HMAC.
///
- public required ushort HmacSize { get; set; }
+ public required ushort HmacSize { get; init; }
///
/// Random values
///
- public required CdpNonce Nonce { get; set; }
+ public required CdpNonce Nonce { get; init; }
///
/// The maximum size of a single message fragment.
/// (Fixed Value of ).
///
- public required uint MessageFragmentSize { get; set; }
+ public required uint MessageFragmentSize { get; init; }
///
/// A fixed-length key.
/// This is the X component of the key.
/// (See )
///
- public required byte[] PublicKeyX { get; set; }
+ public required ReadOnlyMemory PublicKeyX { get; init; }
///
/// A fixed-length key.
/// This is the Y component of the key.
/// (See )
///
- public required byte[] PublicKeyY { get; set; }
+ public required ReadOnlyMemory PublicKeyY { get; init; }
- public static ConnectionRequest Parse(ref EndianReader reader)
+ public static ConnectionRequest Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
- CurveType = (CurveType)reader.ReadByte(),
+ CurveType = (CurveType)reader.ReadUInt8(),
HmacSize = reader.ReadUInt16(),
Nonce = new(reader.ReadUInt64()),
MessageFragmentSize = reader.ReadUInt32(),
- PublicKeyX = reader.ReadBytesWithLength().ToArray(),
- PublicKeyY = reader.ReadBytesWithLength().ToArray()
+ PublicKeyX = reader.ReadBytesWithLength(),
+ PublicKeyY = reader.ReadBytesWithLength()
};
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((byte)CurveType);
writer.Write((ushort)HmacSize);
@@ -57,8 +57,8 @@ public void Write(EndianWriter writer)
writer.Write((uint)MessageFragmentSize);
writer.Write((ushort)PublicKeyX.Length);
- writer.Write(PublicKeyX);
+ writer.Write(PublicKeyX.Span);
writer.Write((ushort)PublicKeyY.Length);
- writer.Write(PublicKeyY);
+ writer.Write(PublicKeyY.Span);
}
}
\ No newline at end of file
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionResponse.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionResponse.cs
index f9a7f47b..dadbbed5 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionResponse.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/ConnectionResponse.cs
@@ -7,53 +7,53 @@ namespace ShortDev.Microsoft.ConnectedDevices.Messages.Connection;
/// The host responds with a connection response message including device information.
/// Only the Result is sent if the Result is anything other than .
///
-public sealed class ConnectionResponse : ICdpPayload
+public readonly record struct ConnectionResponse : IBinaryWritable, IBinaryParsable
{
///
/// The result of the connection request.
///
- public required ConnectionResult Result { get; set; }
+ public required ConnectionResult Result { get; init; }
///
/// The expected size of HMAC.
///
- public required ushort HmacSize { get; set; }
+ public required ushort HmacSize { get; init; }
///
/// Random values.
///
- public required CdpNonce Nonce { get; set; }
+ public required CdpNonce Nonce { get; init; }
///
/// The maximum size of a single message fragment.
/// (Fixed Value of ).
///
- public required uint MessageFragmentSize { get; set; }
+ public required uint MessageFragmentSize { get; init; }
///
/// A fixed-length key that is based on the from , which is sent only if the connection is successful.
/// This is the X component of the key.
/// (See )
///
- public required byte[] PublicKeyX { get; set; }
+ public required ReadOnlyMemory PublicKeyX { get; init; }
///
/// A fixed-length key that is based on the from , which is sent only if the connection is successful.
/// This is the Y component of the key.
/// (See )
///
- public required byte[] PublicKeyY { get; set; }
+ public required ReadOnlyMemory PublicKeyY { get; init; }
- public static ConnectionResponse Parse(ref EndianReader reader)
+ public static ConnectionResponse Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
{
- var result = (ConnectionResult)reader.ReadByte();
+ var result = (ConnectionResult)reader.ReadUInt8();
return new()
{
Result = result,
HmacSize = reader.ReadUInt16(),
Nonce = new(reader.ReadUInt64()),
MessageFragmentSize = reader.ReadUInt32(),
- PublicKeyX = reader.ReadBytesWithLength().ToArray(),
- PublicKeyY = reader.ReadBytesWithLength().ToArray()
+ PublicKeyX = reader.ReadBytesWithLength(),
+ PublicKeyY = reader.ReadBytesWithLength()
};
}
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((byte)Result);
writer.Write((ushort)HmacSize);
@@ -61,8 +61,8 @@ public void Write(EndianWriter writer)
writer.Write((uint)MessageFragmentSize);
writer.Write((ushort)PublicKeyX.Length);
- writer.Write(PublicKeyX);
+ writer.Write(PublicKeyX.Span);
writer.Write((ushort)PublicKeyY.Length);
- writer.Write(PublicKeyY);
+ writer.Write(PublicKeyY.Span);
}
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/DeviceInfo/DeviceInfoMessage.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/DeviceInfo/DeviceInfoMessage.cs
index 642b1094..5b56c0be 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/DeviceInfo/DeviceInfoMessage.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/DeviceInfo/DeviceInfoMessage.cs
@@ -6,9 +6,9 @@ namespace ShortDev.Microsoft.ConnectedDevices.Messages.Connection.DeviceInfo;
///
/// This message requests information from the device.
///
-public sealed class DeviceInfoMessage : ICdpPayload
+public readonly record struct DeviceInfoMessage : IBinaryWritable, IBinaryParsable
{
- public static DeviceInfoMessage Parse(ref EndianReader reader)
+ public static DeviceInfoMessage Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
DeviceInfo = JsonSerializer.Deserialize(reader.ReadStringWithLength()) ?? throw new CdpProtocolException("Invalid device info")
@@ -19,7 +19,7 @@ public static DeviceInfoMessage Parse(ref EndianReader reader)
///
public required CdpDeviceInfo DeviceInfo { get; init; }
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.WriteWithLength(JsonSerializer.Serialize(DeviceInfo));
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/EndpointMetadata.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/EndpointMetadata.cs
index 44bbcd53..c028378d 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/EndpointMetadata.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/EndpointMetadata.cs
@@ -2,20 +2,22 @@
namespace ShortDev.Microsoft.ConnectedDevices.Messages.Connection.TransportUpgrade;
-public record class EndpointMetadata(CdpTransportType Type, byte[] Data) : ICdpPayload, ICdpArraySerializable
+public readonly record struct EndpointMetadata(CdpTransportType Type, byte[] Data) : IBinaryWritable, IBinaryParsable
{
public static EndpointMetadata Tcp { get; } = new(CdpTransportType.Tcp, []);
public static EndpointMetadata WifiDirect { get; } = new(CdpTransportType.WifiDirect, []);
- public static EndpointMetadata Parse(ref EndianReader reader)
+ public static EndpointMetadata Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
{
var type = (CdpTransportType)reader.ReadUInt16();
var length = reader.ReadInt32();
- var data = reader.ReadBytes(length);
- return new(type, data.ToArray());
+
+ byte[] data = new byte[length];
+ reader.ReadBytes(data);
+ return new(type, data);
}
- public static IReadOnlyList ParseArray(ref EndianReader reader)
+ public static IReadOnlyList ParseArray(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
{
var arrayLength = reader.ReadUInt16();
var endpoints = new EndpointMetadata[arrayLength];
@@ -24,17 +26,25 @@ public static IReadOnlyList ParseArray(ref EndianReader reader
return endpoints;
}
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((ushort)Type);
writer.Write((uint)Data.Length);
writer.Write(Data);
}
- public static void WriteArray(EndianWriter writer, IReadOnlyList endpoints)
+ public static void WriteArray(ref TWriter writer, IReadOnlyList endpoints) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((ushort)endpoints.Count);
foreach (var endpoint in endpoints)
- endpoint.Write(writer);
+ endpoint.Write(ref writer);
}
}
+
+public readonly record struct EndpointMetadataArray(IReadOnlyList Endpoints) : IBinaryWritable, IBinaryParsable
+{
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
+ => EndpointMetadata.WriteArray(ref writer, Endpoints);
+ public static EndpointMetadataArray Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
+ => new(EndpointMetadata.ParseArray(ref reader));
+}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeIdPayload.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeIdPayload.cs
index e1a43291..8cd57695 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeIdPayload.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeIdPayload.cs
@@ -4,18 +4,18 @@
/// This message transports the details of the upgrade.
/// (See and )
///
-public sealed class UpgradeIdPayload : ICdpPayload
+public readonly record struct UpgradeIdPayload : IBinaryWritable, IBinaryParsable
{
public required Guid UpgradeId { get; init; }
- public static UpgradeIdPayload Parse(ref EndianReader reader)
+ public static UpgradeIdPayload Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
UpgradeId = reader.ReadGuid()
};
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
- writer.Write(UpgradeId.ToByteArray());
+ writer.Write(UpgradeId);
}
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeRequest.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeRequest.cs
index f1d11ecc..d1402294 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeRequest.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeRequest.cs
@@ -3,7 +3,7 @@
///
/// This message transports the upgrade request.
///
-public sealed class UpgradeRequest : ICdpPayload
+public readonly record struct UpgradeRequest : IBinaryWritable, IBinaryParsable
{
///
/// A random GUID identifying this upgrade process across transports.
@@ -11,16 +11,16 @@ public sealed class UpgradeRequest : ICdpPayload
public required Guid UpgradeId { get; init; }
public required IReadOnlyList Endpoints { get; init; }
- public static UpgradeRequest Parse(ref EndianReader reader)
+ public static UpgradeRequest Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
UpgradeId = reader.ReadGuid(),
Endpoints = EndpointMetadata.ParseArray(ref reader)
};
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
- writer.Write(UpgradeId.ToByteArray());
- EndpointMetadata.WriteArray(writer, Endpoints);
+ writer.Write(UpgradeId);
+ EndpointMetadata.WriteArray(ref writer, Endpoints);
}
}
\ No newline at end of file
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeResponse.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeResponse.cs
index 8f04d512..838fa0ed 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeResponse.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Connection/TransportUpgrade/UpgradeResponse.cs
@@ -5,7 +5,7 @@ namespace ShortDev.Microsoft.ConnectedDevices.Messages.Connection.TransportUpgra
///
/// This message transports the upgrade response.
///
-public sealed class UpgradeResponse : ICdpPayload
+public readonly record struct UpgradeResponse : IBinaryWritable, IBinaryParsable
{
///
/// A length-prefixed list of endpoint structures (see following) that are provided by each transport on the host device.
@@ -13,7 +13,7 @@ public sealed class UpgradeResponse : ICdpPayload
public required IReadOnlyList Endpoints { get; init; }
public required IReadOnlyList MetaData { get; init; }
- public static UpgradeResponse Parse(ref EndianReader reader)
+ public static UpgradeResponse Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
{
var length = reader.ReadUInt16();
var endpoints = new EndpointInfo[length];
@@ -35,7 +35,7 @@ public static UpgradeResponse Parse(ref EndianReader reader)
};
}
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((ushort)Endpoints.Count);
foreach (var endpoint in Endpoints)
@@ -45,6 +45,6 @@ public void Write(EndianWriter writer)
writer.Write((ushort)endpoint.TransportType);
}
- EndpointMetadata.WriteArray(writer, MetaData);
+ EndpointMetadata.WriteArray(ref writer, MetaData);
}
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/ControlHeader.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/ControlHeader.cs
index 6ed8b731..74da603f 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/ControlHeader.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/ControlHeader.cs
@@ -1,18 +1,18 @@
namespace ShortDev.Microsoft.ConnectedDevices.Messages.Control;
-public sealed class ControlHeader : ICdpHeader
+public readonly record struct ControlHeader : IBinaryWritable, IBinaryParsable
{
- public required ControlMessageType MessageType { get; set; }
+ public required ControlMessageType MessageType { get; init; }
- public static ControlHeader Parse(ref EndianReader reader)
+ public static ControlHeader Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
{
return new()
{
- MessageType = (ControlMessageType)reader.ReadByte()
+ MessageType = (ControlMessageType)reader.ReadUInt8()
};
}
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((byte)MessageType);
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/StartChannelRequest.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/StartChannelRequest.cs
index 7bbafecd..b5b6b9e6 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/StartChannelRequest.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/StartChannelRequest.cs
@@ -1,8 +1,8 @@
namespace ShortDev.Microsoft.ConnectedDevices.Messages.Control;
-public sealed class StartChannelRequest : ICdpPayload
+public readonly record struct StartChannelRequest() : IBinaryWritable, IBinaryParsable
{
- public static StartChannelRequest Parse(ref EndianReader reader)
+ public static StartChannelRequest Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
Id = reader.ReadStringWithLength(),
@@ -16,7 +16,7 @@ public static StartChannelRequest Parse(ref EndianReader reader)
public short Reserved1 { get; init; }
public string Reserved2 { get; init; } = string.Empty;
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.WriteWithLength(Id);
writer.WriteWithLength(Name);
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/StartChannelResponse.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/StartChannelResponse.cs
index b82dec9f..d7063e4e 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/StartChannelResponse.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Control/StartChannelResponse.cs
@@ -2,12 +2,12 @@
namespace ShortDev.Microsoft.ConnectedDevices.Messages.Control;
-public sealed class StartChannelResponse : ICdpPayload
+public readonly record struct StartChannelResponse : IBinaryWritable, IBinaryParsable
{
- public static StartChannelResponse Parse(ref EndianReader reader)
+ public static StartChannelResponse Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
- Result = (ChannelResult)reader.ReadByte(),
+ Result = (ChannelResult)reader.ReadUInt8(),
ChannelId = reader.ReadUInt64()
};
@@ -20,7 +20,7 @@ public void ThrowOnError()
throw new CdpProtocolException($"Could not create channel. {Result}");
}
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((byte)Result);
writer.Write(ChannelId);
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Discovery/DiscoveryHeader.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Discovery/DiscoveryHeader.cs
index 1ea762a6..2f3fbe11 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Discovery/DiscoveryHeader.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Discovery/DiscoveryHeader.cs
@@ -1,17 +1,17 @@
namespace ShortDev.Microsoft.ConnectedDevices.Messages.Discovery;
-public sealed class DiscoveryHeader : ICdpHeader
+public readonly record struct DiscoveryHeader : IBinaryWritable, IBinaryParsable
{
- public static DiscoveryHeader Parse(ref EndianReader reader)
+ public static DiscoveryHeader Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
- Type = (DiscoveryType)reader.ReadByte()
+ Type = (DiscoveryType)reader.ReadUInt8()
};
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((byte)Type);
}
- public required DiscoveryType Type { get; set; }
+ public required DiscoveryType Type { get; init; }
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Discovery/PresenceResponse.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Discovery/PresenceResponse.cs
index 83a9c292..2bc0ae13 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Discovery/PresenceResponse.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Discovery/PresenceResponse.cs
@@ -1,9 +1,10 @@
using ShortDev.Microsoft.ConnectedDevices.Messages.Connection;
+using System.Diagnostics;
using System.Security.Cryptography;
namespace ShortDev.Microsoft.ConnectedDevices.Messages.Discovery;
-public class PresenceResponse : ICdpPayload
+public readonly record struct PresenceResponse : IBinaryWritable, IBinaryParsable
{
public required ConnectionMode ConnectionMode { get; init; }
@@ -13,25 +14,25 @@ public class PresenceResponse : ICdpPayload
public required int DeviceIdSalt { get; init; }
- public required byte[] DeviceIdHash { get; init; }
+ public required DeviceIdHash DeviceIdHash { get; init; }
- public static PresenceResponse Parse(ref EndianReader reader)
+ public static PresenceResponse Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
ConnectionMode = (ConnectionMode)reader.ReadInt16(),
DeviceType = (DeviceType)reader.ReadInt16(),
DeviceName = reader.ReadStringWithLength(),
DeviceIdSalt = reader.ReadInt32(),
- DeviceIdHash = reader.ReadBytes(32).ToArray()
+ DeviceIdHash = reader.Read()
};
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((short)ConnectionMode);
writer.Write((short)DeviceType);
writer.WriteWithLength(DeviceName);
writer.Write((int)DeviceIdSalt);
- writer.Write(DeviceIdHash);
+ writer.Write(DeviceIdHash);
}
static readonly HashAlgorithm _hashAlgorithm = SHA256.Create();
@@ -39,15 +40,16 @@ public static PresenceResponse Create(LocalDeviceInfo deviceInfo, ConnectionMode
{
var salt = RandomNumberGenerator.GetInt32(int.MaxValue);
- using MemoryStream stream = new();
- EndianWriter writer = new(Endianness.LittleEndian);
+ using var writer = EndianWriter.Create(Endianness.LittleEndian, ConnectedDevicesPlatform.MemoryPool);
// ToDo: Wrong
writer.Write(salt);
writer.Write(deviceInfo.GetDeduplicationHint());
- writer.CopyTo(stream);
- var hash = _hashAlgorithm.ComputeHash(stream);
+ Debug.Assert(_hashAlgorithm.HashSize / 8 == 32);
+
+ DeviceIdHash hash = default;
+ _hashAlgorithm.TryComputeHash(writer.Stream.WrittenSpan, hash, out _);
return new()
{
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/EmptyMessage.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/EmptyMessage.cs
new file mode 100644
index 00000000..7600f96e
--- /dev/null
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/EmptyMessage.cs
@@ -0,0 +1,12 @@
+namespace ShortDev.Microsoft.ConnectedDevices.Messages;
+
+internal readonly record struct EmptyMessage : IBinaryParsable, IBinaryWritable
+{
+ public readonly void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
+ {
+ // No content to write
+ }
+
+ public static EmptyMessage Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
+ => default;
+}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/HResultPayload.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/HResultPayload.cs
index dbcdbeca..8aaaa476 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/HResultPayload.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/HResultPayload.cs
@@ -3,9 +3,9 @@
///
/// General payload to represent a HRESULT ().
///
-public sealed class HResultPayload : ICdpPayload
+public readonly record struct HResultPayload : IBinaryWritable, IBinaryParsable
{
- public static HResultPayload Parse(ref EndianReader reader)
+ public static HResultPayload Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
HResult = reader.ReadInt32()
@@ -13,7 +13,7 @@ public static HResultPayload Parse(ref EndianReader reader)
public required int HResult { get; init; }
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write(HResult);
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ICdpHeader.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ICdpHeader.cs
deleted file mode 100644
index 05810e68..00000000
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ICdpHeader.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace ShortDev.Microsoft.ConnectedDevices.Messages;
-
-public interface ICdpHeader : ICdpSerializable where T : ICdpHeader { }
\ No newline at end of file
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ICdpPayload.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ICdpPayload.cs
deleted file mode 100644
index 75fd4866..00000000
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ICdpPayload.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-namespace ShortDev.Microsoft.ConnectedDevices.Messages;
-
-public interface ICdpPayload : ICdpSerializable where T : ICdpPayload { }
\ No newline at end of file
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ICdpSerializable.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ICdpSerializable.cs
deleted file mode 100644
index 9642636f..00000000
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ICdpSerializable.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace ShortDev.Microsoft.ConnectedDevices.Messages;
-
-public interface ICdpSerializable : ICdpWriteable where T : ICdpSerializable
-{
- static abstract T Parse(ref EndianReader reader);
- public static bool TryParse(ref EndianReader reader, out T? result, out Exception? error)
- => throw new NotImplementedException();
-}
-
-public interface ICdpArraySerializable where T : ICdpArraySerializable
-{
- static abstract IReadOnlyList ParseArray(ref EndianReader reader);
- static abstract void WriteArray(EndianWriter writer, IReadOnlyList array);
-}
-
-public interface ICdpWriteable
-{
- void Write(EndianWriter writer);
-}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/PeerCapabilities.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/PeerCapabilities.cs
index 0dc84e5e..5b8d4d43 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/PeerCapabilities.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/PeerCapabilities.cs
@@ -1,6 +1,4 @@
-using System;
-
-namespace ShortDev.Microsoft.ConnectedDevices.Messages;
+namespace ShortDev.Microsoft.ConnectedDevices.Messages;
[Flags]
public enum PeerCapabilities : ulong
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ResultPayload.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ResultPayload.cs
index 1a73aff0..61ec9c15 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ResultPayload.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/ResultPayload.cs
@@ -7,17 +7,17 @@ namespace ShortDev.Microsoft.ConnectedDevices.Messages;
///
/// (e.g. )
///
-public sealed class ResultPayload : ICdpPayload
+public readonly record struct ResultPayload : IBinaryWritable, IBinaryParsable
{
- public static ResultPayload Parse(ref EndianReader reader)
+ public static ResultPayload Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
- Result = (CdpResult)reader.ReadByte()
+ Result = (CdpResult)reader.ReadUInt8()
};
public required CdpResult Result { get; init; }
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((byte)Result);
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/AppControlHeader.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/AppControlHeader.cs
index 1fab8dbe..af8c0eea 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/AppControlHeader.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/AppControlHeader.cs
@@ -1,18 +1,18 @@
namespace ShortDev.Microsoft.ConnectedDevices.Messages.Session.AppControl;
-public sealed class AppControlHeader : ICdpHeader
+public readonly record struct AppControlHeader : IBinaryWritable, IBinaryParsable
{
- public required AppControlType MessageType { get; set; }
+ public required AppControlType MessageType { get; init; }
- public static AppControlHeader Parse(ref EndianReader reader)
+ public static AppControlHeader Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
{
return new()
{
- MessageType = (AppControlType)reader.ReadByte()
+ MessageType = (AppControlType)reader.ReadUInt8()
};
}
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write((byte)MessageType);
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriForTargetRequest.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriForTargetRequest.cs
index cf44fa05..bffd276d 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriForTargetRequest.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriForTargetRequest.cs
@@ -1,8 +1,8 @@
namespace ShortDev.Microsoft.ConnectedDevices.Messages.Session.AppControl;
-public sealed class LaunchUriForTargetRequest : ICdpPayload
+public readonly record struct LaunchUriForTargetRequest() : IBinaryWritable, IBinaryParsable
{
- public static LaunchUriForTargetRequest Parse(ref EndianReader reader)
+ public static LaunchUriForTargetRequest Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
Uri = reader.ReadStringWithLength(),
@@ -13,7 +13,7 @@ public static LaunchUriForTargetRequest Parse(ref EndianReader reader)
AlternateId = reader.ReadStringWithLength(),
TitleId = reader.ReadInt32(),
FacadeName = reader.ReadStringWithLength(),
- InputData = reader.ReadBytesWithLength().ToArray()
+ InputData = reader.ReadBytesWithLength()
};
///
@@ -50,9 +50,9 @@ public static LaunchUriForTargetRequest Parse(ref EndianReader reader)
/// BOND.NET serialized data that is passed as a value set to the app launched by the call.
/// (Optional)
///
- public byte[] InputData { get; init; } = [];
+ public ReadOnlyMemory InputData { get; init; } = default;
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.WriteWithLength(Uri);
writer.Write((short)LaunchLocation);
@@ -62,6 +62,6 @@ public void Write(EndianWriter writer)
writer.WriteWithLength(AlternateId);
writer.Write(TitleId);
writer.WriteWithLength(FacadeName);
- writer.WriteWithLength(InputData);
+ writer.WriteWithLength(InputData.Span);
}
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriRequest.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriRequest.cs
index 64d69aad..8ccb896d 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriRequest.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriRequest.cs
@@ -1,8 +1,8 @@
namespace ShortDev.Microsoft.ConnectedDevices.Messages.Session.AppControl;
-public sealed class LaunchUriRequest : ICdpPayload
+public readonly record struct LaunchUriRequest() : IBinaryWritable, IBinaryParsable
{
- public static LaunchUriRequest Parse(ref EndianReader reader)
+ public static LaunchUriRequest Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
Uri = reader.ReadStringWithLength(),
@@ -27,7 +27,7 @@ public static LaunchUriRequest Parse(ref EndianReader reader)
///
public string InputData { get; init; } = string.Empty;
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.WriteWithLength(Uri);
writer.Write((short)LaunchLocation);
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriResult.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriResult.cs
index 716808db..c69f827e 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriResult.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/AppControl/LaunchUriResult.cs
@@ -1,8 +1,8 @@
namespace ShortDev.Microsoft.ConnectedDevices.Messages.Session.AppControl;
-public sealed class LaunchUriResult : ICdpPayload
+public readonly record struct LaunchUriResult : IBinaryWritable, IBinaryParsable
{
- public static LaunchUriResult Parse(ref EndianReader reader)
+ public static LaunchUriResult Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
Result = reader.ReadInt32(),
@@ -20,7 +20,7 @@ public static LaunchUriResult Parse(ref EndianReader reader)
///
public required int ResponseID { get; init; }
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write(Result);
writer.Write(ResponseID);
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/BinaryMsgHeader.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/BinaryMsgHeader.cs
index 3816f874..5468216e 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/BinaryMsgHeader.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/BinaryMsgHeader.cs
@@ -4,13 +4,13 @@
/// cdp.dll!cdp::BinaryFragmenter::GetMessageFragments
///
///
-public readonly struct BinaryMsgHeader() : ICdpHeader
+public readonly record struct BinaryMsgHeader() : IBinaryWritable, IBinaryParsable
{
public uint FragmentCount { get; init; } = 1;
public uint FragmentIndex { get; init; } = 0;
public required uint MessageId { get; init; }
- public static BinaryMsgHeader Parse(ref EndianReader reader)
+ public static BinaryMsgHeader Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
FragmentCount = reader.ReadUInt32(),
@@ -18,7 +18,7 @@ public static BinaryMsgHeader Parse(ref EndianReader reader)
MessageId = reader.ReadUInt32(),
};
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write(FragmentCount);
writer.Write(FragmentIndex);
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/DisconnectMessage.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/DisconnectMessage.cs
index d3246cb1..bf7545b2 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/DisconnectMessage.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Messages/Session/DisconnectMessage.cs
@@ -4,20 +4,20 @@
/// The Disconnect message is an optional message sent by a client or host used to inform the other device to disconnect the connected session.
/// The is sent to identify the session to be disconnected.
///
-public sealed class DisconnectMessage : ICdpPayload
+public readonly record struct DisconnectMessage : IBinaryParsable
{
///
/// ID representing the session.
///
public required ulong SessionId { get; init; }
- public static DisconnectMessage Parse(ref EndianReader reader)
+ public static DisconnectMessage Parse(ref TReader reader) where TReader : struct, IEndianReader, allows ref struct
=> new()
{
SessionId = reader.ReadUInt64()
};
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
writer.Write(SessionId);
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Serialization/BondWriter.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Serialization/BondWriter.cs
deleted file mode 100644
index 1908ebea..00000000
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Serialization/BondWriter.cs
+++ /dev/null
@@ -1,590 +0,0 @@
-using Bond;
-using System.Runtime.CompilerServices;
-using System.Text;
-
-namespace ShortDev.Microsoft.ConnectedDevices.Serialization;
-public readonly ref struct CompactBinaryBondWriter(EndianBuffer buffer)
-{
- const ushort Magic = 16963;
-
- readonly ushort version = 1;
- readonly EndianWriter output = new(Endianness.LittleEndian, buffer);
-
- //
- // Summary:
- // Write protocol magic number and version
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteVersion()
- {
- output.Write((ushort)16963);
- output.Write((ushort)version);
- }
-
- //
- // Summary:
- // End writing a struct
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteStructEnd()
- {
- output.Write((byte)0);
- }
-
- //
- // Summary:
- // End writing a base struct
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteBaseEnd()
- {
- output.Write((byte)1);
- }
-
- //
- // Summary:
- // Start writing a field
- //
- // Parameters:
- // type:
- // Type of the field
- //
- // id:
- // Identifier of the field
- //
- // metadata:
- // Metadata of the field
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteFieldBegin(BondDataType type, ushort id)
- {
- if (id <= 5)
- {
- output.Write((byte)((uint)type | (uint)(id << 5)));
- return;
- }
-
- if (id <= 255)
- {
- output.Write((ushort)((uint)type | (uint)(id << 8) | 0xC0u));
- return;
- }
-
- output.Write((byte)(type | (BondDataType)224));
- output.Write(id);
- }
-
- //
- // Summary:
- // Start writing a list or set container
- //
- // Parameters:
- // count:
- // Number of elements in the container
- //
- // elementType:
- // Type of the elements
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteContainerBegin(int count, BondDataType elementType)
- {
- if (2 == version && count < 7)
- {
- output.Write((byte)((uint)elementType | (uint)(count + 1 << 5)));
- return;
- }
-
- output.Write((byte)elementType);
- IntegerHelper.WriteVarUInt32(output, (uint)count);
- }
-
- //
- // Summary:
- // Start writing a map container
- //
- // Parameters:
- // count:
- // Number of elements in the container
- //
- // keyType:
- // Type of the keys
- //
- // valueType:
- // Type of the values
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteContainerBegin(int count, BondDataType keyType, BondDataType valueType)
- {
- output.Write((byte)keyType);
- output.Write((byte)valueType);
- IntegerHelper.WriteVarUInt32(output, (uint)count);
- }
-
- //
- // Summary:
- // Write array of bytes verbatim
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteBytes(ReadOnlySpan data)
- {
- output.Write(data);
- }
-
- //
- // Summary:
- // Write an UInt8
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteUInt8(byte value)
- {
- output.Write(value);
- }
-
- //
- // Summary:
- // Write an UInt16
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteUInt16(ushort value)
- {
- IntegerHelper.WriteVarUInt16(output, value);
- }
-
- //
- // Summary:
- // Write an UInt16
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteUInt32(uint value)
- {
- IntegerHelper.WriteVarUInt32(output, value);
- }
-
- //
- // Summary:
- // Write an UInt64
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteUInt64(ulong value)
- {
- IntegerHelper.WriteVarUInt64(output, value);
- }
-
- //
- // Summary:
- // Write an Int8
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteInt8(sbyte value)
- {
- output.Write((byte)value);
- }
-
- //
- // Summary:
- // Write an Int16
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteInt16(short value)
- {
- IntegerHelper.WriteVarUInt16(output, IntegerHelper.EncodeZigzag16(value));
- }
-
- //
- // Summary:
- // Write an Int32
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteInt32(int value)
- {
- IntegerHelper.WriteVarUInt32(output, IntegerHelper.EncodeZigzag32(value));
- }
-
- //
- // Summary:
- // Write an Int64
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteInt64(long value)
- {
- IntegerHelper.WriteVarUInt64(output, IntegerHelper.EncodeZigzag64(value));
- }
-
- //
- // Summary:
- // Write a float
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteFloat(float value)
- {
- output.Write(value);
- }
-
- //
- // Summary:
- // Write a double
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteDouble(double value)
- {
- output.Write(value);
- }
-
- //
- // Summary:
- // Write a bool
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteBool(bool value)
- {
- output.Write((byte)(value ? 1u : 0u));
- }
-
- //
- // Summary:
- // Write a UTF-8 string
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteString(string value)
- {
- if (value.Length == 0)
- {
- WriteUInt32(0u);
- return;
- }
-
- int byteCount = Encoding.UTF8.GetByteCount(value);
- WriteUInt32((uint)byteCount);
- // output.WriteString(Encoding.UTF8, value, byteCount);
- output.Write(Encoding.UTF8.GetBytes(value));
- }
-
- //
- // Summary:
- // Write a UTF-16 string
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void WriteWString(string value)
- {
- if (value.Length == 0)
- {
- WriteUInt32(0u);
- return;
- }
-
- int size = checked(value.Length * 2);
- WriteUInt32((uint)value.Length);
- // output.WriteString(Encoding.Unicode, value, size);
- output.Write(Encoding.Unicode.GetBytes(value));
- }
-
- internal static class IntegerHelper
- {
- public const int MaxBytesVarInt16 = 3;
-
- public const int MaxBytesVarInt32 = 5;
-
- public const int MaxBytesVarInt64 = 10;
-
- public static int GetVarUInt16Length(ushort value)
- {
- if (value < 128)
- {
- return 1;
- }
-
- if (value < 16384)
- {
- return 2;
- }
-
- return 3;
- }
-
- public static void WriteVarUInt16(in EndianWriter writer, ushort value)
- {
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80u));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80u));
- value >>= 7;
- }
- }
-
- writer.Write((byte)value);
- }
-
- public static int GetVarUInt32Length(uint value)
- {
- if (value < 128)
- {
- return 1;
- }
-
- if (value < 16384)
- {
- return 2;
- }
-
- if (value < 2097152)
- {
- return 3;
- }
-
- if (value < 268435456)
- {
- return 4;
- }
-
- return 5;
- }
-
- public static void WriteVarUInt32(in EndianWriter writer, uint value)
- {
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80u));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80u));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80u));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80u));
- value >>= 7;
- }
- }
- }
- }
-
- writer.Write((byte)value);
- }
-
- public static int GetVarUInt64Length(ulong value)
- {
- if (value < 128)
- {
- return 1;
- }
-
- if (value < 16384)
- {
- return 2;
- }
-
- if (value < 2097152)
- {
- return 3;
- }
-
- if (value < 268435456)
- {
- return 4;
- }
-
- if (value < 34359738368L)
- {
- return 5;
- }
-
- if (value < 4398046511104L)
- {
- return 6;
- }
-
- if (value < 562949953421312L)
- {
- return 7;
- }
-
- if (value < 72057594037927936L)
- {
- return 8;
- }
-
- if (value < 9223372036854775808uL)
- {
- return 9;
- }
-
- return 10;
- }
-
- public static void WriteVarUInt64(in EndianWriter writer, ulong value)
- {
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80));
- value >>= 7;
- if (value >= 128)
- {
- writer.Write((byte)(value | 0x80));
- value >>= 7;
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- writer.Write((byte)value);
- }
-
- public static ushort DecodeVarUInt16(byte[] data, ref int index)
- {
- int num = index;
- uint num2 = data[num++];
- if (128 <= num2)
- {
- uint num3 = data[num++];
- num2 = (num2 & 0x7Fu) | ((num3 & 0x7F) << 7);
- if (128 <= num3)
- {
- num3 = data[num++];
- num2 |= num3 << 14;
- }
- }
-
- index = num;
- return (ushort)num2;
- }
-
- public static uint DecodeVarUInt32(byte[] data, ref int index)
- {
- int num = index;
- uint num2 = data[num++];
- if (128 <= num2)
- {
- uint num3 = data[num++];
- num2 = (num2 & 0x7Fu) | ((num3 & 0x7F) << 7);
- if (128 <= num3)
- {
- num3 = data[num++];
- num2 |= (num3 & 0x7F) << 14;
- if (128 <= num3)
- {
- num3 = data[num++];
- num2 |= (num3 & 0x7F) << 21;
- if (128 <= num3)
- {
- num3 = data[num++];
- num2 |= num3 << 28;
- }
- }
- }
- }
-
- index = num;
- return num2;
- }
-
- public static ulong DecodeVarUInt64(byte[] data, ref int index)
- {
- int num = index;
- ulong num2 = data[num++];
- if (128 <= num2)
- {
- ulong num3 = data[num++];
- num2 = (num2 & 0x7F) | ((num3 & 0x7F) << 7);
- if (128 <= num3)
- {
- num3 = data[num++];
- num2 |= (num3 & 0x7F) << 14;
- if (128 <= num3)
- {
- num3 = data[num++];
- num2 |= (num3 & 0x7F) << 21;
- if (128 <= num3)
- {
- num3 = data[num++];
- num2 |= (num3 & 0x7F) << 28;
- if (128 <= num3)
- {
- num3 = data[num++];
- num2 |= (num3 & 0x7F) << 35;
- if (128 <= num3)
- {
- num3 = data[num++];
- num2 |= (num3 & 0x7F) << 42;
- if (128 <= num3)
- {
- num3 = data[num++];
- num2 |= (num3 & 0x7F) << 49;
- if (128 <= num3)
- {
- num3 = data[num++];
- num2 |= num3 << 56;
- if (128 <= num3)
- {
- num++;
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- index = num;
- return num2;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ushort EncodeZigzag16(short value)
- {
- return (ushort)((value << 1) ^ (value >> 15));
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint EncodeZigzag32(int value)
- {
- return (uint)((value << 1) ^ (value >> 31));
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong EncodeZigzag64(long value)
- {
- return (ulong)((value << 1) ^ (value >> 63));
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static short DecodeZigzag16(ushort value)
- {
- return (short)((value >> 1) ^ -(value & 1));
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int DecodeZigzag32(uint value)
- {
- return (int)((value >> 1) ^ (0L - (long)(value & 1)));
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long DecodeZigzag64(ulong value)
- {
- return (long)((value >> 1) ^ (0L - (value & 1)));
- }
- }
-}
-
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Serialization/ValueSet.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Serialization/ValueSet.cs
index cb35c12f..cc0a3220 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Serialization/ValueSet.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Serialization/ValueSet.cs
@@ -1,21 +1,21 @@
using Bond;
using Bond.IO.Unsafe;
using Bond.Protocols;
-using ShortDev.Microsoft.ConnectedDevices.Messages;
namespace ShortDev.Microsoft.ConnectedDevices.Serialization;
-public partial class ValueSet : ICdpPayload
+public partial class ValueSet : IBinaryWritable
{
- public static ValueSet Parse(ref EndianReader reader)
+ public static ValueSet Parse(ref HeapEndianReader reader)
{
// ToDo: We really should not re-allocated here!!
- var data = reader.ReadToEnd().ToArray();
+ byte[] data = new byte[reader.Stream.Length - reader.Stream.Position];
+ reader.ReadBytes(data);
CompactBinaryReader bondReader = new(new(data));
return Deserialize.From(bondReader);
}
- public void Write(EndianWriter writer)
+ public void Write(ref TWriter writer) where TWriter : struct, IEndianWriter, allows ref struct
{
OutputBuffer buffer = new();
CompactBinaryWriter bondWriter = new(buffer);
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/ChannelHandler.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/ChannelHandler.cs
index 38fef94c..3f6bafe5 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/ChannelHandler.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/ChannelHandler.cs
@@ -11,7 +11,7 @@ internal abstract class ChannelHandler(CdpSession session) : IDisposable
public CdpSession Session { get; } = session;
- public void HandleControl(CdpSocket socket, CommonHeader header, ref EndianReader reader)
+ public void HandleControl(CdpSocket socket, CommonHeader header, ref HeapEndianReader reader)
{
var controlHeader = ControlHeader.Parse(ref reader);
_logger.ReceivedControlMessage(
@@ -23,7 +23,7 @@ public void HandleControl(CdpSocket socket, CommonHeader header, ref EndianReade
HandleMessageInternal(socket, header, controlHeader, ref reader);
}
- protected abstract void HandleMessageInternal(CdpSocket socket, CommonHeader header, ControlHeader controlHeader, ref EndianReader reader);
+ protected abstract void HandleMessageInternal(CdpSocket socket, CommonHeader header, ControlHeader controlHeader, ref HeapEndianReader reader);
#region Registry
protected readonly AutoKeyRegistry _channelRegistry = [];
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/ClientChannelHandler.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/ClientChannelHandler.cs
index 32be8193..584f4533 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/ClientChannelHandler.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/ClientChannelHandler.cs
@@ -5,7 +5,7 @@
namespace ShortDev.Microsoft.ConnectedDevices.Session.Channels;
internal sealed class ClientChannelHandler(CdpSession session) : ChannelHandler(session)
{
- protected override void HandleMessageInternal(CdpSocket socket, CommonHeader header, ControlHeader controlHeader, ref EndianReader reader)
+ protected override void HandleMessageInternal(CdpSocket socket, CommonHeader header, ControlHeader controlHeader, ref HeapEndianReader reader)
{
if (controlHeader.MessageType != ControlMessageType.StartChannelResponse)
return;
@@ -50,22 +50,24 @@ public async Task CreateChannelAsync(string appId, string appName, C
ulong SendChannelRequest(CdpSocket socket, string appId, string appName)
{
- EndianWriter writer = new(Endianness.BigEndian);
- new ControlHeader()
- {
- MessageType = ControlMessageType.StartChannelRequest
- }.Write(writer);
- new StartChannelRequest()
- {
- Id = appId,
- Name = appName
- }.Write(writer);
-
CommonHeader header = new()
{
Type = MessageType.Control
};
- Session.SendMessage(socket, header, writer, supplyRequestId: true);
+ Session.SendMessage(
+ socket,
+ ref header,
+ new ControlHeader()
+ {
+ MessageType = ControlMessageType.StartChannelRequest
+ },
+ new StartChannelRequest()
+ {
+ Id = appId,
+ Name = appName
+ },
+ supplyRequestId: true
+ );
return header.RequestID;
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/HostChannelHandler.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/HostChannelHandler.cs
index 2f0e36ad..5b6e263e 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/HostChannelHandler.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Channels/HostChannelHandler.cs
@@ -5,7 +5,7 @@
namespace ShortDev.Microsoft.ConnectedDevices.Session.Channels;
internal sealed class HostChannelHandler(CdpSession session) : ChannelHandler(session)
{
- protected override void HandleMessageInternal(CdpSocket socket, CommonHeader header, ControlHeader controlHeader, ref EndianReader reader)
+ protected override void HandleMessageInternal(CdpSocket socket, CommonHeader header, ControlHeader controlHeader, ref HeapEndianReader reader)
{
if (controlHeader.MessageType != ControlMessageType.StartChannelRequest)
return;
@@ -22,18 +22,19 @@ protected override void HandleMessageInternal(CdpSocket socket, CommonHeader hea
_channelRegistry.Create(channelId => CdpChannel.CreateServerChannel(this, socket, request, channelId), out var channelId);
- EndianWriter writer = new(Endianness.BigEndian);
- new ControlHeader()
- {
- MessageType = ControlMessageType.StartChannelResponse
- }.Write(writer);
- new StartChannelResponse()
- {
- Result = ChannelResult.Success,
- ChannelId = channelId
- }.Write(writer);
-
header.Flags = 0;
- Session.SendMessage(socket, header, writer);
+ Session.SendMessage(
+ socket,
+ ref header,
+ new ControlHeader()
+ {
+ MessageType = ControlMessageType.StartChannelResponse
+ },
+ new StartChannelResponse()
+ {
+ Result = ChannelResult.Success,
+ ChannelId = channelId
+ }
+ );
}
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/ClientConnectHandler.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/ClientConnectHandler.cs
index c67571c4..cc3d33b8 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/ClientConnectHandler.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/ClientConnectHandler.cs
@@ -33,30 +33,30 @@ public async Task ConnectAsync(CdpSocket socket, bool upgradeSupported = true, C
}
};
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.ConnectRequest
- }.Write(writer);
-
var publicKey = _localEncryption.PublicKey;
- new ConnectionRequest()
- {
- CurveType = CurveType.CT_NIST_P256_KDF_SHA512,
- HmacSize = Constants.HMacSize,
- MessageFragmentSize = MessageFragmenter.DefaultMessageFragmentSize,
- Nonce = _localEncryption.Nonce,
- PublicKeyX = publicKey.X!,
- PublicKeyY = publicKey.Y!
- }.Write(writer);
-
- _session.SendMessage(socket, header, writer);
+ _session.SendMessage(
+ socket,
+ ref header,
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.ConnectRequest
+ },
+ new ConnectionRequest()
+ {
+ CurveType = CurveType.CT_NIST_P256_KDF_SHA512,
+ HmacSize = Constants.HMacSize,
+ MessageFragmentSize = MessageFragmenter.DefaultMessageFragmentSize,
+ Nonce = _localEncryption.Nonce,
+ PublicKeyX = publicKey.X!,
+ PublicKeyY = publicKey.Y!
+ }
+ );
await _promise;
}
- protected override void HandleMessageInternal(CdpSocket socket, CommonHeader header, ConnectionHeader connectionHeader, ref EndianReader reader)
+ protected override void HandleMessageInternal(CdpSocket socket, CommonHeader header, ConnectionHeader connectionHeader, ref HeapEndianReader reader)
{
if (_promise?.CancellationToken.IsCancellationRequested == true)
return;
@@ -93,7 +93,7 @@ protected override void HandleMessageInternal(CdpSocket socket, CommonHeader hea
}
}
- void HandleConnectResponse(CommonHeader header, ref EndianReader reader, CdpSocket socket)
+ void HandleConnectResponse(CommonHeader header, ref HeapEndianReader reader, CdpSocket socket)
{
_session.HostCapabilities = (PeerCapabilities)(header.TryGetHeader(AdditionalHeaderType.PeerCapabilities)?.AsUInt64() ?? 0);
@@ -103,22 +103,23 @@ void HandleConnectResponse(CommonHeader header, ref EndianReader reader, CdpSock
var secret = _localEncryption.GenerateSharedSecret(_remoteEncryption);
_session.Cryptor = new(secret);
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.DeviceAuthRequest
- }.Write(writer);
- AuthenticationPayload.Create(
- _session.Platform.DeviceInfo.DeviceCertificate!, // ToDo: User cert
- hostNonce: _remoteEncryption!.Nonce, clientNonce: _localEncryption.Nonce
- ).Write(writer);
-
header.Flags = 0;
- _session.SendMessage(socket, header, writer);
+ _session.SendMessage(
+ socket,
+ ref header,
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.DeviceAuthRequest
+ },
+ AuthenticationPayload.Create(
+ _session.Platform.DeviceInfo.DeviceCertificate!, // ToDo: User cert
+ hostNonce: _remoteEncryption!.Nonce, clientNonce: _localEncryption.Nonce
+ )
+ );
}
- void HandleAuthResponse(CommonHeader header, ref EndianReader reader, CdpSocket socket, ConnectionType connectionType)
+ void HandleAuthResponse(CommonHeader header, ref HeapEndianReader reader, CdpSocket socket, ConnectionType connectionType)
{
var authRequest = AuthenticationPayload.Parse(ref reader);
if (!authRequest.VerifyThumbprint(hostNonce: _remoteEncryption!.Nonce, clientNonce: _localEncryption.Nonce))
@@ -150,15 +151,17 @@ async void PrepareSession(CdpSocket socket)
try
{
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.AuthDoneRequest
- }.Write(writer);
-
header.Flags = 0;
- _session.SendMessage(socket, header, writer);
+ _session.SendMessage(
+ socket,
+ ref header,
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.AuthDoneRequest
+ },
+ new EmptyMessage()
+ );
}
catch (Exception ex)
{
@@ -169,44 +172,42 @@ async void PrepareSession(CdpSocket socket)
void HandleDeviceAuthResponse(CdpSocket socket, CommonHeader header)
{
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.UserDeviceAuthRequest
- }.Write(writer);
- AuthenticationPayload.Create(
- _session.Platform.DeviceInfo.DeviceCertificate!, // ToDo: User cert
- hostNonce: _remoteEncryption!.Nonce, clientNonce: _localEncryption.Nonce
- ).Write(writer);
-
header.Flags = 0;
- _session.SendMessage(socket, header, writer);
+ _session.SendMessage(
+ socket,
+ ref header,
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.UserDeviceAuthRequest
+ },
+ AuthenticationPayload.Create(
+ _session.Platform.DeviceInfo.DeviceCertificate!, // ToDo: User cert
+ hostNonce: _remoteEncryption!.Nonce, clientNonce: _localEncryption.Nonce
+ )
+ );
}
- void HandleAuthDoneResponse(CdpSocket socket, ref EndianReader reader)
+ void HandleAuthDoneResponse(CdpSocket socket, ref HeapEndianReader reader)
{
var msg = ResultPayload.Parse(ref reader);
msg.ThrowOnError();
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.DeviceInfoMessage
- }.Write(writer);
- new DeviceInfoMessage()
- {
- DeviceInfo = _session.Platform.GetCdpDeviceInfo()
- }.Write(writer);
-
_session.SendMessage(
socket,
new CommonHeader()
{
Type = MessageType.Connect
},
- writer
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.DeviceInfoMessage
+ },
+ new DeviceInfoMessage()
+ {
+ DeviceInfo = _session.Platform.GetCdpDeviceInfo()
+ }
);
_promise?.TrySetResult();
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/ConnectHandler.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/ConnectHandler.cs
index 11f07edb..2d299e19 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/ConnectHandler.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/ConnectHandler.cs
@@ -16,7 +16,7 @@ internal abstract class ConnectHandler(CdpSession session, UpgradeHandler upgrad
internal UpgradeHandler UpgradeHandler { get; } = upgradeHandler;
- public void HandleConnect(CdpSocket socket, CommonHeader header, ref EndianReader reader)
+ public void HandleConnect(CdpSocket socket, CommonHeader header, ref HeapEndianReader reader)
{
ConnectionHeader connectionHeader = ConnectionHeader.Parse(ref reader);
_logger.ReceivedConnectMessage(
@@ -34,25 +34,27 @@ public void HandleConnect(CdpSocket socket, CommonHeader header, ref EndianReade
HandleMessageInternal(socket, header, connectionHeader, ref reader);
}
- protected abstract void HandleMessageInternal(CdpSocket socket, CommonHeader header, ConnectionHeader connectionHeader, ref EndianReader reader);
+ protected abstract void HandleMessageInternal(CdpSocket socket, CommonHeader header, ConnectionHeader connectionHeader, ref HeapEndianReader reader);
public CdpDeviceInfo? DeviceInfo { get; private set; }
- protected void HandleDeviceInfoMessage(CommonHeader header, ref EndianReader reader, CdpSocket socket)
+ protected void HandleDeviceInfoMessage(CommonHeader header, ref HeapEndianReader reader, CdpSocket socket)
{
var msg = DeviceInfoMessage.Parse(ref reader);
_logger.ReceivedDeviceInfo(msg.DeviceInfo);
DeviceInfo = msg.DeviceInfo;
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.DeviceInfoResponseMessage // Ack
- }.Write(writer);
-
header.Flags = 0;
- _session.SendMessage(socket, header, writer);
+ _session.SendMessage(
+ socket,
+ ref header,
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.DeviceInfoResponseMessage // Ack
+ },
+ new EmptyMessage()
+ );
}
public static ConnectHandler Create(CdpSession session, EndpointInfo initialEndpoint)
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/HostConnectHandler.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/HostConnectHandler.cs
index a2106624..e0939a7b 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/HostConnectHandler.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Connection/HostConnectHandler.cs
@@ -9,7 +9,7 @@
namespace ShortDev.Microsoft.ConnectedDevices.Session.Connection;
internal sealed class HostConnectHandler(CdpSession session, HostUpgradeHandler upgradeHandler) : ConnectHandler(session, upgradeHandler)
{
- protected override void HandleMessageInternal(CdpSocket socket, CommonHeader header, ConnectionHeader connectionHeader, ref EndianReader reader)
+ protected override void HandleMessageInternal(CdpSocket socket, CommonHeader header, ConnectionHeader connectionHeader, ref HeapEndianReader reader)
{
if (connectionHeader.MessageType == ConnectionType.ConnectRequest)
{
@@ -43,73 +43,75 @@ protected override void HandleMessageInternal(CdpSocket socket, CommonHeader hea
}
}
- void HandleConnectRequest(CommonHeader header, ref EndianReader reader, CdpSocket socket)
+ void HandleConnectRequest(CommonHeader header, ref HeapEndianReader reader, CdpSocket socket)
{
_session.ClientCapabilities = (PeerCapabilities)(header.TryGetHeader(AdditionalHeaderType.PeerCapabilities)?.AsUInt64() ?? 0);
var connectionRequest = ConnectionRequest.Parse(ref reader);
_remoteEncryption = CdpEncryptionInfo.FromRemote(connectionRequest.PublicKeyX, connectionRequest.PublicKeyY, connectionRequest.Nonce, CdpEncryptionParams.Default);
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.ConnectResponse
- }.Write(writer);
-
var publicKey = _localEncryption.PublicKey;
- new ConnectionResponse()
- {
- Result = ConnectionResult.Pending,
- HmacSize = connectionRequest.HmacSize,
- MessageFragmentSize = connectionRequest.MessageFragmentSize,
- Nonce = _localEncryption.Nonce,
- PublicKeyX = publicKey.X!,
- PublicKeyY = publicKey.Y!
- }.Write(writer);
-
- _session.SendMessage(socket, header, writer);
+ _session.SendMessage(
+ socket,
+ ref header,
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.ConnectResponse
+ },
+ new ConnectionResponse()
+ {
+ Result = ConnectionResult.Pending,
+ HmacSize = connectionRequest.HmacSize,
+ MessageFragmentSize = connectionRequest.MessageFragmentSize,
+ Nonce = _localEncryption.Nonce,
+ PublicKeyX = publicKey.X!,
+ PublicKeyY = publicKey.Y!
+ }
+ );
// We have to set cryptor after we send the message because it would be encrypted otherwise
var secret = _localEncryption.GenerateSharedSecret(_remoteEncryption);
_session.Cryptor = new(secret);
}
- void HandleAuthRequest(CommonHeader header, ref EndianReader reader, CdpSocket socket, ConnectionType connectionType)
+ void HandleAuthRequest(CommonHeader header, ref HeapEndianReader reader, CdpSocket socket, ConnectionType connectionType)
{
var authRequest = AuthenticationPayload.Parse(ref reader);
if (!authRequest.VerifyThumbprint(hostNonce: _localEncryption.Nonce, clientNonce: _remoteEncryption!.Nonce))
throw new CdpSecurityException("Invalid thumbprint");
- EndianWriter writer = new();
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = connectionType == ConnectionType.DeviceAuthRequest ? ConnectionType.DeviceAuthResponse : ConnectionType.UserDeviceAuthResponse
- }.Write(writer);
- AuthenticationPayload.Create(
- _session.Platform.DeviceInfo.DeviceCertificate, // ToDo: User cert
- hostNonce: _localEncryption.Nonce, clientNonce: _remoteEncryption!.Nonce
- ).Write(writer);
-
header.Flags = 0;
- _session.SendMessage(socket, header, writer);
+ _session.SendMessage(
+ socket,
+ ref header,
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = connectionType == ConnectionType.DeviceAuthRequest ? ConnectionType.DeviceAuthResponse : ConnectionType.UserDeviceAuthResponse
+ },
+ AuthenticationPayload.Create(
+ _session.Platform.DeviceInfo.DeviceCertificate, // ToDo: User cert
+ hostNonce: _localEncryption.Nonce, clientNonce: _remoteEncryption!.Nonce
+ )
+ );
}
void HandleAuthDoneRequest(CommonHeader header, CdpSocket socket)
{
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.AuthDoneRespone // Ack
- }.Write(writer);
- new ResultPayload()
- {
- Result = CdpResult.Success
- }.Write(writer);
-
header.Flags = 0;
- _session.SendMessage(socket, header, writer);
+ _session.SendMessage(
+ socket,
+ ref header,
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.AuthDoneRespone // Ack
+ },
+ new ResultPayload()
+ {
+ Result = CdpResult.Success
+ }
+ );
}
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/ClientUpgradeHandler.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/ClientUpgradeHandler.cs
index ce354501..d57ab690 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/ClientUpgradeHandler.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/ClientUpgradeHandler.cs
@@ -11,7 +11,7 @@ internal sealed class ClientUpgradeHandler(CdpSession session, EndpointInfo init
{
private readonly ILogger _logger = session.Platform.CreateLogger();
- protected override bool TryHandleConnectInternal(CdpSocket socket, ConnectionHeader connectionHeader, ref EndianReader reader)
+ protected override bool TryHandleConnectInternal(CdpSocket socket, ConnectionHeader connectionHeader, ref HeapEndianReader reader)
{
if (!IsSocketAllowed(socket))
return false;
@@ -49,25 +49,23 @@ public async ValueTask UpgradeAsync(CdpSocket oldSocket)
{
_logger.SendingUpgradeRequest(_currentUpgrade.Id, UpgradeEndpoints);
- CommonHeader header = new()
- {
- Type = MessageType.Connect
- };
-
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.UpgradeRequest
- }.Write(writer);
-
- new UpgradeRequest()
- {
- UpgradeId = _currentUpgrade.Id,
- Endpoints = UpgradeEndpoints
- }.Write(writer);
-
- _session.SendMessage(oldSocket, header, writer);
+ _session.SendMessage(
+ oldSocket,
+ new CommonHeader()
+ {
+ Type = MessageType.Connect
+ },
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.UpgradeRequest
+ },
+ new UpgradeRequest()
+ {
+ UpgradeId = _currentUpgrade.Id,
+ Endpoints = UpgradeEndpoints
+ }
+ );
return await _currentUpgrade;
}
@@ -77,7 +75,7 @@ public async ValueTask UpgradeAsync(CdpSocket oldSocket)
}
}
- void HandleUpgradeResponse(CdpSocket oldSocket, ref EndianReader reader)
+ void HandleUpgradeResponse(CdpSocket oldSocket, ref HeapEndianReader reader)
{
if (_currentUpgrade == null)
return;
@@ -117,21 +115,19 @@ async void FindNewEndpoint()
void SendUpgradFinalization(CdpSocket socket)
{
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.UpgradeFinalization
- }.Write(writer);
- EndpointMetadata.WriteArray(writer,
- [
- EndpointMetadata.Tcp
- ]);
-
- _session.SendMessage(socket, new()
- {
- Type = MessageType.Connect,
- }, writer);
+ _session.SendMessage(
+ socket,
+ new CommonHeader()
+ {
+ Type = MessageType.Connect,
+ },
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.UpgradeFinalization
+ },
+ new EndpointMetadataArray([EndpointMetadata.Tcp])
+ );
}
void HandleUpgradeFinalizationResponse()
@@ -147,24 +143,25 @@ void HandleUpgradeFinalizationResponse()
_allowedAddresses.Add(_currentUpgrade.NewSocket.Endpoint.Address);
// Request transport permission for new socket
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.TransportRequest
- }.Write(writer);
- new UpgradeIdPayload()
- {
- UpgradeId = _currentUpgrade.Id
- }.Write(writer);
-
- _session.SendMessage(_currentUpgrade.NewSocket, new()
- {
- Type = MessageType.Connect,
- }, writer);
+ _session.SendMessage(
+ _currentUpgrade.NewSocket,
+ new CommonHeader()
+ {
+ Type = MessageType.Connect,
+ },
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.TransportRequest
+ },
+ new UpgradeIdPayload()
+ {
+ UpgradeId = _currentUpgrade.Id
+ }
+ );
}
- void HandleUpgradeFailure(ref EndianReader reader)
+ void HandleUpgradeFailure(ref HeapEndianReader reader)
{
var msg = HResultPayload.Parse(ref reader);
@@ -173,7 +170,7 @@ void HandleUpgradeFailure(ref EndianReader reader)
);
}
- void HandleTransportConfirmation(CdpSocket socket, ref EndianReader reader)
+ void HandleTransportConfirmation(CdpSocket socket, ref HeapEndianReader reader)
{
var msg = UpgradeIdPayload.Parse(ref reader);
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/HostUpgradeHandler.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/HostUpgradeHandler.cs
index 5d7f15c1..539c0e75 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/HostUpgradeHandler.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/HostUpgradeHandler.cs
@@ -11,7 +11,7 @@ internal sealed class HostUpgradeHandler(CdpSession session, EndpointInfo initia
{
readonly ILogger _logger = session.Platform.CreateLogger();
- protected override bool TryHandleConnectInternal(CdpSocket socket, ConnectionHeader connectionHeader, ref EndianReader reader)
+ protected override bool TryHandleConnectInternal(CdpSocket socket, ConnectionHeader connectionHeader, ref HeapEndianReader reader)
{
// This part needs to be always accessible!
// This is used to validate
@@ -43,7 +43,7 @@ protected override bool TryHandleConnectInternal(CdpSocket socket, ConnectionHea
}
readonly SynchronizedList _upgradeIds = [];
- void HandleTransportRequest(CdpSocket socket, ref EndianReader reader)
+ void HandleTransportRequest(CdpSocket socket, ref HeapEndianReader reader)
{
var msg = UpgradeIdPayload.Parse(ref reader);
@@ -64,25 +64,24 @@ void HandleTransportRequest(CdpSocket socket, ref EndianReader reader)
allowed ? "succeeded" : "failed"
);
- CommonHeader header = new()
- {
- Type = MessageType.Connect
- };
-
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = allowed ? ConnectionType.TransportConfirmation : ConnectionType.UpgradeFailure
- }.Write(writer);
- msg.Write(writer);
-
- _session.SendMessage(socket, header, writer);
+ _session.SendMessage(
+ socket,
+ new CommonHeader()
+ {
+ Type = MessageType.Connect
+ },
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = allowed ? ConnectionType.TransportConfirmation : ConnectionType.UpgradeFailure
+ },
+ msg
+ );
RemoteEndpoint = socket.Endpoint;
}
- void HandleUpgradeRequest(CdpSocket socket, ref EndianReader reader)
+ void HandleUpgradeRequest(CdpSocket socket, ref HeapEndianReader reader)
{
var msg = UpgradeRequest.Parse(ref reader);
_logger.UpgradeRequest(
@@ -99,65 +98,66 @@ void HandleUpgradeRequest(CdpSocket socket, ref EndianReader reader)
var localIp = networkTransport?.Handler.TryGetLocalIp();
if (networkTransport == null || localIp == null)
{
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.UpgradeFailure
- }.Write(writer);
- new HResultPayload()
- {
- HResult = -1
- }.Write(writer);
-
- _session.SendMessage(socket, header, writer);
- return;
+ _session.SendMessage(
+ socket,
+ header,
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.UpgradeFailure
+ },
+ new HResultPayload()
+ {
+ HResult = -1
+ }
+ );
}
-
- _upgradeIds.Add(msg.UpgradeId);
-
+ else
{
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.UpgradeResponse
- }.Write(writer);
- new UpgradeResponse()
- {
- Endpoints =
- [
- EndpointInfo.FromTcp(localIp, networkTransport.TcpPort)
- ],
- MetaData =
- [
- EndpointMetadata.Tcp
- ]
- }.Write(writer);
-
- _session.SendMessage(socket, header, writer);
+ _upgradeIds.Add(msg.UpgradeId);
+
+ _session.SendMessage(
+ socket,
+ ref header,
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.UpgradeResponse
+ },
+ new UpgradeResponse()
+ {
+ Endpoints =
+ [
+ EndpointInfo.FromTcp(localIp, networkTransport.TcpPort)
+ ],
+ MetaData =
+ [
+ EndpointMetadata.Tcp
+ ]
+ }
+ );
}
}
- void HandleUpgradeFinalization(CdpSocket socket, ref EndianReader reader)
+ void HandleUpgradeFinalization(CdpSocket socket, ref HeapEndianReader reader)
{
var msg = EndpointMetadata.ParseArray(ref reader);
_logger.UpgradeFinalization(
msg.Select((x) => x.Type)
);
- CommonHeader header = new()
- {
- Type = MessageType.Connect
- };
-
- EndianWriter writer = new(Endianness.BigEndian);
- new ConnectionHeader()
- {
- ConnectionMode = ConnectionMode.Proximal,
- MessageType = ConnectionType.UpgradeFinalizationResponse
- }.Write(writer);
-
- _session.SendMessage(socket, header, writer);
+ _session.SendMessage(
+ socket,
+ new CommonHeader()
+ {
+ Type = MessageType.Connect
+ },
+ new ConnectionHeader()
+ {
+ ConnectionMode = ConnectionMode.Proximal,
+ MessageType = ConnectionType.UpgradeFinalizationResponse
+ },
+ new EmptyMessage()
+ );
}
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/UpgradeHandler.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/UpgradeHandler.cs
index 0436100d..3ec6471b 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/UpgradeHandler.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Session/Upgrade/UpgradeHandler.cs
@@ -29,8 +29,8 @@ protected set
public bool IsUpgradeSupported
=> (/* ToDo: header131Value & */ _session.ClientCapabilities & _session.HostCapabilities & PeerCapabilities.UpgradeSupport) != 0;
- public bool TryHandleConnect(CdpSocket socket, ConnectionHeader connectionHeader, ref EndianReader reader)
+ public bool TryHandleConnect(CdpSocket socket, ConnectionHeader connectionHeader, ref HeapEndianReader reader)
=> TryHandleConnectInternal(socket, connectionHeader, ref reader);
- protected abstract bool TryHandleConnectInternal(CdpSocket socket, ConnectionHeader connectionHeader, ref EndianReader reader);
+ protected abstract bool TryHandleConnectInternal(CdpSocket socket, ConnectionHeader connectionHeader, ref HeapEndianReader reader);
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/ShortDev.Microsoft.ConnectedDevices.csproj b/lib/ShortDev.Microsoft.ConnectedDevices/ShortDev.Microsoft.ConnectedDevices.csproj
index 33dc3555..c074be3c 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/ShortDev.Microsoft.ConnectedDevices.csproj
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/ShortDev.Microsoft.ConnectedDevices.csproj
@@ -11,6 +11,13 @@
+
+
+
+
+
+
+
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/SpeedMeassure.cs b/lib/ShortDev.Microsoft.ConnectedDevices/SpeedMeassure.cs
new file mode 100644
index 00000000..e09e2286
--- /dev/null
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/SpeedMeassure.cs
@@ -0,0 +1,14 @@
+using System.Diagnostics;
+
+namespace ShortDev.Microsoft.ConnectedDevices;
+
+public ref struct SpeedMeassure(uint length) : IDisposable
+{
+ readonly long _start = Stopwatch.GetTimestamp();
+
+ public readonly void Dispose()
+ {
+ var deltaTime = Stopwatch.GetElapsedTime(_start);
+ Debug.Print($"Speed: {Math.Round(length / 1_000.0 / deltaTime.TotalSeconds)} kByte/s; dT: {deltaTime}");
+ }
+}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Transports/Bluetooth/BLeBeacon.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Transports/Bluetooth/BLeBeacon.cs
index 63ffe903..edf45787 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Transports/Bluetooth/BLeBeacon.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Transports/Bluetooth/BLeBeacon.cs
@@ -20,15 +20,15 @@ public static bool TryParse(byte[] beaconData, [MaybeNullWhen(false)] out BLeBea
if (beaconData == null)
return false;
- EndianReader reader = new(Endianness.BigEndian, beaconData);
+ var reader = EndianReader.FromMemory(Endianness.BigEndian, beaconData);
- var scenarioType = (ScenarioType)reader.ReadByte();
+ var scenarioType = (ScenarioType)reader.ReadUInt8();
if (scenarioType != ScenarioType.Bluetooth)
return false;
- var deviceType = (DeviceType)reader.ReadByte();
+ var deviceType = (DeviceType)reader.ReadUInt8();
- var versionAndFlags = reader.ReadByte();
+ var versionAndFlags = reader.ReadUInt8();
if (versionAndFlags >> 5 != 1)
return false; // wrong version
@@ -37,15 +37,15 @@ public static bool TryParse(byte[] beaconData, [MaybeNullWhen(false)] out BLeBea
return false; // wrong flags
/* deviceStatus */
- _ = (ExtendedDeviceStatus)reader.ReadByte();
+ _ = (ExtendedDeviceStatus)reader.ReadUInt8();
if (flags != BeaconFlags.Public)
return false;
data = new(
deviceType,
- new PhysicalAddress(BinaryConvert.ToReversed(reader.ReadBytes(6))),
- Encoding.UTF8.GetString(reader.ReadToEnd())
+ reader.ReadPhysicalAddress(),
+ reader.ReadString((int)(reader.Stream.Length - reader.Stream.Position - 1))
);
return true;
@@ -53,24 +53,31 @@ public static bool TryParse(byte[] beaconData, [MaybeNullWhen(false)] out BLeBea
public byte[] ToArray()
{
- EndianWriter writer = new(Endianness.LittleEndian);
- writer.Write((byte)ScenarioType.Bluetooth);
- writer.Write((byte)DeviceType);
-
- byte versionAndFlags = (byte)BeaconFlags.Public;
- versionAndFlags |= Constants.BLeBeaconVersion << 5;
- writer.Write(versionAndFlags);
-
- var deviceStatus = ExtendedDeviceStatus.RemoteSessionsNotHosted | ExtendedDeviceStatus.NearShareAuthPolicyPermissive;
- writer.Write((byte)deviceStatus);
-
- writer.Write(BinaryConvert.ToReversed(MacAddress.GetAddressBytes()));
-
- // ToDo: Don't crop characters wider that 2 bytes!
- ReadOnlySpan deviceNameBuffer = Encoding.UTF8.GetBytes(DeviceName);
- var deviceNameLength = Math.Min(deviceNameBuffer.Length, Constants.BLeBeaconDeviceNameMaxByteLength);
- writer.Write(deviceNameBuffer[..deviceNameLength]);
-
- return writer.Buffer.ToArray();
+ var writer = EndianWriter.Create(Endianness.LittleEndian, ConnectedDevicesPlatform.MemoryPool);
+ try
+ {
+ writer.Write((byte)ScenarioType.Bluetooth);
+ writer.Write((byte)DeviceType);
+
+ byte versionAndFlags = (byte)BeaconFlags.Public;
+ versionAndFlags |= Constants.BLeBeaconVersion << 5;
+ writer.Write(versionAndFlags);
+
+ var deviceStatus = ExtendedDeviceStatus.RemoteSessionsNotHosted | ExtendedDeviceStatus.NearShareAuthPolicyPermissive;
+ writer.Write((byte)deviceStatus);
+
+ writer.Write(MacAddress);
+
+ // ToDo: Don't crop characters wider that 2 bytes!
+ ReadOnlySpan deviceNameBuffer = Encoding.UTF8.GetBytes(DeviceName);
+ var deviceNameLength = Math.Min(deviceNameBuffer.Length, Constants.BLeBeaconDeviceNameMaxByteLength);
+ writer.Write(deviceNameBuffer[..deviceNameLength]);
+
+ return writer.Stream.WrittenSpan.ToArray();
+ }
+ finally
+ {
+ writer.Dispose();
+ }
}
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Transports/CdpSocket.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Transports/CdpSocket.cs
index 8ae04a84..15ea2987 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Transports/CdpSocket.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Transports/CdpSocket.cs
@@ -16,6 +16,16 @@ public void SendFragment(ReadOnlySpan fragment)
OutputStream.Flush();
}
+ public void SendFragment(ReadOnlySpan header, ReadOnlySpan payload)
+ {
+ lock (OutputStream)
+ {
+ OutputStream.Write(header);
+ OutputStream.Write(payload);
+ OutputStream.Flush();
+ }
+ }
+
public bool IsClosed { get; private set; }
public Action? Close { private get; set; }
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Transports/MessageFragmenter.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Transports/MessageFragmenter.cs
index 79400bac..edb27c26 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Transports/MessageFragmenter.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Transports/MessageFragmenter.cs
@@ -1,4 +1,5 @@
-using ShortDev.Microsoft.ConnectedDevices.Encryption;
+using ShortDev.IO.Input;
+using ShortDev.Microsoft.ConnectedDevices.Encryption;
using ShortDev.Microsoft.ConnectedDevices.Messages;
using System.Diagnostics;
@@ -41,11 +42,17 @@ static void SendFragment(this IFragmentSender sender, CommonHeader header, ReadO
}
else
{
- EndianWriter writer = new(Endianness.BigEndian);
- header.SetPayloadLength(payload.Length);
- header.Write(writer);
- writer.Write(payload);
- sender.SendFragment(writer.Buffer.AsSpan());
+ var headerWriter = EndianWriter.Create(Endianness.BigEndian, ConnectedDevicesPlatform.MemoryPool);
+ try
+ {
+ header.SetPayloadLength(payload.Length);
+ header.Write(ref headerWriter);
+ sender.SendFragment(headerWriter.Stream.WrittenSpan, payload);
+ }
+ finally
+ {
+ headerWriter.Dispose();
+ }
}
}
}
@@ -55,5 +62,11 @@ public interface IFragmentSender
///
/// Sends a binary fragment.
///
- void SendFragment(ReadOnlySpan fragment);
+ void SendFragment(ReadOnlySpan message);
+
+ ///
+ /// Sends a binary fragment.
+ ///
+ void SendFragment(ReadOnlySpan header, ReadOnlySpan payload)
+ => SendFragment([.. header, .. payload]);
}
diff --git a/lib/ShortDev.Microsoft.ConnectedDevices/Transports/Network/NetworkTransport.cs b/lib/ShortDev.Microsoft.ConnectedDevices/Transports/Network/NetworkTransport.cs
index 6042757b..50f3ecdc 100644
--- a/lib/ShortDev.Microsoft.ConnectedDevices/Transports/Network/NetworkTransport.cs
+++ b/lib/ShortDev.Microsoft.ConnectedDevices/Transports/Network/NetworkTransport.cs
@@ -107,7 +107,7 @@ public async Task Advertise(LocalDeviceInfo deviceInfo, CancellationToken cancel
DiscoveryMessageReceived -= OnMessage;
}
- void OnMessage(IPAddress address, DiscoveryHeader header, EndianReader reader)
+ void OnMessage(IPAddress address, DiscoveryHeader header, ref HeapEndianReader reader)
{
if (header.Type != DiscoveryType.PresenceRequest)
return;
@@ -143,7 +143,7 @@ async Task RunPresenceSendLoop()
}
}
- void OnMessage(IPAddress address, DiscoveryHeader header, EndianReader reader)
+ void OnMessage(IPAddress address, DiscoveryHeader header, ref HeapEndianReader reader)
{
if (header.Type != DiscoveryType.PresenceResponse)
return;
@@ -160,7 +160,7 @@ void OnMessage(IPAddress address, DiscoveryHeader header, EndianReader reader)
}
}
- delegate void DiscoveryMessageReceivedHandler(IPAddress address, DiscoveryHeader header, EndianReader reader);
+ delegate void DiscoveryMessageReceivedHandler(IPAddress address, DiscoveryHeader header, ref HeapEndianReader reader);
event DiscoveryMessageReceivedHandler? DiscoveryMessageReceived;
bool _isListening;
@@ -194,12 +194,12 @@ await Task.Run(async () =>
void HandleMsg(UdpReceiveResult result)
{
- EndianReader reader = new(Endianness.BigEndian, result.Buffer);
+ var reader = EndianReader.FromMemory(Endianness.BigEndian, result.Buffer);
if (!CommonHeader.TryParse(ref reader, out var headers, out _) || headers.Type != MessageType.Discovery)
return;
DiscoveryHeader discoveryHeaders = DiscoveryHeader.Parse(ref reader);
- DiscoveryMessageReceived?.Invoke(result.RemoteEndPoint.Address, discoveryHeaders, reader);
+ DiscoveryMessageReceived?.Invoke(result.RemoteEndPoint.Address, discoveryHeaders, ref reader);
}
}
#endregion
@@ -211,14 +211,21 @@ void SendPresenceRequest()
Type = MessageType.Discovery,
};
- EndianWriter payloadWriter = new(Endianness.BigEndian);
- new DiscoveryHeader()
+ var payloadWriter = EndianWriter.Create(Endianness.BigEndian, ConnectedDevicesPlatform.MemoryPool);
+ try
{
- Type = DiscoveryType.PresenceRequest
- }.Write(payloadWriter);
+ new DiscoveryHeader()
+ {
+ Type = DiscoveryType.PresenceRequest
+ }.Write(ref payloadWriter);
- new UdpFragmentSender(_udpclient, new IPEndPoint(IPAddress.Broadcast, UdpPort))
- .SendMessage(header, payloadWriter.Buffer.AsSpan());
+ new UdpFragmentSender(_udpclient, new IPEndPoint(IPAddress.Broadcast, UdpPort))
+ .SendMessage(header, payloadWriter.Stream.WrittenSpan);
+ }
+ finally
+ {
+ payloadWriter.Dispose();
+ }
}
void SendPresenceResponse(IPAddress device, PresenceResponse response)
@@ -228,15 +235,22 @@ void SendPresenceResponse(IPAddress device, PresenceResponse response)
Type = MessageType.Discovery
};
- EndianWriter payloadWriter = new(Endianness.BigEndian);
- new DiscoveryHeader()
+ var payloadWriter = EndianWriter.Create(Endianness.BigEndian, ConnectedDevicesPlatform.MemoryPool);
+ try
{
- Type = DiscoveryType.PresenceResponse
- }.Write(payloadWriter);
- response.Write(payloadWriter);
+ new DiscoveryHeader()
+ {
+ Type = DiscoveryType.PresenceResponse
+ }.Write(ref payloadWriter);
+ response.Write(ref payloadWriter);
- new UdpFragmentSender(_udpclient, new IPEndPoint(device, UdpPort))
- .SendMessage(header, payloadWriter.Buffer.AsSpan());
+ new UdpFragmentSender(_udpclient, new IPEndPoint(device, UdpPort))
+ .SendMessage(header, payloadWriter.Stream.WrittenSpan);
+ }
+ finally
+ {
+ payloadWriter.Dispose();
+ }
}
sealed class UdpFragmentSender(UdpClient client, IPEndPoint receiver) : IFragmentSender
diff --git a/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/GlobalUsings.cs b/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/GlobalUsings.cs
new file mode 100644
index 00000000..baf2d972
--- /dev/null
+++ b/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/GlobalUsings.cs
@@ -0,0 +1 @@
+global using BenchmarkDotNet.Attributes;
diff --git a/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/Program.cs b/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/Program.cs
new file mode 100644
index 00000000..05b2cd65
--- /dev/null
+++ b/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/Program.cs
@@ -0,0 +1,5 @@
+using BenchmarkDotNet.Running;
+using System.Reflection;
+
+BenchmarkSwitcher.FromAssembly(Assembly.GetExecutingAssembly())
+ .RunAllJoined(args: args);
diff --git a/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/ShortDev.Microsoft.ConnectedDevices.Benchmarks.csproj b/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/ShortDev.Microsoft.ConnectedDevices.Benchmarks.csproj
new file mode 100644
index 00000000..aae7a51c
--- /dev/null
+++ b/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/ShortDev.Microsoft.ConnectedDevices.Benchmarks.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+ ShortDev.Microsoft.ConnectedDevices
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/Transports/CryptorBenchmark.cs b/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/Transports/CryptorBenchmark.cs
new file mode 100644
index 00000000..61d100f4
--- /dev/null
+++ b/tests/ShortDev.Microsoft.ConnectedDevices.Benchmarks/Transports/CryptorBenchmark.cs
@@ -0,0 +1,36 @@
+using ShortDev.Microsoft.ConnectedDevices.Encryption;
+using ShortDev.Microsoft.ConnectedDevices.Messages;
+using System.Security.Cryptography;
+
+namespace ShortDev.Microsoft.ConnectedDevices.Transports;
+
+public class CryptorBenchmark
+{
+ readonly CommonHeader _header = new();
+ readonly Sender _sender = new();
+ readonly CdpCryptor _cryptor = new(RandomNumberGenerator.GetBytes(64));
+
+ [Params(100, 500, MessageFragmenter.DefaultMessageFragmentSize, 20_000)]
+ public int BufferSize { get; set; }
+
+ byte[] _buffer = [];
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ _buffer = RandomNumberGenerator.GetBytes(BufferSize);
+ }
+
+ [Benchmark]
+ public void Speed()
+ {
+ _cryptor.EncryptMessage(_sender, _header, _buffer);
+ }
+
+ sealed class Sender : IFragmentSender
+ {
+ public void SendFragment(ReadOnlySpan message) { }
+
+ public void SendFragment(ReadOnlySpan header, ReadOnlySpan payload) { }
+ }
+}
diff --git a/tests/ShortDev.Microsoft.ConnectedDevices.Test/CryptorTest.cs b/tests/ShortDev.Microsoft.ConnectedDevices.Test/CryptorTest.cs
index 851dc74f..9381595c 100644
--- a/tests/ShortDev.Microsoft.ConnectedDevices.Test/CryptorTest.cs
+++ b/tests/ShortDev.Microsoft.ConnectedDevices.Test/CryptorTest.cs
@@ -22,10 +22,10 @@ public void Decrypt_ShouldYieldSameAsEncrypt()
cryptor.EncryptMessage(fragmentSender, header, payload);
Assert.NotNull(fragmentSender.Fragment);
- EndianReader reader = new(Endianness.BigEndian, fragmentSender.Fragment.Value.Span);
+ var reader = EndianReader.FromSpan(Endianness.BigEndian, fragmentSender.Fragment.Value.Span);
header = CommonHeader.Parse(ref reader);
- var readerContent = reader.ReadToEnd();
+ var readerContent = fragmentSender.Fragment.Value.Span[(int)reader.Stream.Position..];
var encryptedPayload = readerContent[..^Constants.HMacSize];
var hmac = readerContent[^Constants.HMacSize..];
diff --git a/tests/ShortDev.Microsoft.ConnectedDevices.Test/Messages/CommonHeaderTest.cs b/tests/ShortDev.Microsoft.ConnectedDevices.Test/Messages/CommonHeaderTest.cs
index 44168726..c53a90a5 100644
--- a/tests/ShortDev.Microsoft.ConnectedDevices.Test/Messages/CommonHeaderTest.cs
+++ b/tests/ShortDev.Microsoft.ConnectedDevices.Test/Messages/CommonHeaderTest.cs
@@ -1,4 +1,5 @@
using ShortDev.Microsoft.ConnectedDevices.Messages;
+using System.Buffers;
namespace ShortDev.Microsoft.ConnectedDevices.Test.Messages;
@@ -7,36 +8,48 @@ public class CommonHeaderTest
[Fact]
public void CalcSize_YieldsCorrectResult_WhenNoHeaders()
{
- EndianWriter writer = new(Endianness.BigEndian);
-
- CommonHeader header = new();
- header.Write(writer);
- var expected = writer.Buffer.Size;
+ var writer = EndianWriter.Create(Endianness.BigEndian, ArrayPool.Shared);
+ try
+ {
+ CommonHeader header = new();
+ header.Write(ref writer);
+ var expected = writer.Stream.WrittenSpan.Length;
- var actual = header.CalcSize();
+ var actual = header.CalcSize();
- Assert.Equal(expected, actual);
+ Assert.Equal(expected, actual);
+ }
+ finally
+ {
+ writer.Dispose();
+ }
}
[Fact]
public void CalcSize_YieldsCorrectResult_WhenWithHeaders()
{
- EndianWriter writer = new(Endianness.BigEndian);
-
- CommonHeader header = new()
+ var writer = EndianWriter.Create(Endianness.BigEndian, ArrayPool.Shared);
+ try
{
- Type = MessageType.Connect,
- AdditionalHeaders = {
+ CommonHeader header = new()
+ {
+ Type = MessageType.Connect,
+ AdditionalHeaders = {
AdditionalHeader.FromUInt32(AdditionalHeaderType.Header129, 0x70_00_00_03),
AdditionalHeader.FromUInt64(AdditionalHeaderType.PeerCapabilities, (ulong)PeerCapabilities.All),
AdditionalHeader.FromUInt64(AdditionalHeaderType.Header131, 6u)
}
- };
- header.Write(writer);
- var expected = writer.Buffer.Size;
+ };
+ header.Write(ref writer);
+ var expected = writer.Stream.WrittenSpan.Length;
- var actual = header.CalcSize();
+ var actual = header.CalcSize();
- Assert.Equal(expected, actual);
+ Assert.Equal(expected, actual);
+ }
+ finally
+ {
+ writer.Dispose();
+ }
}
}
diff --git a/tests/ShortDev.Microsoft.ConnectedDevices.Test/SerializationTest.cs b/tests/ShortDev.Microsoft.ConnectedDevices.Test/SerializationTest.cs
index e7f91ba5..d8502a1e 100644
--- a/tests/ShortDev.Microsoft.ConnectedDevices.Test/SerializationTest.cs
+++ b/tests/ShortDev.Microsoft.ConnectedDevices.Test/SerializationTest.cs
@@ -1,7 +1,9 @@
+using ShortDev.IO.Output;
using ShortDev.Microsoft.ConnectedDevices.Encryption;
using ShortDev.Microsoft.ConnectedDevices.Messages;
using ShortDev.Microsoft.ConnectedDevices.NearShare.Messages;
using ShortDev.Microsoft.ConnectedDevices.Serialization;
+using System.Buffers;
namespace ShortDev.Microsoft.ConnectedDevices.Test;
@@ -20,9 +22,7 @@ public static IEnumerable> GenerateMsgTypes()
foreach (var type in assembly.DefinedTypes)
{
if (
- IsOk(typeof(ICdpHeader<>), type) ||
- IsOk(typeof(ICdpPayload<>), type) &&
- type.Name != "PresenceResponse"
+ IsOk(typeof(IBinaryWritable), type) && IsOk(typeof(IBinaryParsable<>), type)
)
yield return type;
}
@@ -31,7 +31,9 @@ static bool IsOk(Type TInterface, Type TClass)
{
foreach (var item in TClass.GetInterfaces())
{
- if (item.IsGenericType && item.GetGenericTypeDefinition() == TInterface)
+ if (item == TInterface)
+ return true;
+ else if (item.IsGenericType && item.GetGenericTypeDefinition() == TInterface)
return true;
}
return false;
@@ -49,7 +51,7 @@ public void ParseMessage_ShouldYieldSameAsWritten(Type type)
genericMethod.Invoke(null, [Endianness.LittleEndian]);
genericMethod.Invoke(null, [Endianness.BigEndian]);
- static void TestRun(Endianness endianness) where T : ICdpSerializable
+ static void TestRun(Endianness endianness) where T : IBinaryWritable, IBinaryParsable
{
Type type = typeof(T);
@@ -57,21 +59,35 @@ static void TestRun(Endianness endianness) where T : ICdpSerializable
var instance = TestValueGenerator.RandomValue();
// write - 1st pass
- EndianWriter writer = new(endianness);
- instance.Write(writer);
- var writtenMemory1 = writer.Buffer.AsMemory();
-
- // parse
- EndianReader reader = new(endianness, writtenMemory1.Span);
- var parsedObject = T.Parse(ref reader);
-
- // write - 2nd pass
- writer = new(endianness);
- parsedObject.Write(writer);
- var writtenMemory2 = writer.Buffer.AsMemory();
-
- // assert
- Assert.True(writtenMemory1.Span.SequenceEqual(writtenMemory2.Span));
+ var writer = EndianWriter.Create(endianness, ArrayPool.Shared);
+ try
+ {
+ instance.Write(ref writer);
+ var writtenMemory1 = writer.Stream.WrittenMemory;
+
+ // parse
+ var reader = EndianReader.FromSpan(endianness, writtenMemory1.Span);
+ var parsedObject = T.Parse(ref reader);
+
+ // write - 2nd pass
+ var writer2 = EndianWriter.Create(endianness, ArrayPool.Shared);
+ try
+ {
+ parsedObject.Write(ref writer2);
+ var writtenMemory2 = writer2.Stream.WrittenMemory;
+
+ // assert
+ Assert.True(writtenMemory1.Span.SequenceEqual(writtenMemory2.Span));
+ }
+ finally
+ {
+ writer2.Dispose();
+ }
+ }
+ finally
+ {
+ writer.Dispose();
+ }
}
}
@@ -84,14 +100,28 @@ public void ValueSet()
response.Add("BlobPosition", (ulong)2);
response.Add("DataBlob", (List)[42]);
- EndianWriter writer1 = new(Endianness.BigEndian);
- response.Write(writer1);
+ var writer1 = EndianWriter.Create(Endianness.BigEndian, ArrayPool.Shared);
+ try
+ {
+ response.Write(ref writer1);
- EndianWriter writer2 = new(Endianness.BigEndian);
- FetchDataResponse.Write(writer2, 1, 2, length: 1, out var blob);
- blob[0] = 42;
+ var writer2 = EndianWriter.Create(Endianness.BigEndian, ArrayPool.Shared);
+ try
+ {
+ FetchDataResponse.Write(ref writer2, 1, 2, length: 1, out var blob);
+ blob[0] = 42;
- Assert.Equal(1, blob.Length);
- Assert.Equal(writer1.Buffer.ToArray(), writer2.Buffer.ToArray());
+ Assert.Equal(1, blob.Length);
+ Assert.Equal(writer1.Stream.WrittenMemory, writer2.Stream.WrittenMemory);
+ }
+ finally
+ {
+ writer2.Dispose();
+ }
+ }
+ finally
+ {
+ writer1.Dispose();
+ }
}
}
\ No newline at end of file
diff --git a/tests/ShortDev.Microsoft.ConnectedDevices.Test/ShortDev.Microsoft.ConnectedDevices.Test.csproj b/tests/ShortDev.Microsoft.ConnectedDevices.Test/ShortDev.Microsoft.ConnectedDevices.Test.csproj
index 93dc3f19..00c0b1b0 100644
--- a/tests/ShortDev.Microsoft.ConnectedDevices.Test/ShortDev.Microsoft.ConnectedDevices.Test.csproj
+++ b/tests/ShortDev.Microsoft.ConnectedDevices.Test/ShortDev.Microsoft.ConnectedDevices.Test.csproj
@@ -24,4 +24,10 @@
+
+
+
+
+
+