From a4d1d5acff5760a9432117cae634ca98881ad0ec Mon Sep 17 00:00:00 2001 From: vnugent Date: Sat, 28 Jan 2023 13:40:54 -0500 Subject: Fix FBMMessageHeader default and session connection status --- lib/Net.Messaging.FBM/src/Client/FBMBuffer.cs | 30 ++- lib/Net.Messaging.FBM/src/Client/FBMRequest.cs | 5 +- lib/Net.Messaging.FBM/src/Client/Helpers.cs | 305 ------------------------- 3 files changed, 20 insertions(+), 320 deletions(-) delete mode 100644 lib/Net.Messaging.FBM/src/Client/Helpers.cs (limited to 'lib/Net.Messaging.FBM/src/Client') 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 /// /// Represents a shared internal character and bianry buffer for /// - internal sealed class FBMBuffer : IDisposable + internal sealed class FBMBuffer : IFBMHeaderBuffer, IDisposable { private readonly IMemoryOwner Handle; @@ -70,16 +73,7 @@ namespace VNLib.Net.Messaging.FBM.Client //Return the internal writer return _writer; } - - /// - /// Gets the buffer manager for managing response headers - /// - /// The for managing response header buffers - 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); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + Span IFBMHeaderBuffer.GetSpan(int offset, int count) + { + //Get the character span + Span span = MemoryMarshal.Cast(Handle.Memory.Span); + return span.Slice(offset, count); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + Span IFBMHeaderBuffer.GetSpan() => MemoryMarshal.Cast(Handle.Memory.Span); + + private sealed class BinaryRequestAccumulator : IDataAccumulator { 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 -{ - /// - /// Contains FBM library helper methods - /// - public static class Helpers - { - /// - /// The message-id of a connection control frame / out of band message - /// - public const int CONTROL_FRAME_MID = -500; - - /// - /// Gets the default header character encoding instance - /// - public static Encoding DefaultEncoding { get; } = Encoding.UTF8; - - /// - /// The FBM protocol header line termination symbols - /// - public static ReadOnlyMemory Termination { get; } = new byte[] { 0xFF, 0xF1 }; - - /// - /// Parses the header line for a message-id - /// - /// A sequence of bytes that make up a header line - /// The message-id if parsed, -1 if message-id is not valid - public static int GetMessageId(ReadOnlySpan 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 messageIdSegment = line.Slice(1, sizeof(int)); - - //get the messageid from the messageid segment - return BinaryPrimitives.ReadInt32BigEndian(messageIdSegment); - } - - /// - /// Appends the message id header to the accumulator - /// - /// The accumulatore to write the message id to - /// The message id to write to the accumulator - public static void WriteMessageid(IDataAccumulator accumulator, int messageid) - { - //Alloc buffer for message id + the message id header - Span 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); - } - - - /// - /// Alloctes a random integer to use as a message id - /// - public static int RandomMessageId => RandomNumberGenerator.GetInt32(1, int.MaxValue); - - /// - /// Gets the remaining data after the current position of the stream. - /// - /// The stream to segment - /// The remaining data segment - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan GetRemainingData(VnMemoryStream response) - { - return response.AsSpan()[(int)response.Position..]; - } - - /// - /// Reads the next available line from the response message - /// - /// - /// The read line - public static ReadOnlySpan ReadLine(VnMemoryStream response) - { - //Get the span from the current stream position to end of the stream - ReadOnlySpan line = GetRemainingData(response); - //Search for next line termination - int index = line.IndexOf(Termination.Span); - if (index == -1) - { - return ReadOnlySpan.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]; - } - - /// - /// Parses headers from the request stream, stores headers from the buffer into the - /// header collection - /// - /// The FBM packet buffer - /// The header character buffer to write headers to - /// The collection to store headers in - /// The encoding type used to deocde header values - /// The results of the parse operation - internal static HeaderParseError ParseHeaders(VnMemoryStream vms, in FBMHeaderBuffer buffer, ICollection headers, Encoding encoding) - { - HeaderParseError status = HeaderParseError.None; - - //Get a sliding window writer over the enitre buffer - ForwardOnlyWriter writer = new(buffer.GetSpan()); - - //Accumulate headers - while (true) - { - //Read the next line from the current stream - ReadOnlySpan 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; - } - - /// - /// Gets a enum from the first byte of the message - /// - /// - /// The enum value from hte first byte of the message - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static HeaderCommand GetHeaderCommand(ReadOnlySpan line) - { - return (HeaderCommand)line[0]; - } - - /// - /// Gets the value of the header following the colon bytes in the specifed - /// data message data line - /// - /// The message header line to get the value of - /// The output character buffer to write characters to - /// The encoding to decode the specified data with - /// The number of characters encoded or -1 if the output buffer is too small - public static ERRNO GetHeaderValue(ReadOnlySpan line, Span output, Encoding encoding) - { - //Get the data following the header byte - ReadOnlySpan 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; - } - - - /// - /// Ends the header section of the request and appends the message body to - /// the end of the request - /// - /// - /// The message body to send with request - /// - public static void WriteBody(IDataAccumulator buffer, ReadOnlySpan body) - { - //start with termination - WriteTermination(buffer); - //Write the body - buffer.Append(body); - } - - - /// - /// Rounds the requested byte size up to the 1kb - /// number of bytes - /// - /// The number of bytes to get the rounded 1kb size of - /// The number of bytes equivalent to the requested byte size rounded to the next 1kb size - [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; - } - - - /// - /// Writes a line termination to the message buffer - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteTermination(IDataAccumulator buffer) => buffer.Append(Termination.Span); - - /// - /// Appends an arbitrary header to the current request buffer - /// - /// - /// The of the header - /// The value of the header - /// Encoding to use when writing character message - /// - public static void WriteHeader(IDataAccumulator buffer, byte header, ReadOnlySpan 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); - } - } -} -- cgit