.NET NORM Extension (#85)

* .NET Extension Design (#5)

* Designed .NET classes from Java

Co-authored-by: Sergiy <sergiy.yermak.ctr@us.navy.mil>

* Added NormApi static class

* Started on api uml

Co-authored-by: mullerj <mullerj@users.noreply.github.com>
Co-authored-by: Sylvester Freeman III <Slyfree3@users.noreply.github.com>

* Add static methods to api uml

* add static method to normapi uml

* Add enums

* Changes

* Overload methods with defaults

* type marshalling

* change handles to in nuint

* marshall more handles

* Removed in/ref and reformatted.

Co-authored-by: mullerj <mullerj@users.noreply.github.com>

* Removed duplicate enums

* Removed NormEvent from NormApi

* Fixed typo

* design NormInstance methods

Co-authored-by: mullerj <mullerj@users.noreply.github.com>

* Fixed CreateInstance method

* Changed handles to long

* Change id types to long

* Remove condition checks that do nothing

* Removed UserData functions

* Removed NormAlloc() and NormFree()

* Cleaned up some API methods

* Fix misspelling

Co-authored-by: Sylvester Freeman III <Slyfree3@users.noreply.github.com>

* Design NormSession methods

Co-authored-by: Sylvester Freeman III <Slyfree3@users.noreply.github.com>

* Added missing comma

* Uml for enqueue
Co-authored-by: mullerj <mullerj@users.noreply.github.com>

* Updated design based on enqueue test

* Updated EnqueueFile sequence diagram

Co-authored-by: Sylvester Freeman III <Slyfree3@users.noreply.github.com>

* Moved sequence diagrams

* Added constants to NormApi

* Removed method level sequence diagrams

---------

Co-authored-by: Sergiy <sergiy.yermak.ctr@us.navy.mil>
Co-authored-by: syermak <syerm001@odu.edu>
Co-authored-by: mullerj <mullerj@users.noreply.github.com>
Co-authored-by: Sylvester Freeman III <Slyfree3@users.noreply.github.com>
Co-authored-by: Sergiy <47069243+SergiyYermak@users.noreply.github.com>
Co-authored-by: Sylvester Freeman III <Slyfreeman3@gmail.com>

* .NET Extension Design Implementation (#10)

* changes

* Removed GetsNextEvent test

* Implemented GetNextEvent

* Fixed NormStream design

* Fixed HasNextEvent design

* Added NormGetNextEvent overload

* Implemented HasNextEvent

* Updated design

* Added Kernel32 to design

* Modified to use .NET EventWaitHandle instead of kernel32 P/Invoke

* Modified to only copy norm.dll on Windows

* Added copy for non Windows

* add start and stop receiver

* add receiver

* Modified non-Windows to use Socket for HasNextEvent

* Deleted NormFileTests since they break the other tests

* Fixed ReceiverReceives test

* Updated ReceiverReceives test name

* Modified ReceivesFile to get all events instead of adding to array

* Cleaned up NormInstance formatting

* Refactored tests

* Updated NormFile

* Implemented send stream

* Implemented receive stream

* Implemented NormFile Name

* Updated ReceivesFile to use events

* data enqueue

* Fixed merge

* Fixed ReceivesData test

* Modified data test to compare collections without order

* stop instance working

* enqueues data

* Reverted upgrade to .NET 7

* Restartinstance is working

* Modified NormData to read bytes instead of as string

* Removed using statements in NormData

* Updated design

* Updated design

* Switched to nint

* Switched design to nint

* unfinished test for suspendinstance

* working suspend instance

* added resume function to instance

* Updated session send and receive data tests

* Removed launch settings

* session configuration functions

* Modified to use random port due to intermittent failed tests due to session conflict

* Modified to randomize text content

* Implemented NormNode Address

* Updated design for NormNode

* Implemented NormNode Grtt

* Implemented NormNode Id

* implement session configuration functions

* instance

* missing return types

* add missing handle param

* normNode

* Implemented RequeueObject

* Implemented SetWatermark and AckingNode

* Implemented CancelWatermark

* Implemented ResetWatermark

* Implemented SendCommand

* Implemented CancelCommand

* Implemented DebugLevel. Removed DebugPipe

* Updated SetTxPort

* Updated SetRxPortReuse

* Implemented SetEcnSupport

* Added test for RxLoss

* Implemented ReportInterval

* Refactored session calculated properties

* Updated enqueue methods

* Updated StreamOpen design

* Fixed SetWatermark overload

* Implemented GetAckingStatus

* Removed SendCommand overload

* Removed SetSilentReceiver overload

* Implemented NormEvent ToString

* Implemented NormFile Rename

* Implemented SetUnicastNack

* Added ReceivesCommand test

* Implemented SetNackingMode

* Implemented SetRepairBoundary

* Added Fact to SetsRepairBoundary test

* Implemented SetRxRobustFactor

* Implemented NormNode Command

* Implemented FreeBuffers

* Implemented Retain and Release

* Fix using namespaces

* test get object type

* NormObject get size

* NormObject setNackingMode

* NormObject get bytes pending

* NormObjet cancel

* NormObject retain

* NormObject release

* NormObject get sender

* NormObject get hashcode

* normObject equals

* Implemented NormObject Equals

* Removed redundant cast

* Removed unused using directive

* Removed static using

* Added NormApi to global Usings

* Added Enums to global usings

* Cleaned up NormObject Equals

* Cleaned up NormObject GetHashCode() test

* Cleaned up warning

* normStream has vacancy

* normStream read offset

* normStream seek msg start

* NormEventListener interface

* normStream set push enable

* normStream set auto flush

* Simplified NormApi usage

* Updated design of NormStream

* public interface

* Fixed INormEventListener

* fixing name space

* commit initializing  inputstream

* Added StreamBreakException

* Fixed formatting

* Fixed formatting

* Fixed formatting

* Initial implementation of NormOutputStream

* Cleaned up NormObject Equals

* NormInputStream class

Co-authored-by: mullerj <mullerj@users.noreply.github.com>

* normStream data offset

* move offset length arithmetic into write method

* building normInputstream

* all method implemented

Co-authored-by: mullerj <mullerj@users.noreply.github.com>

* NormStreamRead

* Fixed build error

* Completed ReceivesStreamWithOffset test

* Added retries to GetsCommand test

* Updated type for NormStreamRead

* Simplified NormStream Read

* Simplified NormStream Write

* Added dataOffset to DataEnqueue

* Fixed DataEnqueue overload

* Added infoOffset to FileEnqueue

* Added infoOffset to StreamOpen

* Updated design

* Removed extra overload of FileEnqueue

* Removed DataEnqueue overloads

* Removed extra overload from StreamOpen

* Added HasNextEvent overload

* Implemented OpenDebugPipe

* add thread locking

* locking for properties

* Not supported exceptions

* Implementing sychronize

* fixing inputstream

* adding sychronize message

* Reorganized NormApi and updated design

* Modified to skip GetsCommand test on IO exception

* WIP: 537b706 adding sychronize message

* adding message to expections

* Fixed test file cleanup

* Added locking to NormSession methods that use static field

* Changed StartsSender to skippablefact

* Changed to SetsNackingMode to skippable fact

* Converted tests to skippable

* Converted more tests to skippable

* Converted all tests that start sender to skippable

* Updated README about skipped tests

* documentation

* 2 doc

* Cleaned up input and output stream classes

* Cleaned up NormApi

* Updated NormOutputStream Write

* Added document comments to NormApi

* Added comments to NormApi

* Removed unnecessary usings

* Added comments to NormApi

* set up the rest of doc

* api documentation

* fix typo

* fix spacing

* Doc for instance need clean up

* clean up

* document norm session

* NormStream documentation

* commit for node

* NormObject docs

* Updated NormApi comments

* Cleaned up NormInstance comments

* Cleaned up NormNode comments

* Cleaned up NormObject comments

* Cleaned up NormSession comments

* Cleaned up NormStream comments

* Cleaned up NormObject comments

* Adding commits

* Update get commit

* clean up on data and event

* Norm Data change

* clean up normfile docs

* clean up normstream

* clean up api docs

* Fixed data

* space approved

* Cleaned up NormData comment

* documentation clean up

* Update the ReadMe

* Cleaned up comments

* Added comments to NormAckingStatus

* Added comments to NormEventType

* Added comments to NormFecType

* Added comments to NormNackingMode

* Added comments to NormObjectType

* Added comments to NormProbingMode

* Added comments to NormRepairBoundary

* Added comments to NormFlushMode

* Added comments to NormSyncPolicy

* Cleaned up comments.  Fixed default for StartSender

* Added comments to constants

* Moved constants to relevant classes

* Updated design

* Removed NormDataDetachData since it is not referenced

* Updated design

* Updated input and output stream design

* Updated packaging README

* Removed language version since redundant

* Cleaned up project file

* Updated to package from the dotnet directory (test project is set to not pack)

* Added version to project

---------

Co-authored-by: syermak <syerm001@odu.edu>
Co-authored-by: Sylvester Freeman III <Slyfreeman3@gmail.com>
Co-authored-by: Sergiy <47069243+SergiyYermak@users.noreply.github.com>
Co-authored-by: mullerj <mullerj@users.noreply.github.com>

* NormSession typos in comments (#12)

* Fixed default function comments in NormSession

* Fixed typos in NormSession

* Fixed default function comments

* Feature/9 net norm extension target architecture packages (#13)

* Added Win64 project and release configuration

* Added project reference to Win64 project

* Added Win32 project. Moved norm build actions to scripts

* Added linux .NET extension project

* Modified linux project to copy to output directory

* Fixed linux pack script

* Changed Linux project to copy always

* Changed Linux project package path

* Moved Windows libraries to runtimes path

* Renamed runtime specific projects

* Codespace Configurations (#15)

* Created devcontainer.json

* .NET norm extension GitHub actions (#16)

* Added .NET action

* Update dotnet-publish.yml to use source branch (#18)

* .NET norm package publish (#19)

* Added steps to copy package and check workspace

* Changed trigger for testing

* Removed if statement

* Updated dotnet-publish.yml to copy to  $GITHUB_OUTPUT

* Changed from variable to path

* Removed copy command

* Modified to check runner directory

* Added step to publish package

* Added package write permission

* Added job to publish win-x64

* Fixed package win-x64 step

* Added job to publish win-x86

* Added skip-duplicate to publish commands

* Added publish job

* Changed to . for linux find

* Added workflow trigger

* Added branches filter

* Publish test results (#21)

* Added step to publish test results

* Changed upload step to use wildcard

* Added quotes

* Changed directory to relative path

* Fixed upload step

* Added step to publish test results

* Added permissions

* Dev Container extensions (#23)

* Added extensions

* Cut down on extensions

* Added extension

* Removed pull requests extension

* Added workspace recommendation

* Added powershell feature

* Fixed powershell version

* Updated powershell version and added extension

* Updated to latest powershell

* Dev Container performance (#25)

* Fixed devcontainer format

* Added dotnet-linux-x64 devcontainer

* Changed devcontainer image to python

* Pinned OS version

* Updated devcontainer base image

* Reverted changes to devcontainer

* Moved linux devcontainer file

* Updated dotnet-publish to use subfolder

* Revert "Dev Container performance (#25)" (#27)

This reverts commit 2be146ceed.

* Update action versions for dotnet-publish.yml

* Update action versions for dotnet.yml

* Fixed ReceivesData test to use received events for actual data

* NormData Refactor (#30)

* Switched NormData Data property to a method

* Corrected NormData summary comment

* Updated NormData GetData to use Marshal.Copy

* Fixed warnings

* Updated NormData design

* NormDataEnqueue Refactor (#31)

* Switched NormDataEnqueue to use IntPtr

* Updated NormApi design

* Updated GetSession to use lock

* Updated GetSession to TryGetValue

* DataEnqueue Refactor (#33)

* Refactored DataEnqueue to use pointer arithmetic

* NormDataEnqueue Refactor (#34)

* Updated to use SafeBuffer

* Added ByteBuffer and DirectByteBuffer

* Added pointer overload to DataEnqueue

* Updated FileEnqueue() to use pointer arithmetic

* Updated NormStream to use pointer arithmetic

* Updated NormSendCommand to nint

* Updated NormNodeGetCommand to nint

* Updated NormNodeGetAddress to use nint for buffer

* Updated NormStreamRead to use nint for buffer

* Updated NormObjectGetInfo to use nint for buffer

* Updated NormFileGetName nameBuffer to nint

* Updated NormFile.Name to use PtrToStringAnsi

* Updated NormFile.Name to use stackalloc (#37)

* Updated NormNode.Address to use stackalloc and create IPAddress from bytes

* NormObject Refactor

* Updated NormObjectGetInfo to use byte array

* Updated design

* NormStream Refactor

* Updated NormStream Write to use fixed statement

* Updated NormStream Read to use fixed statement

* Updated design

* NormNode Refactor

* Updated NormNodeGetAddress to use byte* to avoid casting

* Updated NormNode GetCommand to use fixed statement

* Updated design

* NormFile Refactor

* Updated NormFileGetName to use sbyte* to avoid casting

* Updated design

* Added workflow_dispatch to workflows

---------

Co-authored-by: Sergiy <sergiy.yermak.ctr@us.navy.mil>
Co-authored-by: syermak <syerm001@odu.edu>
Co-authored-by: mullerj <mullerj@users.noreply.github.com>
Co-authored-by: Sylvester Freeman III <Slyfree3@users.noreply.github.com>
Co-authored-by: Sergiy <47069243+SergiyYermak@users.noreply.github.com>
Co-authored-by: Sylvester Freeman III <Slyfreeman3@gmail.com>
norm-ccd
mullerj 2025-03-26 01:07:19 -04:00 committed by GitHub
parent 0c2e151a77
commit 4fd768f9cc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
70 changed files with 8782 additions and 0 deletions

View File

@ -0,0 +1,39 @@
{
"image": "mcr.microsoft.com/devcontainers/cpp:1.0.0-buster",
"features": {
"ghcr.io/devcontainers/features/python:1": {
"version": "3.11"
},
"ghcr.io/devcontainers/features/dotnet:1": {
"version": "6"
},
"ghcr.io/devcontainers/features/java:1": {
"version": "17",
"installAnt": true,
"antVersion": "1.10.12"
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"version": "20.10"
},
"ghcr.io/devcontainers/features/powershell:1": {
"version": "7.3"
}
},
"customizations": {
"vscode": {
"extensions": [
"DavidAnson.vscode-markdownlint",
"eamodio.gitlens",
"github.vscode-github-actions",
"GitHub.codespaces",
"jebbs.plantuml",
"ms-python.isort",
"ms-vscode-remote.remote-containers",
"ms-vscode.cpptools-themes",
"ms-vscode.PowerShell",
"tomoki1207.pdf",
"yzhang.markdown-all-in-one"
]
}
}
}

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.sh text eol=lf

142
.github/workflows/dotnet-publish.yml vendored Normal file
View File

@ -0,0 +1,142 @@
name: ".NET Publish"
on:
workflow_run:
workflows: ['.NET']
types:
- completed
branches:
- master
- main
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
permissions:
packages: write
defaults:
run:
working-directory: ./src/dotnet
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x
source-url: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json
env:
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Package .NET
run: dotnet pack . -c Release
- name: Publish .NET
run: |
package=$(find . -type f -name "*.nupkg")
dotnet nuget push "$package" --skip-duplicate
publish-linux-x64:
runs-on: ubuntu-latest
permissions:
packages: write
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Package .NET
uses: devcontainers/ci@v0.3
with:
push: never
runCmd: |
cd ./src/dotnet
chmod 755 *.sh
./pack-linux-x64.sh
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '6.0.x'
source-url: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json
env:
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Publish .NET
run: |
package=$(find . -type f -name "*linux-x64*.nupkg")
dotnet nuget push "$package" --skip-duplicate
publish-win-x64:
runs-on: windows-latest
permissions:
packages: write
defaults:
run:
working-directory: ./src/dotnet
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Python
uses: actions/setup-python@v5.1.0
with:
python-version: 3.x
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x
source-url: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json
env:
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Package .NET
run: .\pack-win-x64.bat
- name: Publish .NET
run: |
$package=Get-ChildItem -Path .\ -Filter *win-x64*.nupkg -Recurse -File | ForEach-Object { $_.FullName }
dotnet nuget push "$package" --skip-duplicate
publish-win-x86:
runs-on: windows-latest
permissions:
packages: write
defaults:
run:
working-directory: ./src/dotnet
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Python
uses: actions/setup-python@v5.1.0
with:
python-version: 3.x
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x
source-url: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json
env:
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Package .NET
run: .\pack-win-x86.bat
- name: Publish .NET
run: |
$package=Get-ChildItem -Path .\ -Filter *win-x86*.nupkg -Recurse -File | ForEach-Object { $_.FullName }
dotnet nuget push "$package" --skip-duplicate

49
.github/workflows/dotnet.yml vendored Normal file
View File

@ -0,0 +1,49 @@
name: .NET
on: [push, pull_request, workflow_dispatch]
jobs:
build:
runs-on: ubuntu-latest
permissions:
checks: write
pull-requests: write
defaults:
run:
working-directory: ./src/dotnet
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Python
uses: actions/setup-python@v5.1.0
with:
python-version: 3.x
- name: Build NORM
run: ./waf
working-directory: .
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore /property:Configuration=Release
- name: Build
run: dotnet build --no-restore --configuration Release
- name: Test
run: dotnet test --no-build --verbosity normal --configuration Release --logger trx --results-directory TestResults
- name: Upload test results
uses: actions/upload-artifact@v4
with:
name: dotnet-results
path: ./src/dotnet/TestResults
if: ${{ always() }}
- name: Publish test results
uses: EnricoMi/publish-unit-test-result-action@v2
with:
files: ./src/dotnet/TestResults/*.trx
if: ${{ always() }}

279
.gitignore vendored
View File

@ -18,9 +18,16 @@ norp/makefiles/norp
*.o *.o
*.a *.a
# build java files
*.class
#build android files
android/.gradle
# waf cruft # waf cruft
.waf* .waf*
.lock-waf* .lock-waf*
waf*/*
# OS generated files # # OS generated files #
.DS_Store .DS_Store
@ -30,3 +37,275 @@ norp/makefiles/norp
.Trashes .Trashes
ehthumbs.db ehthumbs.db
Thumbs.db Thumbs.db
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
*.sqlite
*.sqlite-shm
*.sqlite-wal
# Nuget files
DeploymentSettings.props
Directory.Build.props
Directory.Build.targets
Packages.props
#Local Log Files
log*.txt
.NET Extension Library Files
/src/dotnet/lib

5
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"recommendations": [
"github.vscode-pull-request-github"
]
}

72
README-DotNet.md Normal file
View File

@ -0,0 +1,72 @@
.NET extension for NORM
==========================
By:
Jeff Muller <jeffrey.muller3.ctr@us.navy.mil>
Sylvester Freeman <sylvester.freeman18.civ@us.navy.mil>
Sergiy Yermak <sergiy.yermak.ctr@us.navy.mil>
The .NET extension for NORM provides a .NET wrapper for the NORM C API.
For documentation about the main NORM API calls, refer to the NORM Developers
guide in the regular NORM distribution.
The .NET extension can be built using the .NET CLI.
------------
Requirements
------------
The .NET extension for NORM requires at least .NET SDK 6.0.
The NORM library should be built prior to building the .NET extension since it is invoked by the .NET extension.
------------
Building
------------
To build the .NET extension for NORM, execute the .NET CLI command in the src/dotnet directory:
```
dotnet build .
```
------------
Testing
------------
To test the .NET extension for NORM, execute the .NET CLI command in the src/dotnet directory:
```
dotnet test .
```
The test command results should show that all tests have passed.
Some tests might be skipped due to IO exception.
------------
Packaging
------------
To package the .NET extension for NORM, execute the .NET CLI command in the src/dotnet directory:
```
dotnet pack . -c Release
```
To package the .NET extension for NORM that targets 64-bit Windows, execute the command in the src/dotnet directory:
```
pack-win-x64.bat
```
To package the .NET extension for NORM that targets 32-bit Windows, execute the command in the src/dotnet directory:
```
pack-win-x86.bat
```
To package the .NET extension for NORM that targets 64-bit Linux, execute the command in the src/dotnet directory:
```
./pack-linux-x64.sh
```

View File

@ -0,0 +1,85 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33213.308
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mil.Navy.Nrl.Norm", "src\Mil.Navy.Nrl.Norm\Mil.Navy.Nrl.Norm.csproj", "{0B38FE25-685E-4ADC-B63D-CA43EC023E1F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A6F15F54-6953-49E7-9394-8F6BF6EF64D0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mil.Navy.Nrl.Norm.IntegrationTests", "tests\Mil.Navy.Nrl.Norm.IntegrationTests\Mil.Navy.Nrl.Norm.IntegrationTests.csproj", "{E5CDA4C5-C1A1-4AD7-B10D-80B8A995FC49}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{8B6C912C-2A15-41F3-B3A4-E9C01E6672DE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mil.Navy.Nrl.Norm.win-x64", "src\Mil.Navy.Nrl.Norm.win-x64\Mil.Navy.Nrl.Norm.win-x64.csproj", "{EC81BD1A-ECF0-4F4D-86E3-B0B53531EBD4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mil.Navy.Nrl.Norm.win-x86", "src\Mil.Navy.Nrl.Norm.win-x86\Mil.Navy.Nrl.Norm.win-x86.csproj", "{E5EABC55-159A-4AA2-80EC-F817C20BDA40}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CD4475A5-559A-4852-A2FE-E85A8AB9E0D8}"
ProjectSection(SolutionItems) = preProject
pack-linux.sh = pack-linux.sh
pack-win32.bat = pack-win32.bat
pack-win64.bat = pack-win64.bat
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mil.Navy.Nrl.Norm.linux-x64", "src\Mil.Navy.Nrl.Norm.linux-x64\Mil.Navy.Nrl.Norm.linux-x64.csproj", "{A4967E0C-FF3E-4B61-BD6B-D63D040585CA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Release-linux-x64|Any CPU = Release-linux-x64|Any CPU
Release-win-x64|Any CPU = Release-win-x64|Any CPU
Release-win-x86|Any CPU = Release-win-x86|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0B38FE25-685E-4ADC-B63D-CA43EC023E1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B38FE25-685E-4ADC-B63D-CA43EC023E1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B38FE25-685E-4ADC-B63D-CA43EC023E1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B38FE25-685E-4ADC-B63D-CA43EC023E1F}.Release|Any CPU.Build.0 = Release|Any CPU
{0B38FE25-685E-4ADC-B63D-CA43EC023E1F}.Release-linux-x64|Any CPU.ActiveCfg = Release|Any CPU
{0B38FE25-685E-4ADC-B63D-CA43EC023E1F}.Release-linux-x64|Any CPU.Build.0 = Release|Any CPU
{0B38FE25-685E-4ADC-B63D-CA43EC023E1F}.Release-win-x64|Any CPU.ActiveCfg = Release|Any CPU
{0B38FE25-685E-4ADC-B63D-CA43EC023E1F}.Release-win-x64|Any CPU.Build.0 = Release|Any CPU
{0B38FE25-685E-4ADC-B63D-CA43EC023E1F}.Release-win-x86|Any CPU.ActiveCfg = Release|Any CPU
{0B38FE25-685E-4ADC-B63D-CA43EC023E1F}.Release-win-x86|Any CPU.Build.0 = Release|Any CPU
{E5CDA4C5-C1A1-4AD7-B10D-80B8A995FC49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E5CDA4C5-C1A1-4AD7-B10D-80B8A995FC49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E5CDA4C5-C1A1-4AD7-B10D-80B8A995FC49}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E5CDA4C5-C1A1-4AD7-B10D-80B8A995FC49}.Release|Any CPU.Build.0 = Release|Any CPU
{E5CDA4C5-C1A1-4AD7-B10D-80B8A995FC49}.Release-linux-x64|Any CPU.ActiveCfg = Release|Any CPU
{E5CDA4C5-C1A1-4AD7-B10D-80B8A995FC49}.Release-win-x64|Any CPU.ActiveCfg = Release|Any CPU
{E5CDA4C5-C1A1-4AD7-B10D-80B8A995FC49}.Release-win-x86|Any CPU.ActiveCfg = Release|Any CPU
{EC81BD1A-ECF0-4F4D-86E3-B0B53531EBD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC81BD1A-ECF0-4F4D-86E3-B0B53531EBD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC81BD1A-ECF0-4F4D-86E3-B0B53531EBD4}.Release-linux-x64|Any CPU.ActiveCfg = Release|Any CPU
{EC81BD1A-ECF0-4F4D-86E3-B0B53531EBD4}.Release-win-x64|Any CPU.ActiveCfg = Release|Any CPU
{EC81BD1A-ECF0-4F4D-86E3-B0B53531EBD4}.Release-win-x64|Any CPU.Build.0 = Release|Any CPU
{EC81BD1A-ECF0-4F4D-86E3-B0B53531EBD4}.Release-win-x86|Any CPU.ActiveCfg = Release|Any CPU
{E5EABC55-159A-4AA2-80EC-F817C20BDA40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E5EABC55-159A-4AA2-80EC-F817C20BDA40}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E5EABC55-159A-4AA2-80EC-F817C20BDA40}.Release-linux-x64|Any CPU.ActiveCfg = Release|Any CPU
{E5EABC55-159A-4AA2-80EC-F817C20BDA40}.Release-win-x64|Any CPU.ActiveCfg = Release|Any CPU
{E5EABC55-159A-4AA2-80EC-F817C20BDA40}.Release-win-x86|Any CPU.ActiveCfg = Release|Any CPU
{E5EABC55-159A-4AA2-80EC-F817C20BDA40}.Release-win-x86|Any CPU.Build.0 = Release|Any CPU
{A4967E0C-FF3E-4B61-BD6B-D63D040585CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A4967E0C-FF3E-4B61-BD6B-D63D040585CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A4967E0C-FF3E-4B61-BD6B-D63D040585CA}.Release-linux-x64|Any CPU.ActiveCfg = Release|Any CPU
{A4967E0C-FF3E-4B61-BD6B-D63D040585CA}.Release-linux-x64|Any CPU.Build.0 = Release|Any CPU
{A4967E0C-FF3E-4B61-BD6B-D63D040585CA}.Release-win-x64|Any CPU.ActiveCfg = Release|Any CPU
{A4967E0C-FF3E-4B61-BD6B-D63D040585CA}.Release-win-x86|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{0B38FE25-685E-4ADC-B63D-CA43EC023E1F} = {A6F15F54-6953-49E7-9394-8F6BF6EF64D0}
{E5CDA4C5-C1A1-4AD7-B10D-80B8A995FC49} = {8B6C912C-2A15-41F3-B3A4-E9C01E6672DE}
{EC81BD1A-ECF0-4F4D-86E3-B0B53531EBD4} = {A6F15F54-6953-49E7-9394-8F6BF6EF64D0}
{E5EABC55-159A-4AA2-80EC-F817C20BDA40} = {A6F15F54-6953-49E7-9394-8F6BF6EF64D0}
{A4967E0C-FF3E-4B61-BD6B-D63D040585CA} = {A6F15F54-6953-49E7-9394-8F6BF6EF64D0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8BC1F27F-D633-4B45-A16D-D112CB08840E}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,7 @@
@startuml
abstract class ByteBuffer {
# ByteBuffer()
+ {static} AllocateDirect(capacity:int) : ByteBuffer
}
SafeBuffer <|-- ByteBuffer
@enduml

View File

@ -0,0 +1,7 @@
@startuml
class DirectByteBuffer <<sealed>> {
<<internal>> DirectByteBuffer(capacity:int)
# <<override>> ReleaseHandle() : bool
}
ByteBuffer <|-- DirectByteBuffer
@enduml

View File

@ -0,0 +1,8 @@
@startuml
enum NormAckingStatus {
NORM_ACK_INVALID,
NORM_ACK_FAILURE,
NORM_ACK_PENDING,
NORM_ACK_SUCCESS,
}
@enduml

View File

@ -0,0 +1,33 @@
@startuml
enum NormEventType {
NORM_EVENT_INVALID,
NORM_TX_QUEUE_VACANCY,
NORM_TX_QUEUE_EMPTY,
NORM_TX_FLUSH_COMPLETED,
NORM_TX_WATERMARK_COMPLETED,
NORM_TX_CMD_SENT,
NORM_TX_OBJECT_SENT,
NORM_TX_OBJECT_PURGED,
NORM_TX_RATE_CHANGED,
NORM_LOCAL_SENDER_CLOSED,
NORM_REMOTE_SENDER_NEW,
NORM_REMOTE_SENDER_RESET,
NORM_REMOTE_SENDER_ADDRESS,
NORM_REMOTE_SENDER_ACTIVE,
NORM_REMOTE_SENDER_INACTIVE,
NORM_REMOTE_SENDER_PURGED,
NORM_RX_CMD_NEW,
NORM_RX_OBJECT_NEW,
NORM_RX_OBJECT_INFO,
NORM_RX_OBJECT_UPDATED,
NORM_RX_OBJECT_COMPLETED,
NORM_RX_OBJECT_ABORTED,
NORM_RX_ACK_REQUEST,
NORM_GRTT_UPDATED,
NORM_CC_ACTIVE,
NORM_CC_INACTIVE,
NORM_ACKING_NODE_NEW,
NORM_SEND_ERROR,
NORM_USER_TIMEOUT,
}
@enduml

View File

@ -0,0 +1,7 @@
@startuml
enum NormFecType {
RS,
RS8,
SB,
}
@enduml

View File

@ -0,0 +1,7 @@
@startuml
enum NormFlushMode {
NORM_FLUSH_NONE,
NORM_FLUSH_PASSIVE,
NORM_FLUSH_ACTIVE,
}
@enduml

View File

@ -0,0 +1,7 @@
@startuml
enum NormNackingMode {
NORM_NACK_NONE,
NORM_NACK_INFO_ONLY,
NORM_NACK_NORMAL,
}
@enduml

View File

@ -0,0 +1,8 @@
@startuml
enum NormObjectType {
NORM_OBJECT_NONE,
NORM_OBJECT_DATA,
NORM_OBJECT_FILE,
NORM_OBJECT_STREAM,
}
@enduml

View File

@ -0,0 +1,7 @@
@startuml
enum NormProbingMode {
NORM_PROBE_NONE,
NORM_PROBE_PASSIVE,
NORM_PROBE_ACTIVE,
}
@enduml

View File

@ -0,0 +1,6 @@
@startuml
enum NormRepairBoundary {
NORM_BOUNDARY_BLOCK,
NORM_BOUNDARY_OBJECT,
}
@enduml

View File

@ -0,0 +1,7 @@
@startuml
enum NormSyncPolicy {
NORM_SYNC_CURRENT,
NORM_SYNC_STREAM,
NORM_SYNC_ALL,
}
@enduml

View File

@ -0,0 +1,9 @@
@startuml
enum NormTrackingStatus
{
NORM_TRACK_NONE
NORM_TRACK_RECEIVERS
NORM_TRACK_SENDERS
NORM_TRACK_ALL
}
@enduml

View File

@ -0,0 +1,5 @@
@startuml
interface INormEventListener {
NormEventOccurred(normEvent:NormEvent) : void
}
@enduml

View File

@ -0,0 +1,45 @@
@startuml
class NormInputStream {
- _normStream : NormStream?
- _closed : bool
- _closeLock : object
- _bufferIsEmpty : bool
- _receivedEof : bool
+ NormInputStream(address:string, port:int)
+ OpenDebugLog(fileName:string) : void
+ CloseDebugLog() : void
+ NormSetDebugLevel(level:int) : void
+ SetMessageTrace(messageTrace:bool) : void
+ SetMulticastInterface(multicastInterface:string) : void
+ SetEcnSupport(ecnEnable:bool, ignoreLoss:bool) : void
+ SetTtl(ttl:byte) : void
+ SetTos(tos:byte) : void
+ setSilentReceiver(silent:bool, maxDelay:int) : void
+ SetDefaultUnicastNack(defaultUnicastNack:bool) : void
+ SeekMsgStart() : void
+ AddNormEventListener(normEventListener:INormEventListener) : void
+ RemoveNormEventListener(normEventListener:INormEventListener) : void
- FireNormEventOccured(normEvent:NormEvent) : void
+ Open(bufferSpace:long) : void
+ <<override>> Close() : void
+ IsClosed : bool <<get>>
+ Read() : int
+ <<override>> Read(buffer:byte[], offset:int, count:int) : int
- ProcessEvent() : void
+ <<override>> Flush() : void
+ <<override>> Write(buffer:byte[], offset:int, count:int) : void
+ <<override>> Seek(offset:long, origin:SeekOrigin) : long
+ <<override>> SetLength(value:long) : void
+ <<override>> CanRead : bool <<get>>
+ <<override>> CanSeek : bool <<get>>
+ <<override>> CanWrite : bool <<get>>
+ <<override>> Length : long <<get>>
+ <<override>> Position : long <<get>> <<set>>
}
class "List`1"<T> {
}
Stream <|-- NormInputStream
NormInputStream --> "_normInstance" NormInstance
NormInputStream --> "_normSession" NormSession
NormInputStream --> "_normEventListeners<INormEventListener>" "List`1"
@enduml

View File

@ -0,0 +1,51 @@
@startuml
class NormOutputStream {
- _normStream : NormStream?
- _closed : bool
- _closeLock : object
- _bufferIsFull : bool
+ NormOutputStream(address:string, port:int)
+ OpenDebugLog(filename:string) : void
+ CloseDebugLog() : void
+ SetDebugLevel(level:int) : void
+ SetMessageTrace(messageTrace:bool) : void
+ SetMulticastInterface(multicastInterface:string) : void
+ SetEcnSupport(ecnEnable:bool, ignoreLoss:bool) : void
+ SetTtl(ttl:byte) : void
+ SetTos(tos:byte) : void
+ SetCongestionControl(ccEnabled:bool, ccAdjustRate:bool) : void
+ SetTxRateBounds(minTxRate:double, maxTxRate:double) : void
+ TxRate : double <<get>> <<set>>
+ GrttEstimate : double <<get>> <<set>>
+ SetGroupSize(groupSize:long) : void
+ SetAutoParity(autoParity:short) : void
+ SetBackoffFactor(backoffFactor:double) : void
+ SetAutoFlush(flushMode:NormFlushMode) : void
+ SetPushEnable(pushEnable:bool) : void
+ MarkEom() : void
+ AddNormEventListener(normEventListener:INormEventListener) : void
+ RemoveNormEventListener(normEventListener:INormEventListener) : void
- FireNormEventOccured(normEvent:NormEvent) : void
+ Open(sessionId:int, bufferSpace:long, segmentSize:int, blockSize:short, numParity:short, repairWindow:long) : void
+ <<override>> Close() : void
+ IsClosed : bool <<get>>
+ Write(b:int) : void
+ <<override>> Write(buffer:byte[], offset:int, count:int) : void
- ProcessEvent() : void
+ <<override>> Flush() : void
+ <<override>> Read(buffer:byte[], offset:int, count:int) : int
+ <<override>> Seek(offset:long, origin:SeekOrigin) : long
+ <<override>> SetLength(value:long) : void
+ <<override>> CanRead : bool <<get>>
+ <<override>> CanSeek : bool <<get>>
+ <<override>> CanWrite : bool <<get>>
+ <<override>> Length : long <<get>>
+ <<override>> Position : long <<get>> <<set>>
}
class "List`1"<T> {
}
Stream <|-- NormOutputStream
NormOutputStream --> "_normInstance" NormInstance
NormOutputStream --> "_normSession" NormSession
NormOutputStream --> "_normEventListeners<INormEventListener>" "List`1"
@enduml

View File

@ -0,0 +1,6 @@
@startuml
class StreamBreakException {
+ StreamBreakException(message:string?)
}
IOException <|-- StreamBreakException
@enduml

View File

@ -0,0 +1,119 @@
@startuml
class NormApi <<static>> {
+ <<const>> NORM_LIBRARY : string = "norm"
+ {static} <<extern>> NormCreateInstance(priorityBoost:bool) : long
+ {static} <<extern>> NormDestroyInstance(instanceHandle:long) : void
+ {static} <<extern>> NormStopInstance(instanceHandle:long) : void
+ {static} <<extern>> NormRestartInstance(instanceHandle:long) : bool
+ {static} <<extern>> NormSuspendInstance(instanceHandle:long) : bool
+ {static} <<extern>> NormResumeInstance(instanceHandle:long) : bool
+ {static} <<extern>> NormSetCacheDirectory(instanceHandle:long, cachePath:string) : bool
+ {static} <<extern>> NormGetNextEvent(instanceHandle:long, theEvent:NormEvent, waitForEvent:bool) : bool
+ {static} <<extern>> NormGetDescriptor(instanceHandle:long) : int
+ {static} <<extern>> NormCreateSession(instanceHandle:long, sessionAddress:string, sessionPort:int, localNodeId:long) : long
+ {static} <<extern>> NormDestroySession(sessionHandle:long) : void
+ {static} <<extern>> NormGetLocalNodeId(sessionHandle:long) : long
+ {static} <<extern>> NormSetTxPort(sessionHandle:long, txPortNumber:int, enableReuse:bool, txBindAddress:string?) : bool
+ {static} <<extern>> NormSetTxOnly(sessionHandle:long, txOnly:bool, connectToSessionAddress:bool) : void
+ {static} <<extern>> NormSetRxPortReuse(sessionHandle:long, enableReuse:bool, rxBindAddress:string?, senderAddress:string?, senderPort:int) : void
+ {static} <<extern>> NormSetEcnSupport(sessionHandle:long, ecnEnable:bool, ignoreLoss:bool, tolerateLoss:bool) : void
+ {static} <<extern>> NormSetMulticastInterface(sessionHandle:long, interfaceName:string) : bool
+ {static} <<extern>> NormSetSSM(sessionHandle:long, sourceAddress:string) : bool
+ {static} <<extern>> NormSetTTL(sessionHandle:long, ttl:byte) : bool
+ {static} <<extern>> NormSetTOS(sessionHandle:long, tos:byte) : bool
+ {static} <<extern>> NormSetLoopback(sessionHandle:long, loopback:bool) : bool
+ {static} <<extern>> NormSetMessageTrace(sessionHandle:long, flag:bool) : void
+ {static} <<extern>> NormSetTxLoss(sessionHandle:long, precent:double) : void
+ {static} <<extern>> NormSetRxLoss(sessionHandle:long, precent:double) : void
+ {static} <<extern>> NormOpenDebugLog(instanceHandle:long, path:string) : bool
+ {static} <<extern>> NormCloseDebugLog(instanceHandle:long) : bool
+ {static} <<extern>> NormOpenDebugPipe(instanceHandle:long, pipeName:string) : bool
+ {static} <<extern>> NormSetDebugLevel(level:int) : void
+ {static} <<extern>> NormGetDebugLevel() : int
+ {static} <<extern>> NormSetReportInterval(sessionHandle:long, interval:double) : void
+ {static} <<extern>> NormGetReportInterval(sessionHandle:long) : double
+ {static} <<extern>> NormGetRandomSessionId() : int
+ {static} <<extern>> NormStartSender(instanceHandle:long, instanceId:int, bufferSpace:long, segmentSize:int, numData:short, numParity:short, fecId:NormFecType) : bool
+ {static} <<extern>> NormStopSender(sessionHandle:long) : void
+ {static} <<extern>> NormSetTxRate(sessionHandle:long, rate:double) : void
+ {static} <<extern>> NormGetTxRate(sessionHandle:long) : double
+ {static} <<extern>> NormSetTxSocketBuffer(sessionHandle:long, bufferSize:long) : bool
+ {static} <<extern>> NormSetFlowControl(sessionHandle:long, flowControlFactor:double) : void
+ {static} <<extern>> NormSetCongestionControl(sessionHandle:long, enable:bool, adjustRate:bool) : void
+ {static} <<extern>> NormSetTxRateBounds(sessionHandle:long, rateMin:double, rateMax:double) : void
+ {static} <<extern>> NormSetTxCacheBounds(sessionHandle:long, sizeMax:long, countMin:long, countMax:long) : void
+ {static} <<extern>> NormSetAutoParity(sesssionHandle:long, autoParity:short) : void
+ {static} <<extern>> NormSetGrttEstimate(sessionHandle:long, grtt:double) : void
+ {static} <<extern>> NormGetGrttEstimate(sessionHandle:long) : double
+ {static} <<extern>> NormSetGrttMax(sessionHandle:long, grttMax:double) : void
+ {static} <<extern>> NormSetGrttProbingMode(sesssionHandle:long, probingMode:NormProbingMode) : void
+ {static} <<extern>> NormSetGrttProbingInterval(sessionHandle:long, intervalMin:double, intervalMax:double) : void
+ {static} <<extern>> NormSetBackoffFactor(sessionHandle:long, backoffFactor:double) : void
+ {static} <<extern>> NormSetGroupSize(sessionHandle:long, groupSize:long) : void
+ {static} <<extern>> NormSetTxRobustFactor(sessionHandle:long, txRobustFactor:int) : void
+ {static} <<extern>> NormFileEnqueue(sessionHandle:long, fileName:string, infoPtr:nint, infoLen:int) : long
+ {static} <<extern>> NormDataEnqueue(sessionHandle:long, dataPtr:nint, dataLen:int, infoPtr:nint, infoLen:int) : long
+ {static} <<extern>> NormRequeueObject(sessionHandle:long, objectHandle:long) : bool
+ {static} <<extern>> NormStreamOpen(sessionHandle:long, bufferSize:long, infoPtr:nint, infoLen:int) : long
+ {static} <<extern>> NormStreamClose(streamHandle:long, graceful:bool) : void
+ <<unsafe>> {static} <<extern>> NormStreamWrite(streamHandle:long, buffer:byte*, numBytes:int) : int
+ {static} <<extern>> NormStreamFlush(streamHandle:long, eom:bool, flushMode:NormFlushMode) : void
+ {static} <<extern>> NormStreamSetAutoFlush(streamHandle:long, flushMode:NormFlushMode) : void
+ {static} <<extern>> NormStreamSetPushEnable(streamHandle:long, pushEnable:bool) : void
+ {static} <<extern>> NormStreamHasVacancy(streamHandle:long) : bool
+ {static} <<extern>> NormStreamMarkEom(streamHandle:long) : void
+ {static} <<extern>> NormSetWatermark(sessionHandle:long, objectHandle:long, overrideFlush:bool) : bool
+ {static} <<extern>> NormResetWatermark(sessionHandle:long) : bool
+ {static} <<extern>> NormCancelWatermark(sessionHandle:long) : void
+ {static} <<extern>> NormAddAckingNode(sessionHandle:long, nodeId:long) : bool
+ {static} <<extern>> NormRemoveAckingNode(sessionHandle:long, nodeId:long) : void
+ {static} <<extern>> NormGetAckingStatus(sessionHandle:long, nodeId:long) : NormAckingStatus
+ {static} <<extern>> NormSendCommand(sessionHandle:long, cmdBuffer:nint, cmdLength:int, robust:bool) : bool
+ {static} <<extern>> NormCancelCommand(sessionHandle:long) : void
+ {static} <<extern>> NormStartReceiver(sessionHandle:long, bufferSpace:long) : bool
+ {static} <<extern>> NormStopReceiver(sessionHandle:long) : void
+ {static} <<extern>> NormSetRxCacheLimit(sessionHandle:long, countMax:int) : void
+ {static} <<extern>> NormSetRxSocketBuffer(sessionHandle:long, bufferSize:long) : bool
+ {static} <<extern>> NormSetSilentReceiver(sessionHandle:long, silent:bool, maxDelay:int) : void
+ {static} <<extern>> NormSetDefaultUnicastNack(sessionHandle:long, unicastNacks:bool) : void
+ {static} <<extern>> NormNodeSetUnicastNack(remoteSender:long, unicastNacks:bool) : void
+ {static} <<extern>> NormSetDefaultSyncPolicy(sessionHandle:long, syncPolicy:NormSyncPolicy) : void
+ {static} <<extern>> NormSetDefaultNackingMode(sessionHandle:long, nackingMode:NormNackingMode) : void
+ {static} <<extern>> NormNodeSetNackingMode(remoteSender:long, nackingMode:NormNackingMode) : void
+ {static} <<extern>> NormObjectSetNackingMode(objectHandle:long, nackingMode:NormNackingMode) : void
+ {static} <<extern>> NormSetDefaultRepairBoundary(sessionHandle:long, repairBoundary:NormRepairBoundary) : void
+ {static} <<extern>> NormNodeSetRepairBoundary(remoteSender:long, repairBoundary:NormRepairBoundary) : void
+ {static} <<extern>> NormSetDefaultRxRobustFactor(sessionHandle:long, robustFactor:int) : void
+ {static} <<extern>> NormNodeSetRxRobustFactor(remoteSender:long, robustFactor:int) : void
+ <<unsafe>> {static} <<extern>> NormStreamRead(streamHandle:long, buffer:byte*, numBytes:int) : bool
+ {static} <<extern>> NormStreamSeekMsgStart(streamHandle:long) : bool
+ {static} <<extern>> NormStreamGetReadOffset(streamHandle:long) : long
+ {static} <<extern>> NormObjectGetType(objectHandle:long) : NormObjectType
+ {static} <<extern>> NormObjectHasInfo(objectHandle:long) : bool
+ {static} <<extern>> NormObjectGetInfoLength(objectHandle:long) : int
+ {static} <<extern>> NormObjectGetInfo(objectHandle:long, buffer:byte[], bufferLen:int) : int
+ {static} <<extern>> NormObjectGetSize(objectHandle:long) : int
+ {static} <<extern>> NormObjectGetBytesPending(objectHandle:long) : long
+ {static} <<extern>> NormObjectCancel(objectHandle:long) : void
+ {static} <<extern>> NormObjectRetain(objectHandle:long) : void
+ {static} <<extern>> NormObjectRelease(objectHandle:long) : void
+ <<unsafe>> {static} <<extern>> NormFileGetName(fileHandle:long, nameBuffer:sbyte*, bufferLen:int) : bool
+ {static} <<extern>> NormFileRename(fileHandle:long, fileName:string) : bool
+ {static} <<extern>> NormDataAccessData(objectHandle:long) : nint
+ {static} <<extern>> NormObjectGetSender(objectHandle:long) : long
+ {static} <<extern>> NormNodeGetId(nodeHandle:long) : long
+ <<unsafe>> {static} <<extern>> NormNodeGetAddress(nodeHandle:long, addrBuffer:byte*, bufferLen:int, port:int) : bool
+ {static} <<extern>> NormNodeGetGrtt(nodeHandle:long) : double
+ <<unsafe>> {static} <<extern>> NormNodeGetCommand(remoteSender:long, cmdBuffer:byte*, buflen:int) : bool
+ {static} <<extern>> NormNodeFreeBuffers(remoteSender:long) : void
+ {static} <<extern>> NormNodeRetain(nodeHandle:long) : void
+ {static} <<extern>> NormNodeRelease(nodeHandle:long) : void
}
struct NormEvent {
+ Session : long
+ Sender : long
+ Object : long
}
NormApi +-- NormEvent
NormEvent --> "Type" NormEventType
@enduml

View File

@ -0,0 +1,7 @@
@startuml
class NormData {
+ GetData() : byte[]
<<internal>> NormData(handle:long)
}
NormObject <|-- NormData
@enduml

View File

@ -0,0 +1,14 @@
@startuml
class NormEvent {
- _sessionHandle : long <<get>>
- _nodeHandle : long <<get>>
- _objectHandle : long <<get>>
+ NormEvent(type:NormEventType, sessionHandle:long, nodeHandle:long, objectHandle:long)
+ <<override>> ToString() : string
}
NormEvent --> "_type" NormEventType
NormEvent --> "Type" NormEventType
NormEvent --> "Session" NormSession
NormEvent --> "Node" NormNode
NormEvent --> "Object" NormObject
@enduml

View File

@ -0,0 +1,9 @@
@startuml
class NormFile {
+ <<const>> FILENAME_MAX : int = 260
<<internal>> NormFile(handle:long)
+ <<unsafe>> Name : string <<get>>
+ Rename(filePath:string) : void
}
NormObject <|-- NormFile
@enduml

View File

@ -0,0 +1,24 @@
@startuml
class NormInstance {
+ <<const>> NORM_DESCRIPTOR_INVALID : int = 0
- _handle : long
+ NormInstance(priorityBoost:bool)
+ NormInstance()
- CreateInstance(priorityBoost:bool) : void
+ DestroyInstance() : void
+ CreateSession(address:string, port:int, localNodeId:long) : NormSession
+ HasNextEvent(sec:int, usec:int) : bool
+ HasNextEvent(waitTime:TimeSpan) : bool
+ GetNextEvent(waitForEvent:bool) : NormEvent?
+ GetNextEvent() : NormEvent?
+ SetCacheDirectory(cachePath:string) : void
+ StopInstance() : void
+ RestartInstance() : bool
+ SuspendInstance() : bool
+ ResumeInstance() : void
+ OpenDebugLog(fileName:string) : void
+ CloseDebugLog() : void
+ OpenDebugPipe(pipename:string) : void
+ DebugLevel : int <<get>> <<set>>
}
@enduml

View File

@ -0,0 +1,20 @@
@startuml
class NormNode {
+ <<const>> NORM_NODE_ANY : long = 0xffffffff
+ <<const>> NORM_NODE_NONE : int = 0
+ <<const>> NORM_NODE_INVALID : int = 0
- _handle : long
<<internal>> NormNode(handle:long)
+ Id : long <<get>>
+ Grtt : double <<get>>
+ GetCommand(buffer:byte[], offset:int, length:int) : int
+ SetUnicastNack(state:bool) : void
+ SetNackingMode(nackingMode:NormNackingMode) : void
+ SetRepairBoundary(repairBoundary:NormRepairBoundary) : void
+ SetRxRobustFactor(robustFactor:int) : void
+ FreeBuffers() : void
+ Retain() : void
+ Release() : void
}
NormNode --> "Address" IPEndPoint
@enduml

View File

@ -0,0 +1,19 @@
@startuml
class NormObject {
+ <<const>> NORM_OBJECT_INVALID : int = 0
# _handle : long
<<internal>> NormObject(handle:long)
+ Handle : long <<get>>
+ Info : byte[] <<get>>
+ Size : long <<get>>
+ Sender : long <<get>>
+ SetNackingMode(nackingMode:NormNackingMode) : void
+ GetBytesPending() : long
+ Cancel() : void
+ Retain() : void
+ Release() : void
+ <<override>> GetHashCode() : int
+ <<override>> Equals(obj:object?) : bool
}
NormObject --> "Type" NormObjectType
@enduml

View File

@ -0,0 +1,79 @@
@startuml
class NormSession {
+ <<const>> NORM_SESSION_INVALID : int = 0
- _handle : long
+ LocalNodeId : long <<get>>
+ ReportInterval : double <<get>> <<set>>
+ TxRate : double <<get>> <<set>>
+ GrttEstimate : double <<get>> <<set>>
<<internal>> NormSession(handle:long)
<<internal>> {static} GetSession(handle:long) : NormSession?
+ DestroySession() : void
- DestroySessionNative() : void
+ SetTxPort(port:int) : void
+ SetTxPort(port:int, enableReuse:bool, txBindAddress:string?) : void
+ SetTxOnly(txOnly:bool) : void
+ SetTxOnly(txOnly:bool, connectToSessionAddress:bool) : void
+ SetRxPortReuse(enable:bool) : void
+ SetRxPortReuse(enable:bool, rxBindAddress:string?, senderAddress:string?, senderPort:int) : void
+ SetEcnSupport(ecnEnable:bool, ignoreLoss:bool) : void
+ SetEcnSupport(ecnEnable:bool, ignoreLoss:bool, tolerateLoss:bool) : void
+ SetMulticastInterface(interfaceName:string) : void
+ SetSSM(sourceAddress:string) : void
+ SetTTL(ttl:byte) : void
+ SetTOS(tos:byte) : void
+ SetLoopback(loopbackEnable:bool) : void
+ SetMessageTrace(flag:bool) : void
+ SetTxLoss(precent:double) : void
+ SetRxLoss(precent:double) : void
+ SetFlowControl(precent:double) : void
+ SetTxSocketBuffer(bufferSize:long) : void
+ SetCongestionControl(enable:bool) : void
+ SetCongestionControl(enable:bool, adjustRate:bool) : void
+ SetTxRateBounds(rateMin:double, rateMax:double) : void
+ SetTxCacheBounds(sizeMax:long, countMin:long, countMax:long) : void
+ StartSender(sessionId:int, bufferSpace:long, segmentSize:int, blockSize:short, numParity:short, fecId:NormFecType) : void
+ StartSender(sessionId:int, bufferSpace:long, segmentSize:int, blockSize:short, numParity:short) : void
+ StartSender(bufferSpace:long, segmentSize:int, blockSize:short, numParity:short, fecId:NormFecType) : void
+ StartSender(bufferSpace:long, segmentSize:int, blockSize:short, numParity:short) : void
+ StopSender() : void
+ FileEnqueue(filename:string) : NormFile
+ FileEnqueue(filename:string, info:byte[]?, infoOffset:int, infoLength:int) : NormFile
+ DataEnqueue(dataBuffer:SafeBuffer, dataOffset:int, dataLength:int) : NormData
+ DataEnqueue(dataBuffer:SafeBuffer, dataOffset:int, dataLength:int, info:byte[]?, infoOffset:int, infoLength:int) : NormData
+ DataEnqueue(dataPtr:nint, dataOffset:int, dataLength:int) : NormData
+ DataEnqueue(dataPtr:nint, dataOffset:int, dataLength:int, info:byte[]?, infoOffset:int, infoLength:int) : NormData
+ StreamOpen(bufferSize:long) : NormStream
+ StreamOpen(bufferSize:long, info:byte[]?, infoOffset:int, infoLength:int) : NormStream
+ StartReceiver(bufferSpace:long) : void
+ StopReceiver() : void
+ SetAutoParity(autoParity:short) : void
+ SetGrttMax(grttMax:double) : void
+ SetGrttProbingMode(probingMode:NormProbingMode) : void
+ SetGrttProbingInterval(intervalMin:double, intervalMax:double) : void
+ SetBackoffFactor(backoffFactor:double) : void
+ SetGroupSize(groupSize:long) : void
+ SetTxRobustFactor(txRobustFactor:int) : void
+ RequeueObject(normObject:NormObject) : void
+ SetWatermark(normObject:NormObject) : void
+ SetWatermark(normObject:NormObject, overrideFlush:bool) : void
+ CancelWatermark() : void
+ ResetWatermark() : void
+ AddAckingNode(nodeId:long) : void
+ RemoveAckingNode(nodeId:long) : void
+ GetAckingStatus(nodeId:long) : NormAckingStatus
+ SendCommand(cmdBuffer:byte[], cmdOffset:int, cmdLength:int, robust:bool) : void
+ CancelCommand() : void
+ SetRxCacheLimit(countMax:int) : void
+ SetRxSocketBuffer(bufferSize:long) : void
+ SetSilentReceiver(silent:bool, maxDelay:int) : void
+ SetDefaultUnicastNack(enable:bool) : void
+ SetDefaultSyncPolicy(syncPolicy:NormSyncPolicy) : void
+ SetDefaultNackingMode(nackingMode:NormNackingMode) : void
+ SetDefaultRepairBoundary(repairBoundary:NormRepairBoundary) : void
+ SetDefaultRxRobustFactor(rxRobustFactor:int) : void
}
class "Dictionary`2"<T1,T2> {
}
NormSession o-> "_normSessions<long,NormSession>" "Dictionary`2"
@enduml

View File

@ -0,0 +1,18 @@
@startuml
class NormStream {
+ HasVacancy : bool <<get>>
+ ReadOffset : long <<get>>
<<internal>> NormStream(handle:long)
+ Write(buffer:byte[], offset:int, length:int) : int
+ MarkEom() : void
+ Flush(eom:bool, flushMode:NormFlushMode) : void
+ Flush() : void
+ Close(graceful:bool) : void
+ Close() : void
+ Read(buffer:byte[], offset:int, length:int) : int
+ SeekMsgStart() : bool
+ SetPushEnable(pushEnable:bool) : void
+ SetAutoFlush(flushMode:NormFlushMode) : void
}
NormObject <|-- NormStream
@enduml

View File

@ -0,0 +1,49 @@
@startuml NormFileSend
Client -> NormInstance : new()
NormInstance -> NormInstance : CreateInstance(false)
NormInstance -> NormApi : NormCreateInstance(false)
NormInstance <- NormApi : instanceHandle
Client <- NormInstance : NormInstance
Client -> NormInstance : CreateSession(address, port, localNodeId)
NormInstance -> NormApi : NormCreateSession(instanceHandle, address, port, localNodeId)
NormInstance <- NormApi : sessionHandle
alt sessionHandle == NormApi.NORM_SESSION_INVALID
NormInstance -> IOException : throw new("Failed to create session")
end
NormInstance -> NormSession : new(sessionHandle)
NormInstance <- NormSession : NormSession
Client <- NormInstance : NormSession
Client -> NormSession : StartSender(sessionId, bufferSpace, segmentSize, blockSize, numParity, fecId)
NormSession -> NormApi : NormStartSender(sessionHandle, sessionId, bufferSpace, segmentSize, blockSize, numParity, fecId)
NormSession <- NormApi : success
alt success == false
NormSession -> IOException : throw new("Failed to start sender")
end
Client -> NormSession : FileEnqueue(filename)
NormSession -> ASCII : GetBytes(filename)
NormSession <- ASCII : info
NormSession -> NormApi : NormFileEnqueue(sessionHandle, filename, info, info.Length)
NormSession <- NormApi : objectHandle
alt objectHandle == NormApi.NORM_OBJECT_INVALID
NormSession -> IOException : throw new("Failed to enqueue file")
end
NormSession -> NormFile: new(objectHandle)
NormSession <- NormFile : NormFile
Client <- NormSession : NormFile
loop NormInstance.HasNextEvent(waitTime)
Client -> NormInstance : GetNextEvent(false)
NormInstance -> NormApi : NormGetNextEvent(instanceHandle, NormEvent, false)
NormInstance <- NormApi : success
alt success == false
Client <- NormInstance : null
end
Client <- NormInstance : NormEvent
end
Client -> NormSession : StopSender();
NormSession -> NormApi : NormStopSender(sessionHandle)
Client -> NormSession : DestroySession()
NormSession -> NormSession : DestroySessionNative()
NormSession -> NormApi : NormDestroySession(sessionHandle)
Client -> NormInstance : DestroyInstance()
NormInstance -> NormApi : NormDestroyInstance(instanceHandle)
@enduml

View File

@ -0,0 +1,12 @@
#!/bin/bash
currenPath="$PWD"
cd ../../
./waf
cd "$currenPath"
libPath="$currenPath/lib"
if [ ! -d "$libPath" ]
then
mkdir "$libPath"
fi
cp -f ../../build/libnorm.so "$libPath/norm.so"
dotnet pack . -c Release-linux-x64

View File

@ -0,0 +1,14 @@
set currenPath=%cd%
cd ..\..\
python .\waf configure --msvc_target=x64
python .\waf
cd %currenPath%
if not exist lib\ (
mkdir lib
)
copy ..\..\build\norm*.dll lib
cd lib
del /f norm.dll
ren norm*.dll norm.dll
cd %currenPath%
dotnet pack . -c Release-win-x64

View File

@ -0,0 +1,14 @@
set currenPath=%cd%
cd ..\..\
python .\waf configure --msvc_target=x86
python .\waf
cd %currenPath%
if not exist lib\ (
mkdir lib
)
copy ..\..\build\norm*.dll lib
cd lib
del /f norm.dll
ren norm*.dll norm.dll
cd %currenPath%
dotnet pack . -c Release-win-x86

View File

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
<None Include="$(SolutionDir)lib\norm.so">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<PackagePath>runtimes/linux-x64/native</PackagePath>
<Pack>true</Pack>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Mil.Navy.Nrl.Norm\Mil.Navy.Nrl.Norm.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
<None Include="$(SolutionDir)lib\norm.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<PackagePath>runtimes/win-x64/native</PackagePath>
<Pack>true</Pack>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Mil.Navy.Nrl.Norm\Mil.Navy.Nrl.Norm.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
<None Include="$(SolutionDir)lib\norm.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<PackagePath>runtimes/win-x86/native</PackagePath>
<Pack>true</Pack>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Mil.Navy.Nrl.Norm\Mil.Navy.Nrl.Norm.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,26 @@
using System.Runtime.InteropServices;
namespace Mil.Navy.Nrl.Norm.Buffers
{
/// <summary>
/// A byte buffer
/// </summary>
public abstract class ByteBuffer : SafeBuffer
{
/// <summary>
/// Creates a new buffer
/// </summary>
protected ByteBuffer() : base(true)
{
}
/// <summary>
/// Allocates a new direct byte buffer
/// </summary>
/// <param name="capacity">The new buffer's capacity, in bytes</param>
/// <returns>The new byte buffer</returns>
public static ByteBuffer AllocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}
}
}

View File

@ -0,0 +1,30 @@
using System.Runtime.InteropServices;
namespace Mil.Navy.Nrl.Norm.Buffers
{
/// <summary>
/// A direct byte buffer
/// </summary>
internal sealed class DirectByteBuffer : ByteBuffer
{
/// <summary>
/// Creates a new direct byte buffer with given capacity
/// </summary>
/// <param name="capacity">The new buffer's capacity, in bytes</param>
internal DirectByteBuffer(int capacity)
{
SetHandle(Marshal.AllocHGlobal(capacity));
Initialize(Convert.ToUInt64(capacity));
}
/// <summary>
/// Executes the code required to free the handle
/// </summary>
/// <returns>true if the handle is released successfully; otherwise, in the event of a catastrophic failure, false</returns>
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
return true;
}
}
}

View File

@ -0,0 +1,28 @@
namespace Mil.Navy.Nrl.Norm.Enums
{
/// <summary>
/// The status of the watermark flushing process and/or positive acknowledgment collection.
/// </summary>
public enum NormAckingStatus
{
/// <summary>
/// The given sessionHandle is invalid or the given nodeId is not in the sender's acking list.
/// </summary>
NORM_ACK_INVALID,
/// <summary>
/// The positive acknowledgement collection process did not receive acknowledgment from every
/// listed receiver (nodeId = NORM_NODE_ANY) or the identified nodeId did not respond.
/// </summary>
NORM_ACK_FAILURE,
/// <summary>
/// The flushing process at large has not yet completed (nodeId = NORM_NODE_ANY) or the given
/// individual nodeId is still being queried for response.
/// </summary>
NORM_ACK_PENDING,
/// <summary>
/// All receivers (nodeId = NORM_NODE_ANY) responded with positive acknowledgement or the given
/// specific nodeId did acknowledge.
/// </summary>
NORM_ACK_SUCCESS
}
}

View File

@ -0,0 +1,194 @@
namespace Mil.Navy.Nrl.Norm.Enums
{
/// <summary>
/// The type identifies the event with one of NORM protocol events.
/// </summary>
public enum NormEventType
{
/// <summary>
/// This NormEventType indicates an invalid or "null" notification which should be ignored.
/// </summary>
NORM_EVENT_INVALID,
/// <summary>
/// This event indicates that there is room for additional transmit objects to be enqueued, or,
/// if the handle of NORM_OBJECT_STREAM is given in the corresponding
/// event "object" field, the application may successfully write to the indicated stream
/// object. Note this event is not dispatched until a call to NormFileEnqueue(),
/// NormDataEnqueue(), or NormStreamWrite() fails because of a filled transmit
/// cache or stream buffer.
/// </summary>
NORM_TX_QUEUE_VACANCY,
/// <summary>
/// This event indicates the NORM protocol engine has no new data pending transmission
/// and the application may enqueue additional objects for transmission.
/// If the handle of a sender NORM_OBJECT_STREAM is given in the corresponding event
/// "object" field, this indicates the stream transmit buffer has been emptied and the
/// sender application may write to the stream (Use of NORM_TX_QUEUE_VACANCY may
/// be preferred for this purpose since it allows the application to keep the NORM
/// protocol engine busier sending data, resulting in higher throughput when attempting
/// very high transfer rates).
/// </summary>
NORM_TX_QUEUE_EMPTY,
/// <summary>
/// This event indicates that the flushing process the NORM sender observes when
/// it no longer has data ready for transmission has completed. The completion of the
/// flushing process is a reasonable indicator (with a sufficient NORM "robust factor"
/// value) that the receiver set no longer has any pending repair requests. Note the
/// use of NORM's optional positive acknowledgement feature is more deterministic
/// in this regards, but this notification is useful when there are non-acking (NACK-only)
/// receivers. The default NORM robust factor of 20 (20 flush messages are
/// sent at end-of-transmission) provides a high assurance of reliable transmission,
/// even with packet loss rates of 50%.
/// </summary>
NORM_TX_FLUSH_COMPLETED,
/// <summary>
/// This event indicates that the flushing process initiated by a prior application call
/// to NormSetWatermark() has completed. The posting of this event indicates the
/// appropriate time for the application to make a call NormGetAckingStatus() to
/// determine the results of the watermark flushing process.
/// </summary>
NORM_TX_WATERMARK_COMPLETED,
/// <summary>
/// This event indicates that an application-defined command previously enqueued
/// with a call to NormSendCommand() has been transmitted, including any repetition.
/// </summary>
NORM_TX_CMD_SENT,
/// <summary>
/// This event indicates that the transport object referenced by the event's "object"
/// field has completed at least one pass of total transmission. Note that this does not
/// guarantee that reliable transmission has yet completed; only that the entire object
/// content has been transmitted. Depending upon network behavior, several rounds
/// of NACKing and repair transmissions may be required to complete reliable transfer.
/// </summary>
NORM_TX_OBJECT_SENT,
/// <summary>
/// This event indicates that the NORM protocol engine will no longer refer to the
/// transport object identified by the event's "object" field. Typically, this will occur
/// when the application has enqueued more objects than space available within the
/// set sender transmit cache bounds. Posting of this notification means the application is
/// free to free any resources (memory, files, etc) associated with the indicated "object".
/// After this event, the given "object" handle (NormObjectHandle) is no longer valid unless
/// it is specifically retained by the application.
/// </summary>
NORM_TX_OBJECT_PURGED,
/// <summary>
/// This event indicates that NORM Congestion Control operation has adjusted the
/// transmission rate. The NormGetTxRate() call may be used to retrieve the new
/// corresponding transmission rate. Note that if NormSetCongestionControl() was
/// called with its adjustRate parameter set to false, then no actual rate change has
/// occurred and the rate value returned by NormGetTxRate() reflects a "suggested"
/// rate and not the actual transmission rate.
/// </summary>
NORM_TX_RATE_CHANGED,
/// <summary>
/// This event is posted when the NORM protocol engine completes the "graceful
/// shutdown" of its participation as a sender in the indicated "session".
/// </summary>
NORM_LOCAL_SENDER_CLOSED,
/// <summary>
/// This event is posted when a receiver first receives messages from a specific remote
/// NORM sender. This marks the beginning of the interval during which the application
/// may reference the provided "node" handle (NormNodeHandle).
/// </summary>
NORM_REMOTE_SENDER_NEW,
/// <summary>
/// Remote sender instanceId or FEC params changed.
/// </summary>
NORM_REMOTE_SENDER_RESET,
/// <summary>
/// Remote sender src addr and/or port changed.
/// </summary>
NORM_REMOTE_SENDER_ADDRESS,
/// <summary>
/// This event is posted when a previously inactive (or new) remote sender is detected
/// operating as an active sender within the session.
/// </summary>
NORM_REMOTE_SENDER_ACTIVE,
/// <summary>
/// This event is posted after a significant period of inactivity (no sender messages
/// received) of a specific NORM sender within the session. The NORM protocol
/// engine frees buffering resources allocated for this sender when it becomes inactive.
/// </summary>
NORM_REMOTE_SENDER_INACTIVE,
/// <summary>
/// This event is posted when the NORM protocol engine frees resources for, and
/// thus invalidates the indicated "node" handle.
/// </summary>
NORM_REMOTE_SENDER_PURGED,
/// <summary>
/// This event indicates that an application-defined command has been received from
/// a remote sender. The NormEvent node element indicates the NormNodeHandle
/// value associated with the given sender. The NormNodeGetCommand() call can be
/// used to retrieve the received command content.
/// </summary>
NORM_RX_CMD_NEW,
/// <summary>
/// This event is posted when reception of a new transport object begins and marks
/// the beginning of the interval during which the specified "object" (NormObjectHandle)
/// is valid.
/// </summary>
NORM_RX_OBJECT_NEW,
/// <summary>
/// This notification is posted when the NORM_INFO content for the indicated "object" is received.
/// </summary>
NORM_RX_OBJECT_INFO,
/// <summary>
/// This event indicates that the identified receive "object" has newly received data content.
/// </summary>
NORM_RX_OBJECT_UPDATED,
/// <summary>
/// This event is posted when a receive object is completely received, including
/// available NORM_INFO content. Unless the application specifically retains the "object"
/// handle, the indicated NormObjectHandle becomes invalid and must no longer be
/// referenced.
/// </summary>
NORM_RX_OBJECT_COMPLETED,
/// <summary>
/// This notification is posted when a pending receive object's transmission is aborted
/// by the remote sender. Unless the application specifically retains the "object"
/// handle, the indicated NormObjectHandle becomes invalid and must no longer be
/// referenced.
/// </summary>
NORM_RX_OBJECT_ABORTED,
/// <summary>
/// Upon receipt of app-extended watermark ack request.
/// </summary>
NORM_RX_ACK_REQUEST,
/// <summary>
/// This notification indicates that either the local sender estimate of GRTT has
/// changed, or that a remote sender's estimate of GRTT has changed. The "sender"
/// member of the NormEvent is set to NORM_NODE_INVALID if the local sender's
/// GRTT estimate has changed or to the NormNodeHandle of the remote sender that
/// has updated its estimate of GRTT
/// </summary>
NORM_GRTT_UPDATED,
/// <summary>
/// This event indicates that congestion control feedback from receivers has begun
/// to be received (This also implies that receivers in the group are actually present
/// and can be used as a cue to begin data transmission.). Note that congestion control
/// must be enabled for this event to be posted.
/// Congestion control feedback can be assumed to be received until a NORM_CC_INACTIVE event is posted.
/// </summary>
NORM_CC_ACTIVE,
/// <summary>
/// This event indicates there has been no recent congestion control feedback received
/// from the receiver set and that the local NORM sender has reached its minimum
/// transmit rate. Applications may wish to refrain from new data transmission until
/// a NORM_CC_ACTIVE event is posted. This notification is only posted when congestion
/// control operation is enabled and a previous NORM_CC_ACTIVE event has occurred.
/// </summary>
NORM_CC_INACTIVE,
/// <summary>
/// When NormSetAutoAcking.
/// </summary>
NORM_ACKING_NODE_NEW,
/// <summary>
/// ICMP error (e.g. destination unreachable).
/// </summary>
NORM_SEND_ERROR,
/// <summary>
/// Issues when timeout set by NormSetUserTimer() expires.
/// </summary>
NORM_USER_TIMEOUT
}
}

View File

@ -0,0 +1,21 @@
namespace Mil.Navy.Nrl.Norm.Enums
{
/// <summary>
/// The valid FEC Types.
/// </summary>
public enum NormFecType
{
/// <summary>
/// Fully-specified, general purpose Reed-Solomon.
/// </summary>
RS,
/// <summary>
/// Fully-specified 8-bit Reed-Solmon per RFC 5510.
/// </summary>
RS8,
/// <summary>
/// Partially-specified "small block" codes.
/// </summary>
SB
}
}

View File

@ -0,0 +1,22 @@
namespace Mil.Navy.Nrl.Norm.Enums
{
/// <summary>
/// The possible flush modes.
/// </summary>
public enum NormFlushMode
{
/// <summary>
/// No flushing occurs unless explicitly requested via NormStreamFlush().
/// </summary>
NORM_FLUSH_NONE,
/// <summary>
/// Causes NORM to immediately transmit all enqueued data for the stream (subject to session transmit rate limits),
/// even if this results in NORM_DATA messages with "small" payloads.
/// </summary>
NORM_FLUSH_PASSIVE,
/// <summary>
/// The sender actively transmits NORM_CMD(FLUSH) messages after any enqueued stream content has been sent.
/// </summary>
NORM_FLUSH_ACTIVE
}
}

View File

@ -0,0 +1,21 @@
namespace Mil.Navy.Nrl.Norm.Enums
{
/// <summary>
/// The available nacking modes.
/// </summary>
public enum NormNackingMode
{
/// <summary>
/// Do not transmit any repair requests for the newly received object.
/// </summary>
NORM_NACK_NONE,
/// <summary>
/// Transmit repair requests for NORM_INFO content only as needed.
/// </summary>
NORM_NACK_INFO_ONLY,
/// <summary>
/// Transmit repair requests for entire object as needed.
/// </summary>
NORM_NACK_NORMAL
}
}

View File

@ -0,0 +1,25 @@
namespace Mil.Navy.Nrl.Norm.Enums
{
/// <summary>
/// The possible NORM data transport object types.
/// </summary>
public enum NormObjectType
{
/// <summary>
/// A special NormObjectType value, NORM_OBJECT_NONE, indicates an invalid object type.
/// </summary>
NORM_OBJECT_NONE,
/// <summary>
/// A transport object of type NORM_OBJECT_DATA.
/// </summary>
NORM_OBJECT_DATA,
/// <summary>
/// A transport object of type NORM_OBJECT_FILE.
/// </summary>
NORM_OBJECT_FILE,
/// <summary>
/// A transport object of type NORM_OBJECT_STREAM.
/// </summary>
NORM_OBJECT_STREAM
}
}

View File

@ -0,0 +1,24 @@
namespace Mil.Navy.Nrl.Norm.Enums
{
/// <summary>
/// The possible probing modes.
/// </summary>
public enum NormProbingMode
{
/// <summary>
/// The sender application must explicitly set its estimate of GRTT using the NormSetGrttEstimate() function.
/// </summary>
NORM_PROBE_NONE,
/// <summary>
/// The NORM sender still transmits NORM_CMD(CC) probe messages multiplexed with its data transmission,
/// but the receiver set does not explicitly acknowledge these probes. Instead the receiver set is limited
/// to opportunistically piggy-backing responses when NORM_NACK messages are generated.
/// </summary>
NORM_PROBE_PASSIVE,
/// <summary>
/// In this mode, the receiver set explicitly acknowledges NORM sender GRTT probes ((NORM_CMD(CC) messages)
/// with NORM_ACK responses that are group-wise suppressed.
/// </summary>
NORM_PROBE_ACTIVE
}
}

View File

@ -0,0 +1,22 @@
namespace Mil.Navy.Nrl.Norm.Enums
{
/// <summary>
/// The possible for values for NORM repair boundary.
/// </summary>
/// <remarks>
/// Customizes at what points the receiver initiates the NORM NACK repair process during protocol operation.
/// </remarks>
public enum NormRepairBoundary
{
/// <summary>
/// For smaller block sizes, the NACK repair process is often/quickly initiated and the
/// repair of an object will occur, as needed, during the transmission of the object.
/// </summary>
NORM_BOUNDARY_BLOCK,
/// <summary>
/// Causes the protocol to defer NACK process initiation until the current transport object
/// has been completely transmitted.
/// </summary>
NORM_BOUNDARY_OBJECT
}
}

View File

@ -0,0 +1,22 @@
namespace Mil.Navy.Nrl.Norm.Enums
{
/// <summary>
/// The possible synchronization policies.
/// </summary>
public enum NormSyncPolicy
{
/// <summary>
/// Attempt reception of "current" and new objects only (default).
/// </summary>
NORM_SYNC_CURRENT,
/// <summary>
/// Sync to current stream, but to beginning of stream.
/// </summary>
NORM_SYNC_STREAM,
/// <summary>
/// Attempt recovery and reliable reception of all objects
/// held in sender transmit object cache and newer objects.
/// </summary>
NORM_SYNC_ALL
}
}

View File

@ -0,0 +1,7 @@
namespace Mil.Navy.Nrl.Norm.IO
{
public interface INormEventListener
{
void NormEventOccurred(NormEvent normEvent);
}
}

View File

@ -0,0 +1,332 @@
using System.Runtime.CompilerServices;
namespace Mil.Navy.Nrl.Norm.IO
{
public class NormInputStream : Stream
{
private NormInstance _normInstance;
private NormSession _normSession;
private NormStream? _normStream;
private List<INormEventListener> _normEventListeners;
private bool _closed;
private object _closeLock;
private bool _bufferIsEmpty;
private bool _receivedEof;
/// <exception cref="IOException"></exception>
public NormInputStream(string address, int port)
{
// Create the NORM instance
_normInstance = new NormInstance();
// Create the NORM session
_normSession = _normInstance.CreateSession(address, port, NormNode.NORM_NODE_ANY);
_normStream = null;
_normEventListeners = new List<INormEventListener>();
_closed = true;
_closeLock = new object();
_bufferIsEmpty = true;
_receivedEof = false;
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void OpenDebugLog(string fileName)
{
if (fileName == null)
{
throw new IOException("File was name was not found.");
}
_normInstance.OpenDebugLog(fileName);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void CloseDebugLog() => _normInstance.CloseDebugLog();
[MethodImpl(MethodImplOptions.Synchronized)]
public void NormSetDebugLevel(int level) { _normInstance.DebugLevel = level; }
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetMessageTrace(bool messageTrace) => _normSession.SetMessageTrace(messageTrace);
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetMulticastInterface(string multicastInterface)
{
_normSession.SetMulticastInterface(multicastInterface);
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetEcnSupport(bool ecnEnable, bool ignoreLoss)
{
_normSession.SetEcnSupport(ecnEnable, ignoreLoss);
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetTtl(byte ttl)
{
_normSession.SetTTL(ttl);
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetTos(byte tos)
{
_normSession.SetTOS(tos);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void setSilentReceiver(bool silent, int maxDelay)
{
_normSession.SetSilentReceiver(silent, maxDelay);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetDefaultUnicastNack(bool defaultUnicastNack)
{
_normSession.SetDefaultUnicastNack(defaultUnicastNack);
}
/// <exception cref="InvalidOperationException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void SeekMsgStart()
{
if (_normStream == null)
{
throw new InvalidOperationException("Can only seek msg start after the stream is connected");
}
_normStream.SeekMsgStart();
}
/// <param name="normEventListener">The INormEventListener to add.</param>
[MethodImpl(MethodImplOptions.Synchronized)]
public void AddNormEventListener(INormEventListener normEventListener)
{
lock (_normEventListeners)
{
_normEventListeners.Add(normEventListener);
}
}
/// <param name="normEventListener">The INormEventListener to remove.</param>
[MethodImpl(MethodImplOptions.Synchronized)]
public void RemoveNormEventListener(INormEventListener normEventListener)
{
lock (_normEventListeners)
{
_normEventListeners.Remove(normEventListener);
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
private void FireNormEventOccured(NormEvent normEvent)
{
lock (_normEventListeners)
{
foreach (var normEventListener in _normEventListeners)
{
normEventListener.NormEventOccurred(normEvent);
}
}
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void Open(long bufferSpace)
{
lock (_closeLock)
{
if (!IsClosed)
{
throw new IOException("Stream is already open");
}
_normSession.StartReceiver(bufferSpace);
_closed = false;
}
}
/// <exception cref="IOException"></exception>
public override void Close()
{
lock (_closeLock)
{
if (IsClosed)
{
return;
}
_normStream?.Close(false);
_normSession.StopSender();
_normInstance.StopInstance();
_closed = true;
}
}
public bool IsClosed
{
get
{
lock (_closeLock)
{
return _closed;
}
}
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public int Read()
{
var buffer = new byte[1];
if (IsClosed)
{
throw new IOException("Stream is closed");
}
if (Read(buffer) < 0)
{
return -1;
}
return buffer[0];
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public override int Read(byte[] buffer, int offset, int count)
{
int n;
if (IsClosed)
{
throw new IOException("Stream is closed");
}
do
{
while (_bufferIsEmpty || _normInstance.HasNextEvent(0, 0))
{
ProcessEvent();
if (_receivedEof)
{
return -1;
}
}
if (_normStream == null)
{
return -1;
}
// Read from the stream
if ((n = _normStream.Read(buffer, offset, count)) < 0)
{
throw new IOException("Break in stream integrity");
}
_bufferIsEmpty = n == 0;
}
while (_bufferIsEmpty);
return n;
}
private void ProcessEvent()
{
// Retrieve the next event
var normEvent = _normInstance.GetNextEvent();
// Check if the stream was closed
if (IsClosed)
{
throw new IOException("Stream closed");
}
if (normEvent != null)
{
// Process the event
var eventType = normEvent.Type;
switch (eventType)
{
case NormEventType.NORM_RX_OBJECT_NEW:
var normObject = normEvent.Object;
if (normObject != null && normObject.Type == NormObjectType.NORM_OBJECT_STREAM)
{
_normStream = (NormStream)normObject;
}
break;
case NormEventType.NORM_RX_OBJECT_UPDATED:
var theNormObject = normEvent.Object;
if (theNormObject == null || !theNormObject.Equals(_normStream))
{
break;
}
// Signal that the buffer is not empty
_bufferIsEmpty = false;
break;
case NormEventType.NORM_RX_OBJECT_ABORTED:
case NormEventType.NORM_RX_OBJECT_COMPLETED:
_normStream = null;
// Signal that the stream has ended
_receivedEof = true;
break;
default:
break;
}
// Notify listeners of the norm event
FireNormEventOccured(normEvent);
}
}
public override void Flush()
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => throw new NotSupportedException();
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
}
}

View File

@ -0,0 +1,392 @@
using System.Runtime.CompilerServices;
namespace Mil.Navy.Nrl.Norm.IO
{
public class NormOutputStream : Stream
{
private NormInstance _normInstance;
private NormSession _normSession;
private NormStream? _normStream;
private List<INormEventListener> _normEventListeners;
private bool _closed;
private object _closeLock;
private bool _bufferIsFull;
/// <exception cref="IOException"></exception>
public NormOutputStream(string address, int port)
{
// Create the NORM instance
_normInstance = new NormInstance();
// Create the NORM session
_normSession = _normInstance.CreateSession(address, port, NormNode.NORM_NODE_ANY);
_normStream = null;
_normEventListeners = new List<INormEventListener>();
_closed = true;
_closeLock = new object();
_bufferIsFull = false;
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void OpenDebugLog(string filename)
{
_normInstance.OpenDebugLog(filename);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void CloseDebugLog()
{
_normInstance.CloseDebugLog();
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetDebugLevel(int level)
{
_normInstance.DebugLevel = level;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetMessageTrace(bool messageTrace)
{
_normSession.SetMessageTrace(messageTrace);
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetMulticastInterface(string multicastInterface)
{
_normSession.SetMulticastInterface(multicastInterface);
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetEcnSupport(bool ecnEnable, bool ignoreLoss)
{
_normSession.SetEcnSupport(ecnEnable, ignoreLoss);
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetTtl(byte ttl)
{
_normSession.SetTTL(ttl);
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetTos(byte tos)
{
_normSession.SetTOS(tos);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetCongestionControl(bool ccEnabled, bool ccAdjustRate)
{
_normSession.SetCongestionControl(ccEnabled, ccAdjustRate);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetTxRateBounds(double minTxRate, double maxTxRate)
{
_normSession.SetTxRateBounds(maxTxRate, minTxRate);
}
public double TxRate
{
get
{
lock (this)
{
return _normSession.TxRate;
}
}
set
{
lock (this)
{
_normSession.TxRate = value;
}
}
}
public double GrttEstimate
{
get
{
lock (this)
{
return _normSession.GrttEstimate;
}
}
set
{
lock (this)
{
_normSession.GrttEstimate = value;
}
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetGroupSize(long groupSize)
{
_normSession.SetGroupSize(groupSize);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetAutoParity(short autoParity)
{
_normSession.SetAutoParity(autoParity);
}
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetBackoffFactor(double backoffFactor)
{
_normSession.SetBackoffFactor(backoffFactor);
}
/// <exception cref="InvalidOperationException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetAutoFlush(NormFlushMode flushMode)
{
if (_normStream == null)
{
throw new InvalidOperationException("Can only set auto flush after the stream is open");
}
_normStream.SetAutoFlush(flushMode);
}
/// <exception cref="InvalidOperationException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void SetPushEnable(bool pushEnable)
{
if (_normStream == null)
{
throw new InvalidOperationException("Can only set push enabled after the stream is open");
}
_normStream.SetPushEnable(pushEnable);
}
/// <exception cref="InvalidOperationException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void MarkEom()
{
if (_normStream == null)
{
throw new InvalidOperationException("Can only mark EOM after the stream is open");
}
_normStream.MarkEom();
}
/// <param name="normEventListener">The INormEventListener to add.</param>
public void AddNormEventListener(INormEventListener normEventListener)
{
lock (_normEventListeners)
{
_normEventListeners.Add(normEventListener);
}
}
/// <param name="normEventListener">The INormEventListener to remove.</param>
public void RemoveNormEventListener(INormEventListener normEventListener)
{
lock (_normEventListeners)
{
_normEventListeners.Remove(normEventListener);
}
}
private void FireNormEventOccured(NormEvent normEvent)
{
lock (_normEventListeners)
{
foreach (var normEventListener in _normEventListeners)
{
normEventListener.NormEventOccurred(normEvent);
}
}
}
/// <exception cref="IOException"></exception>
public void Open(int sessionId, long bufferSpace, int segmentSize, short blockSize, short numParity, long repairWindow)
{
lock (_closeLock)
{
if (IsClosed)
{
throw new IOException("Stream is already open");
}
_normSession.StartSender(sessionId, bufferSpace, segmentSize, blockSize, numParity);
// Open the stream
_normStream = _normSession.StreamOpen(repairWindow);
_closed = false;
}
}
/// <exception cref="IOException"></exception>
public override void Close()
{
lock (_closeLock)
{
if (IsClosed)
{
return;
}
_normStream?.Close(false);
_normSession.StopSender();
_normInstance.StopInstance();
_closed = true;
}
}
public bool IsClosed
{
get
{
lock (_closeLock)
{
return _closed;
}
}
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public void Write(int b)
{
if (IsClosed)
{
throw new IOException("Stream is closed");
}
var buffer = new byte[1];
buffer[0] = (byte)b;
Write(buffer);
}
/// <exception cref="IOException"></exception>
[MethodImpl(MethodImplOptions.Synchronized)]
public override void Write(byte[] buffer, int offset, int count)
{
int n;
if (IsClosed)
{
throw new IOException("Stream is closed");
}
while (count > 0)
{
while (_normInstance.HasNextEvent(0, 0))
{
ProcessEvent();
}
// Wait while the buffer is full
while (_bufferIsFull)
{
ProcessEvent();
}
// Write some data
if (_normStream == null || (n = _normStream.Write(buffer, offset, count)) < 0)
{
throw new IOException("Failed to write to stream");
}
_bufferIsFull = n == 0;
count -= n;
offset += n;
}
}
/// <exception cref="IOException"></exception>
private void ProcessEvent()
{
// Retrieve the next event
var normEvent = _normInstance.GetNextEvent();
// Check if the stream was closed
if (IsClosed)
{
throw new IOException("Stream closed");
}
if (normEvent != null)
{
// Process the event
var eventType = normEvent.Type;
switch (eventType)
{
case NormEventType.NORM_TX_QUEUE_VACANCY:
case NormEventType.NORM_TX_QUEUE_EMPTY:
var normObject = normEvent.Object;
if (normObject == null || !normObject.Equals(_normStream))
{
break;
}
// Signal that the buffer is not full
_bufferIsFull = false;
break;
case NormEventType.NORM_TX_OBJECT_SENT:
case NormEventType.NORM_TX_OBJECT_PURGED:
_normStream = null;
break;
default:
break;
}
// Notify listeners of the norm event
FireNormEventOccured(normEvent);
}
}
public override void Flush()
{
throw new NotSupportedException();
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override bool CanRead => false;
public override bool CanSeek => false;
public override bool CanWrite => IsClosed;
public override long Length => throw new NotSupportedException();
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
}
}

View File

@ -0,0 +1,9 @@
namespace Mil.Navy.Nrl.Norm.IO
{
public class StreamBreakException : IOException
{
public StreamBreakException(string? message) : base(message)
{
}
}
}

View File

@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>1.0.0</Version>
</PropertyGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
using System.Runtime.InteropServices;
namespace Mil.Navy.Nrl.Norm
{
/// <summary>
/// A transport object of type NORM_OBJECT_DATA.
/// </summary>
/// <remarks>
/// The data storage area for the specified transport object.
/// </remarks>
public class NormData : NormObject
{
/// <summary>
/// Get the data storage area associated with a transport object of type NORM_OBJECT_DATA.
/// </summary>
public byte[] GetData()
{
var dataPointer = NormDataAccessData(_handle);
var length = NormObjectGetSize(_handle);
var data = new byte[length];
Marshal.Copy(dataPointer, data, 0, length);
return data;
}
/// <summary>
/// Constructor of NormData
/// </summary>
/// <param name="handle">Type is used to reference state kept for data transport objects being actively transmitted or received.</param>
internal NormData(long handle) : base(handle)
{
}
}
}

View File

@ -0,0 +1,112 @@
namespace Mil.Navy.Nrl.Norm
{
/// <summary>
/// The NormEvent type is used to describe significant NORM protocol events.
/// </summary>
public class NormEvent
{
/// <summary>
/// The type identifies the event with one of NORM protocol events.
/// </summary>
private NormEventType _type { get; }
/// <summary>
/// Used to identify application in the NormSession.
/// </summary>
private long _sessionHandle { get; }
/// <summary>
/// This type is used to reference state kept by the NORM implementation with respect to other participants within a NormSession.
/// </summary>
private long _nodeHandle { get; }
/// <summary>
/// This type is used to reference state kept for data transport objects being actively transmitted or received.
/// </summary>
private long _objectHandle { get; }
/// <summary>
/// The Parameterized constructor of NormEvent
/// </summary>
/// <param name="type">indicates the NormEventType and determines how the other fields should be interpreted.</param>
/// <param name="sessionHandle">indicates the applicable NormSessionHandle to which the event applies.</param>
/// <param name="nodeHandle">indicates the applicable NormNodeHandle to which the event applies</param>
/// <param name="objectHandle">indicates the applicable NormObjectHandle to which the event applies.</param>
public NormEvent(NormEventType type, long sessionHandle, long nodeHandle, long objectHandle)
{
_type = type;
_sessionHandle = sessionHandle;
_nodeHandle = nodeHandle;
_objectHandle = objectHandle;
}
/// <summary>
/// The type identifies the event with one of NORM protocol events.
/// </summary>
public NormEventType Type => _type;
/// <summary>
/// The NormSession associated with the event.
/// </summary>
public NormSession? Session
{
get
{
if (_sessionHandle == NormSession.NORM_SESSION_INVALID)
{
return null;
}
return NormSession.GetSession(_sessionHandle);
}
}
/// <summary>
/// A remote participant associated with the event.
/// </summary>
public NormNode? Node
{
get
{
if (_nodeHandle == 0)
{
return null;
}
return new NormNode(_nodeHandle);
}
}
/// <summary>
/// NORM transport object.
/// </summary>
public NormObject? Object
{
get
{
NormObject? normObject = null;
var normObjectType = NormObjectGetType(_objectHandle);
switch (normObjectType)
{
case NormObjectType.NORM_OBJECT_DATA:
normObject = new NormData(_objectHandle);
break;
case NormObjectType.NORM_OBJECT_FILE:
normObject = new NormFile(_objectHandle);
break;
case NormObjectType.NORM_OBJECT_STREAM:
normObject= new NormStream(_objectHandle);
break;
case NormObjectType.NORM_OBJECT_NONE:
default:
break;
}
return normObject;
}
}
/// <summary>
/// This function returns a description of the NORM protocol event
/// </summary>
/// <returns>A string that includes the event type.</returns>
public override string ToString()
{
return $"NormEvent [type={_type}]";
}
}
}

View File

@ -0,0 +1,55 @@
namespace Mil.Navy.Nrl.Norm
{
/// <summary>
/// A transport object of type NORM_OBJECT_FILE.
/// </summary>
public class NormFile : NormObject
{
/// <summary>
/// Maximum length of file names.
/// </summary>
public const int FILENAME_MAX = 260;
/// <summary>
/// Constructor of NormFile
/// </summary>
/// <param name="handle">This type is used to reference state kept for data transport objects being actively transmitted or received.</param>
internal NormFile(long handle) : base(handle)
{
}
/// <summary>
/// The name of the file.
/// </summary>
/// <exception cref="IOException">Thrown when failed to get file name.</exception>
public unsafe string Name
{
get
{
var buffer = stackalloc sbyte[FILENAME_MAX];
if (!NormFileGetName(_handle, buffer, FILENAME_MAX))
{
throw new IOException("Failed to get file name");
}
return new string(buffer);
}
}
/// <summary>
/// This function renames the file used to store content for the NORM_OBJECT_FILE transport object.
/// This allows receiver applications to rename (or move) received files as needed.
/// NORM uses temporary file names for received files until the application explicitly renames the file.
/// </summary>
/// <param name="filePath">The full path of received file.</param>
/// <exception cref="IOException">Thrown when failed to rename file.</exception>
public void Rename(string filePath)
{
if(!NormFileRename(_handle, filePath))
{
throw new IOException("Failed to rename file");
}
}
}
}

View File

@ -0,0 +1,235 @@
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Net.Sockets;
namespace Mil.Navy.Nrl.Norm
{
/// <summary>
/// An instance of a NORM protocol engine
/// </summary>
public class NormInstance
{
/// <summary>
/// Returned on error when getting the file descriptor for a NormInstance.
/// </summary>
public const int NORM_DESCRIPTOR_INVALID = 0;
/// <summary>
/// The _handle refers to the NORM protocol engine instance
/// </summary>
private long _handle;
/// <summary>
/// Constructor for NormInstance with priority boost
/// </summary>
/// <param name="priorityBoost">The priorityBoost parameter, when set to a value of true, specifies that the NORM protocol engine thread be run with higher priority scheduling.</param>
public NormInstance(bool priorityBoost)
{
CreateInstance(priorityBoost);
}
/// <summary>
/// Default constructor for NormInstance
/// </summary>
public NormInstance() : this(false)
{
}
/// <summary>
/// This function creates an instance of a NORM protocol engine and is the necessary first step before any other API functions may be used.
/// </summary>
/// <param name="priorityBoost">The priorityBoost parameter, when set to a value of true, specifies that the NORM protocol engine thread be run with higher priority scheduling.</param>
private void CreateInstance(bool priorityBoost)
{
var handle = NormCreateInstance(priorityBoost);
_handle = handle;
}
/// <summary>
/// The function immediately shuts down and destroys the NORM protocol engine instance referred to by the instanceHandle parameter.
/// </summary>
public void DestroyInstance()
{
NormDestroyInstance(_handle);
}
/// <summary>
/// This function creates a NORM protocol session (NormSession) using the address (multicast or unicast) and port
/// parameters provided. While session state is allocated and initialized, active session participation does not begin
/// until the session starts the sender and/or receiver to join the specified multicast group
/// (if applicable) and start protocol operation.
/// </summary>
/// <param name="address">Specified address determines the destination of NORM messages sent </param>
/// <param name="port">Valid, unused port number corresponding to the desired NORM session address. </param>
/// <param name="localNodeId">Identifies the application's presence in the NormSession </param>
/// <returns>The NormSession that was created</return
/// <exception cref="IOException">Throws when fails to create session</exception>
public NormSession CreateSession(string address, int port, long localNodeId)
{
var session = NormCreateSession(_handle, address, port, localNodeId);
if (session == NormSession.NORM_SESSION_INVALID)
{
throw new IOException("Failed to create session");
}
return new NormSession(session);
}
/// <summary>
/// Determines if the NORM protocol engine instance has a next event
/// </summary>
/// <param name="sec">The seconds to wait</param>
/// <param name="usec">The microseconds to wait</param>
/// <returns>True if the NORM protocol engine instance has a next event</returns>
public bool HasNextEvent(int sec, int usec)
{
var totalMilliseconds = sec * 1000 + usec / 1000;
var waitTime = TimeSpan.FromMilliseconds(totalMilliseconds);
return HasNextEvent(waitTime);
}
/// <summary>
/// Determines if the NORM protocol engine instance has a next event
/// </summary>
/// <param name="waitTime">The time to wait</param>
/// <returns>True if the NORM protocol engine instance has a next event</returns>
public bool HasNextEvent(TimeSpan waitTime)
{
var normDescriptor = NormGetDescriptor(_handle);
if (normDescriptor == NORM_DESCRIPTOR_INVALID)
{
return false;
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
using var eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
eventWaitHandle.SafeWaitHandle = new SafeWaitHandle(new IntPtr(normDescriptor), false);
return eventWaitHandle.WaitOne(waitTime);
}
var hasNextEvent = false;
var timeout = DateTime.Now.Add(waitTime);
while (!hasNextEvent && DateTime.Now <= timeout)
{
using var socketHandle = new SafeSocketHandle(new IntPtr(normDescriptor), false);
using var socket = new Socket(socketHandle);
hasNextEvent = socket.Available > 0;
}
return hasNextEvent;
}
/// <summary>
/// This function retrieves the next available NORM protocol event from the protocol engine.
/// </summary>
/// <param name="waitForEvent">waitForEvent specifies whether the call to this function is blocking or not, if "waitForEvent" is false, this is a non-blocking call. </param>
/// <returns>Returns an instance of NormEvent if NormGetNextEvent() returns true, returns null otherwise. </returns>
public NormEvent? GetNextEvent(bool waitForEvent)
{
bool success = NormGetNextEvent(_handle, out NormApi.NormEvent normEvent, waitForEvent);
if (!success)
{
return null;
}
return new NormEvent(normEvent.Type, normEvent.Session, normEvent.Sender, normEvent.Object);
}
/// <summary>
/// This function retrieves the next available NORM protocol event from the protocol engine.
/// </summary>
/// <remarks>
/// This is an overload which calls GetNextEvent() with waitForEvent set as true.
/// </remarks>
/// <returns>Returns an instance of NormEvent if NormGetNextEvent() returns true, returns null otherwise.</returns>
public NormEvent? GetNextEvent()
{
return GetNextEvent(true);
}
/// <summary>
/// This function sets the directory path used by receivers to cache newly-received NORM_OBJECT_FILE content.
/// </summary>
/// <param name="cachePath">the cachePath is a string specifying a valid (and writable) directory path.</param>
/// <exception cref="IOException">Throws when fails to set the cache directory</exception>
public void SetCacheDirectory(string cachePath)
{
if(!NormSetCacheDirectory(_handle, cachePath))
{
throw new IOException("Failed to set the cache directory");
}
}
/// <summary>
/// This function immediately stops the NORM protocol engine thread.
/// </summary>
public void StopInstance()
{
NormStopInstance(_handle);
}
/// <summary>
/// This function creates and starts an operating system thread to resume NORM protocol engine operation that was previously stopped by a call to StopInstance().
/// </summary>
/// <returns>Boolean as to the success of the instance restart. </return>
public bool RestartInstance()
{
return NormRestartInstance(_handle);
}
/// <summary>
/// Immediately suspends the NORM protocol engine thread.
/// </summary>
/// <returns>Boolean as to the success of the instance suspension. </returns>
public bool SuspendInstance()
{
return NormSuspendInstance(_handle);
}
/// <summary>
/// This function allows NORM debug output to be directed to a file instead of the default STDERR.
/// </summary>
public void ResumeInstance()
{
NormResumeInstance(_handle);
}
/// <summary>
/// This function allows NORM debug output to be directed to a file instead of the default STDERR.
/// </summary>
/// <param name="fileName">Full path and name of the debug log.</param>
/// <exception cref="IOException">Throws when fails to open debug log"</exception>
public void OpenDebugLog(string fileName)
{
if (!NormOpenDebugLog(_handle, fileName))
{
throw new IOException("Failed to open debug log");
}
}
/// <summary>
/// This function disables NORM debug output to be directed to a file instead of the default STDERR.
/// </summary>
public void CloseDebugLog()
{
NormCloseDebugLog(_handle);
}
/// <summary>
/// This function allows NORM debug output to be directed to a named pipe.
/// </summary>
/// <param name="pipename">The debug pipe name.</param>
/// <exception cref="IOException">Throws when fails to open debug pipe.</exception>
public void OpenDebugPipe(string pipename)
{
if (!NormOpenDebugPipe(_handle, pipename))
{
throw new IOException("Failed to open debug pipe");
}
}
/// <summary>
/// The currently set debug level.
/// </summary>
public int DebugLevel
{
get => NormGetDebugLevel();
set => NormSetDebugLevel(value);
}
}
}

View File

@ -0,0 +1,159 @@
using System.Net;
namespace Mil.Navy.Nrl.Norm
{
/// <summary>
/// A participant in a NORM protocol session
/// </summary>
public class NormNode
{
/// <summary>
/// When creating a session, allows the NORM implementation to attempt to pick an identifier based on the host computer's "default" IP address.
/// </summary>
public const long NORM_NODE_ANY = 0xffffffff;
/// <summary>
/// The special value NORM_NODE_NONE corresponds to an invalid (or null) node.
/// </summary>
public const int NORM_NODE_NONE = 0;
/// <summary>
/// The special value NORM_NODE_INVALID corresponds to an invalid reference.
/// </summary>
public const int NORM_NODE_INVALID = 0;
/// <summary>
/// The handle is associated to the NORM protocol engine instance.
/// </summary>
private long _handle;
/// <summary>
/// Parameterized contructor.
/// </summary>
/// <param name="handle">The handle is associated to the NORM protocol engine instance.</param>
internal NormNode(long handle)
{
_handle = handle;
}
/// <summary>
/// The NormNodeId identifier for the remote participant.
/// </summary>
public long Id => NormNodeGetId(_handle);
/// <summary>
/// The current network source address detected for packets received from remote NORM sender.
/// </summary>
public unsafe IPEndPoint Address
{
get
{
var bufferLength = 256;
var buffer = stackalloc byte[bufferLength];
if (!NormNodeGetAddress(_handle, buffer, ref bufferLength, out int port))
{
throw new IOException("Failed to get node address");
}
var addressBytes = new ReadOnlySpan<byte>(buffer, bufferLength);
var ipAddress = new IPAddress(addressBytes);
return new IPEndPoint(ipAddress, port);
}
}
/// <summary>
/// The advertised estimate of group round-trip timing (GRTT) for the remote sender.
/// </summary>
public double Grtt => NormNodeGetGrtt(_handle);
/// <summary>
/// This function retrieves the content of an application-defined command that was received from a remote sender.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">Thrown when the offset or length are outside of the buffer.</exception>
public int GetCommand(byte[] buffer, int offset, int length)
{
if (offset < 0 || offset >= buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset), "The offset is out of range");
}
if (length < 1 || offset + length > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(length), "The length is out of range");
}
unsafe
{
fixed (byte* bufferPtr = buffer)
{
if (!NormNodeGetCommand(_handle, bufferPtr + offset, ref length))
{
throw new IOException("Failed to get command");
}
}
}
return length;
}
/// <summary>
/// This function controls the destination address of receiver feedback messages generated in response to a specific remote NORM sender.
/// </summary>
/// <param name="state">If state is true, "unicast NACKing" is enabled.</param>
public void SetUnicastNack(bool state)
{
NormNodeSetUnicastNack(_handle, state);
}
/// <summary>
/// This function sets the default "nacking mode" used for receiving new objects from a specific sender.
/// </summary>
/// <param name="nackingMode">Specifies the nacking mode.</param>
public void SetNackingMode(NormNackingMode nackingMode)
{
NormNodeSetNackingMode(_handle, nackingMode);
}
/// <summary>
/// This function allows the receiver application to customize at what points the receiver initiates the NORM NACK repair process during protocol operation.
/// </summary>
/// <param name="repairBoundary">Specifies the repair boundary.</param>
public void SetRepairBoundary(NormRepairBoundary repairBoundary)
{
NormNodeSetRepairBoundary(_handle, repairBoundary);
}
/// <summary>
/// This routine sets the robustFactor as described in NormSetDefaultRxRobustFactor() for an individual remote sender.
/// </summary>
/// <param name="robustFactor">The robustFactor value determines how
/// many times a NORM receiver will self-initiate NACKing (repair requests) upon cessation of packet reception from
/// a sender. The default value is 20. Setting rxRobustFactor to -1 will make the NORM receiver infinitely persistent
/// (i.e., it will continue to NACK indefinitely as long as it is missing data content).</param>
public void SetRxRobustFactor(int robustFactor)
{
NormNodeSetRxRobustFactor(_handle, robustFactor);
}
/// <summary>
/// This function releases memory resources that were allocated for a remote sender.
/// </summary>
public void FreeBuffers()
{
NormNodeFreeBuffers(_handle);
}
/// <summary>
/// This function allows the application to retain state associated even when the underlying NORM protocol engine might normally free the associated state.
/// </summary>
public void Retain()
{
NormNodeRetain(_handle);
}
/// <summary>
/// This function releases the Node so that the NORM protocol engine may free associated resources as needed.
/// </summary>
public void Release()
{
NormNodeRelease(_handle);
}
}
}

View File

@ -0,0 +1,165 @@
namespace Mil.Navy.Nrl.Norm
{
/// <summary>
/// The base transport object.
/// </summary>
public class NormObject
{
/// <summary>
/// The special value NORM_OBJECT_INVALID corresponds to an invalid reference.
/// </summary>
public const int NORM_OBJECT_INVALID = 0;
/// <summary>
/// Used to reference state kept for data transport objects being actively transmitted or received.
/// </summary>
protected long _handle;
/// <summary>
/// Internal constructor for NormObject
/// </summary>
/// <param name="handle">Identifies an instance of NormObject</param>
internal NormObject(long handle)
{
_handle = handle;
}
/// <summary>
/// Used to reference state kept for data transport objects being actively transmitted or received.
/// </summary>
public long Handle => _handle;
/// <summary>
/// Data associated with NormObject.
/// </summary>
public byte[]? Info
{
get
{
if (!NormObjectHasInfo(_handle))
{
return null;
}
var length = NormObjectGetInfoLength(_handle);
var buffer = new byte[length];
NormObjectGetInfo(_handle, buffer, length);
return buffer;
}
}
/// <summary>
/// The type of Norm object.
/// Valid types include:
/// NORM_OBJECT_FILE
/// NORM_OBJECT_DATA
/// NORM_OBJECT_STREAM
/// </summary>
public NormObjectType Type
{
get
{
return NormObjectGetType(_handle);
}
}
/// <summary>
/// The size (in bytes) of the transport object.
/// </summary>
public long Size
{
get
{
return NormObjectGetSize(_handle);
}
}
/// <summary>
/// The NormNodeHandle corresponding to the remote sender of the transport object.
/// </summary>
/// <exception cref="IOException">Thrown when NormObjectGetSender() returns NORM_NODE_INVALID, indicating locally originated sender object.</exception>
public long Sender
{
get
{
var sender = NormObjectGetSender(_handle);
if(sender == NormNode.NORM_NODE_INVALID)
{
throw new IOException("Locally originated sender object");
}
return sender;
}
}
/// <summary>
/// This function sets the "nacking mode" used for receiving a specific transport object.
/// </summary>
/// <param name="nackingMode">Specifies the nacking mode.</param>
public void SetNackingMode(NormNackingMode nackingMode)
{
NormObjectSetNackingMode(_handle, nackingMode);
}
/// <summary>
/// This function can be used to determine the progress of reception of the NORM transport object
/// </summary>
/// <returns>A number of object source data bytes pending reception (or transmission) is returned.</returns>
public long GetBytesPending()
{
return NormObjectGetBytesPending(_handle);
}
/// <summary>
/// This function immediately cancels the transmission of a local sender transport object or the reception of a specified
/// object from a remote sender.
/// </summary>
public void Cancel()
{
NormObjectCancel(_handle);
}
/// <summary>
/// This function "retains" the objectHandle and any state associated with it for further use by the application even
/// when the NORM protocol engine may no longer require access to the associated transport object.
/// </summary>
public void Retain()
{
NormObjectRetain(_handle);
}
/// <summary>
/// This function complements the Retain() call by immediately freeing any resources associated with
/// the given objectHandle, assuming the underlying NORM protocol engine no longer requires access to the corresponding
/// transport object. Note the NORM protocol engine retains/releases state for associated objects for its own
/// needs and thus it is very unsafe for an application to call Release() for an objectHandle for which
/// it has not previously explicitly retained via Retain().
/// </summary>
public void Release()
{
NormObjectRelease(_handle);
}
/// <summary>
/// Gets the hash code of the object.
/// </summary>
/// <returns>Returns the handle of the object.</returns>
public override int GetHashCode()
{
return (int)_handle;
}
/// <summary>
/// Decides wether specified object is equal another.
/// </summary>
/// <param name="obj">NormObject to compare to.</param>
/// <returns>Returns true if two objects equal, false otherwise.</returns>
public override bool Equals(object? obj)
{
if(obj is NormObject)
{
return _handle == ((NormObject)obj).Handle;
}
return false;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
namespace Mil.Navy.Nrl.Norm
{
/// <summary>
/// A transport object of type NORM_OBJECT_STREAM.
/// </summary>
public class NormStream : NormObject
{
/// <summary>
/// This boolean tells whether the transmit stream, specified by the streamHandle parameter,
/// has buffer space available so that the application may successfully make a call to NormStreamWrite().
/// </summary>
public bool HasVacancy
{
get
{
return NormStreamHasVacancy(_handle);
}
}
/// <summary>
/// The current read offset value for the receive stream.
/// </summary>
public long ReadOffset
{
get
{
return NormStreamGetReadOffset(_handle);
}
}
/// <summary>
/// Internal constructor for NormStream
/// </summary>
/// <param name="handle">The handle is associated to the NORM protocol engine instance</param>
internal NormStream(long handle) : base(handle)
{
}
/// <summary>
/// This function enqueues data for transmission within the NORM stream.
/// </summary>
/// <param name="buffer">The buffer parameter must be a pointer to the data to be enqueued.</param>
/// <param name="offset">The offset indicated where in the buffer to start writing the data.
/// Note: If the data is written in its entirety, offset should be set to 0.</param>
/// <param name="length">The length parameter indicates the length of the data content.</param>
/// <returns>This function returns the number of bytes of data successfully enqueued for NORM stream transmission.</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when the offset or length are outside of the buffer.</exception>
public int Write(byte[] buffer, int offset, int length)
{
if (offset < 0 || offset >= buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset), "The offset is out of range");
}
if (length < 1 || offset + length > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(length), "The length is out of range");
}
int numBytes;
unsafe
{
fixed (byte* bufferPtr = buffer)
{
numBytes = NormStreamWrite(_handle, bufferPtr + offset, length);
}
}
return numBytes;
}
/// <summary>
/// This function allows the application to indicate to the NORM protocol engine that the last data successfully written
/// to the stream indicated by streamHandle corresponded to the end of an application-defined message boundary.
/// </summary>
public void MarkEom()
{
NormStreamMarkEom(_handle);
}
/// <summary>
/// This function causes an immediate "flush" of the transmit stream.
/// </summary>
/// <param name="eom">The optional eom parameter, when set to true, allows the sender application to mark an end-of-message indication
/// (see NormStreamMarkEom()) for the stream and initiate flushing in a single function call.</param>
/// <param name="flushMode">The default stream "flush" operation invoked via
/// NormStreamFlush() for flushMode equal to NORM_FLUSH_PASSIVE causes NORM to immediately transmit all
/// enqueued data for the stream(subject to session transmit rate limits), even if this results in NORM_DATA messages
/// with "small" payloads.If the optional flushMode parameter is set to NORM_FLUSH_ACTIVE, the application can
/// achieve reliable delivery of stream content up to the current write position in an even more proactive fashion.In
/// this case, the sender additionally, actively transmits NORM_CMD(FLUSH) messages after any enqueued stream
/// content has been sent. This immediately prompt receivers for repair requests which reduces latency of reliable
/// delivery, but at a cost of some additional messaging. Note any such "active" flush activity will be terminated upon
/// the next subsequent write to the stream.If flushMode is set to NORM_FLUSH_NONE, this call has no effect other than
/// the optional end-of-message marking described here. </param>
public void Flush(bool eom, NormFlushMode flushMode)
{
NormStreamFlush(_handle, eom, flushMode);
}
/// <summary>
/// This function causes an immediate "flush" of the transmit stream.
/// </summary>
/// <remarks>
/// This is an overload which calls Flush() with eom set as false and flushMode set to NORM_FLUSH_PASSIVE
/// </remarks>
public void Flush()
{
Flush(false, NormFlushMode.NORM_FLUSH_PASSIVE);
}
/// <summary>
/// This function halts transfer of the stream and releases any resources used unless the associated object
/// has been explicitly retained by a call to NormObjectRetain().
/// </summary>
/// <param name="graceful">The optional graceful parameter, when
/// set to a value of true, may be used by NORM senders to initiate "graceful" shutdown of a transmit stream.</param>
public void Close(bool graceful)
{
NormStreamClose(_handle, graceful);
}
/// <summary>
/// This function halts transfer of the stream and releases any resources used unless the associated object
/// has been explicitly retained by a call to NormObjectRetain().
/// </summary>
/// <remarks>
/// This is an overload which calls Close() with graceful set as false.
/// </remarks>
public void Close()
{
Close(false);
}
/// <summary>
/// This function can be used by the receiver application to read any available data from an incoming NORM stream.
/// </summary>
/// <param name="buffer">The buffer parameter must be a pointer to an array where the received
/// data can be stored of a length as referenced by the length parameter. </param>
/// <param name="offset">Indicates where in the buffer to start reading the data.
/// Note: To read the data in its entirety, begin at offset 0.</param>
/// <param name="length">Expected length of data received</param>
/// <returns>The length of data received</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when the offset or length are outside of the buffer.</exception>
public int Read(byte[] buffer, int offset, int length)
{
if (offset < 0 || offset >= buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset), "The offset is out of range");
}
if (length < 1 || offset + length > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(length), "The length is out of range");
}
unsafe
{
fixed (byte* bufferPtr = buffer)
{
if (!NormStreamRead(_handle, bufferPtr + offset, ref length))
{
length = -1;
}
}
}
return length;
}
/// <summary>
/// This function advances the read offset of the receive stream referenced by the streamHandle parameter to align
/// with the next available message boundary
/// </summary>
/// <returns>
/// This function returns a value of true when start-of-message is found. The next call to NormStreamRead() will
/// retrieve data aligned with the message start. If no new message boundary is found in the buffered receive data for
/// the stream, the function returns a value of false. In this case, the application should defer repeating a call to this
/// function until a subsequent NORM_RX_OBJECT_UPDATE notification is posted.</returns>
public bool SeekMsgStart()
{
return NormStreamSeekMsgStart(_handle);
}
/// <summary>
/// This function controls how the NORM API behaves when the application attempts to enqueue new stream data for transmission
/// when the associated stream's transmit buffer is fully occupied with data pending original or repair transmission.
/// </summary>
/// <param name="pushEnable"> By default (pushEnable = false), a call to NormStreamWrite() will return a zero value under this
/// condition, indicating it was unable to enqueue the new data. However, if pushEnable is set to true for a given
/// streamHandle, the NORM protocol engine will discard the oldest buffered stream data(even if it is pending repair
/// transmission or has never been transmitted) as needed to enqueue the new data.</param>
public void SetPushEnable(bool pushEnable)
{
NormStreamSetPushEnable(_handle, pushEnable);
}
/// <summary>
/// This function sets "automated flushing" for the NORM transmit stream indicated by the streamHandle parameter.
/// </summary>
/// <param name="flushMode">Possible values for the flushMode parameter include NORM_FLUSH_NONE, NORM_FLUSH_PASSIVE, and NORM_FLUSH_ACTIVE.</param>
public void SetAutoFlush(NormFlushMode flushMode)
{
NormStreamSetAutoFlush(_handle, flushMode);
}
}
}

View File

@ -0,0 +1,3 @@
global using static Mil.Navy.Nrl.Norm.NormApi;
global using NormEvent = Mil.Navy.Nrl.Norm.NormEvent;
global using Mil.Navy.Nrl.Norm.Enums;

View File

@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Bogus" Version="34.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Mil.Navy.Nrl.Norm\Mil.Navy.Nrl.Norm.csproj" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="copy ..\..\..\..\build\norm*.dll $(TargetDir)&#xD;&#xA;cd $(TargetDir)&#xD;&#xA;del /f norm.dll&#xD;&#xA;ren norm*.dll norm.dll" Condition="'$(OS)' == 'Windows_NT'" />
<Exec Command="cp -f ../../../../build/libnorm.so $(TargetDir)norm.so" Condition="'$(OS)' != 'Windows_NT'" />
</Target>
</Project>

View File

@ -0,0 +1,266 @@
using Bogus;
using Mil.Navy.Nrl.Norm.Buffers;
using System.Text;
namespace Mil.Navy.Nrl.Norm.IntegrationTests
{
/// <summary>
/// Tests for NORM instance
/// </summary>
public class NormInstanceTests : IDisposable
{
/// <summary>
/// The NORM instance
/// </summary>
private NormInstance _normInstance;
private NormSession? _normSession;
/// <summary>
/// Determines if the NORM instance has been destroyed
/// </summary>
private bool _isDestroyed;
private string _testPath;
private void CreateTestDirectory()
{
if (!Directory.Exists(_testPath))
{
Directory.CreateDirectory(_testPath);
}
}
private void DeleteTestDirectory()
{
if (Directory.Exists(_testPath))
{
Directory.Delete(_testPath, true);
}
}
/// <summary>
/// Default constructor for NORM instance tests
/// </summary>
/// <remarks>
/// Creates the NORM instance.
/// Initializes _isDestroyed to false.
/// </remarks>
public NormInstanceTests()
{
_normInstance = new NormInstance();
_isDestroyed = false;
var currentDirectory = Directory.GetCurrentDirectory();
_testPath = Path.Combine(currentDirectory, Guid.NewGuid().ToString());
CreateTestDirectory();
}
/// <summary>
/// Destroy the NORM instance
/// </summary>
private void DestroyInstance()
{
if (!_isDestroyed)
{
_normSession?.DestroySession();
_normInstance.CloseDebugLog();
_normInstance.DestroyInstance();
_isDestroyed = true;
}
}
/// <summary>
/// Dispose destroys the NORM instance
/// </summary>
public void Dispose()
{
DestroyInstance();
DeleteTestDirectory();
}
/// <summary>
/// Test for creating a NORM instance
/// </summary>
[Fact]
public void CreatesNormInstance()
{
Assert.NotNull(_normInstance);
}
/// <summary>
/// Test for creating a NORM instance
/// </summary>
[Fact]
public void CreatesNormInstanceWithPriorityBoost()
{
_normInstance.DestroyInstance();
_normInstance = new NormInstance(true);
Assert.NotNull(_normInstance);
}
/// <summary>
/// Test for destroying a NORM instance
/// </summary>
[Fact]
public void DestroysNormInstance()
{
DestroyInstance();
}
/// <summary>
/// Test for creating a NORM session
/// </summary>
[Fact]
public void CreatesSession()
{
var faker = new Faker();
var sessionAddress = "224.1.2.3";
var sessionPort = faker.Internet.Port();
var localNodeId = NormNode.NORM_NODE_ANY;
_normSession = _normInstance.CreateSession(sessionAddress, sessionPort, localNodeId);
Assert.NotNull(_normSession);
}
/// <summary>
/// Test for throwing an exception when attempting to create a NORM session with an invalid session address
/// </summary>
[Fact]
public void CreateSessionThrowsExceptionForInvalidSessionAddress()
{
var sessionAddress = "999.999.999.999";
var sessionPort = 6003;
var localNodeId = NormNode.NORM_NODE_ANY;
Assert.Throws<IOException>(() => _normInstance.CreateSession(sessionAddress, sessionPort, localNodeId));
}
[Fact]
public void StopInstance()
{
var sessionAddress = "224.1.2.3";
var sessionPort = 6003;
var localNodeId = NormNode.NORM_NODE_ANY;
_normSession = _normInstance.CreateSession(sessionAddress, sessionPort, localNodeId);
_normInstance.StopInstance();
}
[Fact]
public void RestartInstance()
{
var sessionAddress = "224.1.2.3";
var sessionPort = 6003;
var localNodeId = NormNode.NORM_NODE_ANY;
var expected = true;
_normSession = _normInstance.CreateSession(sessionAddress, sessionPort, localNodeId);
_normInstance.StopInstance();
var actual = _normInstance.RestartInstance();
Assert.Equal(expected,actual);
}
[Fact]
public void SuspendInstance()
{
var sessionAddress = "224.1.2.3";
var sessionPort = 6003;
var localNodeId = NormNode.NORM_NODE_ANY;
var expected = true;
_normSession = _normInstance.CreateSession(sessionAddress, sessionPort, localNodeId);
_normInstance.StopInstance();
var actual = _normInstance.SuspendInstance();
Assert.Equal(expected,actual);
}
[Fact]
public void ResumeInstance()
{
var sessionAddress = "224.1.2.3";
var sessionPort = 6003;
var localNodeId = NormNode.NORM_NODE_ANY;
_normSession = _normInstance.CreateSession(sessionAddress, sessionPort, localNodeId);
_normInstance.StopInstance();
_normInstance.ResumeInstance();
Assert.NotNull(_normInstance);
}
[Fact]
public void OpenDebugLog(){
var fileName = Guid.NewGuid().ToString();
var filePath = Path.Combine(_testPath, fileName);
_normInstance.OpenDebugLog(filePath);
}
[Fact]
public void CloseDebugLog()
{
_normInstance.CloseDebugLog();
}
[Fact]
public void OpensDebugPipe()
{
var pipename = "test.pipe";
Assert.Throws<IOException>(() => _normInstance.OpenDebugPipe(pipename));
}
[Fact]
public void SetsDebugLevel()
{
var expectedDebugLevel = 12;
_normInstance.DebugLevel = expectedDebugLevel;
var actualDebugLevel = _normInstance.DebugLevel;
Assert.Equal(expectedDebugLevel, actualDebugLevel);
}
[SkippableFact(typeof(IOException))]
public void HasEventsFromTimeSpan()
{
var faker = new Faker();
var sessionAddress = "224.1.2.3";
var sessionPort = faker.Internet.Port();
var localNodeId = NormNode.NORM_NODE_ANY;
_normSession = _normInstance.CreateSession(sessionAddress, sessionPort, localNodeId);
_normSession.StartSender(1024 * 1024, 1400, 64, 16);
var dataContent = faker.Lorem.Paragraph();
var data = Encoding.ASCII.GetBytes(dataContent);
using var dataBuffer = ByteBuffer.AllocateDirect(data.Length);
dataBuffer.WriteArray(0, data, 0, data.Length);
_normSession.DataEnqueue(dataBuffer, 0, data.Length);
Assert.True(_normInstance.HasNextEvent(TimeSpan.FromSeconds(1.5)));
_normSession.StopSender();
}
[SkippableFact(typeof(IOException))]
public void HasEventsFromSecondsAndMicroseconds()
{
var faker = new Faker();
var sessionAddress = "224.1.2.3";
var sessionPort = faker.Internet.Port();
var localNodeId = NormNode.NORM_NODE_ANY;
_normSession = _normInstance.CreateSession(sessionAddress, sessionPort, localNodeId);
_normSession.StartSender(1024 * 1024, 1400, 64, 16);
var dataContent = faker.Lorem.Paragraph();
var data = Encoding.ASCII.GetBytes(dataContent);
using var dataBuffer = ByteBuffer.AllocateDirect(data.Length);
dataBuffer.WriteArray(0, data, 0, data.Length);
_normSession.DataEnqueue(dataBuffer, 0, data.Length);
Assert.True(_normInstance.HasNextEvent(1, 500000));
_normSession.StopSender();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
global using Xunit;