From 179193b9059cb8850e93b18b46b16545fd723b57 Mon Sep 17 00:00:00 2001 From: mullerj Date: Thu, 6 Jun 2024 20:12:49 -0400 Subject: [PATCH 1/9] Updated EnqueuesData test to include different offsets and lengths --- .../NormSessionTests.cs | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs b/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs index 1470c07..767efc5 100644 --- a/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs +++ b/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs @@ -186,7 +186,7 @@ public void StopsReceiver() /// Generates text content /// /// The generated text content - private string GenerateTextContent() + private static string GenerateTextContent() { var faker = new Faker(); return faker.Lorem.Paragraph(); @@ -398,17 +398,46 @@ public void ReceivesFileWithRename() } } - [SkippableFact(typeof(IOException))] - public void EnqueuesData() + public static IEnumerable GenerateData() + { + var data = new List(); + + var content = GenerateTextContent(); + var expectedContent = content; + var offset = 0; + var length = content.Length; + data.Add(new object[] { content, expectedContent, offset, length }); + + var faker = new Faker(); + length = faker.Random.Int(content.Length / 2, content.Length - 1); + expectedContent = content.Substring(offset, length); + data.Add(new object[] { content, expectedContent, offset, length }); + + offset = faker.Random.Int(1, content.Length - 1 / 2); + length = content.Length - offset; + expectedContent = content.Substring(offset, length); + data.Add(new object[] { content, expectedContent, offset, length }); + + offset = faker.Random.Int(1, content.Length - 1 / 2); + length = faker.Random.Int(1, content.Length - offset); + expectedContent = content.Substring(offset, length); + data.Add(new object[] { content, expectedContent, offset, length }); + + return data; + } + + [SkippableTheory(typeof(IOException))] + [MemberData(nameof(GenerateData))] + public void EnqueuesData(string content, string expectedContent, int offset, int length) { StartSender(); //Create data to write to the stream - var expectedContent = GenerateTextContent(); - byte[] expectedData = Encoding.ASCII.GetBytes(expectedContent); + var data = Encoding.ASCII.GetBytes(content); + var expectedData = Encoding.ASCII.GetBytes(expectedContent); try { - var normData = _normSession.DataEnqueue(expectedData, 0, expectedData.Length); + var normData = _normSession.DataEnqueue(data, offset, length); var expectedEventTypes = new List { NormEventType.NORM_TX_OBJECT_SENT, NormEventType.NORM_TX_QUEUE_EMPTY }; var actualEventTypes = GetEvents().Select(e => e.Type).ToList(); Assert.Equal(expectedEventTypes, actualEventTypes); From 5fc72ef086e0ac7e4f1bcf88ce000d1582bca3d0 Mon Sep 17 00:00:00 2001 From: mullerj Date: Mon, 10 Jun 2024 22:01:15 -0400 Subject: [PATCH 2/9] Converted ReceivesData test to theory --- .../NormSessionTests.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs b/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs index 767efc5..01eae9d 100644 --- a/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs +++ b/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs @@ -456,8 +456,9 @@ public void EnqueuesData(string content, string expectedContent, int offset, int } } - [SkippableFact(typeof(IOException))] - public void ReceivesData() + [SkippableTheory(typeof(IOException))] + [MemberData(nameof(GenerateData))] + public void ReceivesData(string content, string expectedContent, int offset, int length) { _normSession.SetLoopback(true); StartSender(); @@ -470,12 +471,12 @@ public void ReceivesData() _normInstance.SetCacheDirectory(cachePath); //Create data to be sent - var expectedContent = GenerateTextContent(); + var data = Encoding.ASCII.GetBytes(content); var expectedData = Encoding.ASCII.GetBytes(expectedContent); try { - var normData = _normSession.DataEnqueue(expectedData, 0, expectedData.Length); + var normData = _normSession.DataEnqueue(data, offset, length); var expectedEventTypes = new List { NormEventType.NORM_REMOTE_SENDER_NEW, From 472014ed86163701b4e2dc0a907ed62e81d99096 Mon Sep 17 00:00:00 2001 From: mullerj Date: Mon, 10 Jun 2024 22:24:01 -0400 Subject: [PATCH 3/9] Added argument validation to DataEnqueue --- .../src/Mil.Navy.Nrl.Norm/NormSession.cs | 10 ++++ .../NormSessionTests.cs | 47 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs index f4b9177..5f963df 100644 --- a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs +++ b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs @@ -497,6 +497,7 @@ public NormFile FileEnqueue(string filename, byte[] info, int infoOffset, int in /// Size of the message. /// A NormData is returned which the application may use in other NORM API calls as needed. /// Thrown when NormDataEnqueue() returns NORM_OBJECT_INVALID, indicating the failure to enqueue data. + /// Thrown when the data offset or data length are outside of the data buffer public NormData DataEnqueue(byte[] dataBuffer, int dataOffset, int dataLength) { return DataEnqueue(dataBuffer, dataOffset, dataLength, null, 0, 0); @@ -514,8 +515,17 @@ public NormData DataEnqueue(byte[] dataBuffer, int dataOffset, int dataLength) /// The optional info and infoLength parameters are used to associate NORM_INFO content with the sent transport object. /// A NormData is returned which the application may use in other NORM API calls as needed. /// Thrown when NormDataEnqueue() returns NORM_OBJECT_INVALID, indicating the failure to enqueue data. + /// Thrown when the data offset or data length are outside of the data buffer public NormData DataEnqueue(byte[] dataBuffer, int dataOffset, int dataLength, byte[]? info, int infoOffset, int infoLength) { + if (dataOffset < 0 || dataOffset >= dataBuffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(dataOffset), "The data offset is out of range"); + } + if (dataOffset + dataLength > dataBuffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(dataLength), "The data length is out of range"); + } var dataBytes = dataBuffer.Skip(dataOffset).Take(dataLength).ToArray(); byte[]? infoBytes; if (info != null) diff --git a/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs b/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs index 01eae9d..b3b4c21 100644 --- a/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs +++ b/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs @@ -456,6 +456,53 @@ public void EnqueuesData(string content, string expectedContent, int offset, int } } + public static IEnumerable GenerateOutOfRangeData() + { + var data = new List(); + + var content = GenerateTextContent(); + var faker = new Faker(); + var offset = faker.Random.Int(-content.Length, -1); + var length = content.Length; + data.Add(new object[] { content, offset, length }); + + offset = faker.Random.Int(content.Length, content.Length * 2); + length = content.Length; + data.Add(new object[] { content, offset, length }); + + offset = 0; + length = faker.Random.Int(content.Length + 1, content.Length * 2); + data.Add(new object[] { content, offset, length }); + + offset = content.Length - 1; + length = content.Length; + data.Add(new object[] { content, offset, length }); + + return data; + } + + [SkippableTheory(typeof(IOException))] + [MemberData(nameof(GenerateOutOfRangeData))] + public void EnqueuesDataThrowsExceptionWhenOutOfRange(string content, int offset, int length) + { + StartSender(); + //Create data to write to the stream + var data = Encoding.ASCII.GetBytes(content); + + try + { + Assert.Throws(() => _normSession.DataEnqueue(data, offset, length)); + } + catch (Exception) + { + throw; + } + finally + { + StopSender(); + } + } + [SkippableTheory(typeof(IOException))] [MemberData(nameof(GenerateData))] public void ReceivesData(string content, string expectedContent, int offset, int length) From 6f92da8e64a4bbb9d586abed9886e1c1e94d3532 Mon Sep 17 00:00:00 2001 From: mullerj Date: Mon, 10 Jun 2024 23:09:14 -0400 Subject: [PATCH 4/9] Switched DataEnqueue to use pointer arithmetic --- .../Mil.Navy.Nrl.Norm.csproj | 1 + src/dotnet/src/Mil.Navy.Nrl.Norm/NormApi.cs | 35 --------------- .../src/Mil.Navy.Nrl.Norm/NormSession.cs | 43 ++++++++++++------- 3 files changed, 28 insertions(+), 51 deletions(-) diff --git a/src/dotnet/src/Mil.Navy.Nrl.Norm/Mil.Navy.Nrl.Norm.csproj b/src/dotnet/src/Mil.Navy.Nrl.Norm/Mil.Navy.Nrl.Norm.csproj index efa1468..44ce715 100644 --- a/src/dotnet/src/Mil.Navy.Nrl.Norm/Mil.Navy.Nrl.Norm.csproj +++ b/src/dotnet/src/Mil.Navy.Nrl.Norm/Mil.Navy.Nrl.Norm.csproj @@ -5,6 +5,7 @@ enable enable 1.0.0 + true diff --git a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormApi.cs b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormApi.cs index 5e969e9..e5f56b8 100644 --- a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormApi.cs +++ b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormApi.cs @@ -544,41 +544,6 @@ public struct NormEvent [DllImport(NORM_LIBRARY)] public static extern long NormDataEnqueue(long sessionHandle, nint dataPtr, int dataLen, nint infoPtr, int infoLen); - /// - /// This function enqueues a segment of application memory space for transmission within the specified NORM sessionHandle. - /// - /// Used to identify application in the NormSession. - /// The data parameter must be a managed buffer to be transmitted. - /// The dataLen parameter indicates the quantity of data to transmit. - /// The optional info and infoLen parameters - /// are used to associate NORM_INFO content with the sent transport object. The maximum allowed infoLen - /// corresponds to the segmentSize used in the prior call to NormStartSender(). The use and interpretation of the - /// NORM_INFO content is left to the application's discretion. - /// The optional info and infoLen parameters - /// are used to associate NORM_INFO content with the sent transport object. The maximum allowed infoLen - /// corresponds to the segmentSize used in the prior call to NormStartSender(). The use and interpretation of the - /// NORM_INFO content is left to the application's discretion - /// A NormObjectHandle is returned which the application may use in other NORM API calls as needed. - public static long NormDataEnqueue(long sessionHandle, byte[] data, int dataLen, byte[]? info, int infoLen) - { - long objectHandle; - var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); - var infoHandle = GCHandle.Alloc(info, GCHandleType.Pinned); - - try - { - var dataPtr = dataHandle.AddrOfPinnedObject(); - var infoPtr = infoHandle.AddrOfPinnedObject(); - objectHandle = NormDataEnqueue(sessionHandle, dataPtr, dataLen, infoPtr, infoLen); - } - finally - { - dataHandle.Free(); - infoHandle.Free(); - } - return objectHandle; - } - /// /// This function allows the application to resend (or reset transmission of) a NORM_OBJECT_FILE or NORM_OBJECT_DATA /// transmit object that was previously enqueued for the indicated sessionHandle. diff --git a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs index 5f963df..6bbfee7 100644 --- a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs +++ b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs @@ -526,23 +526,34 @@ public NormData DataEnqueue(byte[] dataBuffer, int dataOffset, int dataLength, b { throw new ArgumentOutOfRangeException(nameof(dataLength), "The data length is out of range"); } - var dataBytes = dataBuffer.Skip(dataOffset).Take(dataLength).ToArray(); - byte[]? infoBytes; - if (info != null) - { - infoBytes = info.Skip(infoOffset).Take(infoLength).ToArray(); - } - else + unsafe { - infoBytes = null; - infoLength = 0; - } - var objectHandle = NormDataEnqueue(_handle, dataBytes, dataLength, infoBytes, infoLength); - if (objectHandle == NormObject.NORM_OBJECT_INVALID) - { - throw new IOException("Failed to enqueue data"); - } - return new NormData(objectHandle); + fixed (byte* dataPointer = &dataBuffer[0]) + { + byte* dataPointerWithOffset = dataPointer + dataOffset; + + byte* infoPointerWithOffset; + + if (info != null) + { + fixed (byte* infoPointer = &info[0]) + { + infoPointerWithOffset = infoPointer + infoOffset; + } + } + else + { + infoPointerWithOffset = null; + infoLength = 0; + } + var objectHandle = NormDataEnqueue(_handle, (IntPtr)dataPointerWithOffset, dataLength, (IntPtr)infoPointerWithOffset, infoLength); + if (objectHandle == NormObject.NORM_OBJECT_INVALID) + { + throw new IOException("Failed to enqueue data"); + } + return new NormData(objectHandle); + } + } } /// From cb9443d6eb493feef77ce2bfa4fa90851b6de3d2 Mon Sep 17 00:00:00 2001 From: mullerj Date: Wed, 12 Jun 2024 07:46:18 -0400 Subject: [PATCH 5/9] Simplified DataEnqueue --- .../Mil.Navy.Nrl.Norm.csproj | 1 - .../src/Mil.Navy.Nrl.Norm/NormSession.cs | 48 +++++++++---------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/dotnet/src/Mil.Navy.Nrl.Norm/Mil.Navy.Nrl.Norm.csproj b/src/dotnet/src/Mil.Navy.Nrl.Norm/Mil.Navy.Nrl.Norm.csproj index 44ce715..efa1468 100644 --- a/src/dotnet/src/Mil.Navy.Nrl.Norm/Mil.Navy.Nrl.Norm.csproj +++ b/src/dotnet/src/Mil.Navy.Nrl.Norm/Mil.Navy.Nrl.Norm.csproj @@ -5,7 +5,6 @@ enable enable 1.0.0 - true diff --git a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs index 6bbfee7..1515f1c 100644 --- a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs +++ b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs @@ -1,4 +1,6 @@ -using System.Text; +using System.Data; +using System.Runtime.InteropServices; +using System.Text; namespace Mil.Navy.Nrl.Norm { @@ -526,34 +528,28 @@ public NormData DataEnqueue(byte[] dataBuffer, int dataOffset, int dataLength, b { throw new ArgumentOutOfRangeException(nameof(dataLength), "The data length is out of range"); } - unsafe + + long objectHandle; + var dataHandle = GCHandle.Alloc(dataBuffer, GCHandleType.Pinned); + var infoHandle = GCHandle.Alloc(info, GCHandleType.Pinned); + + try { - fixed (byte* dataPointer = &dataBuffer[0]) + var dataPtr = dataHandle.AddrOfPinnedObject() + dataOffset; + var infoPtr = infoHandle.AddrOfPinnedObject() + infoOffset; + objectHandle = NormDataEnqueue(_handle, dataPtr, dataLength, infoPtr, infoLength); + if (objectHandle == NormObject.NORM_OBJECT_INVALID) { - byte* dataPointerWithOffset = dataPointer + dataOffset; - - byte* infoPointerWithOffset; - - if (info != null) - { - fixed (byte* infoPointer = &info[0]) - { - infoPointerWithOffset = infoPointer + infoOffset; - } - } - else - { - infoPointerWithOffset = null; - infoLength = 0; - } - var objectHandle = NormDataEnqueue(_handle, (IntPtr)dataPointerWithOffset, dataLength, (IntPtr)infoPointerWithOffset, infoLength); - if (objectHandle == NormObject.NORM_OBJECT_INVALID) - { - throw new IOException("Failed to enqueue data"); - } - return new NormData(objectHandle); + throw new IOException("Failed to enqueue data"); } - } + } + finally + { + dataHandle.Free(); + infoHandle.Free(); + } + + return new NormData(objectHandle); } /// From 18c6bfb45a89c1c10d5f00b324842b98d1cbbb0d Mon Sep 17 00:00:00 2001 From: mullerj Date: Thu, 13 Jun 2024 21:48:12 -0400 Subject: [PATCH 6/9] Added tests for enqueue data with info --- .../NormSessionTests.cs | 114 +++++++++++++----- 1 file changed, 84 insertions(+), 30 deletions(-) diff --git a/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs b/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs index b3b4c21..a52836e 100644 --- a/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs +++ b/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs @@ -192,6 +192,16 @@ private static string GenerateTextContent() return faker.Lorem.Paragraph(); } + /// + /// Generates info content + /// + /// The generated info content + private static string GenerateInfoContent() + { + var faker = new Faker(); + return faker.Lorem.Sentence(); + } + private IEnumerable GetEvents(TimeSpan delayTime) { var normEvents = new List(); @@ -402,49 +412,81 @@ public static IEnumerable GenerateData() { var data = new List(); - var content = GenerateTextContent(); - var expectedContent = content; - var offset = 0; - var length = content.Length; - data.Add(new object[] { content, expectedContent, offset, length }); - - var faker = new Faker(); - length = faker.Random.Int(content.Length / 2, content.Length - 1); - expectedContent = content.Substring(offset, length); - data.Add(new object[] { content, expectedContent, offset, length }); + var dataContent = GenerateTextContent(); + var expectedDataContent = dataContent; + var dataOffset = 0; + var dataLength = dataContent.Length; + data.Add(new object[] { dataContent, expectedDataContent, dataOffset, dataLength }); - offset = faker.Random.Int(1, content.Length - 1 / 2); - length = content.Length - offset; - expectedContent = content.Substring(offset, length); - data.Add(new object[] { content, expectedContent, offset, length }); + var infoContent = GenerateInfoContent(); + var expectedInfoContent = infoContent; + var infoOffset = 0; + var infoLength = infoContent.Length; + data.Add(new object[] { dataContent, expectedDataContent, dataOffset, dataLength, infoContent, expectedInfoContent, infoOffset, infoLength }); - offset = faker.Random.Int(1, content.Length - 1 / 2); - length = faker.Random.Int(1, content.Length - offset); - expectedContent = content.Substring(offset, length); - data.Add(new object[] { content, expectedContent, offset, length }); + var faker = new Faker(); + infoLength = faker.Random.Int(infoContent.Length / 2, infoContent.Length - 1); + expectedInfoContent = infoContent.Substring(infoOffset, infoLength); + data.Add(new object[] { dataContent, expectedDataContent, dataOffset, dataLength, infoContent, expectedInfoContent, infoOffset, infoLength }); + + infoOffset = faker.Random.Int(1, infoContent.Length - 1 / 2); + infoLength = infoContent.Length - infoOffset; + expectedInfoContent = infoContent.Substring(infoOffset, infoLength); + data.Add(new object[] { dataContent, expectedDataContent, dataOffset, dataLength, infoContent, expectedInfoContent, infoOffset, infoLength }); + + infoOffset = faker.Random.Int(1, infoContent.Length - 1 / 2); + infoLength = faker.Random.Int(1, infoContent.Length - infoOffset); + expectedInfoContent = infoContent.Substring(infoOffset, infoLength); + data.Add(new object[] { dataContent, expectedDataContent, dataOffset, dataLength, infoContent, expectedInfoContent, infoOffset, infoLength }); + + dataLength = faker.Random.Int(dataContent.Length / 2, dataContent.Length - 1); + expectedDataContent = dataContent.Substring(dataOffset, dataLength); + data.Add(new object[] { dataContent, expectedDataContent, dataOffset, dataLength }); + + dataOffset = faker.Random.Int(1, dataContent.Length - 1 / 2); + dataLength = dataContent.Length - dataOffset; + expectedDataContent = dataContent.Substring(dataOffset, dataLength); + data.Add(new object[] { dataContent, expectedDataContent, dataOffset, dataLength }); + + dataOffset = faker.Random.Int(1, dataContent.Length - 1 / 2); + dataLength = faker.Random.Int(1, dataContent.Length - dataOffset); + expectedDataContent = dataContent.Substring(dataOffset, dataLength); + data.Add(new object[] { dataContent, expectedDataContent, dataOffset, dataLength }); return data; } [SkippableTheory(typeof(IOException))] [MemberData(nameof(GenerateData))] - public void EnqueuesData(string content, string expectedContent, int offset, int length) + public void EnqueuesData(string dataContent, string expectedDataContent, int dataOffset, int dataLength, string? infoContent = null, string expectedInfoContent = "", int? infoOffset = null, int? infoLength = null) { StartSender(); - //Create data to write to the stream - var data = Encoding.ASCII.GetBytes(content); - var expectedData = Encoding.ASCII.GetBytes(expectedContent); + //Create data to write to enqueue + var data = Encoding.ASCII.GetBytes(dataContent); + var expectedData = Encoding.ASCII.GetBytes(expectedDataContent); + //Create info to enqueue + var info = infoContent != null ? Encoding.ASCII.GetBytes(infoContent) : null; + var expectedInfo = Encoding.ASCII.GetBytes(expectedInfoContent); try { - var normData = _normSession.DataEnqueue(data, offset, length); + var normData = infoOffset != null && infoLength != null ? + _normSession.DataEnqueue(data, dataOffset, dataLength, info, infoOffset.Value, infoLength.Value) : + _normSession.DataEnqueue(data, dataOffset, dataLength); var expectedEventTypes = new List { NormEventType.NORM_TX_OBJECT_SENT, NormEventType.NORM_TX_QUEUE_EMPTY }; var actualEventTypes = GetEvents().Select(e => e.Type).ToList(); Assert.Equal(expectedEventTypes, actualEventTypes); var actualData = normData.GetData(); Assert.Equal(expectedData, actualData); - var actualContent = Encoding.ASCII.GetString(actualData); - Assert.Equal(expectedContent, actualContent); + var actualDataContent = Encoding.ASCII.GetString(actualData); + Assert.Equal(expectedDataContent, actualDataContent); + var actualInfo = normData.Info; + Assert.Equal(expectedInfo, actualInfo); + if (actualInfo != null) + { + var actualInfoContent = Encoding.ASCII.GetString(actualInfo); + Assert.Equal(expectedInfoContent, actualInfoContent); + } } catch (Exception) { @@ -505,7 +547,7 @@ public void EnqueuesDataThrowsExceptionWhenOutOfRange(string content, int offset [SkippableTheory(typeof(IOException))] [MemberData(nameof(GenerateData))] - public void ReceivesData(string content, string expectedContent, int offset, int length) + public void ReceivesData(string content, string expectedDataContent, int dataOffset, int dataLength, string? infoContent = null, string expectedInfoContent = "", int? infoOffset = null, int? infoLength = null) { _normSession.SetLoopback(true); StartSender(); @@ -519,11 +561,16 @@ public void ReceivesData(string content, string expectedContent, int offset, int //Create data to be sent var data = Encoding.ASCII.GetBytes(content); - var expectedData = Encoding.ASCII.GetBytes(expectedContent); + var expectedData = Encoding.ASCII.GetBytes(expectedDataContent); + //Create info to be sent + var info = infoContent != null ? Encoding.ASCII.GetBytes(infoContent) : null; + var expectedInfo = Encoding.ASCII.GetBytes(expectedInfoContent); try { - var normData = _normSession.DataEnqueue(data, offset, length); + var normData = infoOffset != null && infoLength != null ? + _normSession.DataEnqueue(data, dataOffset, dataLength, info, infoOffset.Value, infoLength.Value) : + _normSession.DataEnqueue(data, dataOffset, dataLength); var expectedEventTypes = new List { NormEventType.NORM_REMOTE_SENDER_NEW, @@ -545,8 +592,15 @@ public void ReceivesData(string content, string expectedContent, int offset, int var actualData = actualNormData.GetData(); Assert.Equal(expectedData, actualData); - var actualContent = Encoding.ASCII.GetString(actualData); - Assert.Equal(expectedContent, actualContent); + var actualDataContent = Encoding.ASCII.GetString(actualData); + Assert.Equal(expectedDataContent, actualDataContent); + var actualInfo = normData.Info; + Assert.Equal(expectedInfo, actualInfo); + if (actualInfo != null) + { + var actualInfoContent = Encoding.ASCII.GetString(actualInfo); + Assert.Equal(expectedInfoContent, actualInfoContent); + } } catch (Exception) { From 442c07e5568950896d6bbc9207d3909cc50f5bd3 Mon Sep 17 00:00:00 2001 From: mullerj Date: Thu, 13 Jun 2024 22:17:20 -0400 Subject: [PATCH 7/9] Added info argument validation to DataEnqueue --- .../src/Mil.Navy.Nrl.Norm/NormSession.cs | 12 +++- .../NormSessionTests.cs | 59 +++++++++++++------ 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs index 1515f1c..15c17c7 100644 --- a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs +++ b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs @@ -499,7 +499,7 @@ public NormFile FileEnqueue(string filename, byte[] info, int infoOffset, int in /// Size of the message. /// A NormData is returned which the application may use in other NORM API calls as needed. /// Thrown when NormDataEnqueue() returns NORM_OBJECT_INVALID, indicating the failure to enqueue data. - /// Thrown when the data offset or data length are outside of the data buffer + /// Thrown when the data offset or data length are outside of the data buffer. public NormData DataEnqueue(byte[] dataBuffer, int dataOffset, int dataLength) { return DataEnqueue(dataBuffer, dataOffset, dataLength, null, 0, 0); @@ -517,7 +517,7 @@ public NormData DataEnqueue(byte[] dataBuffer, int dataOffset, int dataLength) /// The optional info and infoLength parameters are used to associate NORM_INFO content with the sent transport object. /// A NormData is returned which the application may use in other NORM API calls as needed. /// Thrown when NormDataEnqueue() returns NORM_OBJECT_INVALID, indicating the failure to enqueue data. - /// Thrown when the data offset or data length are outside of the data buffer + /// Thrown when the data offset, data length, info offset or info length are outside of the associated buffer. public NormData DataEnqueue(byte[] dataBuffer, int dataOffset, int dataLength, byte[]? info, int infoOffset, int infoLength) { if (dataOffset < 0 || dataOffset >= dataBuffer.Length) @@ -528,6 +528,14 @@ public NormData DataEnqueue(byte[] dataBuffer, int dataOffset, int dataLength, b { throw new ArgumentOutOfRangeException(nameof(dataLength), "The data length is out of range"); } + if (infoOffset < 0 || infoOffset >= info?.Length) + { + throw new ArgumentOutOfRangeException(nameof(infoOffset), "The info offset is out of range"); + } + if (infoOffset + infoLength > info?.Length) + { + throw new ArgumentOutOfRangeException(nameof(infoLength), "The info length is out of range"); + } long objectHandle; var dataHandle = GCHandle.Alloc(dataBuffer, GCHandleType.Pinned); diff --git a/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs b/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs index a52836e..a478299 100644 --- a/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs +++ b/src/dotnet/tests/Mil.Navy.Nrl.Norm.IntegrationTests/NormSessionTests.cs @@ -502,38 +502,63 @@ public static IEnumerable GenerateOutOfRangeData() { var data = new List(); - var content = GenerateTextContent(); + var dataContent = GenerateTextContent(); var faker = new Faker(); - var offset = faker.Random.Int(-content.Length, -1); - var length = content.Length; - data.Add(new object[] { content, offset, length }); + var dataOffset = faker.Random.Int(-dataContent.Length, -1); + var dataLength = dataContent.Length; + data.Add(new object[] { dataContent, dataOffset, dataLength }); + + dataOffset = faker.Random.Int(dataContent.Length, dataContent.Length * 2); + dataLength = dataContent.Length; + data.Add(new object[] { dataContent, dataOffset, dataLength }); + + dataOffset = 0; + dataLength = faker.Random.Int(dataContent.Length + 1, dataContent.Length * 2); + data.Add(new object[] { dataContent, dataOffset, dataLength }); + + dataOffset = dataContent.Length - 1; + dataLength = dataContent.Length; + data.Add(new object[] { dataContent, dataOffset, dataLength }); + + dataOffset = 0; + dataLength = dataContent.Length; + + var infoContent = GenerateInfoContent(); + var infoOffset = faker.Random.Int(-infoContent.Length, -1); + var infoLength = infoContent.Length; + data.Add(new object[] { dataContent, dataOffset, dataLength, infoContent, infoOffset, infoLength }); - offset = faker.Random.Int(content.Length, content.Length * 2); - length = content.Length; - data.Add(new object[] { content, offset, length }); + infoOffset = faker.Random.Int(infoContent.Length, infoContent.Length * 2); + infoLength = infoContent.Length; + data.Add(new object[] { dataContent, dataOffset, dataLength, infoContent, infoOffset, infoLength }); - offset = 0; - length = faker.Random.Int(content.Length + 1, content.Length * 2); - data.Add(new object[] { content, offset, length }); + infoOffset = 0; + infoLength = faker.Random.Int(infoContent.Length + 1, infoContent.Length * 2); + data.Add(new object[] { dataContent, dataOffset, dataLength, infoContent, infoOffset, infoLength }); - offset = content.Length - 1; - length = content.Length; - data.Add(new object[] { content, offset, length }); + infoOffset = infoContent.Length - 1; + infoLength = infoContent.Length; + data.Add(new object[] { dataContent, dataOffset, dataLength, infoContent, infoOffset, infoLength }); return data; } [SkippableTheory(typeof(IOException))] [MemberData(nameof(GenerateOutOfRangeData))] - public void EnqueuesDataThrowsExceptionWhenOutOfRange(string content, int offset, int length) + public void EnqueuesDataThrowsExceptionWhenOutOfRange(string dataContent, int dataOffset, int dataLength, string? infoContent = null, int? infoOffset = null, int? infoLength = null) { StartSender(); - //Create data to write to the stream - var data = Encoding.ASCII.GetBytes(content); + //Create data to enqueue + var data = Encoding.ASCII.GetBytes(dataContent); + //Create info to enqueue + var info = infoContent != null ? Encoding.ASCII.GetBytes(infoContent) : null; try { - Assert.Throws(() => _normSession.DataEnqueue(data, offset, length)); + Assert.Throws(() => + infoOffset != null && infoLength != null ? + _normSession.DataEnqueue(data, dataOffset, dataLength, info, infoOffset.Value, infoLength.Value) : + _normSession.DataEnqueue(data, dataOffset, dataLength)); } catch (Exception) { From 6b5a599082100e04d11d69d8d5f73667e909cebc Mon Sep 17 00:00:00 2001 From: mullerj Date: Thu, 13 Jun 2024 22:20:27 -0400 Subject: [PATCH 8/9] Updated design --- src/dotnet/design/Mil/Navy/Nrl/Norm/NormApi.puml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dotnet/design/Mil/Navy/Nrl/Norm/NormApi.puml b/src/dotnet/design/Mil/Navy/Nrl/Norm/NormApi.puml index c23811a..027ac46 100644 --- a/src/dotnet/design/Mil/Navy/Nrl/Norm/NormApi.puml +++ b/src/dotnet/design/Mil/Navy/Nrl/Norm/NormApi.puml @@ -60,7 +60,6 @@ class NormApi + {static} NormSetTxRobustFactor(sessionHandle:long, robustFactor:int) : void + {static} NormFileEnqueue(sessionHandle:long, fileName:string, infoPtr:string, infoLen:int): long + {static} NormDataEnqueue(sessionHandle:long, dataPtr:nint, dataLen:int, infoPtr:nint, infoLen:int) : long - + {static} NormDataEnqueue(sessionHandle:long, data:byte[], dataLen:int, info:byte[], infoLen:int) : long + {static} NormRequeueObject(sessionHandle:long, objectHandle:long) : bool + {static} NormStreamOpen(sessionHandle:long, bufferSize:long, infoPtr:string, infoLen:int) : long + {static} NormStreamClose(streamHandle:long, graceful:bool) : void From ab9450399bc4aaebd3e74f630854a3093e94cfa5 Mon Sep 17 00:00:00 2001 From: mullerj Date: Thu, 13 Jun 2024 22:25:35 -0400 Subject: [PATCH 9/9] Removed unused using statement --- src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs index 15c17c7..b7a318b 100644 --- a/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs +++ b/src/dotnet/src/Mil.Navy.Nrl.Norm/NormSession.cs @@ -1,5 +1,4 @@ -using System.Data; -using System.Runtime.InteropServices; +using System.Runtime.InteropServices; using System.Text; namespace Mil.Navy.Nrl.Norm