aboutsummaryrefslogtreecommitdiff
path: root/lib/Net.Messaging.FBM/src/Client
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2023-01-28 13:40:54 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2023-01-28 13:40:54 -0500
commita4d1d5acff5760a9432117cae634ca98881ad0ec (patch)
treedcc96b9d1d00ff3038f578bba2f434b9bfd31e21 /lib/Net.Messaging.FBM/src/Client
parenta5d88f2cf08ea3aad2c8802bdc416e7b40c0f204 (diff)
Fix FBMMessageHeader default and session connection status
Diffstat (limited to 'lib/Net.Messaging.FBM/src/Client')
-rw-r--r--lib/Net.Messaging.FBM/src/Client/FBMBuffer.cs30
-rw-r--r--lib/Net.Messaging.FBM/src/Client/FBMRequest.cs5
-rw-r--r--lib/Net.Messaging.FBM/src/Client/Helpers.cs305
3 files changed, 20 insertions, 320 deletions
diff --git a/lib/Net.Messaging.FBM/src/Client/FBMBuffer.cs b/lib/Net.Messaging.FBM/src/Client/FBMBuffer.cs
index 95a5bb8..fac41a6 100644
--- a/lib/Net.Messaging.FBM/src/Client/FBMBuffer.cs
+++ b/lib/Net.Messaging.FBM/src/Client/FBMBuffer.cs
@@ -24,6 +24,9 @@
using System;
using System.Buffers;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
using VNLib.Utils.IO;
namespace VNLib.Net.Messaging.FBM.Client
@@ -31,7 +34,7 @@ namespace VNLib.Net.Messaging.FBM.Client
/// <summary>
/// Represents a shared internal character and bianry buffer for
/// </summary>
- internal sealed class FBMBuffer : IDisposable
+ internal sealed class FBMBuffer : IFBMHeaderBuffer, IDisposable
{
private readonly IMemoryOwner<byte> Handle;
@@ -70,16 +73,7 @@ namespace VNLib.Net.Messaging.FBM.Client
//Return the internal writer
return _writer;
}
-
- /// <summary>
- /// Gets the buffer manager for managing response headers
- /// </summary>
- /// <returns>The <see cref="FBMHeaderBuffer"/> for managing response header buffers</returns>
- public FBMHeaderBuffer GetResponseHeaderBuffer()
- {
- //Get a buffer wrapper around the memory handle
- return new FBMHeaderBuffer(Handle.Memory);
- }
+
public void Dispose()
{
@@ -100,6 +94,20 @@ namespace VNLib.Net.Messaging.FBM.Client
Helpers.WriteMessageid(RequestBuffer, messageId);
}
+ ///<inheritdoc/>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ Span<char> IFBMHeaderBuffer.GetSpan(int offset, int count)
+ {
+ //Get the character span
+ Span<char> span = MemoryMarshal.Cast<byte, char>(Handle.Memory.Span);
+ return span.Slice(offset, count);
+ }
+
+ ///<inheritdoc/>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ Span<char> IFBMHeaderBuffer.GetSpan() => MemoryMarshal.Cast<byte, char>(Handle.Memory.Span);
+
+
private sealed class BinaryRequestAccumulator : IDataAccumulator<byte>
{
private readonly int Size;
diff --git a/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs b/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs
index aaf3926..01302a9 100644
--- a/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs
+++ b/lib/Net.Messaging.FBM/src/Client/FBMRequest.cs
@@ -210,12 +210,9 @@ namespace VNLib.Net.Messaging.FBM.Client
* The headers are read into a list of key-value pairs and the stream
* is positioned to the start of the message body
*/
-
- //Get the response header buffer for parsing
- FBMHeaderBuffer headerBuf = Buffer.GetResponseHeaderBuffer();
//Parse message headers
- HeaderParseError statusFlags = Helpers.ParseHeaders(Response, in headerBuf, ResponseHeaderList, HeaderEncoding);
+ HeaderParseError statusFlags = Helpers.ParseHeaders(Response, Buffer, ResponseHeaderList, HeaderEncoding);
//return response structure
return new(Response, statusFlags, ResponseHeaderList, OnResponseDisposed);
diff --git a/lib/Net.Messaging.FBM/src/Client/Helpers.cs b/lib/Net.Messaging.FBM/src/Client/Helpers.cs
deleted file mode 100644
index 0b9e7bd..0000000
--- a/lib/Net.Messaging.FBM/src/Client/Helpers.cs
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
-* Copyright (c) 2022 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Net.Messaging.FBM
-* File: Helpers.cs
-*
-* Helpers.cs is part of VNLib.Net.Messaging.FBM which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Net.Messaging.FBM is free software: you can redistribute it and/or modify
-* it under the terms of the GNU Affero General Public License as
-* published by the Free Software Foundation, either version 3 of the
-* License, or (at your option) any later version.
-*
-* VNLib.Net.Messaging.FBM is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU Affero General Public License for more details.
-*
-* You should have received a copy of the GNU Affero General Public License
-* along with this program. If not, see https://www.gnu.org/licenses/.
-*/
-
-using System;
-using System.IO;
-using System.Text;
-using System.Buffers.Binary;
-using System.Collections.Generic;
-using System.Security.Cryptography;
-using System.Runtime.CompilerServices;
-
-using VNLib.Utils;
-using VNLib.Utils.IO;
-using VNLib.Utils.Memory;
-using VNLib.Utils.Extensions;
-
-namespace VNLib.Net.Messaging.FBM
-{
- /// <summary>
- /// Contains FBM library helper methods
- /// </summary>
- public static class Helpers
- {
- /// <summary>
- /// The message-id of a connection control frame / out of band message
- /// </summary>
- public const int CONTROL_FRAME_MID = -500;
-
- /// <summary>
- /// Gets the default header character encoding instance
- /// </summary>
- public static Encoding DefaultEncoding { get; } = Encoding.UTF8;
-
- /// <summary>
- /// The FBM protocol header line termination symbols
- /// </summary>
- public static ReadOnlyMemory<byte> Termination { get; } = new byte[] { 0xFF, 0xF1 };
-
- /// <summary>
- /// Parses the header line for a message-id
- /// </summary>
- /// <param name="line">A sequence of bytes that make up a header line</param>
- /// <returns>The message-id if parsed, -1 if message-id is not valid</returns>
- public static int GetMessageId(ReadOnlySpan<byte> line)
- {
- //Make sure the message line is large enough to contain a message-id
- if (line.Length < 1 + sizeof(int))
- {
- return -1;
- }
-
- //The first byte should be the header id
- HeaderCommand headerId = (HeaderCommand)line[0];
-
- //Make sure the headerid is set
- if (headerId != HeaderCommand.MessageId)
- {
- return -2;
- }
-
- //Get the messageid after the header byte
- ReadOnlySpan<byte> messageIdSegment = line.Slice(1, sizeof(int));
-
- //get the messageid from the messageid segment
- return BinaryPrimitives.ReadInt32BigEndian(messageIdSegment);
- }
-
- /// <summary>
- /// Appends the message id header to the accumulator
- /// </summary>
- /// <param name="accumulator">The accumulatore to write the message id to</param>
- /// <param name="messageid">The message id to write to the accumulator</param>
- public static void WriteMessageid(IDataAccumulator<byte> accumulator, int messageid)
- {
- //Alloc buffer for message id + the message id header
- Span<byte> buffer = stackalloc byte[sizeof(int) + 1];
-
- //Set 1st byte as message id
- buffer[0] = (byte)HeaderCommand.MessageId;
-
- //Write the message id as a big-endian message
- BinaryPrimitives.WriteInt32BigEndian(buffer[1..], messageid);
-
- //Write the header and message id + the trailing termination
- accumulator.Append(buffer);
-
- WriteTermination(accumulator);
- }
-
-
- /// <summary>
- /// Alloctes a random integer to use as a message id
- /// </summary>
- public static int RandomMessageId => RandomNumberGenerator.GetInt32(1, int.MaxValue);
-
- /// <summary>
- /// Gets the remaining data after the current position of the stream.
- /// </summary>
- /// <param name="response">The stream to segment</param>
- /// <returns>The remaining data segment</returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ReadOnlySpan<byte> GetRemainingData(VnMemoryStream response)
- {
- return response.AsSpan()[(int)response.Position..];
- }
-
- /// <summary>
- /// Reads the next available line from the response message
- /// </summary>
- /// <param name="response"></param>
- /// <returns>The read line</returns>
- public static ReadOnlySpan<byte> ReadLine(VnMemoryStream response)
- {
- //Get the span from the current stream position to end of the stream
- ReadOnlySpan<byte> line = GetRemainingData(response);
- //Search for next line termination
- int index = line.IndexOf(Termination.Span);
- if (index == -1)
- {
- return ReadOnlySpan<byte>.Empty;
- }
- //Update stream position to end of termination
- response.Seek(index + Termination.Length, SeekOrigin.Current);
- //slice up line and exclude the termination
- return line[..index];
- }
-
- /// <summary>
- /// Parses headers from the request stream, stores headers from the buffer into the
- /// header collection
- /// </summary>
- /// <param name="vms">The FBM packet buffer</param>
- /// <param name="buffer">The header character buffer to write headers to</param>
- /// <param name="headers">The collection to store headers in</param>
- /// <param name="encoding">The encoding type used to deocde header values</param>
- /// <returns>The results of the parse operation</returns>
- internal static HeaderParseError ParseHeaders(VnMemoryStream vms, in FBMHeaderBuffer buffer, ICollection<FBMMessageHeader> headers, Encoding encoding)
- {
- HeaderParseError status = HeaderParseError.None;
-
- //Get a sliding window writer over the enitre buffer
- ForwardOnlyWriter<char> writer = new(buffer.GetSpan());
-
- //Accumulate headers
- while (true)
- {
- //Read the next line from the current stream
- ReadOnlySpan<byte> line = ReadLine(vms);
-
- if (line.IsEmpty)
- {
- //Done reading headers
- break;
- }
-
- //Read the header command from the next line
- HeaderCommand cmd = GetHeaderCommand(line);
-
- //Write the next header value from the line to the remaining space in the buffer
- ERRNO charsRead = GetHeaderValue(line, writer.Remaining, encoding);
-
- if (charsRead < 0)
- {
- //Out of buffer space
- status |= HeaderParseError.HeaderOutOfMem;
- break;
- }
- else if (!charsRead)
- {
- //Invalid header
- status |= HeaderParseError.InvalidHeaderRead;
- }
- else
- {
- //Use the writer to capture the offset, and the character size
- FBMMessageHeader header = new(buffer, cmd, writer.Written, (int)charsRead);
-
- //Store header as a read-only sequence
- headers.Add(header);
-
- //Advance the writer
- writer.Advance(charsRead);
- }
- }
- return status;
- }
-
- /// <summary>
- /// Gets a <see cref="HeaderCommand"/> enum from the first byte of the message
- /// </summary>
- /// <param name="line"></param>
- /// <returns>The <see cref="HeaderCommand"/> enum value from hte first byte of the message</returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static HeaderCommand GetHeaderCommand(ReadOnlySpan<byte> line)
- {
- return (HeaderCommand)line[0];
- }
-
- /// <summary>
- /// Gets the value of the header following the colon bytes in the specifed
- /// data message data line
- /// </summary>
- /// <param name="line">The message header line to get the value of</param>
- /// <param name="output">The output character buffer to write characters to</param>
- /// <param name="encoding">The encoding to decode the specified data with</param>
- /// <returns>The number of characters encoded or -1 if the output buffer is too small</returns>
- public static ERRNO GetHeaderValue(ReadOnlySpan<byte> line, Span<char> output, Encoding encoding)
- {
- //Get the data following the header byte
- ReadOnlySpan<byte> value = line[1..];
- //Calculate the character account
- int charCount = encoding.GetCharCount(value);
- //Determine if the output buffer is large enough
- if (charCount > output.Length)
- {
- return -1;
- }
- //Decode the characters and return the char count
- _ = encoding.GetChars(value, output);
- return charCount;
- }
-
-
- /// <summary>
- /// Ends the header section of the request and appends the message body to
- /// the end of the request
- /// </summary>
- /// <param name="buffer"></param>
- /// <param name="body">The message body to send with request</param>
- /// <exception cref="OutOfMemoryException"></exception>
- public static void WriteBody(IDataAccumulator<byte> buffer, ReadOnlySpan<byte> body)
- {
- //start with termination
- WriteTermination(buffer);
- //Write the body
- buffer.Append(body);
- }
-
-
- /// <summary>
- /// Rounds the requested byte size up to the 1kb
- /// number of bytes
- /// </summary>
- /// <param name="byteSize">The number of bytes to get the rounded 1kb size of</param>
- /// <returns>The number of bytes equivalent to the requested byte size rounded to the next 1kb size</returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static nint ToNearestKb(nint byteSize)
- {
- //Get page count by dividing count by number of pages
- nint kbs = (nint)Math.Ceiling(byteSize / (double)1024);
-
- //Multiply back to page sizes
- return kbs * 1024;
- }
-
-
- /// <summary>
- /// Writes a line termination to the message buffer
- /// </summary>
- /// <param name="buffer"></param>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteTermination(IDataAccumulator<byte> buffer) => buffer.Append(Termination.Span);
-
- /// <summary>
- /// Appends an arbitrary header to the current request buffer
- /// </summary>
- /// <param name="buffer"></param>
- /// <param name="header">The <see cref="HeaderCommand"/> of the header</param>
- /// <param name="value">The value of the header</param>
- /// <param name="encoding">Encoding to use when writing character message</param>
- /// <exception cref="ArgumentException"></exception>
- public static void WriteHeader(IDataAccumulator<byte> buffer, byte header, ReadOnlySpan<char> value, Encoding encoding)
- {
- //Write header command enum value
- buffer.Append(header);
- //Convert the characters to binary and write to the buffer
- int written = encoding.GetBytes(value, buffer.Remaining);
- //Advance the buffer
- buffer.Advance(written);
- //Write termination (0)
- WriteTermination(buffer);
- }
- }
-}