Compare commits
124 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
1686404314 | |
|
|
75a3dd59ee | |
|
|
d6b4695c4c | |
|
|
0c4b130c7b | |
|
|
fcd2554051 | |
|
|
b0c38b4184 | |
|
|
823e3e8c88 | |
|
|
f3a60510ff | |
|
|
6a2da08d86 | |
|
|
9500578e89 | |
|
|
3802edadf1 | |
|
|
1c534c05f1 | |
|
|
4fd768f9cc | |
|
|
0c2e151a77 | |
|
|
9a613d4150 | |
|
|
a626a98f63 | |
|
|
d4faaebba4 | |
|
|
c8ffc272ee | |
|
|
006f9d29aa | |
|
|
b7b252fd55 | |
|
|
7a6c09ae17 | |
|
|
9a28f755cf | |
|
|
bc6e81feda | |
|
|
0c6e516c90 | |
|
|
2dfd41a0c5 | |
|
|
669fc4f671 | |
|
|
ebc65bd140 | |
|
|
78052bdb29 | |
|
|
f242b53b72 | |
|
|
8da63844ed | |
|
|
0015af3bb6 | |
|
|
2ae69e6e96 | |
|
|
6188965887 | |
|
|
a992176873 | |
|
|
af9a238a70 | |
|
|
4b34fffa8e | |
|
|
8ae9df5607 | |
|
|
69a9e4828d | |
|
|
34e582bfac | |
|
|
a15e91379e | |
|
|
11b271cc28 | |
|
|
1af8531178 | |
|
|
17dc41ab72 | |
|
|
61b6e31f6f | |
|
|
5b7239523f | |
|
|
78d7ac78a2 | |
|
|
a319a5b2d6 | |
|
|
6e7f2c3548 | |
|
|
b8ce922a36 | |
|
|
c0463960cb | |
|
|
92927c8a37 | |
|
|
6318f9bf62 | |
|
|
9f65f5e20a | |
|
|
40717bb5dd | |
|
|
b7f2a7073b | |
|
|
360996e4c7 | |
|
|
dbbbee1798 | |
|
|
ddd02a9010 | |
|
|
4fe403e7d8 | |
|
|
b43af9fc85 | |
|
|
f1e240cb28 | |
|
|
80fa426b0b | |
|
|
8842897961 | |
|
|
5adfa5902c | |
|
|
e9658ab837 | |
|
|
d00ebc22d2 | |
|
|
acbc31c1d0 | |
|
|
ea8a22c180 | |
|
|
b896f5408f | |
|
|
2e3d00e254 | |
|
|
61a87e6b5f | |
|
|
a00ea1b2df | |
|
|
e8fe5f4fcd | |
|
|
f8edc36cbf | |
|
|
a8c5688d40 | |
|
|
5872195eaa | |
|
|
d1d69f7820 | |
|
|
684c7303e2 | |
|
|
001d50aa46 | |
|
|
a08f387ec5 | |
|
|
a1bb33c354 | |
|
|
cc3a29b025 | |
|
|
f7f9d794f9 | |
|
|
858be37709 | |
|
|
1ba16231bb | |
|
|
5cd6498c39 | |
|
|
972b1a3e0b | |
|
|
9e796e69b2 | |
|
|
22aceaa271 | |
|
|
76023bd750 | |
|
|
053aa16eb8 | |
|
|
e9e3c99b21 | |
|
|
46a030891d | |
|
|
c29ef4adbd | |
|
|
039e70d601 | |
|
|
b9fab02215 | |
|
|
ebd51d79de | |
|
|
6f59618f4a | |
|
|
3fd9bad54e | |
|
|
2558ffcdc7 | |
|
|
38b61e3320 | |
|
|
8c9f0951ff | |
|
|
b997771fec | |
|
|
5dc78909ce | |
|
|
7c5afec284 | |
|
|
d1e8413cd3 | |
|
|
be88d6e79a | |
|
|
29bd835c69 | |
|
|
4f6f663671 | |
|
|
12c729aaff | |
|
|
5bf8b44cff | |
|
|
3306537ded | |
|
|
b44ce93125 | |
|
|
1bca647ef4 | |
|
|
4746eafe4f | |
|
|
ddb974e0ae | |
|
|
476b8bb7eb | |
|
|
01e161a31a | |
|
|
b66598c119 | |
|
|
9c367b50bc | |
|
|
213adb3938 | |
|
|
789ca317d6 | |
|
|
d73491bc28 | |
|
|
54bb708d48 |
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
*.sh text eol=lf
|
||||
|
|
@ -17,18 +17,19 @@ jobs:
|
|||
matrix:
|
||||
config:
|
||||
- {
|
||||
name: "Windows Latest MSVC Shared", artifact: "Windows-MSVC-shared.tar.xz",
|
||||
os: windows-latest,
|
||||
name: "Windows 2022 MSVC Shared", artifact: "Windows-MSVC-shared.tar.xz",
|
||||
os: windows-2022,
|
||||
cc: "cl", cxx: "cl",
|
||||
shared: "ON",
|
||||
environment_script: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat"
|
||||
environment_script: "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvars64.bat"
|
||||
}
|
||||
- {
|
||||
name: "Windows Latest MSVC", artifact: "Windows-MSVC.tar.xz",
|
||||
os: windows-latest,
|
||||
name: "Windows 2022 MSVC", artifact: "Windows-MSVC.tar.xz",
|
||||
os: windows-2022,
|
||||
cc: "cl", cxx: "cl",
|
||||
shared: "OFF",
|
||||
environment_script: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat"
|
||||
environment_script: "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvars64.bat"
|
||||
|
||||
}
|
||||
- {
|
||||
name: "Windows Latest MinGW", artifact: "Windows-MinGW.tar.xz",
|
||||
|
|
@ -50,7 +51,7 @@ jobs:
|
|||
}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download Ninja and CMake
|
||||
id: cmake_and_ninja
|
||||
|
|
@ -101,7 +102,7 @@ jobs:
|
|||
string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC)
|
||||
message("::set-output name=timestamp::${current_date}")
|
||||
- name: ccache cache files
|
||||
uses: actions/cache@v1.1.0
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .ccache
|
||||
key: ${{ matrix.config.name }}-ccache-${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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() }}
|
||||
|
|
@ -1,25 +1,37 @@
|
|||
|
||||
# build executables
|
||||
build/
|
||||
lib/
|
||||
bin/
|
||||
makefiles/norm
|
||||
makefiles/normMsgr
|
||||
makefiles/normStreamer
|
||||
makefiles/normCast
|
||||
makefiles/normCastApp
|
||||
makefiles/normClient
|
||||
makefiles/normServer
|
||||
makefiles/npc
|
||||
makefiles/raft
|
||||
makefiles/pcap2norm
|
||||
norp/makefiles/norp
|
||||
|
||||
# build object files
|
||||
*.o
|
||||
*.a
|
||||
|
||||
# python build files
|
||||
src/pynorm.egg-info
|
||||
**/__pycache__/
|
||||
|
||||
# build java files
|
||||
*.class
|
||||
|
||||
#build android files
|
||||
android/.gradle
|
||||
|
||||
# waf cruft
|
||||
.waf*
|
||||
.lock-waf*
|
||||
waf*/*
|
||||
|
||||
# OS generated files #
|
||||
.DS_Store
|
||||
|
|
@ -29,3 +41,275 @@ makefiles/pcap2norm
|
|||
.Trashes
|
||||
ehthumbs.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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"github.vscode-pull-request-github"
|
||||
]
|
||||
}
|
||||
|
|
@ -6,11 +6,26 @@ To see a full list of options, run:
|
|||
|
||||
./waf -h
|
||||
|
||||
Note: if attempting to run waf as an executable as shown above results in a
|
||||
message like this:
|
||||
|
||||
/usr/bin/env: ‘python’: No such file or directory
|
||||
|
||||
then try calling python directly:
|
||||
|
||||
python waf <args>
|
||||
|
||||
or
|
||||
|
||||
python3 waf <args>
|
||||
|
||||
For more background information about waf, visit the gitlab page at
|
||||
https://gitlab.com/ita1024/./waf/
|
||||
|
||||
Configuring
|
||||
-----------
|
||||
|
||||
To perform the configure checks, run:
|
||||
To perform the configuration checks, run:
|
||||
|
||||
./waf configure
|
||||
|
||||
|
|
@ -51,6 +66,9 @@ To install, run:
|
|||
This will install the compiled library and headers to wherever your prefix was
|
||||
specified. (See configure flags)
|
||||
|
||||
This command may have to be run with root priviledges for certain prefix
|
||||
directories depending on your system setup.
|
||||
|
||||
Uninstalling
|
||||
------------
|
||||
|
||||
|
|
@ -70,3 +88,8 @@ will delete all compiled files and configuration settings.
|
|||
./waf distclean
|
||||
|
||||
will do the same as clean, and additionally delete the waf cache files.
|
||||
|
||||
|
||||
ANDROID Build
|
||||
-------------
|
||||
See the "android" directory README for instructions.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
cmake_minimum_required(VERSION 3.11)
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
cmake_policy(SET CMP0077 NEW)
|
||||
# set the project name
|
||||
project(norm VERSION 1.5.8)
|
||||
project(norm VERSION 1.5.10)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(COMMON src/common)
|
||||
|
||||
|
|
@ -121,12 +125,26 @@ target_compile_options(norm PUBLIC ${PLATFORM_FLAGS})
|
|||
target_include_directories(norm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
target_include_directories(norm PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)
|
||||
|
||||
if(BUILD_SHARED_LIBS AND WIN32)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
set_target_properties(norm PROPERTIES SOVERSION 1.5.10)
|
||||
if(WIN32)
|
||||
target_compile_definitions(norm PUBLIC NORM_USE_DLL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_SHARED_LIBS AND BUILD_STATIC_LIBS)
|
||||
add_library(norm-static STATIC ${PLATFORM_SOURCE_FILES} ${COMMON_SOURCE_FILES} ${PUBLIC_HEADER_FILES})
|
||||
target_link_libraries(norm-static PRIVATE protokit::protokit)
|
||||
target_compile_definitions(norm-static PUBLIC ${PLATFORM_DEFINITIONS})
|
||||
target_compile_options(norm-static PUBLIC ${PLATFORM_FLAGS})
|
||||
target_include_directories(norm-static PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
target_include_directories(norm-static PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)
|
||||
set_target_properties(norm-static PROPERTIES OUTPUT_NAME "norm" PREFIX "lib")
|
||||
set(NORM_STATIC "norm-static")
|
||||
endif()
|
||||
|
||||
# Install target
|
||||
install( TARGETS norm protokit EXPORT normTargets
|
||||
install( TARGETS norm ${NORM_STATIC} protokit EXPORT normTargets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
|
|
@ -142,6 +160,16 @@ install( EXPORT normTargets
|
|||
|
||||
install(FILES include/normApi.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
# Create pkg-config file norm.pc
|
||||
# TODO: once waf is removed, norm.pc.in can be edited to use the variables CMake sets directly, and
|
||||
# remove these re-definitions
|
||||
set(VERSION ${PROJECT_VERSION})
|
||||
set(PREFIX ${CMAKE_INSTALL_PREFIX})
|
||||
set(LIBDIR ${CMAKE_INSTALL_LIBDIR})
|
||||
set(STATIC_LIBS "libprotokit.a")
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/norm.pc.in ${CMAKE_CURRENT_BINARY_DIR}/norm.pc @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/norm.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
|
||||
# Create a ConfigVersion.cmake file
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
|
|
@ -184,6 +212,7 @@ if(NORM_BUILD_EXAMPLES)
|
|||
normMsgr
|
||||
normStreamer
|
||||
normCast
|
||||
chant
|
||||
normClient
|
||||
normServer
|
||||
#wintest
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
ARG platformName=ubuntu
|
||||
ARG platformVersion=latest
|
||||
FROM ${platformName}:${platformVersion}
|
||||
|
||||
ARG version
|
||||
ARG configure
|
||||
ARG build="--targets=*"
|
||||
|
||||
ENV NORM_DIR=/norm-staging
|
||||
ENV NORM_BUILD=$NORM_DIR/build
|
||||
ENV WAF_CONFIGURE=${configure}
|
||||
ENV WAF_BUILD=${build}
|
||||
|
||||
ADD ./ ${NORM_DIR}
|
||||
|
||||
# Step 1: dependencies
|
||||
RUN VERSION=${version} ${NORM_DIR}/docker/setup.sh
|
||||
|
||||
# Step 2: build
|
||||
RUN cd ${NORM_DIR} && ./waf ${WAF_BUILD}
|
||||
|
||||
# Step 3: install
|
||||
RUN cd ${NORM_DIR} && ./waf install
|
||||
|
||||
# Step 4: expose
|
||||
COPY ./docker/run.sh /usr/bin/run-norm-example
|
||||
ENTRYPOINT [ "run-norm-example" ]
|
||||
|
|
@ -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
|
||||
```
|
||||
|
|
@ -28,7 +28,7 @@ in similar places as your system's compiler. On UNIX systems, this is usually
|
|||
PATH environment variable.
|
||||
|
||||
On Windows, PyNORM requires the "PyWin32" module, available at:
|
||||
http://sf.net/projects/pywin32
|
||||
https://sourceforge.net/projects/pywin32
|
||||
|
||||
-------------
|
||||
Installation
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
# norm
|
||||
|
||||
```
|
||||
NORM SOURCE CODE RELEASE
|
||||
|
||||
/*********************************************************************
|
||||
|
|
@ -29,6 +31,7 @@
|
|||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
********************************************************************/
|
||||
```
|
||||
|
||||
This is the NRL NORM source code repository.
|
||||
|
||||
|
|
@ -96,6 +99,37 @@ More info is available in the norp/doc directory, as well as the
|
|||
NORP website: https://www.nrl.navy.mil/itd/ncs/products/norp
|
||||
|
||||
|
||||
|
||||
Docker
|
||||
======
|
||||
A `Dockerfile` is provided to facilitate containerized NORM environment testing. Notable
|
||||
build arguments passed to `docker build` will influence how the image is created.
|
||||
|
||||
- `platformName` represents the base image name (defaults to `ubuntu`)
|
||||
- `platformVersion` represents the tagged version for the base image (defaults to `latest`)
|
||||
- `version` is a 1:1 mapping to this repo's tag (defaults to `v1.5.9`)
|
||||
- `configure` is piped to `./waf configure` (defaults to "")
|
||||
- `build` is piped to `./waf` (defaults to `--targets=*`)
|
||||
|
||||
Example usage:
|
||||
|
||||
CentOS7 build
|
||||
```
|
||||
docker build --build-arg platformName=centos \
|
||||
--build-arg platformVersion=7 \
|
||||
--build-arg="--build-java" \
|
||||
-t norm:centos-1.5.9 .
|
||||
```
|
||||
|
||||
Running the data send and recv examples:
|
||||
```
|
||||
# Sender in one terminal
|
||||
docker run -it --rm --name norm-send <norm:image> normDataSend
|
||||
# Receiver in another terminal
|
||||
docker run -it --rm --name norm-recv <norm:image> normDataRecv
|
||||
```
|
||||
|
||||
|
||||
OTHER FILES:
|
||||
============
|
||||
|
||||
|
|
@ -112,6 +146,8 @@ VERSION.TXT - NORM version history notes
|
|||
|
||||
README.md - this file
|
||||
|
||||
docker - directory containing docker container support
|
||||
|
||||
|
||||
NOTES:
|
||||
======
|
||||
|
|
@ -138,6 +174,3 @@ git checkout master
|
|||
|
||||
This will enable you to issue 'git pull', etc to treat the 'protolib'
|
||||
sub-directory as its own (sub-) repository.
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
NORM Version History
|
||||
|
||||
|
||||
Version 1.5.9 (in progress)
|
||||
Version 1.5.10 (in progress)
|
||||
=============
|
||||
- NormSocket API improvements
|
||||
|
||||
Version 1.5.9
|
||||
=============
|
||||
- Added "normCast" file send/receive example
|
||||
- Protolib ProtoTimer fix for "long" timeout intervals
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
This directoy contains Android Studio project files for building the NORM
|
||||
library for Android.
|
||||
|
||||
TO BUILD:
|
||||
|
||||
./gradlew build
|
||||
|
||||
The lib/build/ directory will contain the binary libraries built.
|
||||
|
||||
The "./gradlew clean" command can be used to delete the files built.
|
||||
|
||||
This directory may also be opened as an Android Studio project and built from
|
||||
the IDE GUI.
|
||||
|
||||
This will evolve as we update NORM and associated projects to the newer Android
|
||||
Studio tool chain.
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
This directory contains Android Studio project files for building the NORM
|
||||
library for Android.
|
||||
|
||||
REQUIREMENTS:
|
||||
|
||||
Ninja is required in order to run the ant build for the java .jar file
|
||||
|
||||
Download and install ndk and cmake using the SDK manager within Android Studio. To do this:
|
||||
|
||||
-> Tools -> SDK Manager -> System Settings -> Android SDK -> SDK Tools -> Select 'Show Package Details' at the bottom
|
||||
|
||||
The latest compatible versions are ndk version 20.0.5594570 and cmake version 3.10.2.4988404
|
||||
|
||||
* Important *
|
||||
If you decide to install different version of the SDK Tools above, make sure to edit the path locations in the local.properties file
|
||||
|
||||
TO BUILD:
|
||||
|
||||
./gradlew build
|
||||
|
||||
The lib/build/ directory will contain the binary libraries built.
|
||||
|
||||
The "./gradlew clean" command can be used to delete the files built.
|
||||
|
||||
This directory may also be opened as an Android Studio project and built from
|
||||
the IDE GUI.
|
||||
|
||||
This will evolve as we update NORM and associated projects to the newer Android
|
||||
Studio tool chain.
|
||||
|
||||
USAGE:
|
||||
|
||||
Copy the .aar file into your ${project.rootDir}/app/libs/ folder
|
||||
|
||||
Within your app level build.gradle include the following two tasks before your dependencies section:
|
||||
|
||||
```
|
||||
task extractSo(type: Copy) {
|
||||
println 'Extracting *.so file(s)....'
|
||||
|
||||
from zipTree("${project.rootDir}/app/libs/lib-release_-release.aar")
|
||||
into "${project.rootDir}/app/src/main/jniLibs"
|
||||
include "jni/**/*.so"
|
||||
|
||||
eachFile {
|
||||
def segments = it.getRelativePath().getSegments() as List
|
||||
println segments
|
||||
it.setPath(segments.tail().join("/"))
|
||||
return it
|
||||
}
|
||||
includeEmptyDirs = false
|
||||
}
|
||||
|
||||
task extractJar(type: Copy, dependsOn: extractSo) {
|
||||
println 'Extracting *.jar file(s)....'
|
||||
|
||||
from zipTree("${project.rootDir}/app/libs/lib-release_-release.aar")
|
||||
into "${project.rootDir}/app/libs/"
|
||||
include "norm-*.jar"
|
||||
}
|
||||
```
|
||||
|
|
@ -4,7 +4,7 @@ buildscript {
|
|||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.1'
|
||||
classpath 'com.android.tools.build:gradle:4.2.1'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1 +1,5 @@
|
|||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
|||
|
|
@ -1,74 +1,129 @@
|
|||
#!/usr/bin/env bash
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
|
@ -77,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
|||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
|
|
@ -85,76 +140,95 @@ location of your Java installation."
|
|||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,19 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
|
|
@ -8,20 +24,23 @@
|
|||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
|
@ -35,7 +54,7 @@ goto fail
|
|||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
|
|
@ -45,34 +64,14 @@ echo location of your Java installation.
|
|||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
project("norm")
|
||||
|
||||
add_definitions("-DANDROID=1" "-DANDROID_API_VERSION=24" "-DPUSH_NOTIFICATIONS=1" "-DANDROID" "-DLINUX" "-DUNIX" "-DHAVE_IPV6" "-DHAVE_DIRFD" "-DPROTO_DEBUG" "-DHAVE_ASSERT" "-DHAVE_GETLOGIN" "-DUSE_SELECT" "-D_FILE_OFFSET_BITS=64" "-DHAVE_OLD_SIGNALHANDLER" "-DHAVE_SCHED" "-DNO_SCM_RIGHTS" "-Wno-attributes" "-DAPP_VERSION=1.0.0" "-DAPP_VERSION_HEX=0x10000")
|
||||
|
||||
include_directories( AFTER
|
||||
"../../OID_NDK}/sources/android/cpufeatures"
|
||||
"../../include"
|
||||
"../../protolib/include"
|
||||
)
|
||||
|
||||
find_program(ANTPATH ant)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${ANTPATH}
|
||||
WORKING_DIRECTORY "$ENV{HOME}/norm/makefiles/java/"
|
||||
)
|
||||
|
||||
enable_language(ASM)
|
||||
|
||||
IF(BUILD_CONFIGURATION MATCHES "DEBUG")
|
||||
SET(BINARY_NAME "norm")
|
||||
add_definitions("-DDEBUG=1" "-D_DEBUG=1")
|
||||
ELSEIF(BUILD_CONFIGURATION MATCHES "RELEASE")
|
||||
SET(BINARY_NAME "norm")
|
||||
add_definitions("-DNDEBUG=1")
|
||||
ELSE(BUILD_CONFIGURATION MATCHES "DEBUG")
|
||||
MESSAGE( FATAL_ERROR "No matching build-configuration found." )
|
||||
ENDIF(BUILD_CONFIGURATION MATCHES "DEBUG")
|
||||
|
||||
add_subdirectory("../../protolib/android/lib" ./protolib)
|
||||
|
||||
add_library( ${BINARY_NAME}
|
||||
|
||||
STATIC
|
||||
|
||||
"../../src/common/galois.cpp"
|
||||
"../../src/common/normApi.cpp"
|
||||
"../../src/common/normEncoder.cpp"
|
||||
"../../src/common/normEncoderMDP.cpp"
|
||||
"../../src/common/normEncoderRS16.cpp"
|
||||
"../../src/common/normEncoderRS8.cpp"
|
||||
"../../src/common/normFile.cpp"
|
||||
"../../src/common/normMessage.cpp"
|
||||
"../../src/common/normNode.cpp"
|
||||
"../../src/common/normObject.cpp"
|
||||
"../../src/common/normSegment.cpp"
|
||||
"../../src/common/normSession.cpp"
|
||||
)
|
||||
|
||||
add_library( mil_navy_nrl_norm
|
||||
|
||||
SHARED
|
||||
|
||||
"../../src/java/jni/normDataJni.cpp"
|
||||
"../../src/java/jni/normEventJni.cpp"
|
||||
"../../src/java/jni/normFileJni.cpp"
|
||||
"../../src/java/jni/normInstanceJni.cpp"
|
||||
"../../src/java/jni/normJni.cpp"
|
||||
"../../src/java/jni/normNodeJni.cpp"
|
||||
"../../src/java/jni/normObjectJni.cpp"
|
||||
"../../src/java/jni/normSessionJni.cpp"
|
||||
"../../src/java/jni/normStreamJni.cpp"
|
||||
)
|
||||
|
||||
find_library(log "log")
|
||||
find_library(android "android")
|
||||
find_library(glesv2 "GLESv2")
|
||||
find_library(egl "EGL")
|
||||
|
||||
target_link_libraries(mil_navy_nrl_norm
|
||||
norm
|
||||
protokit
|
||||
${log}
|
||||
${android}
|
||||
${glesv2}
|
||||
${egl}
|
||||
)
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 34
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
signingConfigs {
|
||||
normSigning {
|
||||
storeFile file("${System.properties['user.home']}${File.separator}.android${File.separator}debug.keystore")
|
||||
storePassword "android"
|
||||
keyAlias "androiddebugkey"
|
||||
keyPassword "android"
|
||||
storeType "jks"
|
||||
}
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
arguments "-DANDROID_TOOLCHAIN=clang", "-DANDROID_PLATFORM=android-24", "-DCMAKE_MAKE_PROGRAM=/usr/local/bin/ninja", "-DANDROID_STL=c++_static", "-DANDROID_CPP_FEATURES=exceptions rtti", "-DANDROID_ARM_MODE=arm", "-DANDROID_ARM_NEON=TRUE"
|
||||
cFlags "-fsigned-char"
|
||||
cppFlags "-fsigned-char", "-std=c++14"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
initWith debug
|
||||
debuggable true
|
||||
jniDebuggable true
|
||||
signingConfig signingConfigs.normSigning
|
||||
}
|
||||
release {
|
||||
initWith release
|
||||
debuggable false
|
||||
jniDebuggable false
|
||||
signingConfig signingConfigs.normSigning
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "default"
|
||||
productFlavors {
|
||||
debug_ {
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
targets "norm", "mil_navy_nrl_norm"
|
||||
arguments "-DBUILD_CONFIGURATION=DEBUG", "-DCMAKE_CXX_FLAGS_DEBUG=-O0", "-DCMAKE_C_FLAGS_DEBUG=-O0"
|
||||
}
|
||||
}
|
||||
|
||||
dimension "default"
|
||||
}
|
||||
release_ {
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
targets "norm", "mil_navy_nrl_norm"
|
||||
arguments "-DBUILD_CONFIGURATION=RELEASE", "-DCMAKE_CXX_FLAGS_RELEASE=-O3", "-DCMAKE_C_FLAGS_RELEASE=-O3"
|
||||
}
|
||||
}
|
||||
|
||||
dimension "default"
|
||||
}
|
||||
}
|
||||
|
||||
variantFilter { variant ->
|
||||
def names = variant.flavors*.name
|
||||
if (names.contains ("debug_")
|
||||
&& variant.buildType.name != "debug") {
|
||||
setIgnore(true)
|
||||
}
|
||||
if (names.contains ("release_")
|
||||
&& variant.buildType.name != "release") {
|
||||
setIgnore(true)
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
task copyReleaseJar(type: Copy) {
|
||||
println 'Unzipping release .aar and including .jar....'
|
||||
|
||||
if (file("${project.rootDir}/lib/build/outputs/aar/lib-release_-release.aar").exists()) {
|
||||
from zipTree("${project.rootDir}/lib/build/outputs/aar/lib-release_-release.aar")
|
||||
into "${project.rootDir}/lib/build/outputs/aar/lib-release_-release"
|
||||
|
||||
from "${System.env.HOME}/norm/lib/norm-1.0.0.jar"
|
||||
into "${project.rootDir}/lib/build/outputs/aar/lib-release_-release/"
|
||||
}
|
||||
}
|
||||
|
||||
task copyDebugJar(type: Copy, dependsOn: copyReleaseJar) {
|
||||
println 'Unzipping debug .aar and including .jar....'
|
||||
|
||||
if (file("${project.rootDir}/lib/build/outputs/aar/lib-debug_-debug.aar").exists()){
|
||||
from zipTree("${project.rootDir}/lib/build/outputs/aar/lib-debug_-debug.aar")
|
||||
into "${project.rootDir}/lib/build/outputs/aar/lib-debug_-debug"
|
||||
|
||||
from "${System.env.HOME}/norm/lib/norm-1.0.0.jar"
|
||||
into "${project.rootDir}/lib/build/outputs/aar/lib-debug_-debug/"
|
||||
}
|
||||
}
|
||||
|
||||
task zipReleaseAAR(type: Exec, dependsOn: copyDebugJar) {
|
||||
println 'Creating new release .aar..'
|
||||
ignoreExitValue true
|
||||
workingDir "${project.rootDir}/lib/build/outputs/aar/"
|
||||
executable 'jar'
|
||||
def releaseArgsList = ['cvf', 'lib-release_-release.aar', '-C', 'lib-release_-release/', '.']
|
||||
args releaseArgsList
|
||||
}
|
||||
|
||||
task zipDebugAAR(type: Exec, dependsOn: zipReleaseAAR) {
|
||||
println 'Creating new debug .aar..'
|
||||
ignoreExitValue true
|
||||
workingDir "${project.rootDir}/lib/build/outputs/aar/"
|
||||
executable 'jar'
|
||||
def debugArgsList = ['cvf', 'lib-debug_-debug.aar', '-C', 'lib-debug_-debug/', '.']
|
||||
args debugArgsList
|
||||
}
|
||||
|
||||
task deleteAARAssets(type: Delete, dependsOn: zipDebugAAR) {
|
||||
delete "${project.rootDir}/lib/build/outputs/aar/lib-release_-release"
|
||||
delete "${project.rootDir}/lib/build/outputs/aar/lib-debug_-debug"
|
||||
}
|
||||
|
||||
|
||||
this.build.finalizedBy(deleteAARAssets)
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0.0"
|
||||
package="mil.navy.nrl.norm">
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
|
|
@ -13,19 +13,19 @@
|
|||
|
||||
<abstract>
|
||||
<para>This document describes an application programming interface (API)
|
||||
for the <ulink url="http://norm.pf.itd.nrl.navy.mil/">Nack-Oriented
|
||||
for the <ulink url="https://www.nrl.navy.mil/Our-Work/Areas-of-Research/Information-Technology/NCS/NORM/">Nack-Oriented
|
||||
Reliable Multicast (NORM)</ulink> protocol implementation developed by
|
||||
the Protocol Engineering and Advance Networking (<ulink
|
||||
url="http://cs.itd.nrl.navy.mil/">PROTEAN</ulink>) Research Group of the
|
||||
United States <ulink url="http://www.nrl.navy.mil/">Naval Research
|
||||
url="https://www.nrl.navy.mil/itd/ncs/">PROTEAN</ulink>) Research Group of the
|
||||
United States <ulink url="https://www.nrl.navy.mil/">Naval Research
|
||||
Laboratory</ulink> (NRL). The NORM protocol provides general purpose
|
||||
reliable data transport for applications wishing to use Internet
|
||||
Protocol (IP) Multicast services for group data delivery. NORM can also
|
||||
support unicast (point-to-point) data communication and may be used for
|
||||
such when deemed appropriate. The current NORM protocol specification is
|
||||
given in the <ulink url="http://www.ietf.org/">Internet Engineering Task
|
||||
given in the <ulink url="https://www.ietf.org/">Internet Engineering Task
|
||||
Force</ulink> (IETF) <ulink
|
||||
url="http://norm.pf.itd.nrl.navy.mil/rfc3940.pdf">RFC 3940</ulink>. This
|
||||
url="https://datatracker.ietf.org/doc/html/rfc5740">RFC 5740</ulink>. This
|
||||
document is currently a reference guide to the NORM API of the NRL
|
||||
reference implementation. More tutorial material may be include in a
|
||||
future version of this document or a separate developer's tutorial may
|
||||
|
|
@ -37,19 +37,19 @@
|
|||
<title>Background</title>
|
||||
|
||||
<para>This document describes an application programming interface (API)
|
||||
for the <ulink url="http://norm.pf.itd.nrl.navy.mil/">Nack-Oriented
|
||||
for the <ulink url="https://www.nrl.navy.mil/Our-Work/Areas-of-Research/Information-Technology/NCS/NORM/">Nack-Oriented
|
||||
Reliable Multicast (NORM)</ulink> protocol implementation developed by the
|
||||
Protocol Engineering and Advance Networking (<ulink
|
||||
url="http://cs.itd.nrl.navy.mil/">PROTEAN</ulink>) Research Group of the
|
||||
United States <ulink url="http://www.nrl.navy.mil/">Naval Research
|
||||
url="https://www.nrl.navy.mil/itd/ncs/">PROTEAN</ulink>) Research Group of the
|
||||
United States <ulink url="https://www.nrl.navy.mil/">Naval Research
|
||||
Laboratory</ulink> (NRL). The NORM protocol provides general purpose
|
||||
reliable data transport for applications wishing to use Internet Protocol
|
||||
(IP) Multicast services for group data delivery. NORM can also support
|
||||
unicast (point-to-point) data communication and may be used for such when
|
||||
deemed appropriate. The current NORM protocol specification is given in
|
||||
the <ulink url="http://www.ietf.org/">Internet Engineering Task
|
||||
the <ulink url="https://www.ietf.org/">Internet Engineering Task
|
||||
Force</ulink> (IETF) <ulink
|
||||
url="http://norm.pf.itd.nrl.navy.mil/rfc5740.pdf">RFC 5740</ulink>.</para>
|
||||
url="https://datatracker.ietf.org/doc/html/rfc5740">RFC 5740</ulink>.</para>
|
||||
|
||||
<para>The NORM protocol is designed to provide end-to-end reliable
|
||||
transport of bulk data objects or streams over generic IP multicast
|
||||
|
|
@ -134,7 +134,7 @@
|
|||
may participate as senders and/or receivers within a NORM session. NORM
|
||||
senders transmit data to the session destination address (usually an IP
|
||||
multicast group) while receivers are notified of incoming data. The NORM
|
||||
API provides and event notification scheme to notify the application of
|
||||
API provides an event notification scheme to notify the application of
|
||||
significant sender and receiver events. There are also a number support
|
||||
functions provided for the application to control and monitor its
|
||||
participation within a NORM transport session.</para>
|
||||
|
|
@ -159,7 +159,7 @@
|
|||
linkend="NormCreateInstance"><literal>NormCreateInstance()</literal></link>)
|
||||
as needed for applications with specific requirements for accessing and
|
||||
controlling participation in multiple <emphasis>NormSessions</emphasis>
|
||||
from separate operating system multiple threads. Or, alternatively, a
|
||||
from separate operating system threads. Or, alternatively, a
|
||||
single <emphasis>NormInstance</emphasis> could be used, with a "master
|
||||
thread" serving as an intermediary between the <link
|
||||
linkend="NormGetNextEvent"><literal>NormGetNextEvent()</literal></link>
|
||||
|
|
@ -194,7 +194,7 @@
|
|||
number of concurrently active senders, this may translate to significant
|
||||
memory allocation on receiver nodes. Currently, the API allows the
|
||||
application to control how much buffer space is allocated for each
|
||||
active sender (NOTE: In the future, API functions may be provided limit
|
||||
active sender (NOTE: In the future, API functions may be provided to limit
|
||||
the number of active senders monitored and/or provide the application
|
||||
with finer control over receive buffer allocation, perhaps on a per
|
||||
sender basis).</para>
|
||||
|
|
@ -227,7 +227,7 @@
|
|||
<title>Data Transmission</title>
|
||||
|
||||
<para>The behavior of data transport operation is largely placed in
|
||||
the control of the NORM sender(s). NORM senders controls their data
|
||||
the control of the NORM sender(s). NORM senders control their data
|
||||
transmission rate, forward error correction (FEC) encoding settings,
|
||||
and parameters controlling feedback from the receiver group. Multiple
|
||||
senders may operate in a session, each with independent transmission
|
||||
|
|
@ -253,7 +253,7 @@
|
|||
be called before any calls to <link
|
||||
linkend="NormStartReceiver"><literal>NormStartReceiver()</literal></link>
|
||||
are made. However, note that the cache directory may be changed even
|
||||
during active NORM reception. In this case, the new specified
|
||||
during active NORM reception. In this case, the newly specified
|
||||
directory path will be used for subsequently-received files. Any files
|
||||
received before a directory path change will remain in the previous
|
||||
cache location. Note that the <link
|
||||
|
|
@ -477,15 +477,14 @@
|
|||
Protokit. These are described below.</para>
|
||||
|
||||
<para>The "makefiles" directory contains Unix Makefiles for various
|
||||
platforms the "win32" and "wince" sub-directories there contain Microsoft
|
||||
platforms. The "win32" and "wince" sub-directories there contain Microsoft
|
||||
Visual C++ (VC++) and Embedded VC++ project files for building the NORM
|
||||
implementation. Additionally, a "waf" (Python-based build tool) build
|
||||
option is supported that can be used to build and install the NORM library
|
||||
code on the supported platforms. Finally, Python and Java bindings to the
|
||||
NORM API are included and "src/python" and "src/java" directories contain
|
||||
the code for these and the "makefiles/java" directory contains Makefiles
|
||||
to build the NORM Java JNI bindings. Note the "waf" tool can also be used
|
||||
to build the Java and Python bindings.</para>
|
||||
NORM API are included in the "src/python" and "src/java" directories and the
|
||||
"makefiles/java" directory contains Makefiles to build the NORM Java JNI bindings.
|
||||
Note the "waf" tool can also be used to build the Java and Python bindings.</para>
|
||||
|
||||
<sect2>
|
||||
<title>Unix Platforms</title>
|
||||
|
|
@ -791,7 +790,7 @@
|
|||
{
|
||||
NormEventType type;
|
||||
<link linkend="NormSessionHandle"><literal>NormSessionHandle</literal></link> session;
|
||||
<link linkend="NormNodeHandle"><literal>NormNodeHandle</literal></link> node;
|
||||
<link linkend="NormNodeHandle"><literal>NormNodeHandle</literal></link> sender;
|
||||
<link linkend="NormObjectHandle"><literal>NormObjectHandle</literal></link> object;
|
||||
} <link linkend="NormEvent"><literal>NormEvent</literal></link>;</programlisting></para>
|
||||
|
||||
|
|
@ -801,7 +800,7 @@
|
|||
all <link
|
||||
linkend="NormEventType"><literal>NormEventType</literal></link> fields
|
||||
are relevant to all events. The <parameter>session</parameter>,
|
||||
<parameter>node</parameter>, and <parameter>object</parameter> fields
|
||||
<parameter>sender</parameter>, and <parameter>object</parameter> fields
|
||||
indicate the applicable <link
|
||||
linkend="NormSessionHandle"><literal>NormSessionHandle</literal></link>,
|
||||
<link
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -96,11 +96,13 @@
|
|||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>Download and unpack the NORM source code tarball.</para>
|
||||
<para>Download and unpack the NORM source code tarball or clone the github
|
||||
repository using
|
||||
<literal>git clone --recurse-submodules https://github.com/USNavalResearchLaboratory/norm.git</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>cd norm/unix</literal></para>
|
||||
<para><literal>cd norm/makefiles</literal></para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
|
|
@ -118,7 +120,8 @@
|
|||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>Download and unpack the NORM source code tarball</para>
|
||||
<para>Download and unpack the NORM source code tarball or clone the
|
||||
repository as described in the section above.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
|
|
@ -128,7 +131,7 @@
|
|||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Open the "<filename>norm.sln</filename>" (VC++ .Net),
|
||||
<para>Inside the "<filename>norm/makefiles/win32</filename>" directory, open the "<filename>norm.sln</filename>" (VC++ .Net),
|
||||
"<filename>norm.dsw</filename>" (VC++ 6.0), or
|
||||
"<filename>norm.vcw</filename>" (Embedded VC++) workspace
|
||||
file.</para>
|
||||
|
|
@ -137,9 +140,14 @@
|
|||
<listitem>
|
||||
<para>The "<emphasis>norm</emphasis>" project can be selected and
|
||||
built. The "<filename>norm.exe</filename>" file will be found in
|
||||
the "<filename>norm/win32/norm/Release</filename>" directory.</para>
|
||||
the "<filename>norm/Win32/norm/Release</filename>" directory.</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<para>The easiest way to run these builds is with Visual Studio. If you do not already have Visual Studio installed, then it can
|
||||
be downloaded for free <ulink url="https://visualstudio.microsoft.com/downloads/?cid=learn-onpage-download-cta">here</ulink>.
|
||||
When you launch Visual Studio, make sure to select "Visual C++" and open the "<filename>norm.sln</filename>" file.
|
||||
This should load all of the project files and allow you to right-click on any of them in the Solution Explorer on the
|
||||
left side and select "build".</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
|
|
@ -380,7 +388,7 @@
|
|||
<para>A minimal example <emphasis>norm</emphasis> sender command-line
|
||||
syntax is:</para>
|
||||
|
||||
<para><literal>norm addr <addr/port> sendFile
|
||||
<para><literal>norm addr <addr/port> sendfile
|
||||
<fileName></literal></para>
|
||||
|
||||
<para>The corresponding minimal <emphasis>norm</emphasis> receiver
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -0,0 +1,413 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
|
||||
<article lang="">
|
||||
<articleinfo>
|
||||
<title><inlinemediaobject>
|
||||
<imageobject>
|
||||
<imagedata align="center" fileref="NormLogo.gif" scale="50"/>
|
||||
</imageobject>
|
||||
</inlinemediaobject> <command>npc</command> User Guide</title>
|
||||
|
||||
<subtitle>(NORM Precoder User Guide)</subtitle>
|
||||
|
||||
<titleabbrev><command>npc</command> User Guide</titleabbrev>
|
||||
</articleinfo>
|
||||
|
||||
<sect1>
|
||||
<title>Background</title>
|
||||
|
||||
<para>The NACK-Oriented Reliable Multicast (NORM) protocol is capable of
|
||||
supporting robust transmission of content to "silent" receivers that are
|
||||
required or only capable of operating in an emission-controlled (EMCON)
|
||||
manner. This capability is enabled when the NORM sender is configured to
|
||||
proactively transmit Forward Error Correction (FEC) erasure coding content
|
||||
as part of its original data transmission. For NACK-based operation, the
|
||||
FEC repair packets are usually sent only reactively, in response to repair
|
||||
requests (NACKs) from the receiver group. However, hybrid operation with a
|
||||
combination of proactive FEC content and additional reactive FEC repairs
|
||||
as needed is also supported. Similarly, a mix of nacking and silent
|
||||
receivers may be supported with silent receivers capitalizing on the FEC
|
||||
repair information sent proactively and/or reactively. The purpose of the
|
||||
NORM Pre-Coder (<command>npc</command>) software utility described here is
|
||||
to support additional robustness for purely-proactive sessions, where the
|
||||
receivers are unable to request repair or retransmission of
|
||||
content.</para>
|
||||
|
||||
<para>The Naval Research Laboratory (NRL) reference implementation of the
|
||||
NORM protocol includes support for 8-bit and 16-bit Reed-Solomon FEC
|
||||
encoding with additional support for other coding algorithms (e.g.,
|
||||
Low-Density Parity Check (LDPC)) planned for the future. The NORM
|
||||
specification allows for different FEC algorithms to be applied within the
|
||||
protocol. The current Reed-Solomon NORM FEC algorithms in the NRL
|
||||
implementation are limited to modest code block sizes (With 16-bit
|
||||
Reed-Solomon coding, larger block sizes will be allowed but very high data
|
||||
rates may not be possible). For channels with random errors, the current
|
||||
NORM FEC codecs are often adequate as there is flexibility in how the
|
||||
encoded data can be partitioned into FEC blocks (a block consists of some
|
||||
number of data segments (packets)) and the number of FEC parity packets
|
||||
that can computed and possibly transmitted per source data block. For
|
||||
channels with large bursts of packet loss (with respect to the configured
|
||||
NORM FEC block size), it is quite possible that the number of lost packets
|
||||
(erasures) that occur within a NORM FEC block may exceed the configured
|
||||
erasure-filling capability. The <command>npc</command> utility was created
|
||||
to "pre-encode" (and "post-decode") files for NORM transmission to silent
|
||||
(non- NACKing) receivers by adding additional FEC encoding, and
|
||||
importantly, interleaving of the FEC segments (packets) to re-distribute
|
||||
bursts of packet losses as random losses over the entire file. It is thus
|
||||
most applicable to very large files (with respect to FEC block
|
||||
sizes).</para>
|
||||
|
||||
<para>The NORM protocol is described in Internet Engineering Task Force
|
||||
(IETF) Request For Comments (RFC) RFC 5740 and RFC 5741. NRL provides a
|
||||
NORM protocol library with a well-defined API that it is suitable for
|
||||
application development. Refer to the NORM website <<ulink
|
||||
url="https://github.com/USNavalResearchLaboratory/norm">https://github.com/USNavalResearchLaboratory/norm</ulink>>
|
||||
for these other components as well as up-to-date versions of this
|
||||
demonstration application and documentation.</para>
|
||||
|
||||
<para>The <command>npc</command> tool is designed to use in conjunction
|
||||
with the NORM protocol and accompanying NORM file transfer examples that
|
||||
are part of the NORM source code distribution. However, the encoded file
|
||||
format that <command>npc</command> creates can be use with other
|
||||
transports as well. The key is to align the segmentation parameters of the
|
||||
<command>npc</command> configuration with that of the intended transport
|
||||
mechanism.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Overview</title>
|
||||
|
||||
<para>The <command>npc</command> utility takes, as input", a file and
|
||||
logically divides it into segments, adding cyclic-redundancy checksum
|
||||
(CRC) to the segments, encoding the source segments with Reeed-Solomon
|
||||
encoding (adding a configurable number of parity segments per FEC source
|
||||
block), and interleaves the source and encoding segments to an output
|
||||
file. The use of the CRC allows erasure to be detected and also provides
|
||||
additional assurance of correct content delivery by possibly detecting bit
|
||||
errors that may have been undetected during transport (i.e., link-layer
|
||||
framing, Internet Protocol (IP), and/or User Datagram Protocol (UDP)
|
||||
checksums). The interleaving by default is a block interleaver using the
|
||||
entire file as a logical block, but a limit on the interleaving size can
|
||||
be set to help increase the speed of the <command>npc</command>
|
||||
encoding/decoding process. This may be useful for extremely large file
|
||||
sizes.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Usage</title>
|
||||
|
||||
<para>The following is a synopsis of <command>npc</command> usage:</para>
|
||||
|
||||
<programlisting>npc {encode|decode} input <inFile> [output <outFile>][segment <segmentSize>]
|
||||
{[[block <numData>][parity <numParity>]] |
|
||||
[auto <parityPercentage>][bmax <maxBlockSize>]}
|
||||
[imax <widthLimit>][ibuffer <bytes>][background][help][debug <debugLevel>]</programlisting>
|
||||
|
||||
<para>The <command>npc</command> utility may be instructed to either
|
||||
"encode" a file (add FEC content and interleaving to the given
|
||||
<inFile>) or "decode" a file that was previously encoded with
|
||||
<command>npc</command>. The ".npc" file extension is suggested to
|
||||
delineate files that are of the <command>npc</command> encoded format.
|
||||
Note the "output" filename is optional. By default, <command>npc</command>
|
||||
will use the filename of the <inFile> as the output filename,
|
||||
replacing the '.' extension delimiter with a '_' (underscore) and adding
|
||||
the ".npc" extension suffix. The <command>npc</command> format includes
|
||||
some minimal "meta-data" in the first encoded <segmentSize> to
|
||||
convey the file size and name of the original file. On decoding, if the
|
||||
"output" file option is omitted, this "meta-data" is used to name the
|
||||
decoded output file.</para>
|
||||
|
||||
<para>The optional FEC parameters,
|
||||
<parameter><segmentSize></parameter>,
|
||||
<parameter><numData></parameter>, and
|
||||
<parameter><numParity></parameter> control the logical segmentation,
|
||||
blocking, and amount of FEC parity content added to the file. For use with
|
||||
NORM, it is recommended that the
|
||||
<parameter><segmentSize></parameter> value correspond to the same
|
||||
segmentation size used for NORM transmission. The
|
||||
<parameter><numData></parameter> (source segments per FEC encoding
|
||||
block) and <parameter><numParity></parameter> parameters should be
|
||||
selected to provide erasure filling coverage for the expected transmission
|
||||
packet loss characteristics. Note that when used with proactive NORM FEC
|
||||
transmission, the <command>npc</command> encoding provides an "inner" FEC
|
||||
code and interleaving and the NORM protocol provides an "outer" FEC
|
||||
encoding. The "outer" NORM code might be configured to deal with typical
|
||||
random packet loss due to channel BER, etc and the "inner"
|
||||
<command>npc</command> interleaving and coding could be correspondingly
|
||||
configured to handle expected burst losses (e.g. outages) that might
|
||||
occur.</para>
|
||||
|
||||
<para>The <parameter><auto></parameter> option provides an
|
||||
alternative means for setting the FEC encoding protection level instead of
|
||||
using the <parameter><block></parameter> and
|
||||
<parameter><parity></parameter> options. First the
|
||||
<parameter><auto></parameter> option causes <command>npc</command>
|
||||
to select a block size corresponding to the entire input file size (plus
|
||||
the segment of meta data information that npc adds). Then, the
|
||||
<parameter><auto></parameter> option
|
||||
<parameter><parityPercentage></parameter> value is used to set the
|
||||
number of parity packets per encoding block to the given percentage of the
|
||||
automatically determined block size. For exanple, the command
|
||||
"<option>auto 100"</option> causes <command>npc</command> to set an
|
||||
encoding rate of 100%. I.e., the parity segments sent will equal the
|
||||
number of segments in a bock. Note that the
|
||||
<parameter><parityPercentage></parameter> can even exceed 100% if
|
||||
desired for high levels of loss protection. Also note that the percentage
|
||||
here is _not_ a loss protection percentage with a 100%
|
||||
<parameter><parityPercentage></parameter> value being able to
|
||||
correct up to 50% errored or lost packets within a coding block. With 50%
|
||||
uniform random packet loss, this would result in successful file transfer
|
||||
about 50% of the time as, per Gaussian distribution, burst error
|
||||
probabilities would result in half of blocks arriving with greater than
|
||||
50% packet loss and half with less than 50% packet loss.</para>
|
||||
|
||||
<para>When the <command>npc</command> encoder uses the
|
||||
"<option>auto</option>" command the <command>npc</command> decoder MUST
|
||||
also use the "<option>auto</option>" command and be configured with the
|
||||
same <parameter><segmentSize></parameter> and
|
||||
<parameter><parityPercentage></parameter> values. Similarly when the
|
||||
"<option>block</option>" and "<option>parity</option>" commands are used
|
||||
to explicitly set the <parameter><numdData></parameter> and
|
||||
<parameter><numParity></parameter> at the encoder, the decoder MUST
|
||||
be configured with the same corresponding options and values, again
|
||||
including <parameter><segmentSize></parameter>. And for use with
|
||||
NORM protocol transport, the <parameter><segmentSize></parameter>
|
||||
parameter SHOULD be matched for best coding gain performance. The NORM
|
||||
block size (numData) and parity (numParity) parameters may be set
|
||||
indepedently. Basically, the NORM protocol proactive erasure coding can be
|
||||
configured to deal with expected short term random packet loss while the
|
||||
<command>npc</command> parameters can be configured to counter large burst
|
||||
(or outage) losses. The inner/outer encoding approach that the combination
|
||||
of <command>npc</command> and NORM provides, can allow for a sort of
|
||||
multiplicative coding gain to deal well with both random packet loss and
|
||||
bursts or outages with lower FEC overhead. However, when the
|
||||
<command>npc</command> coding is configured (e.g., via the "auto" option)
|
||||
to encapsulate an entire file into a single logical coding block, the
|
||||
desired level of loss protection can be simply "dialed into" the
|
||||
<command>npc</command> <parameter><parityPercentage></parameter>
|
||||
option. The tradeoff is that the larger FEC block size increases the
|
||||
computational requirement for file encoding and decoding. Future versions
|
||||
of <command>npc</command> may provide additional FEC code types</para>
|
||||
|
||||
<para>As basic example usage, to encode a file name "originalFile.txt"
|
||||
with the default <command>npc</command> naming convention, FEC, and
|
||||
interleaving parameters, use the following syntax:</para>
|
||||
|
||||
<programlisting>npc encode input originalFile.txt</programlisting>
|
||||
|
||||
<para>This will produce and output file named
|
||||
"<filename>originalFile_txt.npc</filename>" in the current working
|
||||
directory. The default <command>npc</command> configuration is
|
||||
"<command>auto 100.0</command>" providing 100% parity content which makes
|
||||
the encoded file size roughly double the input file. The original file can
|
||||
be recovered (decoded) using the syntax:</para>
|
||||
|
||||
<programlisting>npc decode input originalFile_txt.npc</programlisting>
|
||||
|
||||
<para>This will decode the ".npc" file, and in this case produce a file
|
||||
named "<filename>originalFile.txt"</filename> in the current working
|
||||
directory. (The file name information was stored in first "meta data"
|
||||
segment of the ".npc" file). This default naming convention can be
|
||||
overridden by using the <command>npc</command> "<option>output</option>"
|
||||
command. For example, the syntax:</para>
|
||||
|
||||
<programlisting>npc decode input originalFile_txt.npc output file.txt</programlisting>
|
||||
|
||||
<para>will produce a file named "<filename>file.txt</filename>" that is
|
||||
identical in content to "<filename>originalFile.txt</filename>".</para>
|
||||
|
||||
<sect2>
|
||||
<title>Notes</title>
|
||||
|
||||
<para>The FEC and interleaving parameters that are used for
|
||||
<command>npc</command> encoding MUST be exactly matched to successfully
|
||||
decode the encoded file. I.e., if the defaults are used for encoding,
|
||||
the defaults must be used for decoding. The parameters that must match
|
||||
include <parameter><segmentSize></parameter>,
|
||||
<parameter><parityPercentage></parameter> and
|
||||
<parameter><maxBlockSize></parameter> (or
|
||||
<parameter><numData></parameter> and
|
||||
<parameter><numParity></parameter>), and
|
||||
<parameter><widthMax></parameter>.</para>
|
||||
|
||||
<para>It is possible that in some cases it may be beneficial to apply
|
||||
more proactive FEC content with the <command>npc</command> program
|
||||
instead of with the NORM transport. The trade-offs are
|
||||
scenario-specific.</para>
|
||||
|
||||
<para>The NRL "<command>norm</command>" demonstration application has
|
||||
commands included to support transport of <command>npc</command> encoded
|
||||
files. The distinction here is that a file that _fails_ NORM transport
|
||||
might still be successfully decoded with <command>npc</command>. There
|
||||
are two receiver-side <command>norm</command> demo application options
|
||||
that apply here:</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>The "<option>saveAborts</option>" command causes
|
||||
<command>norm</command> to not delete (and attempt to postprocess)
|
||||
"aborted" files (files that failed reliable NORM transport).</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>The <command>norm</command> "<option>lowDelay</option>"
|
||||
command should be applied for silent-receivers to more immediately
|
||||
deliver "failed" files to the application for post-processing (i.e.,
|
||||
attempted <command>npc</command> decoding)</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title><command>npc</command> Command Reference</title>
|
||||
|
||||
<para>The following table describes each of the <command>npc</command>
|
||||
commands available in the command-line syntax.</para>
|
||||
|
||||
<informaltable frame="all">
|
||||
<tgroup cols="2">
|
||||
<colspec colnum="1" colwidth="1*"/>
|
||||
|
||||
<colspec colname="2" colwidth="2*"/>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><para><option>encode</option> |
|
||||
<option>decode</option></para></entry>
|
||||
|
||||
<entry><para>Determine whether <command>npc</command> is to encode
|
||||
or decode the given <parameter><inFile></parameter>. This
|
||||
option is required and only one should be given.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>input
|
||||
</option><parameter><inFile></parameter></para></entry>
|
||||
|
||||
<entry><para>Specifies the file to be processed. Required
|
||||
command.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>output
|
||||
</option><parameter><outFile></parameter></para></entry>
|
||||
|
||||
<entry><para>Specifies the name of the output file to be produced.
|
||||
Overrides the default <command>npc</command> output file naming
|
||||
convention. Optional.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>segment
|
||||
</option><parameter><segmentSize></parameter></para></entry>
|
||||
|
||||
<entry><para>Sets the segmentation size (e.g., packet payload
|
||||
size) in bytes. Note four bytes of the
|
||||
<parameter><segmentSize></parameter> are used for a 32-bit
|
||||
CRC that <command>npc</command> applies to each segment. (Default
|
||||
<parameter><segmentSize></parameter> is 1024
|
||||
bytes)</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>block
|
||||
</option><parameter><numData></parameter></para></entry>
|
||||
|
||||
<entry><para>Specify the number of source data segments (packets)
|
||||
per <command>npc</command> FEC coding block. (Default block sizing
|
||||
is auto)</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>parity
|
||||
</option><parameter><numParity></parameter></para></entry>
|
||||
|
||||
<entry><para>Specify the number of FEC parity segments (packets)
|
||||
added per <command>npc</command> FEC coding block. (Default is 2
|
||||
segments).</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>auto
|
||||
</option><parameter><parityPercentage></parameter></para></entry>
|
||||
|
||||
<entry><para>Specifies automatic FEC block sizing with
|
||||
<parameter><parityPercentage></parameter> indicating the
|
||||
percentage of FEC parity segments to include per block. The "auto"
|
||||
block sizing sets the block size as large as possible to treat the
|
||||
entire files as one logical FEC block to maximize FEC performance.
|
||||
The maximum possible block size currently supported by
|
||||
<command>npc</command> are blocks where (numData + numParity) is
|
||||
less than or equal to 65536. The maximum buffer size can be
|
||||
limited by using the <option>bmax</option> command.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>bmax
|
||||
</option><parameter><maxBlockSize></parameter></para></entry>
|
||||
|
||||
<entry><para>Limits the maximum block size when the
|
||||
<option>auto</option> command is used for automatic block sizing
|
||||
(Default is 65536)</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>imax
|
||||
</option><parameter><widthMax></parameter></para></entry>
|
||||
|
||||
<entry><para>Limits interleaving of encoded file to a maximum
|
||||
interleaver width of <parameter><widthMax></parameter>
|
||||
segments. A value of ZERO (or less) defaults to
|
||||
<command>npc</command> calculating a block interleaver that
|
||||
encompasses the entire encoded file size. For extremely large
|
||||
files, this option may be beneficial to limit file seeking
|
||||
operations required to interleave the file. If the encoded file
|
||||
size is less than
|
||||
<parameter><widthMax></parameter>*<parameter><widthMax></parameter>
|
||||
segments, <command>npc</command> will again calculate its own
|
||||
maximum block size. (Default is 1000 segments interleaver depth
|
||||
(i.e., about 1 Gbyte interleaver size with the default 1024 byte
|
||||
<parameter><segmentSize></parameter> value))</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>ibuffer
|
||||
</option><parameter><bufferSize></parameter></para></entry>
|
||||
|
||||
<entry><para>This sets the maximum memory (in bytes) that
|
||||
<command>npc</command> allocates for encoding. A larger value
|
||||
allows <command>npc</command> to perform file input/output with
|
||||
less seeking and improved encoding/decoding times can be achieved.
|
||||
(Default is 1.5 GByte)</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>debug
|
||||
</option><parameter><debugLevel></parameter></para></entry>
|
||||
|
||||
<entry><para>Specifies debug output verbosity. Higher number is
|
||||
more verbose debugging information. (Default is
|
||||
ZERO).</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>background</option></para></entry>
|
||||
|
||||
<entry><para>Sets percentage of received messages that are
|
||||
randomly dropped (for testing purposes). Default = 0.0
|
||||
percent.</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><para><option>help</option></para></entry>
|
||||
|
||||
<entry><para>Displays <command>npc</command> usage
|
||||
statement.</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
</sect1>
|
||||
</article>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
echo Running example $@
|
||||
|
||||
exec "$NORM_BUILD/$@"
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eux
|
||||
|
||||
install_debian()
|
||||
{
|
||||
apt-get update
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||
python2.7 \
|
||||
g++ \
|
||||
libxml2-dev \
|
||||
libnetfilter-queue-dev
|
||||
|
||||
ln -s /usr/bin/python2.7 /usr/bin/python
|
||||
|
||||
if [ "$VERSION" != "" ]; then
|
||||
apt-get install -yq git-core
|
||||
cd $NORM_DIR && git checkout $VERSION && git submodule update --checkout --init --force
|
||||
fi
|
||||
|
||||
if [[ "$WAF_CONFIGURE" =~ "java" && -z `which java` ]]; then
|
||||
apt-get install -yq default-jdk-headless
|
||||
export JAVA_HOME=$(readlink -f `which java` | sed 's/\/bin\/java//')
|
||||
fi
|
||||
}
|
||||
|
||||
install_redhat()
|
||||
{
|
||||
yum update -y
|
||||
yum install -y \
|
||||
which \
|
||||
centos-release-scl
|
||||
yum install -y \
|
||||
gcc-c++ \
|
||||
libxml2-devel \
|
||||
libnetfilter_queue-devel
|
||||
|
||||
if [ "$VERSION" != "" ]; then
|
||||
yum install -y git
|
||||
cd $NORM_DIR && git checkout $VERSION && git submodule update --checkout --init --force
|
||||
fi
|
||||
|
||||
if [[ "$WAF_CONFIGURE" =~ "java" && -z `which java` ]]; then
|
||||
yum install -y java-1.8.0-openjdk-devel
|
||||
export JAVA_HOME=$(readlink -f `which java` | sed 's/\/jre\/bin\/java//')
|
||||
fi
|
||||
}
|
||||
|
||||
configure_norm()
|
||||
{
|
||||
cd $NORM_DIR && ./waf configure ${WAF_CONFIGURE}
|
||||
}
|
||||
|
||||
if [ ! -z `which apt` ]; then
|
||||
install_debian
|
||||
elif [ ! -z $(which yum) ] || [ "$?" = "1" ]; then
|
||||
install_redhat
|
||||
fi
|
||||
configure_norm
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -10,8 +10,8 @@ public class NormStreamSend {
|
|||
static final long REPAIR_WINDOW_SIZE = 1024 * 1024;
|
||||
static final long SESSION_BUFFER_SIZE = 1024 * 1024;
|
||||
static final int SEGMENT_SIZE = 1400;
|
||||
static final int BLOCK_SIZE = 64;
|
||||
static final int PARITY_SEGMENTS = 16;
|
||||
static final short BLOCK_SIZE = 64;
|
||||
static final short PARITY_SEGMENTS = 16;
|
||||
static final String DEST_ADDRESS = "224.1.2.3";
|
||||
static final int DEST_PORT = 6003;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
#include "normApi.h"
|
||||
#include "normPostProcess.h"
|
||||
#include <stdio.h> // for printf(), etc
|
||||
#include <stdlib.h> // for atoi(), etc
|
||||
#include <cassert>
|
||||
|
|
@ -48,6 +49,7 @@
|
|||
#include "protoFile.h" // for ProtoFile::PathList and iterator for tx file/directory queue
|
||||
#include "protoString.h" // for ProtoTokenator
|
||||
#include "protoAddress.h" // for ProtoAddress
|
||||
#include "protoTime.h" // for ProtoTime
|
||||
|
||||
class NormCaster
|
||||
{
|
||||
|
|
@ -59,6 +61,7 @@ class NormCaster
|
|||
enum CCMode {NORM_FIXED, NORM_CC, NORM_CCE, NORM_CCL};
|
||||
|
||||
void Destroy();
|
||||
bool Init();
|
||||
|
||||
bool OpenNormSession(NormInstanceHandle instance,
|
||||
const char* addr,
|
||||
|
|
@ -70,6 +73,12 @@ class NormCaster
|
|||
|
||||
void SetNormCongestionControl(CCMode ccMode);
|
||||
|
||||
void SetGrttEstimate(double grtt_estimate)
|
||||
{
|
||||
assert(NORM_SESSION_INVALID != norm_session);
|
||||
assert(grtt_estimate > 0);
|
||||
NormSetGrttEstimate(norm_session, grtt_estimate);
|
||||
}
|
||||
void SetNormTxRate(double bitsPerSecond)
|
||||
{
|
||||
assert(NORM_SESSION_INVALID != norm_session);
|
||||
|
|
@ -80,6 +89,14 @@ class NormCaster
|
|||
assert(NORM_SESSION_INVALID != norm_session);
|
||||
NormSetMulticastInterface(norm_session, ifaceName);
|
||||
}
|
||||
bool SetNormTxPort(UINT16 txPort,
|
||||
bool enableReuse,
|
||||
const char* txAddress)
|
||||
{
|
||||
assert(NORM_SESSION_INVALID != norm_session);
|
||||
return NormSetTxPort(norm_session, txPort, enableReuse, txAddress);
|
||||
|
||||
}
|
||||
void SetLoopback(bool state)
|
||||
{
|
||||
loopback = state;
|
||||
|
|
@ -110,8 +127,18 @@ class NormCaster
|
|||
|
||||
void HandleNormEvent(const NormEvent& event);
|
||||
|
||||
void HandleTimeout();
|
||||
|
||||
// Sender methods
|
||||
bool AddTxItem(const char* path);
|
||||
void SetRepeat(double interval, bool updatesOnly)
|
||||
{
|
||||
repeat_interval = interval;
|
||||
tx_file_iterator.SetUpdatesOnly(updatesOnly); // TBD - add option to send new files only
|
||||
}
|
||||
double GetTimerDelay() const
|
||||
{return timer_delay;}
|
||||
|
||||
bool StageNextTxFile();
|
||||
bool TxFilePending()
|
||||
{return '\0' != tx_pending_path[0];}
|
||||
|
|
@ -130,7 +157,11 @@ class NormCaster
|
|||
void SetNumParity(unsigned short numParity)
|
||||
{num_parity = numParity;}
|
||||
void SetAutoParity(unsigned short autoParity)
|
||||
{auto_parity = autoParity;}
|
||||
{
|
||||
auto_parity = autoParity;
|
||||
if (norm_session != NORM_SESSION_INVALID)
|
||||
NormSetAutoParity(norm_session, auto_parity < num_parity ? auto_parity : num_parity);
|
||||
}
|
||||
|
||||
// Receiver methods
|
||||
void SetRxCacheDirectory(const char* path)
|
||||
|
|
@ -148,6 +179,14 @@ class NormCaster
|
|||
{return rx_cache_path;}
|
||||
void SetRxSocketBufferSize(unsigned int value)
|
||||
{rx_socket_buffer_size = value;}
|
||||
bool SetPostProcessorCommand(const char* cmd)
|
||||
{return post_processor->SetCommand(cmd);}
|
||||
bool SetSentProcessorCommand(const char* cmd)
|
||||
{return sent_processor->SetCommand(cmd);}
|
||||
bool SetPurgedProcessorCommand(const char* cmd)
|
||||
{return purged_processor->SetCommand(cmd);}
|
||||
void SaveAborts(bool save_aborts)
|
||||
{save_aborted_files = save_aborts;}
|
||||
|
||||
// These can only be called post-OpenNormSession()
|
||||
|
||||
|
|
@ -158,24 +197,49 @@ class NormCaster
|
|||
norm_acking = enable;
|
||||
}
|
||||
void SetSilentReceiver(bool state)
|
||||
{NormSetSilentReceiver(norm_session, state);}
|
||||
{
|
||||
assert(NORM_SESSION_INVALID != norm_session);
|
||||
NormSetSilentReceiver(norm_session, state);
|
||||
}
|
||||
|
||||
void SetProbeTOS(UINT8 value)
|
||||
{probe_tos = value;}
|
||||
|
||||
void SetProbeMode(NormProbingMode mode)
|
||||
{probe_mode = mode;}
|
||||
|
||||
void SetTxLoss(double txloss)
|
||||
{NormSetTxLoss(norm_session, txloss);}
|
||||
{
|
||||
assert(NORM_SESSION_INVALID != norm_session);
|
||||
assert(0 <= txloss);
|
||||
NormSetTxLoss(norm_session, txloss);
|
||||
}
|
||||
|
||||
void SetRxLoss(double rxloss)
|
||||
{
|
||||
assert(NORM_SESSION_INVALID != norm_session);
|
||||
assert(0 <= rxloss);
|
||||
NormSetRxLoss(norm_session, rxloss);
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_running;
|
||||
NormSessionHandle norm_session;
|
||||
NormPostProcessor* post_processor;
|
||||
NormPostProcessor* sent_processor;
|
||||
NormPostProcessor* purged_processor;
|
||||
bool save_aborted_files;
|
||||
ProtoFile::PathList tx_file_list;
|
||||
ProtoFile::PathList::PathIterator tx_file_iterator;
|
||||
char tx_pending_path[PATH_MAX + 1];
|
||||
unsigned int tx_pending_prefix_len;
|
||||
double repeat_interval;
|
||||
double timer_delay; // currently tracks the repeat timeout only
|
||||
ProtoTime timer_start; // used to mark timer start time
|
||||
bool is_multicast;
|
||||
bool loopback;
|
||||
UINT8 probe_tos;
|
||||
NormProbingMode probe_mode;
|
||||
unsigned int norm_tx_queue_max; // max number of objects that can be enqueued at once
|
||||
unsigned int norm_tx_queue_count; // count of unacknowledged enqueued objects (TBD - optionally track size too)
|
||||
bool norm_flow_control_pending;
|
||||
|
|
@ -203,8 +267,10 @@ class NormCaster
|
|||
}; // end class NormCaster
|
||||
|
||||
NormCaster::NormCaster()
|
||||
: norm_session(NORM_SESSION_INVALID), tx_file_iterator(tx_file_list),
|
||||
tx_pending_prefix_len(0), is_multicast(false), loopback(false), probe_tos(0),
|
||||
: norm_session(NORM_SESSION_INVALID), post_processor(NULL), sent_processor(NULL),
|
||||
purged_processor(NULL), save_aborted_files(false), tx_file_iterator(tx_file_list),
|
||||
tx_pending_prefix_len(0), repeat_interval(-1.0), timer_delay(-1.0),
|
||||
is_multicast(false), loopback(false), probe_tos(0), probe_mode(NORM_PROBE_ACTIVE),
|
||||
norm_tx_queue_max(8), norm_tx_queue_count(0),
|
||||
norm_flow_control_pending(false), norm_tx_vacancy(true), norm_acking(false),
|
||||
norm_flushing(true), norm_flush_object(NORM_OBJECT_INVALID), norm_last_object(NORM_OBJECT_INVALID),
|
||||
|
|
@ -226,14 +292,47 @@ NormCaster::~NormCaster()
|
|||
void NormCaster::Destroy()
|
||||
{
|
||||
tx_file_list.Destroy();
|
||||
if (post_processor)
|
||||
{
|
||||
delete post_processor;
|
||||
post_processor = NULL;
|
||||
}
|
||||
if (sent_processor)
|
||||
{
|
||||
delete sent_processor;
|
||||
sent_processor = NULL;
|
||||
}
|
||||
if (purged_processor)
|
||||
{
|
||||
delete purged_processor;
|
||||
purged_processor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool NormCaster::Init()
|
||||
{
|
||||
if (!(post_processor = NormPostProcessor::Create()))
|
||||
{
|
||||
fprintf(stderr, "normCast error: unable to create post processor\n");
|
||||
return false;
|
||||
}
|
||||
if (!(sent_processor = NormPostProcessor::Create()))
|
||||
{
|
||||
fprintf(stderr, "normCast error: unable to create sent processor\n");
|
||||
return false;
|
||||
}
|
||||
if (!(purged_processor = NormPostProcessor::Create()))
|
||||
{
|
||||
fprintf(stderr, "normCast error: unable to create purged processor\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NormCaster::AddTxItem(const char* path)
|
||||
{
|
||||
bool result = tx_file_list.AppendPath(path);
|
||||
if (!result)
|
||||
perror("NormCaster::AddTxItem() error");
|
||||
if (!TxFilePending()) StageNextTxFile();
|
||||
if (!result) perror("NormCaster::AddTxItem() error");
|
||||
return result;
|
||||
} // end NormCaster::AddTxItem()
|
||||
|
||||
|
|
@ -271,7 +370,8 @@ bool NormCaster::OpenNormSession(NormInstanceHandle instance, const char* addr,
|
|||
|
||||
//NormSetTxRobustFactor(norm_session, 20);
|
||||
|
||||
NormSetGrttProbingTOS(norm_session, probe_tos);
|
||||
NormSetGrttProbingTOS(norm_session, probe_tos); // this was for some experimental protocol work
|
||||
NormSetGrttProbingMode(norm_session, probe_mode);
|
||||
|
||||
return true;
|
||||
} // end NormCaster::OpenNormSession()
|
||||
|
|
@ -332,10 +432,9 @@ bool NormCaster::Start(bool sender, bool receiver)
|
|||
}
|
||||
else
|
||||
{
|
||||
// Uncommant and adjust this for more/less robust timer-based flow control as desired
|
||||
// Uncomment and adjust this for more/less robust timer-based flow control as desired (API default: 2.0)
|
||||
//NormSetFlowControl(norm_session, 10.0);
|
||||
}
|
||||
NormSetGrttEstimate(norm_session, 0.001);
|
||||
//NormSetGrttMax(norm_session, 0.100);
|
||||
NormSetBackoffFactor(norm_session, 0);
|
||||
|
||||
|
|
@ -351,6 +450,8 @@ bool NormCaster::Start(bool sender, bool receiver)
|
|||
NormSetAutoParity(norm_session, auto_parity < num_parity ? auto_parity : num_parity);
|
||||
if (0 != tx_socket_buffer_size)
|
||||
NormSetTxSocketBuffer(norm_session, tx_socket_buffer_size);
|
||||
|
||||
|
||||
}
|
||||
is_running = true;
|
||||
return true;
|
||||
|
|
@ -379,6 +480,7 @@ bool NormCaster::TxReady() const
|
|||
bool NormCaster::StageNextTxFile()
|
||||
{
|
||||
// Pull next file path from "tx_file_list" and stage as "tx_pending_path"
|
||||
tx_pending_path[0] = '\0';
|
||||
if (tx_file_iterator.GetNextFile(tx_pending_path))
|
||||
{
|
||||
// This code omits the source directory prefix from the name transmitted
|
||||
|
|
@ -408,13 +510,42 @@ bool NormCaster::StageNextTxFile()
|
|||
}
|
||||
else
|
||||
{
|
||||
// Either done need to reset tx_file_iterator
|
||||
// Either done or need to reset tx_file_iterator
|
||||
tx_pending_path[0] = '\0';
|
||||
tx_pending_prefix_len = 0;
|
||||
|
||||
// We have reached end of tx_file_list, so either
|
||||
// we're done or we reset tx_file_iterator (when 'repeat' option (TBD) is enabled)
|
||||
if (repeat_interval >= 0.0)
|
||||
{
|
||||
timer_start.GetCurrentTime();
|
||||
timer_delay = repeat_interval;
|
||||
tx_file_iterator.Reset();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // end NormCaster::StageNextTxFile()
|
||||
|
||||
void NormCaster::HandleTimeout()
|
||||
{
|
||||
if (timer_delay < 0.0) return; // no timeout pending
|
||||
ProtoTime currentTime;
|
||||
currentTime.GetCurrentTime();
|
||||
double elapsedTime = currentTime - timer_start;
|
||||
if (elapsedTime >= timer_delay)
|
||||
{
|
||||
// Timer has expired.(currently repeat_interval is only timeout)
|
||||
timer_delay = -1.0;
|
||||
if (StageNextTxFile())
|
||||
SendFiles();
|
||||
// else repeat timer was reset
|
||||
}
|
||||
else
|
||||
{
|
||||
timer_delay -= elapsedTime;
|
||||
}
|
||||
} // end NormCaster::HandleTimeout()
|
||||
|
||||
void NormCaster::SendFiles()
|
||||
{
|
||||
// Send pending file and subsequent files from tx_file_iterator as available/possible
|
||||
|
|
@ -429,8 +560,6 @@ void NormCaster::SendFiles()
|
|||
// Get next file name from our "tx_file_list"
|
||||
if (!StageNextTxFile())
|
||||
{
|
||||
// We have reach end of tx_file_list, so either
|
||||
// we're done or we reset tx_file_iterator (when 'repeat' option (TBD) is enabled)
|
||||
// If we're done and requesting ACK, finish up nicely with final waterrmark
|
||||
if (norm_acking)
|
||||
{
|
||||
|
|
@ -457,8 +586,10 @@ bool NormCaster::EnqueueFileObject()
|
|||
{
|
||||
assert(norm_tx_queue_count < norm_tx_queue_max);
|
||||
if (norm_tx_queue_count >= norm_tx_queue_max)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// This is our cheesy approach of using the NORM_INFO to convey the file name
|
||||
// (TBD - implement something more sophisticated like our FCAST (RFC 6968) concept)
|
||||
|
|
@ -533,6 +664,7 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
|
|||
{
|
||||
case NORM_TX_QUEUE_EMPTY:
|
||||
case NORM_TX_QUEUE_VACANCY:
|
||||
//fprintf(stderr, "normCast: NORM_TX_QUEUE EMPTY/VACANCY\n");
|
||||
norm_tx_vacancy = true;
|
||||
if (TxFilePending()) SendFiles();
|
||||
break;
|
||||
|
|
@ -542,8 +674,10 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
|
|||
break;
|
||||
|
||||
case NORM_TX_WATERMARK_COMPLETED:
|
||||
{
|
||||
if (NORM_ACK_SUCCESS == NormGetAckingStatus(norm_session))
|
||||
{
|
||||
fprintf(stderr, "normCast: NORM_TX_WATERMARK_COMPLETED, NORM_ACK_SUCCESS\n");
|
||||
// All receivers acknowledged.
|
||||
norm_last_object = NORM_OBJECT_INVALID;
|
||||
bool txFilePending = TxFilePending(); // need to check this _before_ possible call to SendFiles()
|
||||
|
|
@ -569,7 +703,7 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
|
|||
}
|
||||
else
|
||||
{
|
||||
|
||||
fprintf(stderr, "normCast: NORM_TX_WATERMARK_COMPLETED, _NOT_ NORM_ACK_SUCCESS\n");
|
||||
// In multicast, there is a chance some nodes ACK ...
|
||||
// so let's see who did, if any.
|
||||
// This iterates through the acking nodes looking for responses
|
||||
|
|
@ -582,7 +716,7 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
|
|||
ProtoAddress addr;
|
||||
addr.SetRawHostAddress(ProtoAddress::IPv4, (char*)&tmp, 4);
|
||||
if (NORM_ACK_SUCCESS != ackingStatus)
|
||||
fprintf(stderr, "normCast: node %lu (IP address: %s) failed to acnowledge.\n",
|
||||
fprintf(stderr, "normCast: node %lu (IP address: %s) failed to acnkowledge.\n",
|
||||
(unsigned long)nodeId, addr.GetHostString());
|
||||
else
|
||||
fprintf(stderr, "normCast: node %lu (IP address: %s) acknowledged.\n",
|
||||
|
|
@ -595,7 +729,7 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
|
|||
{
|
||||
NormResetWatermark(norm_session);
|
||||
}
|
||||
else // might as request ack for most recent enqueued object
|
||||
else // might as well request ack for most recent enqueued object (not sure why I did this?)
|
||||
{
|
||||
NormSetWatermark(norm_session, norm_flush_object, true);
|
||||
norm_last_object = norm_flush_object;
|
||||
|
|
@ -603,13 +737,59 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
|
|||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NORM_TX_FLUSH_COMPLETED:
|
||||
{
|
||||
fprintf(stderr, "normCast: NORM_TX_FLUSH_COMPLETED\n");
|
||||
if (!TxFilePending() && (repeat_interval < 0.0)&& !norm_acking)
|
||||
{
|
||||
// No more files to send, and not ack or repeat mode
|
||||
fprintf(stderr, "normCast: flush after final file send, exiting ...\n");
|
||||
is_running = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NORM_TX_OBJECT_PURGED:
|
||||
{
|
||||
if(event.object == norm_flush_object)
|
||||
norm_flush_object = NORM_OBJECT_INVALID;
|
||||
if (NORM_OBJECT_FILE != NormObjectGetType(event.object))
|
||||
{
|
||||
fprintf(stderr, "normCast: purged invalid object type?!\n");
|
||||
break;
|
||||
}
|
||||
char fileName[PATH_MAX + 1];
|
||||
fileName[PATH_MAX] = '\0';
|
||||
NormFileGetName(event.object, fileName, PATH_MAX);
|
||||
fprintf(stderr, "normCast: send file purged: \"%s\"\n", fileName);
|
||||
// This is where we could delete the associated tx file if desired
|
||||
// (e.g., for an "outbox" use case)
|
||||
if (purged_processor->IsEnabled())
|
||||
{
|
||||
if (!purged_processor->ProcessFile(fileName))
|
||||
fprintf(stderr, "normCast: purged processing error\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NORM_TX_OBJECT_SENT:
|
||||
{
|
||||
if (NORM_OBJECT_FILE != NormObjectGetType(event.object))
|
||||
{
|
||||
fprintf(stderr, "normCast: sent invalid object type?!\n");
|
||||
break;
|
||||
}
|
||||
char fileName[PATH_MAX + 1];
|
||||
fileName[PATH_MAX] = '\0';
|
||||
NormFileGetName(event.object, fileName, PATH_MAX);
|
||||
fprintf(stderr, "normCast: initial send complete for \"%s\"\n", fileName);
|
||||
if (sent_processor->IsEnabled())
|
||||
{
|
||||
if (!sent_processor->ProcessFile(fileName))
|
||||
fprintf(stderr, "normCast: sent processing error\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -620,6 +800,8 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
|
|||
ProtoAddress addr;
|
||||
addr.SetRawHostAddress(ProtoAddress::IPv4, (char*)&tmp, 4);
|
||||
fprintf(stderr, "normCast: new acking node: %lu (IP address: %s)\n", (unsigned long)id, addr.GetHostString());
|
||||
// This next line of code updates the current watermark request (if there is one) so the new acking node is included
|
||||
NormResetWatermark(norm_session);
|
||||
}
|
||||
|
||||
case NORM_REMOTE_SENDER_INACTIVE:
|
||||
|
|
@ -628,8 +810,32 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
|
|||
break;
|
||||
|
||||
case NORM_RX_OBJECT_ABORTED:
|
||||
{
|
||||
//fprintf(stderr, "NORM_RX_OBJECT_ABORTED\n");// %hu\n", NormObjectGetTransportId(event.object));
|
||||
if (NORM_OBJECT_FILE != NormObjectGetType(event.object))
|
||||
{
|
||||
fprintf(stderr, "normCast: received invalid object type?!\n");
|
||||
break;
|
||||
}
|
||||
char fileName[PATH_MAX + 1];
|
||||
fileName[PATH_MAX] = '\0';
|
||||
NormFileGetName(event.object, fileName, PATH_MAX);
|
||||
fprintf(stderr, "normCast: aborted reception of \"%s\"\n", fileName);
|
||||
if (save_aborted_files)
|
||||
{
|
||||
if (post_processor->IsEnabled())
|
||||
{
|
||||
if (!post_processor->ProcessFile(fileName))
|
||||
fprintf(stderr, "normCast: post processing error\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (remove(fileName) != 0)
|
||||
fprintf(stderr, "normCast: error deleting aborted file \"%s\"\n", fileName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NORM_RX_OBJECT_INFO:
|
||||
{
|
||||
|
|
@ -670,7 +876,11 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
|
|||
fileName[PATH_MAX] = '\0';
|
||||
NormFileGetName(event.object, fileName, PATH_MAX);
|
||||
fprintf(stderr, "normCast: completed reception of \"%s\"\n", fileName);
|
||||
// TBD - implement receive post processing option ...
|
||||
if (post_processor->IsEnabled())
|
||||
{
|
||||
if (!post_processor->ProcessFile(fileName))
|
||||
fprintf(stderr, "normCast: post processing error\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -683,13 +893,19 @@ void NormCaster::HandleNormEvent(const NormEvent& event)
|
|||
|
||||
void Usage()
|
||||
{
|
||||
fprintf(stderr, "Usage: normCast id <nodeIdInteger> {send <file/dir list> &| recv <rxCacheDir>}\n"
|
||||
" [addr <addr>[/<port>]] [interface <name>] [loopback]\n"
|
||||
fprintf(stderr, "Usage: normCast {send <file/dir list> &| recv <rxCacheDir>} [silent {on|off}]\n"
|
||||
" [repeat <interval> [updatesOnly]] [id <nodeIdInteger>]\n"
|
||||
" [addr <addr>[/<port>]][txaddr <addr>[/<port>]][txport <port>]\n"
|
||||
" [interface <name>][reuse][loopback]\n"
|
||||
" [ack auto|<node1>[,<node2>,...]] [segment <bytes>]\n"
|
||||
" [block <count>] [parity <count>] [auto <count>]\n"
|
||||
" [cc|cce|ccl|rate <bitsPerSecond>] [ptos <value>]\n"
|
||||
" [flush {none|passive|active}] [silent] [txloss <lossFraction>]\n"
|
||||
" [buffer <bytes>] [txsockbuffer <bytes>] [rxsockbuffer <bytes>]\n"
|
||||
" [cc|cce|ccl|rate <bitsPerSecond>] [rxloss <lossFraction>]\n"
|
||||
" [txloss <lossFraction>] [flush {none|passive|active}]\n"
|
||||
" [grttprobing {none|passive|active}] [grtt <secs>]\n"
|
||||
" [ptos <value>] [processor <processorCmdLine>] [saveaborts]\n"
|
||||
" [sentprocessor <processorCmdLine>]\n"
|
||||
" [purgeprocessor <processorCmdLine>] [buffer <bytes>]\n"
|
||||
" [txsockbuffer <bytes>] [rxsockbuffer <bytes>]\n"
|
||||
" [debug <level>] [trace] [log <logfile>]\n");
|
||||
} // end Usage()
|
||||
|
||||
|
|
@ -700,10 +916,18 @@ int main(int argc, char* argv[])
|
|||
bool send = false;
|
||||
bool recv = false;
|
||||
|
||||
double repeatInterval = -1.0;
|
||||
bool updatesOnly = false;
|
||||
|
||||
char sessionAddr[64];
|
||||
strcpy(sessionAddr, "224.1.2.3");
|
||||
unsigned int sessionPort = 6003;
|
||||
|
||||
char sessionTxAddr[64];
|
||||
sessionTxAddr[0] = '\0';
|
||||
unsigned int sessionTxPort = 0;
|
||||
|
||||
|
||||
bool autoAck = false;
|
||||
NormNodeId ackingNodeList[256];
|
||||
unsigned int ackingNodeCount = 0;
|
||||
|
|
@ -718,9 +942,15 @@ int main(int argc, char* argv[])
|
|||
bool trace = false;
|
||||
bool silentReceiver = false;
|
||||
double txloss = 0.0;
|
||||
double rxloss = 0.0;
|
||||
double grtt_estimate = 0.001;
|
||||
NormProbingMode grtt_probing_mode = NORM_PROBE_ACTIVE;
|
||||
bool loopback = false;
|
||||
bool reuse = false;
|
||||
|
||||
NormCaster normCast;
|
||||
if (!normCast.Init())
|
||||
return -1;
|
||||
|
||||
// Parse command-line
|
||||
int i = 1;
|
||||
|
|
@ -751,6 +981,25 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
send = true;
|
||||
}
|
||||
else if (0 == strncmp(cmd, "repeat", len))
|
||||
{
|
||||
if (i >= argc)
|
||||
{
|
||||
fprintf(stderr, "normCast error: missing 'repeat' <interval> value!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
if (1 != sscanf(argv[i++], "%lf", &repeatInterval))
|
||||
{
|
||||
fprintf(stderr, "normCast error: invalid repeat interval!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "updatesOnly", len))
|
||||
{
|
||||
updatesOnly = true;
|
||||
}
|
||||
else if (0 == strncmp(cmd, "recv", len))
|
||||
{
|
||||
if (i >= argc)
|
||||
|
|
@ -819,6 +1068,58 @@ int main(int argc, char* argv[])
|
|||
sessionPort = atoi(portPtr);
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "txaddr", len))
|
||||
{
|
||||
const char* addrPtr = argv[i++];
|
||||
const char* portPtr = strchr(addrPtr, '/');
|
||||
if (NULL == portPtr)
|
||||
{
|
||||
strncpy(sessionTxAddr, addrPtr, 63);
|
||||
sessionTxAddr[63] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t addrLen = portPtr - addrPtr;
|
||||
if (addrLen > 63)
|
||||
{
|
||||
fprintf(stderr, "normCast error: 'txaddr' value too long!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
strncpy(sessionTxAddr, addrPtr, addrLen);
|
||||
sessionTxAddr[addrLen] = '\0';
|
||||
portPtr++;
|
||||
int txPort = atoi(argv[i++]);
|
||||
if ((txPort <=0) || (txPort > 0x0000ffff))
|
||||
{
|
||||
fprintf(stderr, "normCast error: invalid 'txport' value!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
sessionTxPort = txPort;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "txport", len))
|
||||
{
|
||||
if (i >= argc)
|
||||
{
|
||||
fprintf(stderr, "normCast error: missing 'txport' value!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
int txPort = atoi(argv[i++]);
|
||||
if ((txPort <=0) || (txPort > 0x0000ffff))
|
||||
{
|
||||
fprintf(stderr, "normCast error: invalid 'txport' value!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
sessionTxPort = txPort;
|
||||
}
|
||||
else if (0 == strncmp(cmd, "reuse", len))
|
||||
{
|
||||
reuse = true;
|
||||
}
|
||||
else if (0 == strncmp(cmd, "id", len))
|
||||
{
|
||||
if (i >= argc)
|
||||
|
|
@ -888,6 +1189,7 @@ int main(int argc, char* argv[])
|
|||
else
|
||||
{
|
||||
fprintf(stderr, "normCast error: invalid 'flush' mode \"%s\"\n", mode);
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1050,9 +1352,30 @@ int main(int argc, char* argv[])
|
|||
normCast.SetAutoParity(value);
|
||||
}
|
||||
else if (0 == strncmp(cmd, "silent", len))
|
||||
{
|
||||
// "on", or "off"
|
||||
if (i >= argc)
|
||||
{
|
||||
fprintf(stderr, "normCast error: missing 'silent' <mode>!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
const char* mode = argv[i++];
|
||||
if (0 == strcmp(mode, "on"))
|
||||
{
|
||||
silentReceiver = true;
|
||||
}
|
||||
else if (0 == strcmp(mode, "off"))
|
||||
{
|
||||
silentReceiver = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "normCast error: invalid 'silent' mode \"%s\"\n", mode);
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "txloss", len))
|
||||
{
|
||||
if (1 != sscanf(argv[i++], "%lf", &txloss))
|
||||
|
|
@ -1062,6 +1385,53 @@ int main(int argc, char* argv[])
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "rxloss", len))
|
||||
{
|
||||
if (1 != sscanf(argv[i++], "%lf", &rxloss))
|
||||
{
|
||||
fprintf(stderr, "normCast error: invalid 'rxloss' value!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "grtt", len))
|
||||
{
|
||||
if (1 != sscanf(argv[i++], "%lf", &grtt_estimate))
|
||||
{
|
||||
fprintf(stderr, "normCast error: invalid 'grtt' value!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "grttprobing", len))
|
||||
{
|
||||
// "none", "passive", or "active"
|
||||
if (i >= argc)
|
||||
{
|
||||
fprintf(stderr, "normCast error: missing 'grttprobing' <mode>!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
const char* pmode = argv[i++];
|
||||
if (0 == strcmp(pmode, "none"))
|
||||
{
|
||||
grtt_probing_mode = NORM_PROBE_NONE;
|
||||
}
|
||||
else if (0 == strcmp(pmode, "passive"))
|
||||
{
|
||||
grtt_probing_mode = NORM_PROBE_PASSIVE;
|
||||
}
|
||||
else if (0 == strcmp(pmode, "active"))
|
||||
{
|
||||
grtt_probing_mode = NORM_PROBE_ACTIVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "normCast error: invalid 'grttprobing' mode \"%s\"\n", pmode);
|
||||
return -1;
|
||||
}
|
||||
normCast.SetProbeMode(grtt_probing_mode);
|
||||
}
|
||||
else if (0 == strncmp(cmd, "debug", len))
|
||||
{
|
||||
if (i >= argc)
|
||||
|
|
@ -1091,6 +1461,55 @@ int main(int argc, char* argv[])
|
|||
Usage();
|
||||
return 0;
|
||||
}
|
||||
else if (0 == strncmp(cmd, "processor", len))
|
||||
{
|
||||
if (i >= argc)
|
||||
{
|
||||
fprintf(stderr, "normCast error: missing 'processor' commandline!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
if (!normCast.SetPostProcessorCommand(argv[i++]))
|
||||
{
|
||||
fprintf(stderr, "normCast error: unable to set 'processor'!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "sentprocessor", len))
|
||||
{
|
||||
if (i >= argc)
|
||||
{
|
||||
fprintf(stderr, "normCast error: missing 'sentprocessor' commandline!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
if (!normCast.SetSentProcessorCommand(argv[i++]))
|
||||
{
|
||||
fprintf(stderr, "normCast error: unable to set 'sentprocessor'!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "purgeprocessor", len))
|
||||
{
|
||||
if (i >= argc)
|
||||
{
|
||||
fprintf(stderr, "normCast error: missing 'purgeprocessor' commandline!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
if (!normCast.SetPurgedProcessorCommand(argv[i++]))
|
||||
{
|
||||
fprintf(stderr, "normCast error: unable to set 'purgeprocessor'!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "saveaborts", len))
|
||||
{
|
||||
normCast.SaveAborts(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "normCast error: invalid command \"%s\"!\n", cmd);
|
||||
|
|
@ -1142,6 +1561,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
if (silentReceiver) normCast.SetSilentReceiver(true);
|
||||
if (txloss > 0.0) normCast.SetTxLoss(txloss);
|
||||
if (rxloss > 0.0) normCast.SetRxLoss(rxloss);
|
||||
|
||||
|
||||
if (autoAck)
|
||||
|
|
@ -1159,13 +1579,27 @@ int main(int argc, char* argv[])
|
|||
normCast.SetNormTxRate(txRate);
|
||||
if (NULL != mcastIface)
|
||||
normCast.SetNormMulticastInterface(mcastIface);
|
||||
if ('\0' != sessionTxAddr[0])
|
||||
normCast.SetNormTxPort(sessionTxPort, reuse, sessionTxAddr);
|
||||
|
||||
if (trace) normCast.SetNormMessageTrace(true);
|
||||
|
||||
normCast.SetRepeat(repeatInterval, updatesOnly);
|
||||
|
||||
// TBD - set NORM session parameters
|
||||
normCast.Start(send, recv);
|
||||
normCast.SetGrttEstimate(grtt_estimate);
|
||||
|
||||
if (send)
|
||||
{
|
||||
// This initiates repeat timer when there is no current files pending
|
||||
//if ((repeatInterval >= 0.0) && !normCast.TxFilePending())
|
||||
normCast.StageNextTxFile();
|
||||
|
||||
if (normCast.TxFilePending())
|
||||
normCast.SendFiles();
|
||||
}
|
||||
|
||||
if (normCast.TxFilePending()) normCast.SendFiles();
|
||||
|
||||
#ifdef WIN32
|
||||
//Win32InputHandler inputHandler;
|
||||
|
|
@ -1188,12 +1622,16 @@ int main(int argc, char* argv[])
|
|||
// (on Windows, would use the win32InputHandler code in norm/examples)
|
||||
bool normEventPending = false;
|
||||
bool inputEventPending = false;
|
||||
double timerDelay = normCast.GetTimerDelay();
|
||||
#ifdef WIN32
|
||||
DWORD handleCount = inputNeeded ? 2 : 1;
|
||||
DWORD msec = INFINITE;
|
||||
if (timerDelay >= 0.0)
|
||||
msec = (DWORD)(timerDelay*1000);
|
||||
DWORD waitStatus =
|
||||
MsgWaitForMultipleObjectsEx(handleCount, // number of handles in array
|
||||
handleArray, // object-handle array
|
||||
INFINITE, // time-out interval
|
||||
msec, // time-out interval
|
||||
QS_ALLINPUT, // input-event type
|
||||
0);
|
||||
if ((WAIT_OBJECT_0 <= waitStatus) && (waitStatus < (WAIT_OBJECT_0 + handleCount)))
|
||||
|
|
@ -1219,12 +1657,17 @@ int main(int argc, char* argv[])
|
|||
FD_SET(normfd, &fdsetInput);
|
||||
//FD_SET(inputfd, &fdsetInput);
|
||||
//if (inputfd > maxfd) maxfd = inputfd;
|
||||
if (maxfd >= 0)
|
||||
if ((maxfd >= 0) || (timerDelay >= 0.0))
|
||||
{
|
||||
struct timeval* timeoutPtr = NULL;
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
int result = select(maxfd+1, &fdsetInput, NULL, NULL, NULL); //&timeout);
|
||||
if (timerDelay >= 0.0)
|
||||
{
|
||||
timeout.tv_sec = (time_t)timerDelay;
|
||||
timeout.tv_usec = (timerDelay - timeout.tv_sec)*1.0e+06;
|
||||
timeoutPtr = &timeout;
|
||||
}
|
||||
int result = select(maxfd+1, &fdsetInput, NULL, NULL, timeoutPtr);
|
||||
switch (result)
|
||||
{
|
||||
case -1:
|
||||
|
|
@ -1253,10 +1696,10 @@ int main(int argc, char* argv[])
|
|||
} // end if (maxfd >= 0)
|
||||
#endif // if/else WIN32/UNIX
|
||||
|
||||
// if (inputEventPending)
|
||||
// {
|
||||
if (inputEventPending)
|
||||
{
|
||||
// TBD - could parse input for runtime commands (e.g., send <file>), etc
|
||||
// }
|
||||
}
|
||||
if (normEventPending)
|
||||
{
|
||||
// Handle all pending NORM notification events
|
||||
|
|
@ -1268,7 +1711,7 @@ int main(int argc, char* argv[])
|
|||
normCast.HandleNormEvent(event);
|
||||
}
|
||||
}
|
||||
// Invoke any 'timeout' actions here
|
||||
normCast.HandleTimeout(); // checks for and acts on any pending timeout
|
||||
|
||||
} // end while(normCast.IsRunning()
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -202,6 +202,8 @@ class NormMsgr
|
|||
{NormSetSilentReceiver(norm_session, state);}
|
||||
void SetTxLoss(double txloss)
|
||||
{NormSetTxLoss(norm_session, txloss);}
|
||||
void SetRxLoss(double rxloss)
|
||||
{NormSetRxLoss(norm_session, rxloss);}
|
||||
|
||||
private:
|
||||
bool is_running;
|
||||
|
|
@ -783,7 +785,8 @@ void Usage()
|
|||
" [ack auto|<node1>[,<node2>,...]] [output <outFile>]\n"
|
||||
" [cc|cce|ccl|rate <bitsPerSecond>] [interface <name>] [loopback]\n"
|
||||
" [debug <level>] [trace] [log <logfile>] [silent]\n"
|
||||
" [flush {none|passive|active}] [omit] [txloss <lossFraction>]\n");
|
||||
" [flush {none|passive|active}] [omit] [txloss <lossFraction>]\n"
|
||||
" [rxloss <lossFraction>]\n");
|
||||
}
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
|
@ -811,6 +814,7 @@ int main(int argc, char* argv[])
|
|||
bool omitHeaderOnOutput = false;
|
||||
bool silentReceiver = false;
|
||||
double txloss = 0.0;
|
||||
double rxloss = 0.0;
|
||||
bool loopback = false;
|
||||
|
||||
NormMsgr normMsgr;
|
||||
|
|
@ -1003,6 +1007,15 @@ int main(int argc, char* argv[])
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "rxloss", len))
|
||||
{
|
||||
if (1 != sscanf(argv[i++], "%lf", &rxloss))
|
||||
{
|
||||
fprintf(stderr, "nodeMsgr error: invalid 'rxloss' value!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "debug", len))
|
||||
{
|
||||
if (i >= argc)
|
||||
|
|
@ -1073,6 +1086,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
if (silentReceiver) normMsgr.SetSilentReceiver(true);
|
||||
if (txloss > 0.0) normMsgr.SetTxLoss(txloss);
|
||||
if (rxloss > 0.0) normMsgr.SetRxLoss(rxloss);
|
||||
|
||||
if (autoAck)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ const char* NormNodeGetAddressString(NormNodeHandle node)
|
|||
else
|
||||
addrFamily = AF_INET6;
|
||||
inet_ntop(addrFamily, addr, text, 31);
|
||||
sprintf(text + strlen(text), "/%hu", port);
|
||||
snprintf(text + strlen(text), 64 - strlen(text), "/%hu", port);
|
||||
return text;
|
||||
}
|
||||
else
|
||||
|
|
@ -521,9 +521,9 @@ bool NormSocket::Listen(UINT16 serverPort, const char* groupAddr, const char* se
|
|||
// So that the listener can construct (unsent) ACKs without failure
|
||||
NormSetDefaultUnicastNack(norm_session, true);
|
||||
|
||||
// Note we use a small buffer size here since a "listening" socket isn't
|
||||
// Note we use a _small_ buffer size here since a "listening" socket isn't
|
||||
// going to be receiving data (TBD - implement a mechanism to handoff remote
|
||||
// sender (i.e. "client") from parent
|
||||
// sender (i.e. "client") from parent directly?)
|
||||
if (!NormStartReceiver(norm_session, 2048))
|
||||
{
|
||||
fprintf(stderr, "NormSocket::Listen() error: NormStartReceiver() failure (perhaps port already in use)\n");
|
||||
|
|
@ -580,7 +580,7 @@ NormSocket* NormSocket::Accept(NormNodeHandle client, NormInstanceHandle instanc
|
|||
// However, note that even though we've "connected" this sender,
|
||||
// there is a chance that additional packets in the "serverSession"
|
||||
// rx socket buffer may look like a new sender if deleted now, so
|
||||
// we wait for NORM_REMOTE_SENDER_INACTIVE to delete
|
||||
// we wait for NORM_REMOTE_SENDER_INACTIVE to delete the remote sender from the listener sesssion
|
||||
|
||||
#ifndef WIN32
|
||||
// Enable rx port reuse since it's the server port, and connect
|
||||
|
|
@ -1180,6 +1180,7 @@ void NormSocket::GetSocketEvent(const NormEvent& event, NormSocketEvent& socketE
|
|||
socketEvent.type = NORM_SOCKET_CONNECT;
|
||||
NormSetSynStatus(norm_session, false);
|
||||
socket_state = CONNECTED;
|
||||
|
||||
// Since UDP connect/bind doesn't really work properly on
|
||||
// Windows, the Windows NormSocket server farms out client connections
|
||||
// to new ephemeral port numbers, so we need to update
|
||||
|
|
@ -1187,12 +1188,11 @@ void NormSocket::GetSocketEvent(const NormEvent& event, NormSocketEvent& socketE
|
|||
remote_node = event.sender;
|
||||
UpdateRemoteAddress();
|
||||
NormChangeDestination(norm_session, NULL, remote_port);
|
||||
if (NORM_OBJECT_INVALID == tx_stream)
|
||||
if ((NORM_OBJECT_INVALID == tx_stream) && !(IsMulticastClient() && IsServerSide()))
|
||||
{
|
||||
tx_stream = NormStreamOpen(norm_session, socket_option.buffer_size);
|
||||
InitTxStream(tx_stream, socket_option.buffer_size, socket_option.segment_size, socket_option.num_data);
|
||||
}
|
||||
|
||||
break;
|
||||
case CONNECTED:
|
||||
if (IsMulticastSocket())
|
||||
|
|
@ -1200,9 +1200,33 @@ void NormSocket::GetSocketEvent(const NormEvent& event, NormSocketEvent& socketE
|
|||
if (IsServerSocket())
|
||||
{
|
||||
// New client showing up at our multicast party
|
||||
NormSocketInfo* socketInfo = client_table.FindSocketInfo(event.sender);
|
||||
if (NULL == socketInfo)
|
||||
{
|
||||
// Add info for client socket pending acceptance
|
||||
socketInfo = new NormSocketInfo(NormGetSocketInfo(event.sender));
|
||||
if (NULL != socketInfo)
|
||||
{
|
||||
client_table.Insert(*socketInfo);
|
||||
socketEvent.type = NORM_SOCKET_ACCEPT;
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("NormSocket::GetSocketEvent() error: unable to add pending client info to server socket:\n");
|
||||
}
|
||||
}
|
||||
else // duplicative accept event for existing socket, so ignore
|
||||
{
|
||||
ProtoAddress remoteAddr;
|
||||
socketInfo->GetRemoteAddress(remoteAddr);
|
||||
fprintf(stderr, "NormSocket::GetSocketEvent() warning: duplicative %s from client %s/%hu...\n",
|
||||
(NORM_REMOTE_SENDER_NEW == event.type) ? "new" : "reset",
|
||||
remoteAddr.GetHostString(), remoteAddr.GetPort());
|
||||
// TBD - should we go ahead and delete this event.sender???
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// TBD - validate if this same server or not (e.g. by source addr/port)
|
||||
// Different sender showing up in multicast group!?
|
||||
|
|
@ -1429,7 +1453,6 @@ void NormSocket::GetSocketEvent(const NormEvent& event, NormSocketEvent& socketE
|
|||
else
|
||||
{
|
||||
// This still allows at least a chance of an ACK to be sent upon completion
|
||||
TRACE("NormSetUserTimer(5) session: %p\n", norm_session);
|
||||
NormSetUserTimer(norm_session, 0.0);
|
||||
}
|
||||
socketEvent.type = NORM_SOCKET_CLOSING;
|
||||
|
|
|
|||
|
|
@ -92,6 +92,30 @@ ssize_t NormWrite(NormSocketHandle normSocket, const void* buf, size_t nbyte);
|
|||
|
||||
int NormFlush(NormSocketHandle normSocket);
|
||||
|
||||
/*
|
||||
|
||||
// These calls _will_ be used for file/data object and message-stream delivery. (Sketching the calls out for now)
|
||||
|
||||
NormObject NormSendFile(NormSocketHandle normSocket,
|
||||
const char* filePath,
|
||||
const char* infoPtr,
|
||||
ssize_t infoLen);
|
||||
|
||||
NormObject NormSendData(NormSocketHandle normSocket,
|
||||
const char* data, // NormSocket will copy the "data" unlike NORM low-level API
|
||||
ssize_t nbyte,
|
||||
const char* infoPtr,
|
||||
ssize_t infoLen);
|
||||
|
||||
// Notification events will indicate receipt of file/data objects. Are additional NormSocket API calls
|
||||
// needed to manage receipt?
|
||||
|
||||
ssize_t NormSendMsg(NormSocketHandle normSocket, const char* data, ssize_t nbyte, bool flush);
|
||||
|
||||
ssize_t NormRecvMsg(NormSocketHandle normSocket, const char* data, ssize_t nbyte);
|
||||
|
||||
*/
|
||||
|
||||
// NormSocket helper functions
|
||||
|
||||
void NormSetSocketUserData(NormSocketHandle normSocket, const void* userData);
|
||||
|
|
@ -119,7 +143,7 @@ typedef enum NormSocketEventType
|
|||
} NormSocketEventType;
|
||||
|
||||
|
||||
// Right now, these options MUST be set after NormOpen()
|
||||
// Right now, these options MUST be set _after_ NormOpen()
|
||||
// but _before_ NormConnect() or NormListen()
|
||||
// (This will be expanded, perhaps to include parameters
|
||||
// that can be changed after connection setup)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
#include <sys/timerfd.h>
|
||||
#endif // LINUX
|
||||
|
||||
const unsigned int LOOP_MAX = 100;
|
||||
const unsigned int LOOP_MAX = 1;
|
||||
|
||||
// Setting SHOOT_FIRST to non-zero means that an ACK request
|
||||
// will be used to advance the acking "watermark" point
|
||||
|
|
@ -70,7 +70,10 @@ class NormStreamer
|
|||
{
|
||||
loopback = state;
|
||||
if (NORM_SESSION_INVALID != norm_session)
|
||||
{
|
||||
NormSetMulticastLoopback(norm_session, state);
|
||||
NormSetLoopback(norm_session, state); // XXX test code
|
||||
}
|
||||
}
|
||||
void SetFtiInfo(bool state)
|
||||
{
|
||||
|
|
@ -256,6 +259,8 @@ class NormStreamer
|
|||
{NormSetSilentReceiver(norm_session, state);}
|
||||
void SetTxLoss(double txloss)
|
||||
{NormSetTxLoss(norm_session, txloss);}
|
||||
void SetRxLoss(double rxloss)
|
||||
{NormSetRxLoss(norm_session, rxloss);}
|
||||
// Set the scheduler for running the app and norm threads.
|
||||
static bool BoostPriority();
|
||||
|
||||
|
|
@ -565,11 +570,14 @@ bool NormStreamer::OpenNormSession(NormInstanceHandle instance, const char* addr
|
|||
{
|
||||
NormSetRxPortReuse(norm_session, true);
|
||||
if (loopback)
|
||||
{
|
||||
NormSetMulticastLoopback(norm_session, true);
|
||||
}
|
||||
}
|
||||
NormSetLoopback(norm_session, loopback);
|
||||
|
||||
// Set some default parameters (maybe we should put parameter setting in Start())
|
||||
NormSetDefaultSyncPolicy(norm_session, NORM_SYNC_STREAM);
|
||||
NormSetDefaultSyncPolicy(norm_session, NORM_SYNC_CURRENT);
|
||||
|
||||
if (!is_multicast)
|
||||
NormSetDefaultUnicastNack(norm_session, true);
|
||||
|
|
@ -703,7 +711,7 @@ bool NormStreamer::Start(bool sender, bool receiver)
|
|||
void NormStreamer::ReadInputSocket()
|
||||
{
|
||||
unsigned int loopCount = 0;
|
||||
NormSuspendInstance(NormGetInstance(norm_session));
|
||||
//NormSuspendInstance(NormGetInstance(norm_session));
|
||||
while (input_needed && input_ready && (loopCount < LOOP_MAX))
|
||||
{
|
||||
loopCount++;
|
||||
|
|
@ -731,7 +739,7 @@ void NormStreamer::ReadInputSocket()
|
|||
input_ready = false;
|
||||
}
|
||||
}
|
||||
NormResumeInstance(NormGetInstance(norm_session));
|
||||
//NormResumeInstance(NormGetInstance(norm_session));
|
||||
} // end NormStreamer::ReadInputSocket()
|
||||
|
||||
void NormStreamer::ReadInput()
|
||||
|
|
@ -740,7 +748,7 @@ void NormStreamer::ReadInput()
|
|||
// The loop count makes sure we don't spend too much time here
|
||||
// before going back to the main loop to handle NORM events, etc
|
||||
unsigned int loopCount = 0;
|
||||
NormSuspendInstance(NormGetInstance(norm_session));
|
||||
//NormSuspendInstance(NormGetInstance(norm_session));
|
||||
while (input_needed && input_ready && (loopCount < LOOP_MAX))
|
||||
{
|
||||
loopCount++;
|
||||
|
|
@ -758,7 +766,9 @@ void NormStreamer::ReadInput()
|
|||
assert(input_index < input_msg_length);
|
||||
numBytes = input_msg_length - input_index;
|
||||
}
|
||||
//TRACE("reading STDIN ...\n");
|
||||
ssize_t result = read(input_fd, input_buffer + input_index, numBytes);
|
||||
//TRACE(" result: %d\n", (int)result);
|
||||
if (result > 0)
|
||||
{
|
||||
input_index += result;
|
||||
|
|
@ -825,7 +835,7 @@ void NormStreamer::ReadInput()
|
|||
break;
|
||||
}
|
||||
} // end while (input_needed && input_ready)
|
||||
NormResumeInstance(NormGetInstance(norm_session));
|
||||
//NormResumeInstance(NormGetInstance(norm_session));
|
||||
} // end NormStreamer::ReadInput()
|
||||
|
||||
void NormStreamer::SendData()
|
||||
|
|
@ -887,11 +897,11 @@ unsigned int NormStreamer::WriteToStream(const char* buffer, unsigned int numByt
|
|||
if (ack_ex)
|
||||
{
|
||||
const char* req = "Hello, acker";
|
||||
NormSetWatermarkEx(norm_session, tx_stream, req, strlen(req) + 1);
|
||||
NormSetWatermarkEx(norm_session, tx_stream, req, strlen(req) + 1);//, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
NormSetWatermark(norm_session, tx_stream);
|
||||
NormSetWatermark(norm_session, tx_stream);//, true);
|
||||
}
|
||||
|
||||
tx_watermark_pending = true;
|
||||
|
|
@ -992,7 +1002,7 @@ void NormStreamer::RecvData()
|
|||
// before going back to the main loop to handle NORM events, etc
|
||||
unsigned int loopCount = 0;
|
||||
// Reads data from rx_stream to available output_buffer
|
||||
NormSuspendInstance(NormGetInstance(norm_session));
|
||||
//NormSuspendInstance(NormGetInstance(norm_session));
|
||||
while (rx_needed && rx_ready && (loopCount < LOOP_MAX))
|
||||
{
|
||||
loopCount++;
|
||||
|
|
@ -1057,7 +1067,7 @@ void NormStreamer::RecvData()
|
|||
WriteOutput();
|
||||
}
|
||||
}
|
||||
NormResumeInstance(NormGetInstance(norm_session));
|
||||
//NormResumeInstance(NormGetInstance(norm_session));
|
||||
|
||||
} // end NormStreamer::RecvData()
|
||||
|
||||
|
|
@ -1112,8 +1122,8 @@ void NormStreamer::WriteOutput()
|
|||
if (0 != output_bucket_depth)
|
||||
{
|
||||
// Debit output token bucket since it's active
|
||||
if (result > output_bucket_count)
|
||||
TRACE("result:%d output_bucket_count:%u\n", (int)result, output_bucket_count);
|
||||
//if (result > output_bucket_count)
|
||||
// TRACE("result:%d output_bucket_count:%u\n", (int)result, output_bucket_count);
|
||||
ASSERT(output_bucket_count >= result);
|
||||
output_bucket_count -= result;
|
||||
}
|
||||
|
|
@ -1166,7 +1176,7 @@ void NormStreamer::HandleNormEvent(const NormEvent& event)
|
|||
break;
|
||||
|
||||
case NORM_GRTT_UPDATED:
|
||||
//fprintf(stderr, "new GRTT = %lf\n", NormGetGrttEstimate(norm_session));
|
||||
//TRACE("normStreamer: new GRTT = %lf\n", NormGetGrttEstimate(norm_session));
|
||||
break;
|
||||
|
||||
case NORM_ACKING_NODE_NEW:
|
||||
|
|
@ -1176,7 +1186,6 @@ void NormStreamer::HandleNormEvent(const NormEvent& event)
|
|||
break;
|
||||
|
||||
case NORM_TX_WATERMARK_COMPLETED:
|
||||
TRACE("NORM_TX_WATERMARK_COMPLETED ...\n");
|
||||
if (NORM_ACK_SUCCESS == NormGetAckingStatus(norm_session))
|
||||
{
|
||||
//fprintf(stderr, "WATERMARK COMPLETED\n");
|
||||
|
|
@ -1353,8 +1362,8 @@ void Usage()
|
|||
" [insockbuffer <bytes>] [outsockbuffer <bytes>]\n"
|
||||
" [txsockbuffer <bytes>] [rxsockbuffer <bytes>]\n"
|
||||
" [streambuffer <bytes>]\n"
|
||||
" [check64 | check32]\n"
|
||||
" [omit] [silent] [txloss <lossFraction>]\n");
|
||||
" [check64 | check32] [omit] [silent]\n"
|
||||
" [txloss <lossFraction>] [rxloss <lossFraction>]\n");
|
||||
} // end Usage()
|
||||
|
||||
void PrintHelp()
|
||||
|
|
@ -1437,6 +1446,7 @@ int main(int argc, char* argv[])
|
|||
bool omitHeaderOnOutput = false;
|
||||
bool silentReceiver = false;
|
||||
double txloss = 0.0;
|
||||
double rxloss = 0.0;
|
||||
bool boostPriority = false;
|
||||
unsigned int checkSequence = 0; // can set to 64 or 32
|
||||
// TBD - set these defaults to reasonable values or just use NormStreamer constructor defaults
|
||||
|
|
@ -1445,7 +1455,7 @@ int main(int argc, char* argv[])
|
|||
unsigned long outputSocketBufferSize = 0; // 6*1024*1024;
|
||||
unsigned long txSocketBufferSize = 0; // 6*1024*1024;
|
||||
unsigned long rxSocketBufferSize = 0; // 6*1024*1024;
|
||||
unsigned long streamBufferSize = 1*1024*1024;
|
||||
unsigned long streamBufferSize = 2*1024*1024;
|
||||
|
||||
// Instantiate a NormStreamer and set default params
|
||||
NormStreamer normStreamer;
|
||||
|
|
@ -1955,6 +1965,15 @@ int main(int argc, char* argv[])
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "rxloss", len))
|
||||
{
|
||||
if (1 != sscanf(argv[i++], "%lf", &rxloss))
|
||||
{
|
||||
fprintf(stderr, "normStreamer error: invalid 'rxloss' value!\n");
|
||||
Usage();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (0 == strncmp(cmd, "debug", len))
|
||||
{
|
||||
if (i >= argc)
|
||||
|
|
@ -2040,6 +2059,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
// TBD - should provide more error checking of NORM API calls
|
||||
NormInstanceHandle normInstance = NormCreateInstance(boostPriority);
|
||||
|
||||
NormSetDebugLevel(debugLevel);
|
||||
if ((NULL != logFile) && !NormOpenDebugLog(normInstance, logFile))
|
||||
{
|
||||
|
|
@ -2069,6 +2089,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
if (silentReceiver) normStreamer.SetSilentReceiver(true);
|
||||
if (txloss > 0.0) normStreamer.SetTxLoss(txloss);
|
||||
if (rxloss > 0.0) normStreamer.SetRxLoss(rxloss);
|
||||
|
||||
for (unsigned int i = 0; i < ackingNodeCount; i++)
|
||||
normStreamer.AddAckingNode(ackingNodeList[i]);
|
||||
|
|
@ -2117,6 +2138,7 @@ int main(int argc, char* argv[])
|
|||
int maxfd = -1;
|
||||
int fdMask = 0;
|
||||
bool waitOnNorm = false;
|
||||
bool waitOnInput = false;
|
||||
double timeoutInterval = -1.0;
|
||||
if (send)
|
||||
{
|
||||
|
|
@ -2132,6 +2154,7 @@ int main(int argc, char* argv[])
|
|||
FD_SET(inputfd, &fdsetInput);
|
||||
if (inputfd > maxfd) maxfd = inputfd;
|
||||
fdMask |= 0x01;
|
||||
waitOnInput = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -2249,6 +2272,7 @@ int main(int argc, char* argv[])
|
|||
timeout.tv_sec = timeout.tv_usec = 0;
|
||||
}
|
||||
#endif // if/else LINUX
|
||||
//ßTRACE("waitOnNorm:%d waitOnInput:%d\n", waitOnNorm, waitOnInput);
|
||||
int result = select(maxfd+1, &fdsetInput, &fdsetOutput, NULL, timeoutPtr);
|
||||
switch (result)
|
||||
{
|
||||
|
|
@ -2285,9 +2309,14 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
// We always clear out/handle pending NORM API events
|
||||
// (to keep event queue from building up)
|
||||
unsigned int eventCount = 0;
|
||||
const unsigned int maxBurstCount = 50;
|
||||
NormEvent event;
|
||||
while (NormGetNextEvent(normInstance, &event, false))
|
||||
while ((eventCount < maxBurstCount) && (NormGetNextEvent(normInstance, &event, false)))
|
||||
{
|
||||
normStreamer.HandleNormEvent(event);
|
||||
eventCount += 1;
|
||||
}
|
||||
|
||||
struct timeval thisTime;
|
||||
gettimeofday(&thisTime, NULL);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ def main(argv):
|
|||
(opts, args) = get_option_parser().parse_args(argv)
|
||||
|
||||
if len(args) != 1:
|
||||
print USAGE
|
||||
print(USAGE)
|
||||
return 1
|
||||
|
||||
pipep = PipeParser(opts.pipe)
|
||||
|
|
@ -53,7 +53,7 @@ def main(argv):
|
|||
except IndexError:
|
||||
continue
|
||||
pipep.reports.task_done()
|
||||
print "Exiting..."
|
||||
print("Exiting...")
|
||||
# g.reset()
|
||||
# g.close()
|
||||
# del g
|
||||
|
|
|
|||
|
|
@ -0,0 +1,425 @@
|
|||
'''
|
||||
|
||||
LD_LIBRARY_PATH=/home/honglei/norm_test/
|
||||
|
||||
'''
|
||||
# sender/Win10:
|
||||
#--id 34252 --send "C:\Users\Admin\AppData\Roaming\Wing Pro 9" --repeat 1 --addr 224.1.2.4/6003 --txaddr 10.65.39.191/8002 --cc rate 5000 --ack auto --grttprobing active --debug 4
|
||||
# receiver/Debian10
|
||||
#--id 172042016 --recv "~/recvFiles" --addr 224.1.2.4/6003 --interface ens33 --unicast_nack --debug 4
|
||||
import sys
|
||||
import os
|
||||
if os.name =='nt':
|
||||
os.add_dll_directory(os.path.dirname(__file__))
|
||||
import argparse
|
||||
import traceback
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
import enum
|
||||
|
||||
class CCEnum(enum.Enum):
|
||||
CC = "cc"
|
||||
CCE = "cce"
|
||||
CCL = "ccl"
|
||||
Fixed = "rate"
|
||||
|
||||
class FlushEnum(enum.Enum):
|
||||
none='none'
|
||||
passive='passive'
|
||||
active='active'
|
||||
|
||||
class GrttEnum(enum.Enum):
|
||||
none='none'
|
||||
passive='passive'
|
||||
active='active'
|
||||
|
||||
|
||||
class EnumAction(argparse.Action):
|
||||
"""
|
||||
Argparse action for handling Enums
|
||||
from https://stackoverflow.com/questions/43968006/support-for-enum-arguments-in-argparse
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
# Pop off the type value
|
||||
enum_type = kwargs.pop("type", None)
|
||||
|
||||
# Ensure an Enum subclass is provided
|
||||
if enum_type is None:
|
||||
raise ValueError("type must be assigned an Enum when using EnumAction")
|
||||
if not issubclass(enum_type, enum.Enum):
|
||||
raise TypeError("type must be an Enum when using EnumAction")
|
||||
|
||||
# Generate choices from the Enum
|
||||
#kwargs.setdefault("choices", tuple(e.value for e in enum_type)) #if e!=CCEnum.rate else "rate <bitsPerSecond>"
|
||||
|
||||
super(EnumAction, self).__init__(**kwargs)
|
||||
|
||||
self._enum = enum_type
|
||||
|
||||
def __call__(self, parser, namespace, values:list|str, option_string=None):
|
||||
# Convert value back into an Enum
|
||||
if isinstance(values,list):
|
||||
if len(values) ==2:
|
||||
value = int(values[1])
|
||||
elif len(values) ==1:
|
||||
value = self._enum( values[0].lower())
|
||||
else:
|
||||
value = self._enum(values.lower() )
|
||||
setattr(namespace, self.dest, value)
|
||||
|
||||
'''
|
||||
norm.cpp:
|
||||
|
||||
fprintf(stderr, "Usage: normCast {send <file/dir list> &| recv <rxCacheDir>} [silent {on|off}]\n"
|
||||
" [repeat <interval> [updatesOnly]] [id <nodeIdInteger>]\n"
|
||||
" [addr <addr>[/<port>]][txaddr <addr>[/<port>]][txport <port>]\n"
|
||||
" [interface <name>][reuse][loopback]\n"
|
||||
" [ack auto|<node1>[,<node2>,...]] [segment <bytes>]\n"
|
||||
" [block <count>] [parity <count>] [auto <count>]\n"
|
||||
" [cc|cce|ccl|rate <bitsPerSecond>] [rxloss <lossFraction>]\n"
|
||||
" [txloss <lossFraction>] [flush {none|passive|active}]\n"
|
||||
" [grttprobing {none|passive|active}] [grtt <secs>]\n"
|
||||
" [ptos <value>] [processor <processorCmdLine>] [saveaborts]\n"
|
||||
" [sentprocessor <processorCmdLine>]\n"
|
||||
" [purgeprocessor <processorCmdLine>] [buffer <bytes>]\n"
|
||||
" [txsockbuffer <bytes>] [rxsockbuffer <bytes>]\n"
|
||||
" [debug <level>] [trace] [log <logfile>]\n");
|
||||
|
||||
'''
|
||||
# Instantiate the parser
|
||||
|
||||
def get_arg_options():
|
||||
parser = argparse.ArgumentParser(description='Optional app description')
|
||||
|
||||
## Required positional argument
|
||||
parser.add_argument('--id', type=int, required=True,
|
||||
help='id <nodeIdInteger>')
|
||||
|
||||
parser.add_argument('--send', '-S',nargs='+',
|
||||
help='send <file/dir list>')
|
||||
|
||||
parser.add_argument('--recv', '-R',
|
||||
help='recv <rxCacheDir>')
|
||||
|
||||
parser.add_argument('--repeat','-r', type=int, default=60,
|
||||
help='[repeat <interval> [updatesOnly]]')
|
||||
|
||||
parser.add_argument('--interface', '-i',
|
||||
help='addr <addr>[/<port>]')
|
||||
|
||||
parser.add_argument('--addr', '-a',
|
||||
help='addr <addr>[/<port>]')
|
||||
|
||||
parser.add_argument('--txaddr', '-t',
|
||||
help='txaddr <addr>[/<port>]')
|
||||
parser.add_argument('--txport', type=int,
|
||||
help='txport <port>')
|
||||
|
||||
parser.add_argument('--ack', nargs='+', #nargs='?',
|
||||
help='ack auto|<node1>[,<node2>,...')
|
||||
|
||||
|
||||
#To create an option that needs no value, set the action [docs] of it to 'store_const', 'store_true' or 'store_false'
|
||||
parser.add_argument('--loopback', action='store_true',help='')
|
||||
parser.add_argument('--segment', type=int,
|
||||
help='segment <bytes>')
|
||||
parser.add_argument('--block', type=int,
|
||||
help='[block <count>] ')
|
||||
parser.add_argument('--parity', type=int,
|
||||
help='[parity <count>]')
|
||||
parser.add_argument('--auto', type=int,
|
||||
help='[auto <count>]')
|
||||
|
||||
|
||||
parser.add_argument('--grttprobing', type=GrttEnum, action=EnumAction,
|
||||
help='[grttprobing {none|passive|active}]')
|
||||
parser.add_argument('--grtt', type=int, help='[grtt <secs>]')
|
||||
|
||||
parser.add_argument('--ptos', type=int,
|
||||
help='[ptos <value>]')
|
||||
|
||||
parser.add_argument('--flush', type=FlushEnum, action=EnumAction,
|
||||
help='[flush {none|passive|active}]')
|
||||
|
||||
parser.add_argument('--silent', action='store_true',help='')
|
||||
parser.add_argument('--unicast_nack', action='store_true', help='')
|
||||
|
||||
parser.add_argument('--txloss', type=float, help='[txloss <lossFraction>]')
|
||||
parser.add_argument('--rxloss', type=float, help='[rxloss <lossFraction>]')
|
||||
|
||||
parser.add_argument('--buffer', type=int, help='[buffer <bytes>]')
|
||||
parser.add_argument('--txsockbuffer', type=int, help=' [txsockbuffer <bytes>]')
|
||||
parser.add_argument('--rxsockbuffer', type=int, help='[rxsockbuffer <bytes>]')
|
||||
parser.add_argument('--debug', type=int, help='[debug <level>]')
|
||||
parser.add_argument('--cc',type=CCEnum, nargs='+', action=EnumAction,
|
||||
help='[cc|cce|ccl|rate <bitsPerSecond>] '
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
import pynorm
|
||||
|
||||
def create_session(instance:pynorm.Instance, opts:argparse.Namespace):
|
||||
'''
|
||||
use opts to create a NORM session
|
||||
'''
|
||||
sessionAddr ='224.1.2.3'
|
||||
sessionPort = 6003
|
||||
|
||||
if opts.addr:
|
||||
args = opts.addr.split('/')
|
||||
if len(args) >0:
|
||||
sessionAddr = args[0]
|
||||
if len(args) ==2:
|
||||
sessionPort = int(args[1])
|
||||
session = instance.createSession(sessionAddr, sessionPort, localId=opts.id)
|
||||
|
||||
|
||||
sessionTxAddr:str = None
|
||||
sessionTxPort = 8002
|
||||
if opts.txaddr:
|
||||
args = opts.txaddr.split('/')
|
||||
if len(args) >0:
|
||||
sessionTxAddr = args[0]
|
||||
if len(args) ==2:
|
||||
sessionTxPort = int(args[1])
|
||||
|
||||
if sessionTxAddr:
|
||||
session.setTxPort(txPort=sessionTxPort, txBindAddr=sessionTxAddr)
|
||||
|
||||
if opts.interface:
|
||||
session.setMulticastInterface(opts.interface)
|
||||
if opts.loopback:
|
||||
session.setLoopback(loopbackEnable=True)
|
||||
|
||||
if opts.silent:
|
||||
session.setSilentReceiver(True)
|
||||
|
||||
if opts.unicast_nack:
|
||||
session.setDefaultUnicastNack(enable=True)
|
||||
|
||||
autoAck:bool = False
|
||||
ackingNodeList:list[int] =[]
|
||||
if opts.ack:
|
||||
if 'auto' == opts.ack[0]:
|
||||
autoAck = True
|
||||
session.setAutoAckingNodes(pynorm.TrackingStatus.RECEIVERS)
|
||||
else:
|
||||
ackingNodeList = [ int(i) for i in opts.ack]
|
||||
|
||||
for ackingNondeID in ackingNodeList:
|
||||
session.addAckingNode(ackingNondeID)
|
||||
|
||||
if opts.txloss and opts.txloss>0:
|
||||
session.setTxLoss(opts.txloss)
|
||||
|
||||
if opts.rxloss and opts.rxloss>0:
|
||||
session.setRxLoss(opts.rxloss)
|
||||
|
||||
# Congestion Control
|
||||
if opts.cc:
|
||||
if isinstance(opts.cc,int):
|
||||
session.setTxRate(opts.cc)
|
||||
session.setEcnSupport(ecnEnable=False)
|
||||
else:
|
||||
if opts.cc == CCEnum.CC: # default TCP-friendly congestion control
|
||||
session.setEcnSupport(ecnEnable=False)
|
||||
elif opts.cc == CCEnum.CCE: #"wireless-ready" ECN-only congestion control
|
||||
session.setEcnSupport(ecnEnable=True, ignoreLoss=True)
|
||||
elif opts.cc == CCEnum.CCL: # "loss tolerant", non-ECN congestion control
|
||||
session.setEcnSupport(ecnEnable=False, ignoreLoss=False, tolerateLoss=True)
|
||||
|
||||
defaultBufferSpace = 64*1024*1024
|
||||
defaultTxSocketBufferSize = 4*1024*1024
|
||||
defaultRxSocketBufferSize = 6*1024*1024
|
||||
|
||||
bufferSpace = opts.buffer if opts.buffer else defaultBufferSpace
|
||||
if opts.send:
|
||||
if opts.ack:
|
||||
session.setFlowControl(flowControlFactor=0) #// ack-based flow control enabled on command-line, so disable timer-based flow control
|
||||
session.setBackoffFactor(0)
|
||||
#FEC
|
||||
session.startSender(sessionId=opts.id,
|
||||
bufferSpace=bufferSpace,
|
||||
segmentSize=opts.segment if opts.segment else 1400,
|
||||
blockSize=opts.block if opts.block else 64,
|
||||
numParity=opts.parity if opts.parity else 0,
|
||||
fecId=0)
|
||||
|
||||
if opts.auto:
|
||||
session.setAutoParity(opts.auto)
|
||||
session.setTxSocketBuffer(opts.txsockbuffer if opts.txsockbuffer else defaultTxSocketBufferSize )
|
||||
|
||||
if opts.recv:
|
||||
session.startReceiver(bufferSpace=bufferSpace)
|
||||
session.setRxSocketBuffer(opts.rxsockbuffer if opts.rxsockbuffer else defaultRxSocketBufferSize )
|
||||
|
||||
if opts.grttprobing:
|
||||
session.setGrttProbingMode(pynorm.ProbingMode[ opts.grttprobing.value.upper() ] )
|
||||
|
||||
return session
|
||||
|
||||
from pynorm import EventType
|
||||
|
||||
from typing import Iterable
|
||||
def listFiles( dirFileList:list[str]) -> Iterable[str]:
|
||||
for dirFile in dirFileList:
|
||||
if os.path.isfile(dirFile):
|
||||
yield dirFile
|
||||
elif os.path.isdir(dirFile):
|
||||
for filename in os.scandir(dirFile):
|
||||
if filename.is_file():
|
||||
yield filename.path
|
||||
else:
|
||||
raise FileExistsError(f"{dirFile} is not a valid file/dir")
|
||||
|
||||
import logging
|
||||
import ipaddress
|
||||
|
||||
class NormCaster():
|
||||
def __init__(self,instance:pynorm.Instance, opts:argparse.Namespace ):
|
||||
self.opts:argparse.Namespace = opts
|
||||
self.recvDir:Optional[str] = os.path.expanduser(opts.recv) if opts.recv else None
|
||||
|
||||
self.instance:pynorm.Instance = instance
|
||||
|
||||
self.session:pynorm.Session = create_session(instance, opts)
|
||||
self.fileIterator:Iterable[str] = listFiles(opts.send)
|
||||
self.is_running:bool = True
|
||||
self.pendingSendFilePath:Optional[str] = None #
|
||||
|
||||
def addOneFile(self,session):
|
||||
'''
|
||||
|
||||
'''
|
||||
if self.pendingSendFilePath is None:
|
||||
try:
|
||||
self.pendingSendFilePath:str = self.fileIterator.__next__()
|
||||
except StopIteration:
|
||||
self.is_running = False
|
||||
return
|
||||
|
||||
lastSlash = self.pendingSendFilePath.rfind('/')
|
||||
filename = self.pendingSendFilePath[lastSlash+1:]
|
||||
obj:Optional[pynorm.Object] = session.fileEnqueue(self.pendingSendFilePath, info= filename.encode() )
|
||||
if obj:
|
||||
if self.opts.ack:
|
||||
session.setWatermark(obj,True)
|
||||
logging.info(f"add file:{self.pendingSendFilePath} {obj._object}")
|
||||
self.pendingSendFilePath = None # succeed enqued
|
||||
else:
|
||||
logging.warning(f"fileEnqueue: {self.pendingSendFilePath} failure!")
|
||||
|
||||
def handle_norm_event(self, event:pynorm.Event):
|
||||
session:pynorm.Session = event.session
|
||||
|
||||
evtType:pynorm.EventType = event.type
|
||||
logging.info(evtType )
|
||||
if evtType in (EventType.TX_QUEUE_EMPTY, EventType.TX_QUEUE_VACANCY):
|
||||
self.addOneFile(session)
|
||||
elif evtType == EventType.GRTT_UPDATED:
|
||||
pass
|
||||
elif evtType == EventType.TX_WATERMARK_COMPLETED:
|
||||
if pynorm.AckingStatus.SUCCESS == session.getAckingStatus():
|
||||
logging.warning( "normCast: NORM_TX_WATERMARK_COMPLETED, NORM_ACK_SUCCESS");
|
||||
self.addOneFile(session)
|
||||
else:
|
||||
logging.warning( "normCast: NORM_TX_WATERMARK_COMPLETED, _NOT_ NORM_ACK_SUCCESS");
|
||||
obj = event.object
|
||||
if obj is None:
|
||||
session.resetWatermark()
|
||||
elif evtType == EventType.TX_FLUSH_COMPLETED:
|
||||
pass
|
||||
elif evtType == EventType.TX_OBJECT_PURGED:
|
||||
obj = event.object
|
||||
if obj and obj.type== pynorm.ObjectType.FILE:
|
||||
logging.info(f"normCast: send file purged: {obj.info.decode()}")
|
||||
elif evtType == EventType.TX_OBJECT_SENT:
|
||||
obj = event.object
|
||||
if obj and obj.type== pynorm.ObjectType.FILE:
|
||||
logging.info(f"initial send complete: {obj.info.decode()}")
|
||||
self.addOneFile(session)
|
||||
elif evtType == EventType.ACKING_NODE_NEW:
|
||||
|
||||
sender = event.sender
|
||||
logging.info(f"normCast: new acking node: {sender.id} IP address{sender.address}")
|
||||
elif evtType == EventType.REMOTE_SENDER_INACTIVE:
|
||||
pass
|
||||
elif evtType == EventType.RX_OBJECT_ABORTED:
|
||||
obj = event.object
|
||||
if obj and obj.type is not pynorm.ObjectType.FILE:
|
||||
logging.error("normCast: received invalid object type?!")
|
||||
return
|
||||
filePath = event.object.filename
|
||||
event.object.cancel()
|
||||
#remove temparary file if recv aborted.
|
||||
os.remove(filePath)
|
||||
logging.info("")
|
||||
|
||||
elif evtType == EventType.RX_OBJECT_INFO:
|
||||
pass
|
||||
elif evtType == EventType.RX_OBJECT_COMPLETED:
|
||||
obj = event.object
|
||||
if obj and obj.type is not pynorm.ObjectType.FILE:
|
||||
logging.error("normCast: received invalid object type?!")
|
||||
return
|
||||
file_path = event.object.info.decode()
|
||||
fileName = os.path.split(file_path)[-1]
|
||||
path = os.path.join( self.recvDir, fileName )
|
||||
oldPath = event.object.filename
|
||||
|
||||
logging.debug (f"{oldPath=}")
|
||||
try:
|
||||
if os.path.isfile(path):
|
||||
os.remove(path)
|
||||
os.rename(src=oldPath, dst=path)
|
||||
except Exception as e:
|
||||
logging.error ( traceback.format_exc() )
|
||||
|
||||
|
||||
def getAckNodesStatus(self,session):
|
||||
isSuccess, nodeID, nodeAckStatus = session.getNextAckingNode()
|
||||
while isSuccess:
|
||||
ip=ipaddress.IPv4Address(nodeID)
|
||||
if pynorm.AckingStatus.SUCCESS == nodeAckStatus:
|
||||
logging.info( f"normCast: node {nodeID} (IP address: {str(ip)}) acnkowledged.")
|
||||
else:
|
||||
logging.info( f"normCast: node {nodeID} (IP address: {str(ip)}) failed to acnkowledge.")
|
||||
isSuccess, nodeID, nodeAckStatus = session.getNextAckingNode()
|
||||
|
||||
def run(self):
|
||||
while self.is_running:
|
||||
event: Optional[pynorm.Event,bool,None] = self.instance.getNextEvent(timeout=self.opts.repeat)
|
||||
while event:
|
||||
self.handle_norm_event(event)
|
||||
event = self.instance.getNextEvent(timeout=self.opts.repeat)
|
||||
if event is None and self.opts.send:
|
||||
self.addOneFile(self.session) # means timeout
|
||||
logging.warning("normCast exits!")
|
||||
|
||||
|
||||
def main(argv):
|
||||
opts:argparse.Namespace = get_arg_options()
|
||||
instance = pynorm.Instance()
|
||||
if opts.debug:
|
||||
instance.setDebugLevel(level=pynorm.DebugLevel(opts.debug) )
|
||||
if opts.recv:
|
||||
recvPath:str = os.path.expanduser( opts.recv )
|
||||
if not os.path.isdir(recvPath): #create is not exists!
|
||||
os.makedirs( recvPath )
|
||||
instance.setCacheDirectory( recvPath )
|
||||
|
||||
normCast:NormCaster = NormCaster(instance, opts)
|
||||
if opts.send:
|
||||
normCast.addOneFile(normCast.session)
|
||||
|
||||
normCast.run()
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
sys.exit(main(sys.argv))
|
||||
|
|
@ -28,7 +28,7 @@ def main(argv):
|
|||
(opts, args) = get_option_parser().parse_args(argv)
|
||||
|
||||
if len(args) != 2:
|
||||
print get_option_parser().get_usage()
|
||||
print(get_option_parser().get_usage())
|
||||
return 1
|
||||
|
||||
path = os.path.abspath(args[1])
|
||||
|
|
@ -45,26 +45,26 @@ def main(argv):
|
|||
for event in instance:
|
||||
if event == 'NORM_RX_OBJECT_INFO':
|
||||
event.object.filename = os.path.join(path, event.object.info)
|
||||
print 'Downloading file %s' % event.object.filename
|
||||
print('Downloading file %s' % event.object.filename)
|
||||
|
||||
elif event == 'NORM_RX_OBJECT_UPDATED':
|
||||
print 'File %s - %i bytes left to download' % (
|
||||
event.object.filename, event.object.bytesPending)
|
||||
print('File %s - %i bytes left to download' % (
|
||||
event.object.filename, event.object.bytesPending))
|
||||
|
||||
elif event == 'NORM_RX_OBJECT_COMPLETED':
|
||||
print 'File %s completed' % event.object.filename
|
||||
print('File %s completed' % event.object.filename)
|
||||
return 0
|
||||
|
||||
elif event == 'NORM_RX_OBJECT_ABORTED':
|
||||
print 'File %s aborted' % event.object.filename
|
||||
print('File %s aborted' % event.object.filename)
|
||||
return 1
|
||||
|
||||
else:
|
||||
print event
|
||||
print(event)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
print 'Exiting.'
|
||||
print('Exiting.')
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from random import randint
|
|||
import pynorm
|
||||
|
||||
USAGE = 'usage: %s [options] <file>' % sys.argv[0]
|
||||
DEFAULT_ADDR = '224.1.2.3'
|
||||
DEFAULT_ADDR = u'224.1.2.3'
|
||||
DEFAULT_PORT = 6003
|
||||
|
||||
def get_option_parser():
|
||||
|
|
@ -29,7 +29,7 @@ def main(argv):
|
|||
(opts, args) = get_option_parser().parse_args(argv)
|
||||
|
||||
if len(args) != 2:
|
||||
print get_option_parser().get_usage()
|
||||
print(get_option_parser().get_usage())
|
||||
return 1
|
||||
|
||||
filepath = os.path.abspath(args[1])
|
||||
|
|
@ -40,23 +40,23 @@ def main(argv):
|
|||
session = instance.createSession(opts.address, opts.port)
|
||||
if opts.iface:
|
||||
session.setMulticastInterface(opts.iface)
|
||||
session.setTxRate(256e10)
|
||||
session.setTxRate(1.0e+06)
|
||||
session.startSender(randint(0, 1000), 1024**2, 1400, 64, 16)
|
||||
|
||||
print 'Sending file %s' % filename
|
||||
session.fileEnqueue(filepath, filename)
|
||||
print(('Sending file %s' % filename))
|
||||
session.fileEnqueue(filepath, info=filename.encode())
|
||||
|
||||
try:
|
||||
for event in instance:
|
||||
if event == 'NORM_TX_FLUSH_COMPLETED':
|
||||
print 'Flush completed, exiting.'
|
||||
print(event)
|
||||
if str(event) == 'NORM_TX_FLUSH_COMPLETED':
|
||||
print('Flush completed, exiting.')
|
||||
return 0
|
||||
else:
|
||||
print event
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
print 'Exiting.'
|
||||
print('Exiting.')
|
||||
return 0
|
||||
# end main
|
||||
|
||||
|
|
|
|||
|
|
@ -14,19 +14,19 @@ class InputThread(Thread):
|
|||
|
||||
def __init__(self, parent, *args, **kwargs):
|
||||
super(InputThread, self).__init__(*args, **kwargs)
|
||||
self.setDaemon(True) ;# this is "child" daemon thread
|
||||
self.daemon = True
|
||||
self.msgr = parent
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
try:
|
||||
msgHdr = bytearray(sys.stdin.read(MSG_HDR_SIZE))
|
||||
msgHdr = sys.stdin.buffer.read(MSG_HDR_SIZE)
|
||||
except:
|
||||
sys.stderr.write("normMsgr: input thread end-of-file 1 ...\n")
|
||||
return
|
||||
try:
|
||||
msgSize = 256*int(msgHdr[0]) + int(msgHdr[1])
|
||||
msgBuffer = sys.stdin.read(msgSize - 2)
|
||||
msgBuffer = sys.stdin.buffer.read(msgSize - 2)
|
||||
except:
|
||||
sys.stderr.write("normMsgr: input thread end-of-file 2 ...\n")
|
||||
return
|
||||
|
|
@ -37,7 +37,7 @@ class OutputThread(Thread):
|
|||
|
||||
def __init__(self, parent, *args, **kwargs):
|
||||
super(OutputThread, self).__init__(*args, **kwargs)
|
||||
self.setDaemon(True) ;# this is "child" daemon thread
|
||||
self.daemon = True
|
||||
self.msgr = parent
|
||||
|
||||
def run(self):
|
||||
|
|
@ -47,11 +47,15 @@ class OutputThread(Thread):
|
|||
msgHeader = bytearray(MSG_HDR_SIZE)
|
||||
msgHeader[0] = (msgLen >> 8) & 0x00ff
|
||||
msgHeader[1] = msgLen & 0x00ff
|
||||
sys.stdout.write(msgHeader)
|
||||
sys.stdout.write(msg)
|
||||
try:
|
||||
sys.stdout.buffer.write(msgHeader)
|
||||
sys.stdout.buffer.write(msg)
|
||||
sys.stdout.flush()
|
||||
except:
|
||||
sys.stderr.write("normMsgr: output thread exiting ...\n")
|
||||
return
|
||||
del msg
|
||||
|
||||
|
||||
class NormMsgr:
|
||||
"""This class keeps state for NORM tx/rx operations"""
|
||||
|
||||
|
|
@ -78,10 +82,12 @@ class NormMsgr:
|
|||
# Create a NormSession and set some default parameters
|
||||
self.normSession = self.normInstance.createSession(addr, port, nodeId)
|
||||
self.normSession.setRxCacheLimit(2*self.norm_tx_queue_max) ;# we let the receiver track some extra objects
|
||||
self.normSession.setDefaultSyncPolicy(pynorm.NORM_SYNC_ALL);
|
||||
self.normSession.setDefaultSyncPolicy(pynorm.SyncPolicy.ALL);
|
||||
self.normSession.setDefaultUnicastNack(True);
|
||||
self.normSession.setTxCacheBounds(10*1024*1024, self.norm_tx_queue_max, self.norm_tx_queue_max);
|
||||
self.normSession.setCongestionControl(True, True);
|
||||
self.normSession.setRxPortReuse(True)
|
||||
self.normSession.setMulticastLoopback(True)
|
||||
return self.normSession
|
||||
|
||||
def addAckingNode(self, nodeId):
|
||||
|
|
@ -203,7 +209,7 @@ class NormMsgr:
|
|||
|
||||
def onNormRxObjectCompleted(self, obj):
|
||||
with self.normRxLock:
|
||||
if pynorm.NORM_OBJECT_DATA == obj.getType():
|
||||
if pynorm.ObjectType.DATA == obj.getType():
|
||||
if 0 != len(self.output_msg_queue):
|
||||
wasEmpty = False
|
||||
else:
|
||||
|
|
@ -233,7 +239,8 @@ class NormEventHandler(Thread):
|
|||
|
||||
def __init__(self, parentMsgr, *args, **kwargs):
|
||||
super(NormEventHandler, self).__init__(*args, **kwargs)
|
||||
self.setDaemon(True) ;# this is "child" daemon thread
|
||||
#self.setDaemon(True) ;# this is "child" daemon thread (setDaemon is deprecated)
|
||||
self.daemon = True
|
||||
self.lock = Lock()
|
||||
self.msgr = parentMsgr
|
||||
|
||||
|
|
@ -248,12 +255,12 @@ class NormEventHandler(Thread):
|
|||
return
|
||||
if event is None:
|
||||
break
|
||||
if pynorm.NORM_EVENT_INVALID == event.type:
|
||||
if pynorm.EventType.EVENT_INVALID == event.type:
|
||||
continue
|
||||
elif pynorm.NORM_TX_QUEUE_EMPTY == event.type or pynorm.NORM_TX_QUEUE_VACANCY == event.type:
|
||||
elif pynorm.EventType.TX_QUEUE_EMPTY == event.type or pynorm.EventType.TX_QUEUE_VACANCY == event.type:
|
||||
msgr.onNormTxQueueVacancy()
|
||||
elif pynorm.NORM_TX_WATERMARK_COMPLETED == event.type:
|
||||
if pynorm.NORM_ACK_SUCCESS == event.session.getAckingStatus():
|
||||
elif pynorm.EventType.TX_WATERMARK_COMPLETED == event.type:
|
||||
if pynorm.EventType.ACK_SUCCESS == event.session.getAckingStatus():
|
||||
# All receivers acknowledged
|
||||
msgr.onNormTxWatermarkCompleted()
|
||||
else:
|
||||
|
|
@ -261,12 +268,12 @@ class NormEventHandler(Thread):
|
|||
# from our acking list. For now, we are infinitely
|
||||
# persistent by resetting watermark ack request
|
||||
event.session.resetWatermark()
|
||||
elif pynorm.NORM_TX_OBJECT_PURGED == event.type:
|
||||
elif pynorm.EventType.TX_OBJECT_PURGED == event.type:
|
||||
msgr.onNormTxObjectPurged(event.object)
|
||||
elif pynorm.NORM_RX_OBJECT_COMPLETED == event.type:
|
||||
elif pynorm.EventType.RX_OBJECT_COMPLETED == event.type:
|
||||
msgr.onNormRxObjectCompleted(event.object)
|
||||
#else:
|
||||
# sys.stderr.write("normMsgr: NormEventHandler warning: unhandled event: %s\n" % str(event))
|
||||
#sys.stderr.write("normMsgr: NormEventHandler warning: unhandled event: %s\n" % pynorm.EventType(event.type))
|
||||
sys.stderr.write("normMsgr: NormEventHandler thread exiting ...\n");
|
||||
self.lock.release()
|
||||
|
||||
|
|
@ -393,4 +400,9 @@ except KeyboardInterrupt:
|
|||
#sys.stderr.write("exception while waiting on input thread ..\n");
|
||||
pass
|
||||
|
||||
# TBD - shut the NormEventHandler thread down in a graceful way
|
||||
if send:
|
||||
inputThread.join()
|
||||
if recv:
|
||||
outputThread.join()
|
||||
sys.stderr.write("normMsgr: Done.\n")
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ extern "C" {
|
|||
|
||||
#define NORM_VERSION_MAJOR 1
|
||||
#define NORM_VERSION_MINOR 5
|
||||
#define NORM_VERSION_PATCH 7
|
||||
#define NORM_VERSION_PATCH 10
|
||||
|
||||
/** NORM API Types */
|
||||
typedef const void* NormInstanceHandle;
|
||||
|
|
@ -96,74 +96,65 @@ typedef __int64 NormSize;
|
|||
typedef off_t NormSize;
|
||||
#endif // WIN32
|
||||
|
||||
NORM_API_LINKAGE
|
||||
typedef enum NormObjectType
|
||||
{
|
||||
NORM_OBJECT_NONE,
|
||||
NORM_OBJECT_DATA,
|
||||
NORM_OBJECT_FILE,
|
||||
NORM_OBJECT_STREAM
|
||||
} NormObjectType;
|
||||
} NORM_API_LINKAGE NormObjectType;
|
||||
|
||||
NORM_API_LINKAGE
|
||||
typedef enum NormFlushMode
|
||||
{
|
||||
NORM_FLUSH_NONE,
|
||||
NORM_FLUSH_PASSIVE,
|
||||
NORM_FLUSH_ACTIVE
|
||||
} NormFlushMode;
|
||||
} NORM_API_LINKAGE NormFlushMode;
|
||||
|
||||
NORM_API_LINKAGE
|
||||
typedef enum NormNackingMode
|
||||
{
|
||||
NORM_NACK_NONE,
|
||||
NORM_NACK_INFO_ONLY,
|
||||
NORM_NACK_NORMAL
|
||||
} NormNackingMode;
|
||||
} NORM_API_LINKAGE NormNackingMode;
|
||||
|
||||
NORM_API_LINKAGE
|
||||
typedef enum NormAckingStatus
|
||||
{
|
||||
NORM_ACK_INVALID,
|
||||
NORM_ACK_FAILURE,
|
||||
NORM_ACK_PENDING,
|
||||
NORM_ACK_SUCCESS
|
||||
} NormAckingStatus;
|
||||
} NORM_API_LINKAGE NormAckingStatus;
|
||||
|
||||
NORM_API_LINKAGE
|
||||
typedef enum NormTrackingStatus
|
||||
{
|
||||
NORM_TRACK_NONE,
|
||||
NORM_TRACK_RECEIVERS,
|
||||
NORM_TRACK_SENDERS,
|
||||
NORM_TRACK_ALL
|
||||
} NormTrackingStatus;
|
||||
} NORM_API_LINKAGE NormTrackingStatus;
|
||||
|
||||
|
||||
NORM_API_LINKAGE
|
||||
typedef enum NormProbingMode
|
||||
{
|
||||
NORM_PROBE_NONE,
|
||||
NORM_PROBE_PASSIVE,
|
||||
NORM_PROBE_ACTIVE
|
||||
} NormProbingMode;
|
||||
} NORM_API_LINKAGE NormProbingMode;
|
||||
|
||||
NORM_API_LINKAGE
|
||||
typedef enum NormSyncPolicy
|
||||
{
|
||||
NORM_SYNC_CURRENT, // attempt to receiver current/new objects only, join mid-stream
|
||||
NORM_SYNC_STREAM, // sync to current stream, but to beginning of stream
|
||||
NORM_SYNC_ALL // attempt to receive old and new objects
|
||||
} NormSyncPolicy;
|
||||
} NORM_API_LINKAGE NormSyncPolicy;
|
||||
|
||||
NORM_API_LINKAGE
|
||||
typedef enum NormRepairBoundary
|
||||
{
|
||||
NORM_BOUNDARY_BLOCK,
|
||||
NORM_BOUNDARY_OBJECT
|
||||
} NormRepairBoundary;
|
||||
} NORM_API_LINKAGE NormRepairBoundary;
|
||||
|
||||
NORM_API_LINKAGE
|
||||
typedef enum NormEventType
|
||||
{
|
||||
NORM_EVENT_INVALID = 0,
|
||||
|
|
@ -195,7 +186,7 @@ typedef enum NormEventType
|
|||
NORM_ACKING_NODE_NEW, // whe NormSetAutoAcking
|
||||
NORM_SEND_ERROR, // ICMP error (e.g. destination unreachable)
|
||||
NORM_USER_TIMEOUT // issues when timeout set by NormSetUserTimer() expires
|
||||
} NormEventType;
|
||||
} NORM_API_LINKAGE NormEventType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
|
@ -210,7 +201,6 @@ typedef struct
|
|||
typedef char* (*NormAllocFunctionHandle)(size_t);
|
||||
typedef void (*NormFreeFunctionHandle)(char*);
|
||||
|
||||
|
||||
/** NORM API General Initialization and Operation Functions */
|
||||
|
||||
NORM_API_LINKAGE
|
||||
|
|
@ -218,9 +208,6 @@ int NormGetVersion(int* major DEFAULT((int*)0),
|
|||
int* minor DEFAULT((int*)0),
|
||||
int* patch DEFAULT((int*)0));
|
||||
|
||||
|
||||
|
||||
|
||||
NORM_API_LINKAGE
|
||||
NormInstanceHandle NormCreateInstance(bool priorityBoost DEFAULT(false));
|
||||
|
||||
|
|
@ -246,8 +233,8 @@ NORM_API_LINKAGE
|
|||
bool NormSetCacheDirectory(NormInstanceHandle instanceHandle,
|
||||
const char* cachePath);
|
||||
|
||||
// This call blocks until the next NormEvent is ready unless asynchronous
|
||||
// notification is used (see below)
|
||||
// This call blocks until the next NormEvent is ready unless
|
||||
// "waitForEvent" is set to "false"
|
||||
NORM_API_LINKAGE
|
||||
bool NormGetNextEvent(NormInstanceHandle instanceHandle, NormEvent* theEvent, bool waitForEvent DEFAULT(true));
|
||||
|
||||
|
|
@ -274,7 +261,7 @@ void NormSetAllocationFunctions(NormInstanceHandle instance,
|
|||
NormAllocFunctionHandle allocFunc,
|
||||
NormFreeFunctionHandle freeFunc);
|
||||
|
||||
/** NORM Session Creation and Control Functions */
|
||||
// NORM Session Creation and Control Functions
|
||||
|
||||
NORM_API_LINKAGE
|
||||
NormSessionHandle NormCreateSession(NormInstanceHandle instanceHandle,
|
||||
|
|
@ -338,9 +325,9 @@ bool NormPresetObjectInfo(NormSessionHandle sessionHandle, // FEC O
|
|||
UINT16 segmentSize,
|
||||
UINT16 numData,
|
||||
UINT16 numParity);
|
||||
// non-public on purpose
|
||||
//NORM_API_LINKAGE
|
||||
//void NormSetId(NormSessionHandle sessionHandle, NormNodeId normId);
|
||||
|
||||
NORM_API_LINKAGE
|
||||
void NormSetId(NormSessionHandle sessionHandle, NormNodeId normId);
|
||||
|
||||
// This does not affect the rx_socket binding if already bound (sender or receiver already started)
|
||||
// (i.e., just affects where NORM packets are sent)
|
||||
|
|
|
|||
|
|
@ -69,12 +69,12 @@ inline UINT16 NormQuantizeLoss(double lossFraction)
|
|||
lossFraction = MIN(lossFraction, 65535.0);
|
||||
return (UINT16)lossFraction;
|
||||
} // end NormQuantizeLossFraction()
|
||||
|
||||
inline double NormUnquantizeLoss(UINT16 lossQuantized)
|
||||
{
|
||||
return (((double)lossQuantized) / 65535.0);
|
||||
} // end NormUnquantizeLossFraction()
|
||||
|
||||
|
||||
// Extended precision Norm loss quantize/unquantize with
|
||||
// 32-bit precision (needed for low BER, high bandwidth*delay)
|
||||
inline UINT32 NormQuantizeLoss32(double lossFraction)
|
||||
|
|
@ -195,13 +195,11 @@ class NormObjectId
|
|||
UINT16 diff = value - id.value;
|
||||
return ((diff > 0x8000) || ((0x8000 == diff) && (value > id.value)));
|
||||
}
|
||||
|
||||
bool operator>(const NormObjectId& id) const
|
||||
{
|
||||
UINT16 diff = id.value - value;
|
||||
return ((diff > 0x8000) || ((0x8000 == diff) && (id.value > value)));
|
||||
}
|
||||
|
||||
bool operator<=(const NormObjectId& id) const
|
||||
{return ((value == id.value) || (*this < id));}
|
||||
bool operator>=(const NormObjectId& id) const
|
||||
|
|
@ -936,10 +934,10 @@ class NormFtiExtension5 : public NormHeaderExtension
|
|||
enum
|
||||
{
|
||||
OBJ_SIZE_MSB_OFFSET = (CONTENT_OFFSET)/2, // UINT16 offset
|
||||
OBJ_SIZE_LSB_OFFSET = ((OBJ_SIZE_MSB_OFFSET*2)+2)/4,
|
||||
SEG_SIZE_OFFSET = ((OBJ_SIZE_LSB_OFFSET*4)+4)/2,
|
||||
FEC_NDATA_OFFSET = ((SEG_SIZE_OFFSET+1)*2),
|
||||
FEC_NPARITY_OFFSET = (FEC_NDATA_OFFSET+1)
|
||||
OBJ_SIZE_LSB_OFFSET = ((OBJ_SIZE_MSB_OFFSET*2)+2)/4,// UINT32 offset
|
||||
SEG_SIZE_OFFSET = ((OBJ_SIZE_LSB_OFFSET*4)+4)/2, // UINT16 offset
|
||||
FEC_NDATA_OFFSET = ((SEG_SIZE_OFFSET+1)*2), // UINT8 offset
|
||||
FEC_NPARITY_OFFSET = (FEC_NDATA_OFFSET+1) // UINT8 offset
|
||||
};
|
||||
}; // end class NormFtiExtension5
|
||||
|
||||
|
|
@ -1803,7 +1801,7 @@ class NormCCFeedbackExtension : public NormHeaderExtension
|
|||
CC_LOSS_OFFSET = (CC_RTT_OFFSET + 1)/2,
|
||||
CC_RATE_OFFSET = ((CC_LOSS_OFFSET*2)+2)/2,
|
||||
//CC_RESERVED_OFFSET = ((CC_RATE_OFFSET*2)+2)/2
|
||||
CC_LOSS_EX_OFFSET = ((CC_RATE_OFFSET*2)+2)/2 // extended precision loss estimate (non-RFC5940 compliant, but compatible)
|
||||
CC_LOSS_EX_OFFSET = ((CC_RATE_OFFSET*2)+2)/2 // extended precision loss estimate (non-RFC5740 compliant, but compatible)
|
||||
};
|
||||
|
||||
}; // end class NormCCFeedbackExtension
|
||||
|
|
|
|||
|
|
@ -188,6 +188,28 @@ class NormLossEstimator2
|
|||
|
||||
}; // end class NormLossEstimator2
|
||||
|
||||
class NormCongestionDetector
|
||||
{
|
||||
// This class implements a delay-based congestion indicator
|
||||
// based on feedback from NORM receivers. Similar to loss-based
|
||||
// congestion detection, this detector monitors the history of
|
||||
// RTT measurement
|
||||
|
||||
// NOTES:
|
||||
// 1) One challenge to consider is reverse path contribution
|
||||
// to RTT may create "false positives" on RTT change detection.
|
||||
// A technique to mitigate is to use reference timing that the
|
||||
// receiver can establish on expected sender packet arrivals
|
||||
// given rate information to helps separate sender->receiver
|
||||
// contribution to RTT versus the reverse path receiver->sender
|
||||
// aspect. E.g., the receiver could compare the stats of arriving
|
||||
// sender packets in reference to advertised rate to have an indication
|
||||
// of increasing (or decreasing) sender->receiver latency.
|
||||
//
|
||||
// 2)
|
||||
//
|
||||
}; // end class NormCongestionDetector
|
||||
|
||||
class NormAckingNode : public NormNode
|
||||
{
|
||||
public:
|
||||
|
|
@ -556,7 +578,7 @@ class NormSenderNode : public NormNode, public ProtoTree::Item
|
|||
|
||||
UINT8 GetGrttQuantized() const
|
||||
{return grtt_quantized;}
|
||||
UINT8 GetBackoffFactor() const
|
||||
double GetBackoffFactor() const
|
||||
{return backoff_factor;}
|
||||
UINT8 GetGroupSizeQuantized() const
|
||||
{return gsize_quantized;}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class NormObject
|
|||
|
||||
enum CheckLevel
|
||||
{
|
||||
BLIND_CHECK,
|
||||
TO_OBJECT,
|
||||
THRU_INFO,
|
||||
TO_BLOCK,
|
||||
|
|
@ -360,6 +361,7 @@ class NormFileObject : public NormObject
|
|||
const char* infoPtr = NULL,
|
||||
UINT16 infoLen = 0);
|
||||
bool Accept(const char* thePath);
|
||||
void CloseFile();
|
||||
void Close();
|
||||
|
||||
const char* GetPath() {return path;}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,6 @@
|
|||
|
||||
#ifndef _NORM_VERSION
|
||||
#define _NORM_VERSION
|
||||
#define VERSION "1.5.9"
|
||||
#define VERSION "1.5.10"
|
||||
#endif // _NORM_VERSION
|
||||
|
||||
|
|
|
|||
|
|
@ -188,7 +188,8 @@ normStreamer: $(STREAMER_OBJ) libnorm.a $(LIBPROTO)
|
|||
cp $@ ../bin/$@
|
||||
|
||||
# (normCast) file sender/receiver
|
||||
CAST_SRC = $(EXAMPLE)/normCast.cpp
|
||||
CAST_SRC = $(EXAMPLE)/normCast.cpp $(COMMON)/normPostProcess.cpp \
|
||||
$(UNIX)/unixPostProcess.cpp
|
||||
CAST_OBJ = $(CAST_SRC:.cpp=.o)
|
||||
|
||||
normCast: $(CAST_OBJ) libnorm.a $(LIBPROTO)
|
||||
|
|
@ -196,6 +197,26 @@ normCast: $(CAST_OBJ) libnorm.a $(LIBPROTO)
|
|||
mkdir -p ../bin
|
||||
cp $@ ../bin/$@
|
||||
|
||||
# (normCastApp) file sender/receiver
|
||||
CASTAPP_SRC = $(EXAMPLE)/normCastApp.cpp $(COMMON)/normPostProcess.cpp \
|
||||
$(UNIX)/unixPostProcess.cpp
|
||||
CASTAPP_OBJ = $(CASTAPP_SRC:.cpp=.o)
|
||||
|
||||
normCastApp: $(CASTAPP_OBJ) libnorm.a $(LIBPROTO)
|
||||
$(CC) $(CFLAGS) -o $@ $(CASTAPP_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS)
|
||||
mkdir -p ../bin
|
||||
cp $@ ../bin/$@
|
||||
|
||||
# (chant) NORM command-line chat sender/receiver
|
||||
CHANT_SRC = $(EXAMPLE)/chant.cpp
|
||||
CHANT_OBJ = $(CHANT_SRC:.cpp=.o)
|
||||
|
||||
chant: $(CHANT_OBJ) libnorm.a $(LIBPROTO)
|
||||
$(CC) $(CFLAGS) -o $@ $(CHANT_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS)
|
||||
mkdir -p ../bin
|
||||
cp $@ ../bin/$@
|
||||
|
||||
|
||||
# These are the new "NormSocket" API extension examples
|
||||
SERVER_SRC = $(EXAMPLE)/normServer.cpp $(EXAMPLE)/normSocket.cpp
|
||||
SERVER_OBJ = $(SERVER_SRC:.cpp=.o)
|
||||
|
|
|
|||
|
|
@ -44,8 +44,10 @@ SYSTEM_SRC = ../protolib/src/unix/bpfCap.cpp
|
|||
# The "SYSTEM" keyword can be used for dependent makes
|
||||
SYSTEM = macosx
|
||||
|
||||
# TBD - provide means to build universal Mac OSX library (x86/arm64)
|
||||
|
||||
CC = g++
|
||||
SYSTEM_CFLAGS = -Wall -Wcast-align -fPIC -arch x86_64
|
||||
SYSTEM_CFLAGS = -Wall -Wcast-align -fPIC
|
||||
SYSTEM_SOFLAGS = -dynamiclib
|
||||
SYSTEM_SOEXT = dylib
|
||||
RANLIB = ranlib
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue