git subtree add --squash -P external/nng https://github.com/nanomsg/nng.git v1.8.0

Merge commit '7063e2102e655079574d6644b323f28f48685c5a' as 'external/nng'
This commit is contained in:
oxmox 2024-12-18 18:29:29 +01:00
commit b3f1d5611f
774 changed files with 131758 additions and 0 deletions

16
external/nng/.clang-format vendored Normal file
View file

@ -0,0 +1,16 @@
BasedOnStyle: WebKit
UseTab: ForIndentation
IndentWidth: 8
ColumnLimit: 79
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignTrailingComments: true
AlignEscapedNewlines: Left
PointerAlignment: Right
DerivePointerAlignment: false
ForEachMacros: ['NNI_LIST_FOREACH']
AlwaysBreakAfterReturnType: TopLevelDefinitions
SpaceAfterCStyleCast: true
AllowShortFunctionsOnASingleLine: Inline
BreakBeforeBinaryOperators: None
TabWidth: 8

7
external/nng/.codecov.yml vendored Normal file
View file

@ -0,0 +1,7 @@
ignore:
- "tests"
- "src/testing"
- "perf"
- "**/*_test.c"
coverage:
range: 50..95

2
external/nng/.gitattributes vendored Normal file
View file

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

5
external/nng/.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,5 @@
# These are supported funding model platforms
github: gdamore
patreon: gedamore
custom: [ "https://staysail.tech/support/" ]
custom: [ "https://leanpub.com/nngref2e" ]

View file

@ -0,0 +1,30 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Actual Behavior**
Describe what occurred.
**To Reproduce**
If possible include actual reproduction test code here.
Minimal C test cases are perferred.
** Environment Details **
- NNG version
- Operating system and version
- Compiler and language used
- Shared or static library
**Additional context**
Add any other context about the problem here.

View file

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View file

@ -0,0 +1,7 @@
fixes #<issue number> <issue synopsis>
<Comments describing your change. Not all changes need this.>
Note that the above format should be used in your git commit comments.
You agree that by submitting a PR, you have read and agreed to our
contributing guidelines.

View file

@ -0,0 +1,72 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '27 2 * * 2'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View file

@ -0,0 +1,65 @@
name: coverage
on: [push]
jobs:
linux-coverage:
name: linux
runs-on: [ ubuntu-latest ]
steps:
- name: Check out code
uses: actions/checkout@v1
- name: Install mbedTLS
run: sudo apt-get install libmbedtls-dev
- name: Install ninja
run: sudo apt-get install ninja-build
- name: Configure
run: mkdir build && cd build && cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DNNG_ENABLE_COVERAGE=ON -DNNG_ENABLE_TLS=ON ..
- name: build
run: cd build && ninja
- name: Test
run: cd build && ctest --output-on-failure
- name: Upload report
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
yml: ./.codecov.yml
darwin-coverage:
name: darwin
runs-on: [ macos-latest ]
steps:
- name: Check out code
uses: actions/checkout@v1
- name: Install mbedTLS
run: brew install mbedtls
- name: Install ninja
run: brew install ninja
- name: Install lcov
run: brew install lcov
- name: Configure
run: mkdir build && cd build && cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DNNG_ENABLE_COVERAGE=ON -DNNG_ENABLE_TLS=ON ..
- name: build
run: cd build && ninja
- name: Test
run: cd build && ctest --output-on-failure
- name: Preprocess
run: cd build && lcov -c -d . -o lcov.info
- name: Upload report
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
yml: ./.codecov.yml

View file

@ -0,0 +1,24 @@
name: darwin
on: [push, pull_request]
jobs:
build:
name: build
runs-on: [macos-latest]
steps:
- name: Check out code
uses: actions/checkout@v1
- name: Install Mbed TLS
run: brew install mbedtls
- name: Install ninja
run: brew install ninja
- name: Configure
run: mkdir build && cd build && cmake -G Ninja -DNNG_ENABLE_TLS=ON ..
- name: build
run: cd build && ninja
- name: Test
run: cd build && ctest --output-on-failure

View file

@ -0,0 +1,25 @@
name: linux
on: [push, pull_request]
jobs:
build:
name: build
runs-on: [ ubuntu-latest ]
steps:
- name: Check out code
uses: actions/checkout@v1
- name: Install mbedTLS
run: sudo apt-get install libmbedtls-dev
- name: Install ninja
run: sudo apt-get install ninja-build
- name: Configure
run: mkdir build && cd build && cmake -G Ninja -D NNG_ENABLE_TLS=ON ..
- name: Build
run: cd build && ninja
- name: Test
run: cd build && ctest --output-on-failure

View file

@ -0,0 +1,36 @@
name: sanitize
on: [push, pull_request]
jobs:
sanitize:
env:
CC: clang
CXX: clang++
CTEST_OUTPUT_ON_FAILURE: 1
runs-on: ${{ matrix.os }}
strategy:
matrix:
sanitizer: [ address, undefined, thread ]
os: [ ubuntu-latest ]
steps:
- uses: actions/checkout@v1
- name: Install mbedTLS
run: sudo apt-get install libmbedtls-dev
- name: Install ninja
run: sudo apt-get install ninja-build
- name: Configure
run: |
mkdir build
cd build
cmake -G Ninja -DNNG_SANITIZER=${{ matrix.sanitizer }} -DCMAKE_BUILD_TYPE=Debug -DNNG_ENABLE_TLS=ON -DNNG_TOOLS=OFF ..
- name: Build
run: |
cd build
ninja
- name: Test
run: |
cd build
ninja test

View file

@ -0,0 +1,29 @@
name: windows
on: [push, pull_request]
jobs:
build:
name: build
runs-on: [windows-latest]
steps:
- name: Check out code
uses: actions/checkout@v1
- name: vcpkg build
id: vcpkg
uses: johnwason/vcpkg-action@v6
with:
pkgs: mbedtls
triplet: x64-windows
token: ${{ github.token }}
github-binarycache: true
- name: Configure
run: cmake ${{ steps.vcpkg.outputs.vcpkg-cmake-config }} -D NNG_ENABLE_TLS=ON -B build
- name: Build
run: cmake --build build
- name: Test
run: |
cd build
ctest -C Debug --output-on-failure

13
external/nng/.gitignore vendored Normal file
View file

@ -0,0 +1,13 @@
build
lxbuild
winbuild
wbuild
.cache
.vs
.vscode/.cmaketools.json
.vscode
.idea
.DS_Store
etc/nng.sublime-workspace
cmake-build-*
docs/**/*.html

3
external/nng/.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "extern/nng-wolfssl"]
path = extern/nng-wolfssl
url = https://github.com/staysail/nng-wolfssl

5
external/nng/.grcov.yml vendored Normal file
View file

@ -0,0 +1,5 @@
branch: true
ignore-not-existing: true
filter: covered
output-type: lcov
output-file: lcov.info

312
external/nng/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,312 @@
#
# Copyright 2024 Staysail Systems, Inc. <info@staysail.tech>
# Copyright (c) 2012 Martin Sustrik All rights reserved.
# Copyright (c) 2013 GoPivotal, Inc. All rights reserved.
# Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved.
# Copyright 2016 Franklin "Snaipe" Mathieu <franklinmathieu@gmail.com>
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom
# the Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
cmake_minimum_required(VERSION 3.13)
project(nng C)
include(CheckCCompilerFlag)
include(GNUInstallDirs)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
include(NNGHelpers)
include(NNGOptions)
set(CMAKE_C_STANDARD 99)
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" isSystemDir)
if ("${isSystemDir}" STREQUAL "-1")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif ("${isSystemDir}" STREQUAL "-1")
set(NNG_DESCRIPTION "High-Performance Scalability Protocols NextGen")
set(ISSUE_REPORT_MSG "Please consider opening an issue at https://github.com/nanomsg/nng")
# Determine library versions.
file(READ "include/nng/nng.h" nng_ver_h)
string(REGEX MATCH "NNG_MAJOR_VERSION ([0-9]*)" _ ${nng_ver_h})
set(NNG_MAJOR_VERSION ${CMAKE_MATCH_1})
string(REGEX MATCH "NNG_MINOR_VERSION ([0-9]*)" _ ${nng_ver_h})
set(NNG_MINOR_VERSION ${CMAKE_MATCH_1})
string(REGEX MATCH "NNG_PATCH_VERSION ([0-9]*)" _ ${nng_ver_h})
set(NNG_PATCH_VERSION ${CMAKE_MATCH_1})
string(REGEX MATCH "NNG_RELEASE_SUFFIX \"([a-z0-9]*)\"" _ ${nng_ver_h})
if (NOT ("${CMAKE_MATCH_1}" STREQUAL ""))
set(NNG_PRERELEASE "-${CMAKE_MATCH_1}")
endif ()
set(NNG_ABI_SOVERSION 1)
set(NNG_ABI_VERSION "${NNG_MAJOR_VERSION}.${NNG_MINOR_VERSION}.${NNG_PATCH_VERSION}${NNG_PRERELEASE}")
set(NNG_PACKAGE_VERSION "${NNG_ABI_VERSION}")
message(STATUS "Configuring for NNG version ${NNG_ABI_VERSION}")
# User-defined options.
# This prefix is appended to by subdirectories, so that each test
# gets named based on where it is in the tree.
set(NNG_TEST_PREFIX nng)
# Enable access to private APIs for our own use.
add_definitions(-DNNG_PRIVATE)
if (NOT (BUILD_SHARED_LIBS))
set(NNG_STATIC_LIB ON)
message(STATUS "Building static libs.")
endif ()
# These are library targets. The "nng" library is the main public library.
# The "nng_testing" is a full build of the library for test cases
# only, which is done statically and includes even portions of the code
# that are not part of the public library (things that may have been elided.)
# The "nng_private" library is an interface that allows some internal tools
# to obtain details about how the public library was built, so that we can
# include or not include code based on what's actually present.
add_library(nng)
add_library(nng_testing STATIC EXCLUDE_FROM_ALL)
target_compile_definitions(nng_testing PUBLIC NNG_STATIC_LIB NNG_TEST_LIB NNG_PRIVATE)
add_library(nng_private INTERFACE)
target_compile_definitions(nng_private INTERFACE NNG_PRIVATE)
if (NNG_ELIDE_DEPRECATED)
target_compile_definitions(nng PRIVATE NNG_ELIDE_DEPRECATED)
endif()
if (NNG_ENABLE_COMPAT)
target_compile_definitions(nng PRIVATE NNG_ENABLE_COMPAT)
endif()
# We can use rlimit to configure the stack size for systems
# that have too small defaults. This is not used for Windows,
# which can grow thread stacks sensibly. (Note that NNG can get
# by with a smallish stack, but application callbacks might require
# larger values if using aio completion callbacks. TLS libraries may
# require larger stacks however.)
if (NOT WIN32)
option(NNG_SETSTACKSIZE "Use rlimit for thread stack size" OFF)
if (NNG_SETSTACKSIZE)
add_definitions(-DNNG_SETSTACKSIZE)
endif ()
mark_as_advanced(NNG_SETSTACKSIZE)
endif ()
nng_defines_if(NNG_ENABLE_STATS NNG_ENABLE_STATS)
# IPv6 enable
nng_defines_if(NNG_ENABLE_IPV6 NNG_ENABLE_IPV6)
set(NNG_RESOLV_CONCURRENCY 4 CACHE STRING "Resolver (DNS) concurrency.")
mark_as_advanced(NNG_RESOLV_CONCURRENCY)
if (NNG_RESOLV_CONCURRENCY)
add_definitions(-DNNG_RESOLV_CONCURRENCY=${NNG_RESOLV_CONCURRENCY})
endif ()
set(NNG_NUM_TASKQ_THREADS 0 CACHE STRING "Fixed number of task threads, 0 for automatic")
mark_as_advanced(NNG_NUM_TASKQ_THREADS)
if (NNG_NUM_TASKQ_THREADS)
add_definitions(-DNNG_NUM_TASKQ_THREADS=${NNG_NUM_TASKQ_THREADS})
endif ()
set(NNG_MAX_TASKQ_THREADS 16 CACHE STRING "Upper bound on task threads, 0 for no limit")
mark_as_advanced(NNG_MAX_TASKQ_THREADS)
if (NNG_MAX_TASKQ_THREADS)
add_definitions(-DNNG_MAX_TASKQ_THREADS=${NNG_MAX_TASKQ_THREADS})
endif ()
# Expire threads. This runs the timeout handling, and having more of them
# reduces contention on the common locks used for aio expiration.
set(NNG_NUM_EXPIRE_THREADS 0 CACHE STRING "Fixed number of expire threads, 0 for automatic")
mark_as_advanced(NNG_NUM_EXPIRE_THREADS)
if (NNG_NUM_EXPIRE_THREADS)
add_definitions(-DNNG_NUM_EXPIRE_THREADS=${NNG_NUM_EXPIRE_THREADS})
endif ()
set(NNG_MAX_EXPIRE_THREADS 8 CACHE STRING "Upper bound on expire threads, 0 for no limit")
mark_as_advanced(NNG_MAX_EXPIRE_THREADS)
if (NNG_MAX_EXPIRE_THREADS)
add_definitions(-DNNG_MAX_EXPIRE_THREADS=${NNG_MAX_EXPIRE_THREADS})
endif()
# Poller threads. These threads run the pollers. This is mostly used
# on Windows right now, as the POSIX platforms use a single threaded poller.
set(NNG_NUM_POLLER_THREADS 0 CACHE STRING "Fixed number of I/O poller threads, 0 for automatic")
if (NNG_NUM_POLLER_THREADS)
add_definitions(-DNNG_NUM_POLLER_THREADS=${NNG_NUM_POLLER_THREADS})
endif ()
mark_as_advanced(NNG_NUM_POLLER_THREADS)
set(NNG_MAX_POLLER_THREADS 8 CACHE STRING "Upper bound on I/O poller threads, 0 for no limit")
mark_as_advanced(NNG_MAX_POLLER_THREADS)
if (NNG_MAX_POLLER_THREADS)
add_definitions(-DNNG_MAX_POLLER_THREADS=${NNG_MAX_POLLER_THREADS})
endif()
# Platform checks.
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
set(NNG_WARN_FLAGS "-Wall -Wextra -fno-omit-frame-pointer")
elseif (CMAKE_C_COMPILER_ID MATCHES "Clang")
set(NNG_WARN_FLAGS "-Wall -Wextra -fno-omit-frame-pointer")
endif ()
include(CheckSanitizer)
CheckSanitizer()
if (NOT NNG_SANITIZER STREQUAL "none")
set(NNG_SANITIZER_FLAGS "-fsanitize=${NNG_SANITIZER}")
endif ()
if (NNG_ENABLE_COVERAGE)
# NB: This only works for GCC and Clang 3.0 and newer. If your stuff
# is older than that, you will need to find something newer. For
# correct reporting, we always turn off all optimizations.
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
set(NNG_COVERAGE_C_FLAGS "-g -O0 --coverage")
set(CMAKE_SHARED_LINKER_FLAGS --coverage)
elseif (CMAKE_C_COMPILER_ID MATCHES "Clang")
set(NNG_COVERAGE_C_FLAGS "-g -O0 --coverage")
set(CMAKE_SHARED_LINKER_FLAGS --coverage)
else ()
message(FATAL_ERROR "Unable to enable coverage for your compiler.")
endif ()
endif ()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${NNG_WARN_FLAGS} ${NNG_COVERAGE_C_FLAGS} ${NNG_SANITIZER_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${NNG_WARN_FLAGS} ${NNG_COVERAGE_C_FLAGS} ${NNG_SANITIZER_FLAGS}")
# If the compiler is not on Windows, does it support hiding the
# symbols by default? For shared libraries we would like to do this.
if (NOT WIN32 AND NOT CYGWIN)
check_c_compiler_flag(-fvisibility=hidden NNG_HIDDEN_VISIBILITY)
if (NNG_HIDDEN_VISIBILITY)
add_definitions(-DNNG_HIDDEN_VISIBILITY)
endif ()
endif ()
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
add_definitions(-DNNG_PLATFORM_POSIX)
add_definitions(-DNNG_PLATFORM_LINUX)
add_definitions(-DNNG_USE_EVENTFD)
add_definitions(-DNNG_HAVE_ABSTRACT_SOCKETS)
# Windows subsystem for Linux -- smells like Linux, but it has
# some differences (SO_REUSEADDR for one).
if (CMAKE_SYSTEM_VERSION MATCHES "Microsoft")
add_definitions(-DNNG_PLATFORM_WSL)
endif ()
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "Android")
add_definitions(-DNNG_PLATFORM_POSIX)
add_definitions(-DNNG_PLATFORM_LINUX)
add_definitions(-DNNG_PLATFORM_ANDROID)
add_definitions(-DNNG_USE_EVENTFD)
set(NNG_PLATFORM_POSIX ON)
elseif (APPLE)
add_definitions(-DNNG_PLATFORM_POSIX)
add_definitions(-DNNG_PLATFORM_DARWIN)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
add_definitions(-DNNG_PLATFORM_POSIX)
add_definitions(-DNNG_PLATFORM_FREEBSD)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
add_definitions(-DNNG_PLATFORM_POSIX)
add_definitions(-DNNG_PLATFORM_NETBSD)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
add_definitions(-DNNG_PLATFORM_POSIX)
add_definitions(-DNNG_PLATFORM_OPENBSD)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "SunOS")
add_definitions(-DNNG_PLATFORM_POSIX)
add_definitions(-DNNG_PLATFORM_SUNOS)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
add_definitions(-DNNG_PLATFORM_WINDOWS)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-D_CRT_RAND_S)
set(NNG_PLATFORM_WINDOWS ON)
# Target Windows Vista and later
add_definitions(-D_WIN32_WINNT=0x0600)
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_WIN32_WINNT=0x0600)
elseif (CMAKE_SYSTEM_NAME MATCHES "QNX")
add_definitions(-DNNG_PLATFORM_POSIX)
add_definitions(-D__EXT_BSD)
add_definitions(-D_QNX_SOURCE)
add_definitions(-DNNG_PLATFORM_QNX)
set(NNG_PLATFORM_POSIX ON)
else ()
message(AUTHOR_WARNING "WARNING: This platform may not be supported: ${CMAKE_SYSTEM_NAME}")
message(AUTHOR_WARNING "${ISSUE_REPORT_MSG}")
# blithely hope for POSIX to work
add_definitions(-DNNG_PLATFORM_POSIX)
set(NNG_PLATFORM_POSIX ON)
endif ()
if (NNG_ENABLE_TLS)
add_definitions(-DNNG_SUPP_TLS)
endif ()
if (NNG_TESTS)
enable_testing()
set(all_tests, "")
endif ()
add_subdirectory(src)
if (NNG_TESTS)
add_subdirectory(tests)
endif ()
# Build the tools
add_subdirectory(docs/man)
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
set(CPACK_PACKAGE_VERSION ${NNG_PACKAGE_VERSION})
set(CPACK_PACKAGE_CONTACT "nanomsg@freelists.org")
set(CPACK_PACKAGE_VENDOR "nanomsg.org")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "nanomsg next generation library")
set(CPACK_SOURCE_GENERATOR "TBZ2;TGZ;ZIP")
set(CPACK_SOURCE_IGNORE_FILES "/build/;/.git/;~$;${CPACK_SOURCE_IGNORE_FILES}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME
"${PROJECT_NAME}-v${NNG_PACKAGE_VERSION}-src")
set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt)
set(CPACK_PACKAGE_INSTALL_DIRECTORY "nng")
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-v${NNG_PACKAGE_VERSION}")
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
include(CPack)

74
external/nng/CODE_OF_CONDUCT.adoc vendored Normal file
View file

@ -0,0 +1,74 @@
= NNG Code of Conduct
== Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of
experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
== Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
== Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
== Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
== Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at garrett@damore.org. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an
incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
== Attribution
This Code of Conduct is adapted from the
https://www.contributor-convent.org[Contributor Covenant], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

22
external/nng/LICENSE.txt vendored Normal file
View file

@ -0,0 +1,22 @@
The MIT License
Copyright 2021 Staysail Systems, Inc. <info@staysail.tech>
Copyright 2018 Capitar IT Group BV <info@capitar.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

180
external/nng/README.adoc vendored Normal file
View file

@ -0,0 +1,180 @@
ifdef::env-github[]
:note-caption: :information_source:
:important-caption: :heavy_exclamation_mark:
endif::[]
= nng - nanomsg-next-gen
// Note: This README is optimized for display with Asciidoctor, or
// on the GitHub project page at https://github.com/nanomsg/nng.
image:https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg[Stand With Ukraine,link="https://stand-with-ukraine.pp.ua"]
image:https://img.shields.io/github/actions/workflow/status/nanomsg/nng/linux.yml?branch=master&logoColor=grey&logo=ubuntu&label=[Linux Status,link="https://github.com/nanomsg/nng/actions"]
image:https://img.shields.io/github/actions/workflow/status/nanomsg/nng/windows.yml?branch=master&logoColor=grey&logo=windows&label=[Windows Status,link="https://github.com/nanomsg/nng/actions"]
image:https://img.shields.io/github/actions/workflow/status/nanomsg/nng/darwin.yml?branch=master&logoColor=grey&logo=apple&label=[macOS Status,link="https://github.com/nanomsg/nng/actions"]
image:https://img.shields.io/codecov/c/github/nanomsg/nng?logo=codecov&logoColor=grey&label=[Coverage,link="https://codecov.io/gh/nanomsg/nng"]
image:https://img.shields.io/discord/639573728212156478?label=&logo=discord[Discord,link="https://discord.gg/Xnac6b9"]
image:https://img.shields.io/static/v1?label=&message=docs&logo=asciidoctor&logoColor=silver&color=blue[Manual,link="https://nng.nanomsg.org/man"]
image:https://img.shields.io/github/license/nanomsg/nng.svg?logoColor=silver&logo=open-source-initiative&label=&color=blue[MIT License,link="https://github.com/nanomsg/nng/blob/master/LICENSE.txt"]
image:https://img.shields.io/github/v/tag/nanomsg/nng.svg?logo=github&label=[Latest version,link="https://github.com/nanomsg/nng/releases"]
Please see <<UKRAINE#,here>> for an important message for the people of Russia.
NOTE: If you are looking for the legacy version of nanomsg, please
see the https://github.com/nanomsg/nanomsg[nanomsg] repository.
This project is a rewrite of the Scalability Protocols
library known as https://github.com/nanomsg/nanomsg[libnanomsg],
and adds significant new capabilities, while retaining
compatibility with the original.
It may help to think of this as "nanomsg-next-generation".
== NNG: Lightweight Messaging Library
NNG, like its predecessors http://nanomsg.org[nanomsg] (and to some extent
http://zeromq.org/[ZeroMQ]), is a lightweight, broker-less library,
offering a simple API to solve common recurring messaging problems,
such as publish/subscribe, RPC-style request/reply, or service discovery.
The API frees the programmer from worrying about details like connection
management, retries, and other common considerations, so that they
can focus on the application instead of the plumbing.
NNG is implemented in C, requiring only C99 and CMake to build.
It can be built as a shared or a static library, and is readily
embeddable. It is also designed to be easy to port to new platforms
if your platform is not already supported.
== License
NNG is licensed under a liberal, and commercial friendly, MIT license.
The goal to the license is to minimize friction in adoption, use, and
contribution.
== Enhancements (Relative to nanomsg)
Here are areas where this project improves on "nanomsg":
[horizontal]
*Reliability*:: NNG is designed for production use from the beginning. Every
error case is considered, and it is designed to avoid crashing except in cases
of gross developer error. (Hopefully we don't have any of these in our own
code.)
*Scalability*:: NNG scales out to engage multiple cores using a bespoke
asynchronous I/O framework, using thread pools to spread load without
exceeding typical system limits.
*Maintainability*:: NNG's architecture is designed to be modular and
easily grasped by developers unfamiliar with the code base. The code
is also well documented.
*Extensibility*:: Because it avoids ties to file descriptors, and avoids
confusing interlocking state machines, it is easier to add new protocols
and transports to NNG. This was demonstrated by the addition of the
TLS and ZeroTier transports.
*Security*:: NNG provides TLS 1.2 and ZeroTier transports, offering
support for robust and industry standard authentication and encryption.
In addition, it is hardened to be resilient against malicious attackers,
with special consideration given to use in a hostile Internet.
*Usability*:: NNG eschews slavish adherence parts of the more complex and
less well understood POSIX APIs, while adopting the semantics that are
familiar and useful. New APIs are intuitive, and the optional support
for separating protocol context and state from sockets makes creating
concurrent applications vastly simpler than previously possible.
== Compatibility
This project offers both wire compatibility and API compatibility,
so most nanomsg users can begin using NNG right away.
Existing nanomsg and https://github.com/nanomsg/mangos[mangos] applications
can inter-operate with NNG applications automatically.
That said, there are some areas where legacy nanomsg still offers
capabilities NNG lacks -- specifically enhanced observability with
statistics, and tunable prioritization of different destinations
are missing, but will be added in a future release.
Additionally, some API capabilities that are useful for foreign
language bindings are not implemented yet.
Some simple single threaded, synchronous applications may perform better under
legacy nanomsg than under NNG. (We believe that these applications are the
least commonly deployed, and least interesting from a performance perspective.
NNG's internal design is slightly less efficient in such scenarios, but it
greatly benefits when concurrency or when multiple sockets or network peers
are involved.)
== Supported Platforms
NNG supports Linux, macOS, Windows (Vista or better), illumos, Solaris,
FreeBSD, Android, and iOS. Most other POSIX platforms should work out of
the box but have not been tested. Very old versions of otherwise supported
platforms might not work.
== Requirements
To build this project, you will need a C99 compatible compiler and
http://www.cmake.org[CMake] version 3.13 or newer.
We recommend using the https://ninja-build.org[Ninja] build
system (pass "-G Ninja" to CMake) when you can.
(And not just because Ninja sounds like "NNG" -- it's also
blindingly fast and has made our lives as developers measurably better.)
If you want to build with TLS support you will also need
https://tls.mbed.org[Mbed TLS]. See <<docs/BUILD_TLS.adoc#>> for details.
== Quick Start
With a Linux or UNIX environment:
[source,sh]
----
$ mkdir build
$ cd build
$ cmake -G Ninja ..
$ ninja
$ ninja test
$ ninja install
----
== API Documentation
The API documentation is provided in Asciidoc format in the
`docs/man` subdirectory, and also
https://nanomsg.github.io/nng[online].
The <<docs/man/nng.7.adoc#,nng(7)>> page provides a conceptual overview and links to
manuals for various patterns.
The <<docs/man/libnng.3.adoc#,libnng(3)>> page is a good starting point for the API reference.
You can also purchase a copy of the
http://staysail.tech/books/nng_reference/index.html[__NNG Reference Manual__].
(It is published in both electronic and printed formats.)
Purchases of the book help fund continued development of NNG.
== Example Programs
Some demonstration programs have been created to help serve as examples.
These are located in the `demo` directory.
== Legacy Compatibility
A legacy `libnanomsg` compatible API is available, and while it offers
less capability than the modern NNG API, it may serve as a transition aid.
Please see <<docs/man/nng_compat.3compat.adoc#,nng_compat(3)>> for details.
== Commercial Support
Commercial support for NNG is available.
Please contact mailto:info@staysail.tech[Staysail Systems, Inc.] to
inquire further.
== Commercial Sponsors
The development of NNG has been made possible through the generous
sponsorship of https://www.capitar.com[Capitar IT Group BV] and
http://staysail.tech[Staysail Systems, Inc.].

115
external/nng/RELEASE_NOTES.adoc vendored Normal file
View file

@ -0,0 +1,115 @@
ifdef::env-github[]
:note-caption: :information_source:
:important-caption: :heavy_exclamation_mark:
endif::[]
= RELEASE NOTES FOR NNG v1.7.0
This document has the following sections:
* Notable Changes
* End of Feature Announcements
== Notable Changes (since 1.6.0)
A new compile time setting, `NNG_MAX_POLLER_THREADS` is introduced,
with a default value of 8, and will limit the number of threads
used for pollers that are concurrent (currently only Windows).
Additionally, for single core systems only two threads will be started
instead of four.
A new supplemental API, nng_id_map(3), is made available.
This exposes the internal ID hash API NNG uses mapping integer IDs
(like socket IDs) to data structures.
It also brings back support for 64-bit IDs.
See bug #1740.
Setting the `NNG_OPT_RECVMAXSZ` setting no longer affects pipes
that are already established. The old behavior was undocumented
and racy. Please set this setting before starting any listeners
or dialers.
A new transport (experimental), for `socket://` is available.
This allows one to create a connection using sockets created
with `socketpair()` (or the new `nng_socket_pair()` supplemental API),
which can help use cases where file descriptors are passed between
processes or inherited via `fork()`. This API is only available on
Linux. It does have somewhat different semantics for establishing
the connection, so please see the manual page for `nng_socket(5)` for more information.
WebSocket close is fixed to conform to RFC 6455, sending the
close frame, and waiting to receive the close frame from the
peer. This allows websocket based connections to ensure that
data messages are fully delivered before shutting down.
See bugs #1733, #1734 and #1735.
Thanks @alawn-wang for the inspiration and a first
draft of the change.
The REQ and SURVEYOR protocols were fixed to improve scalability
when many clients or many contexts are used. As part of this change,
a new option, `NNG_OPT_REQ_RESENDTICK` is available to adjust how
often we check for expired requests.
A new ability to override compile-time settings for thread counts
is available. This facility is considered experimental, and is not
documented in manual pages -- and is subject to change without notice.
Please see nng_init_set_parameter() in the nng.h header file. The
values that can be tuned are listed there along with comments
describing their use. See bug #1572.
As part of the fixes for #1572, tunable values for setting fixed
values (rather upper limits) for thread counts are now exposed properly
via CMake variables. These are `NNG_NUM_EXPIRE_THREADS` and `NNG_NUM_TASKQ_THREADS`.
A new API, `nng_aio_set_expire()` is introduced as a complement to
`nng_aio_set_timeout()`. This provides absolute expiration times,
which may be easier in circumstances involving multiple actions such
as common state-machine based idioms.
A bug which caused TLS connections to spin on accept, causing high
CPU usage, is fixed. (See bug #1673)
Various minor documentation fixes were made, some contributed by
Patrik Wenger <patrik.wenger@mindclue.ch>.
== End of Feature Announcements
=== Windows Legacy Support
As announced in 1.6.0,
NNG no longer officially claims support for Windows Vista, Windows 7, Windows 8, or Windows 8.1.
We have no ability to build or test these versions, and Microsoft no longer supports them.
Continued use of these systems may be possible, but future changes may break
compatibility with these systems without further notice.
=== Windows Named Pipe Support Changes
A future release of NNG may make the ipc:// URL format operate over UNIX domain sockets by default.
We plan to do this for the other projects we control, such as mangos, as well.
Should this occur, it will be breaking for Windows versions older than Windows 10 17063.
=== macOS Legacy Support
As announced in 1.6.0,
NNG no longer officially supports macOS versions older than 10.12.
Future versions of NNG may depend on features not available on versions of macOS older than 10.12.
=== Documentation Restructuring
A future release of NNG may restructure the documentation to make it more
approachable for more users. This would break the organization as UNIX manual
pages, and would also drop the ability to format them as UNIX nroff source.
The best way to view this documentation is on the NNG website, or with the PDF or printed manual.
=== ZeroTier Incompatible Changes
A future release of NNG may break compatibility for applications built using earlier versions
of NNG when using the ZeroTier transport. ZeroTier support is an experimental feature.
=== Pair1 Polyamorous Mode
A future release of NNG may remove Pair 1 Polyamorous support, but *only* if a suitable
replacement is provided. Pair1 Polyamorous mode is an experimental feature.
Alternatively we may change the Pair1 wire protocol in a way that breaks compatibility with
earlier versions of Pair1 Polyamorous mode.

90
external/nng/UKRAINE.adoc vendored Normal file
View file

@ -0,0 +1,90 @@
# Ukraine, Russia, and a World Tragedy
## A message to those inside Russia
### Written March 4, 2022.
It is with a very heavy heart that I write this. I am normally opposed to the use of open source
projects to communicate political positions or advocate for things outside the immediate relevancy
to that project.
However, the events occurring in Ukraine, and specifically the unprecedented invasion of Ukraine by
Russian forces operating under orders from Russian President Vladimir Putin compel me to speak out.
Those who know me, know that I have family, friends, and colleagues in Russia, and Ukraine both. My closest friends
have historically been Russian friends my wife's hometown of Chelyabinsk. I myself have in the past
frequently traveled to Russia, and indeed operated a software development firm with offices in St. Petersburg.
I had a special kinship with Russia and its people.
I say "had", because I fear that the actions of Putin, and the massive disinformation campaign that his regime
has waged inside Russia, mean that it's likely that I won't see those friends again. At present, I'm not sure
my wife will see her own mother again. We no longer feel it's safe for either of us to return Russia given
actions taken by the regime to crack down on those who express disagreement.
Russian citizens are being led to believe it is acting purely defensively, and that only legitimate military
targets are being targeted, and that all the information we have received in the West are fakes.
I am confident that nothing could be further from the truth.
This has caused many in Russia, including people whom I respect and believe to be smarter than this, to
stand by Putin, and endorse his actions. The claim is that the entirety of NATO is operating at the behest
of the USA, and that the entirety of Europe was poised to attack Russia. While this is clearly absurd to those
of us with any understanding of western politics, Russian citizens are being fed this lie, and believing it.
If you're reading this from inside Russia -- YOU are the person that I hope this message reaches. Your
government is LYING to you. Of course, all governments lie all the time. But consider this. Almost the
entire world has condemned the invasion of Ukraine as criminal, and has applied sanctions. Even countries
which have poor relations with the US sanctioning Russia, as well as nations which historically have remained
neutral. (Famously neutral -- even during World War II, Switzerland has acted to apply sanctions in
concert with the rest of the world.)
Ask yourself, why does Putin fear a free press so much, if what he says is true? Why the crack-downs on
children expressing only a desire for peace with Ukraine? Why would the entire world unified against him,
if Putin was in the right? Why would the only countries that stood with Russia against
the UN resolution to condemn these acts as crimes be Belarus, North Korea, and Syria? Even countries normally
allied to Russia could not bring themselves to do more than abstain from the vote to condemn it.
To be clear, I do not claim that the actions taken by the West or by the Ukrainian government were completely
blameless. On the contrary, I understand that Western media is biased, and the truth is rarely exactly
as reported. I believe that there is a kernel of truth in the claims of fascists and ultra-nationalist
militias operating in Ukraine and specifically Donbas. However, I am also equally certain that Putin's
response is out of proportion, and that concerns about such militias are principally just a pretext to justify
an invasion.
Europe is at war, unlike we've seen in my lifetime. The world is more divided, and closer to nuclear holocaust
than it has been since the Cold War. And that is 100% the fault of Putin.
While Putin remains in power, there cannot really be any way for Russian international relations to return
to normal. Putin has set your country on a path to return to the Cold War, likely because he fancies himself
to be a new Stalin. However, unlike the Soviet Union, the Russian economy does not have the wherewithal to
stand on its own, and the invasion of Ukraine has fully ensured that Russia will not find any friends anywhere
else in Europe, and probably few places in Asia.
The *only* paths forward for Russia are either a Russia without Putin (and those who would support his agenda),
or a complete breakdown of Russian prosperity, likely followed by the increasing international conflict that will
be the natural escalation from a country that is isolated and impoverished. Those of us observing from the West are
gravely concerned, because we cannot see any end to this madness that does not result in nuclear conflict,
unless from within.
In the meantime, the worst prices will be paid for by innocents in Ukraine, and by young Russian men
forced to carry out the orders of Putin's corrupt regime.
And *that* is why I write this -- to appeal to those within Russia to open your eyes, and think with
your minds. It is right and proper to be proud of your country and its rich heritage. But it is also
right and proper to look for ways to save it from the ruinous path that its current leadership has set it upon,
and to recognize when that leadership is no longer acting in interest of the country or its people.
- Garrett D'Amore, March 4, 2022
Updates on March 16, 2024:
I've made some minor typographical fixes.
It is extremely distressing to see that two years on, the
people of both Ukraine and Russia continue to suffer under this needless, pointless, conflict fought solely to assuage
the ego of a dictator.
The actions done here, have killed thousands, probably hundreds of thousands, of soldiers and civilians alike, and there seems to be no end to the madness. I still pray for sanity to return, because the current path, if followed
to its logical conclusion, most likely ends in apocalpyse.
If you find my sharing these truths uncomfortable, please feel welcome to cease use of my software. While the license does permit use by anyone for any reason, I would not be displeased if the Russian military, and those sympathetic to it, declined from use of any of my work.

30
external/nng/cmake/CheckSanitizer.cmake vendored Normal file
View file

@ -0,0 +1,30 @@
#
# Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
# Copyright 2017 Capitar IT Group BV <info@capitar.com>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
#
macro (CheckSanitizer)
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
set(NNG_SAN_LIST none address leak memory thread undefined)
elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
set(NNG_SAN_LIST none address leak memory thread undefined)
elseif (CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
set(NNG_SAN_LIST none address thread undefined)
else ()
set(NNG_SAN_LIST none)
endif ()
set (NNG_SANITIZER none CACHE STRING "Sanitizer to use (clang or gcc).")
set_property(CACHE NNG_SANITIZER PROPERTY STRINGS ${NNG_SAN_LIST})
mark_as_advanced (NNG_SANITIZER)
if (NOT NNG_SANITIZER STREQUAL "none")
set (NNG_C_FLAG_SANITIZER "-fsanitize=${NNG_SANITIZER}")
message(STATUS "Enabling sanitizer: ${NNG_C_FLAG_SANITIZER}")
endif()
endmacro ()

119
external/nng/cmake/FindMbedTLS.cmake vendored Normal file
View file

@ -0,0 +1,119 @@
#
# Copyright 2024 Staysail Systems, Inc. <info@staysail.tech>
# Copyright 2017 Capitar IT Group BV <info@capitar.com>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
#
#
# Try to find the Mbed TLS libraries.
# This tries to emulate the same expectations that the stock Mbed TLS
# module uses in Mbed TLS v3.x.
#
# Sets the following:
#
# MbedTLS_FOUND - True if we found Mbed TLS.
# MbedTLS_TARGET - Target of the mbedtls library.
# MbedX509_TARGET - Target of the mbedx509 library.
# MbedCrypto_TARGET - Target of the mbedcrypto library.
# MbedTLS_VERSION - $major.$minor.$revision (e.g. ``2.6.0``).
#
# MBEDTLS_CRYPTO_LIBRARY - The mbedcrypto library.
# MBEDTLS_X509_LIBRARY - The mbedx509 library.
# MBEDTLS_TLS_LIBRARY - The mbedtls library.
# MBEDTLS_LIBRARIES - List of all three Mbed TLS libraries.
#
# Hints:
#
# Set ``MBEDTLS_ROOT`` to the root directory of Mbed TLS installation.
#
set(_MBEDTLS_ROOT_HINTS ${MBEDTLS_ROOT} ENV MBEDTLS_ROOT)
if (NOT _MBEDTLS_ROOT_HINTS)
set(_MBEDTLS_ROOT_HINTS ${MBEDTLS_ROOT_DIR} ENV MBEDTLS_ROOT_DIR)
endif()
set(_MBED_REQUIRED_VARS MbedTLS_TARGET MbedX509_TARGET MbedCrypto_TARGET MbedTLS_VERSION)
include(FindPackageHandleStandardArgs)
include(CMakePushCheckState)
find_path(_MBEDTLS_INCLUDE_DIR
NAMES mbedtls/ssl.h
HINTS ${_MBEDTLS_ROOT_HINTS}
# PATHS /usr/local
PATH_SUFFIXES include)
find_library(_MBEDCRYPTO_LIBRARY
NAMES mbedcrypto
HINTS ${_MBEDTLS_ROOT_HINTS}
# PATHS /usr/local
# PATH_SUFFIXES lib
)
find_library(_MBEDX509_LIBRARY
NAMES mbedx509
HINTS ${_MBEDTLS_ROOT_HINTS}
#PATHS /usr/local
# PATH_SUFFIXES lib
)
find_library(_MBEDTLS_LIBRARY
NAMES mbedtls
HINTS ${_MBEDTLS_ROOT_HINTS}
#PATHS /usr/local
#PATH_SUFFIXES lib
)
if ("${_MBEDTLS_TLS_LIBRARY}" STREQUAL "_MBEDTLS_TLS_LIBRARY-NOTFOUND")
message("Failed to find Mbed TLS library")
else()
cmake_push_check_state(RESET)
set(CMAKE_REQUIRED_INCLUDES ${_MBEDTLS_INCLUDE_DIR} ${CMAKE_REQUIRED_INCLUDES_${BUILD_TYPE}})
list(APPEND CMAKE_REQUIRED_LIBRARIES ${_MBEDTLS_LIBRARY} ${_MBEDX509_LIBRARY} ${_MBEDCRYPTO_LIBRARY})
check_symbol_exists(mbedtls_ssl_init "mbedtls/ssl.h" _MBEDTLS_V2_OR_NEWER)
cmake_pop_check_state()
if (NOT _MBEDTLS_V2_OR_NEWER)
message("Mbed TLS too old (must be version 2 or newer) ${_MBEDTLS_V2_OR_NEWER} UP ${_MbedTLS_V2}")
else()
# Extract the version from the header... hopefully it matches the library.
if (EXISTS ${_MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h)
file(STRINGS ${_MBEDTLS_INCLUDE_DIR}/mbedtls/build_info.h _MBEDTLS_VERLINE
REGEX "^#define[ \t]+MBEDTLS_VERSION_STRING[\t ].*")
else ()
file(STRINGS ${_MBEDTLS_INCLUDE_DIR}/mbedtls/version.h _MBEDTLS_VERLINE
REGEX "^#define[ \t]+MBEDTLS_VERSION_STRING[\t ].*")
endif ()
string(REGEX REPLACE ".*MBEDTLS_VERSION_STRING[\t ]+\"(.*)\"" "\\1" MbedTLS_VERSION ${_MBEDTLS_VERLINE})
message("Mbed TLS version: ${MbedTLS_VERSION}")
endif()
endif()
add_library(MbedTLS::mbedtls UNKNOWN IMPORTED)
add_library(MbedTLS::mbedx509 UNKNOWN IMPORTED)
add_library(MbedTLS::mbedcrypto UNKNOWN IMPORTED)
set_target_properties(MbedTLS::mbedtls PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${_MBEDTLS_INCLUDE_DIR}")
set_target_properties(MbedTLS::mbedx509 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${_MBEDTLS_INCLUDE_DIR}")
set_target_properties(MbedTLS::mbedcrypto PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${_MBEDTLS_INCLUDE_DIR}")
set_target_properties(MbedTLS::mbedtls PROPERTIES IMPORTED_LOCATION "${_MBEDTLS_LIBRARY}")
set_target_properties(MbedTLS::mbedx509 PROPERTIES IMPORTED_LOCATION "${_MBEDX509_LIBRARY}")
set_target_properties(MbedTLS::mbedcrypto PROPERTIES IMPORTED_LOCATION "${_MBEDCRYPTO_LIBRARY}")
set(MbedTLS_TARGET MbedTLS::mbedtls)
set(MbedX509_TARGET MbedTLS::mbedx509)
set(MbedCrypto_TARGET MbedTLS::mbedcrypto)
find_package_handle_standard_args(MbedTLS REQUIRED_VARS ${_MBED_REQUIRED_VARS})
mark_as_advanced(${_MBED_REQUIRED_VARS})

173
external/nng/cmake/NNGHelpers.cmake vendored Normal file
View file

@ -0,0 +1,173 @@
#
# Copyright 2024 Staysail Systems, Inc. <info@staysail.tech>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
#
# Some NNG helper functions.
include(CheckFunctionExists)
include(CheckSymbolExists)
include(CheckStructHasMember)
include(CheckLibraryExists)
include(CheckCSourceCompiles)
# nng_sources adds library sources using files in the current directory.
function(nng_sources)
foreach (f ${ARGN})
target_sources(nng PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${f})
target_sources(nng_testing PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${f})
endforeach ()
endfunction()
# nng_headers adds library sources as public headers taken rooted at the include/ directory.
function(nng_headers)
foreach (f ${ARGN})
target_sources(nng PRIVATE ${PROJECT_SOURCE_DIR}/include/${f})
target_sources(nng_testing PRIVATE ${PROJECT_SOURCE_DIR}/include/${f})
endforeach ()
endfunction()
# nng_defines adds defines unconditionally.
# The public library keeps these defines private, but the test library exposes these definitions
# as some of our test cases would like to know details about how the library was compiled
# as that may modify the tests themselves.
function(nng_defines)
target_compile_definitions(nng PRIVATE ${ARGN})
target_compile_definitions(nng_testing PUBLIC ${ARGN})
target_compile_definitions(nng_private INTERFACE ${ARGN})
endfunction()
# nng_find_package looks up required package and adds dependency to the cmake config.
macro(nng_find_package PACKAGE_NAME)
find_package(${PACKAGE_NAME} REQUIRED)
list(APPEND NNG_PKGS ${PACKAGE_NAME})
list(REMOVE_DUPLICATES NNG_PKGS)
set(NNG_PKGS ${NNG_PKGS} CACHE INTERNAL "nng package dependencies" FORCE)
endmacro()
# nng_link_libraries adds link dependencies to the libraries.
function(nng_link_libraries)
target_link_libraries(nng PRIVATE ${ARGN})
target_link_libraries(nng_testing PRIVATE ${ARGN})
endfunction()
function(nng_link_libraries_public)
target_link_libraries(nng PRIVATE ${ARGN})
target_link_libraries(nng_testing PRIVATE ${ARGN})
endfunction()
# nng_include_directories adds include directories.
function(nng_include_directories)
target_include_directories(nng PRIVATE ${ARGN})
target_include_directories(nng_testing PRIVATE ${ARGN})
endfunction()
# nng_sources_if adds the sources unconditionally to the test library,
# but conditionally to the production library. This allows us to get
# full test coverage while allowing a minimized delivery.
function(nng_sources_if COND)
foreach (f ${ARGN})
if (${COND})
target_sources(nng PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${f})
endif ()
target_sources(nng_testing PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${f})
endforeach ()
endfunction()
function(nng_headers_if COND)
foreach (f ${ARGN})
if (COND)
target_sources(nng PRIVATE ${PROJECT_SOURCE_DIR}/include/${f})
endif ()
target_sources(nng_testing PRIVATE ${PROJECT_SOURCE_DIR}/include/${f})
endforeach ()
endfunction()
function(nng_defines_if COND)
if (${COND})
target_compile_definitions(nng PRIVATE ${ARGN})
target_compile_definitions(nng_private INTERFACE ${ARGN})
endif ()
target_compile_definitions(nng_testing PUBLIC ${ARGN})
endfunction()
function(nng_link_libraries_if COND)
if (${COND})
target_link_libraries(nng PRIVATE ${ARGN})
endif ()
target_link_libraries(nng_testing PRIVATE ${ARGN})
endfunction()
function(nng_test NAME)
if (NNG_TESTS)
add_executable(${NAME} ${NAME}.c ${ARGN})
target_link_libraries(${NAME} nng_testing)
target_include_directories(${NAME} PRIVATE
${PROJECT_SOURCE_DIR}/tests
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/include)
add_test(NAME ${NNG_TEST_PREFIX}.${NAME} COMMAND ${NAME} -t -v)
set_tests_properties(${NNG_TEST_PREFIX}.${NAME} PROPERTIES TIMEOUT 180)
endif ()
endfunction()
function(nng_test_if COND NAME)
if (${COND} AND NNG_TESTS)
add_executable(${NAME} ${NAME}.c ${ARGN})
target_link_libraries(${NAME} nng_testing)
target_include_directories(${NAME} PRIVATE
${PROJECT_SOURCE_DIR}/tests
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/include)
add_test(NAME ${NNG_TEST_PREFIX}.${NAME} COMMAND ${NAME} -t -v)
set_tests_properties(${NNG_TEST_PREFIX}.${NAME} PROPERTIES TIMEOUT 180)
endif ()
endfunction()
function(nng_check_func SYM DEF)
check_function_exists(${SYM} ${DEF})
if (${DEF})
target_compile_definitions(nng PRIVATE ${DEF}=1)
target_compile_definitions(nng_testing PUBLIC ${DEF}=1)
target_compile_definitions(nng_private INTERFACE ${DEF}=1)
endif ()
endfunction(nng_check_func)
function(nng_check_sym SYM HDR DEF)
check_symbol_exists(${SYM} ${HDR} ${DEF})
if (${DEF})
target_compile_definitions(nng PRIVATE ${DEF}=1)
target_compile_definitions(nng_testing PUBLIC ${DEF}=1)
target_compile_definitions(nng_private INTERFACE ${DEF}=1)
endif ()
endfunction(nng_check_sym)
function(nng_check_lib LIB SYM DEF)
check_library_exists(${LIB} ${SYM} "" ${DEF})
if (${DEF})
target_compile_definitions(nng PRIVATE ${DEF}=1)
target_compile_definitions(nng_testing PUBLIC ${DEF}=1)
target_compile_definitions(nng_private INTERFACE ${DEF}=1)
target_link_libraries(nng PRIVATE ${LIB})
target_link_libraries(nng_testing PRIVATE ${LIB})
endif ()
endfunction(nng_check_lib)
function(nng_check_struct_member STR MEM HDR DEF)
check_struct_has_member("struct ${STR}" ${MEM} ${HDR} ${DEF})
if (${DEF})
target_compile_definitions(nng PRIVATE ${DEF}=1)
target_compile_definitions(nng_testing PUBLIC ${DEF}=1)
target_compile_definitions(nng_private INTERFACE ${DEF}=1)
endif ()
endfunction(nng_check_struct_member)
macro(nng_directory DIR)
set(NNG_TEST_PREFIX ${NNG_TEST_PREFIX}.${DIR})
endmacro(nng_directory)

153
external/nng/cmake/NNGOptions.cmake vendored Normal file
View file

@ -0,0 +1,153 @@
#
# Copyright 2024 Staysail Systems, Inc. <info@staysail.tech>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
#
# NNG Options. These are user configurable knobs.
include(CMakeDependentOption)
if (CMAKE_CROSSCOMPILING)
set(NNG_NATIVE_BUILD OFF)
else ()
set(NNG_NATIVE_BUILD ON)
endif ()
# Global options.
option(BUILD_SHARED_LIBS "Build shared library" ${BUILD_SHARED_LIBS})
# We only build command line tools and tests if we are not in a
# cross-compile situation. Cross-compiling users who still want to
# build these must enable them explicitly. Some of these switches
# must be enabled rather early as we use their values later.
option(NNG_TESTS "Build and run tests." ${NNG_NATIVE_BUILD})
option(NNG_TOOLS "Build extra tools." ${NNG_NATIVE_BUILD})
option(NNG_ENABLE_NNGCAT "Enable building nngcat utility." ${NNG_TOOLS})
option(NNG_ENABLE_COVERAGE "Enable coverage reporting." OFF)
# Eliding deprecated functionality can be used to build a slimmed down
# version of the library, or alternatively to test for application
# preparedness for expected feature removals (in the next major release.)
# Applications can also set the NNG_ELIDE_DEPRECATED preprocessor symbol
# before including <nng/nng.h> -- this will prevent declarations from
# being exposed to applications, but it will not affect their ABI
# availability for existing compiled applications.
# Note: Currently this breaks the test suite, so we only do it
# for the public library.
option(NNG_ELIDE_DEPRECATED "Elide deprecated functionality." OFF)
# Turning off the compatibility layer can save some space, and
# compilation time, but may break legacy applications It should
# be left enabled when building a shared library.
option(NNG_ENABLE_COMPAT "Enable legacy nanomsg API." ON)
option(NNG_ENABLE_STATS "Enable statistics." ON)
mark_as_advanced(NNG_ENABLE_STATS)
# Protocols.
option (NNG_PROTO_BUS0 "Enable BUSv0 protocol." ON)
mark_as_advanced(NNG_PROTO_BUS0)
option (NNG_PROTO_PAIR0 "Enable PAIRv0 protocol." ON)
mark_as_advanced(NNG_PROTO_PAIR0)
option (NNG_PROTO_PAIR1 "Enable PAIRv1 protocol." ON)
mark_as_advanced(NNG_PROTO_PAIR1)
option (NNG_PROTO_PUSH0 "Enable PUSHv0 protocol." ON)
mark_as_advanced(NNG_PROTO_PUSH0)
option (NNG_PROTO_PULL0 "Enable PULLv0 protocol." ON)
mark_as_advanced(NNG_PROTO_PULL0)
option (NNG_PROTO_PUB0 "Enable PUBv0 protocol." ON)
mark_as_advanced(NNG_PROTO_PUB0)
option (NNG_PROTO_SUB0 "Enable SUBv0 protocol." ON)
mark_as_advanced(NNG_PROTO_SUB0)
option(NNG_PROTO_REQ0 "Enable REQv0 protocol." ON)
mark_as_advanced(NNG_PROTO_REQ0)
option(NNG_PROTO_REP0 "Enable REPv0 protocol." ON)
mark_as_advanced(NNG_PROTO_REP0)
option (NNG_PROTO_RESPONDENT0 "Enable RESPONDENTv0 protocol." ON)
mark_as_advanced(NNG_PROTO_RESPONDENT0)
option (NNG_PROTO_SURVEYOR0 "Enable SURVEYORv0 protocol." ON)
mark_as_advanced(NNG_PROTO_SURVEYOR0)
# TLS support.
# Enabling TLS is required to enable support for the TLS transport
# and WSS. It does require a 3rd party TLS engine to be selected.
option(NNG_ENABLE_TLS "Enable TLS support." OFF)
if (NNG_ENABLE_TLS)
set(NNG_SUPP_TLS ON)
endif ()
if (NNG_ENABLE_TLS)
set(NNG_TLS_ENGINES mbed wolf none)
# We assume Mbed for now. (Someday replaced perhaps with Bear.)
set(NNG_TLS_ENGINE mbed CACHE STRING "TLS engine to use.")
set_property(CACHE NNG_TLS_ENGINE PROPERTY STRINGS ${NNG_TLS_ENGINES})
else ()
set(NNG_TLS_ENGINE none)
endif ()
# HTTP API support.
option (NNG_ENABLE_HTTP "Enable HTTP API." ON)
if (NNG_ENABLE_HTTP)
set(NNG_SUPP_HTTP ON)
endif()
mark_as_advanced(NNG_ENABLE_HTTP)
# Some sites or kernels lack IPv6 support. This override allows us
# to prevent the use of IPv6 in environments where it isn't supported.
option (NNG_ENABLE_IPV6 "Enable IPv6." ON)
mark_as_advanced(NNG_ENABLE_IPV6)
#
# Transport Options.
#
option (NNG_TRANSPORT_INPROC "Enable inproc transport." ON)
mark_as_advanced(NNG_TRANSPORT_INPROC)
option (NNG_TRANSPORT_IPC "Enable IPC transport." ON)
mark_as_advanced(NNG_TRANSPORT_IPC)
# TCP transport
option (NNG_TRANSPORT_TCP "Enable TCP transport." ON)
mark_as_advanced(NNG_TRANSPORT_TCP)
# TLS transport
option (NNG_TRANSPORT_TLS "Enable TLS transport." ON)
mark_as_advanced(NNG_TRANSPORT_TLS)
# WebSocket
option (NNG_TRANSPORT_WS "Enable WebSocket transport." ON)
mark_as_advanced(NNG_TRANSPORT_WS)
CMAKE_DEPENDENT_OPTION(NNG_TRANSPORT_WSS "Enable WSS transport." ON
"NNG_ENABLE_TLS" OFF)
mark_as_advanced(NNG_TRANSPORT_WSS)
option (NNG_TRANSPORT_FDC "Enable File Descriptor transport (EXPERIMENTAL)" ON)
mark_as_advanced(NNG_TRANSPORT_FDC)
# ZeroTier
option (NNG_TRANSPORT_ZEROTIER "Enable ZeroTier transport (requires libzerotiercore)." OFF)
mark_as_advanced(NNG_TRANSPORT_ZEROTIER)
if (NNG_TRANSPORT_WS OR NNG_TRANSPORT_WSS)
# Make sure things we *MUST* have are enabled.
set(NNG_SUPP_WEBSOCKET ON)
set(NNG_SUPP_HTTP ON)
set(NNG_SUPP_BASE64 ON)
set(NNG_SUPP_SHA1 ON)
endif()

26
external/nng/cmake/nng-config.cmake.in vendored Normal file
View file

@ -0,0 +1,26 @@
# Copyright 2023 Staysail Systems, Inc. <info@staysail.tech>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
@PACKAGE_INIT@
set(NNG_MAJOR_VERSION "@NNG_MAJOR_VERSION@")
set(NNG_MINOR_VERSION "@NNG_MINOR_VERSION@")
set(NNG_PATCH_VERSION "@NNG_PATCH_VERSION@")
set_and_check(NNG_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIRS@")
include("${CMAKE_CURRENT_LIST_DIR}/nng-targets.cmake")
# Make sure we find packages for our dependencies
foreach(_PKG IN ITEMS @NNG_PKGS@)
find_package(${_PKG} REQUIRED)
endforeach ()
set(NNG_LIBRARY nng::nng)
check_required_components(@PROJECT_NAME@)

27
external/nng/demo/async/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,27 @@
#
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
cmake_minimum_required (VERSION 2.8.12)
project(nng-asyncdemo)
set(PARALLEL 128 CACHE STRING "Parallelism (min 4, max 1000)")
# Call this from your own project's makefile.
find_package(nng CONFIG REQUIRED)
find_package(Threads)
add_executable(server server.c)
target_link_libraries(server nng::nng)
target_compile_definitions(server PRIVATE NNG_ELIDE_DEPRECATED PARALLEL=${PARALLEL})
add_executable(client client.c)
target_link_libraries(client nng::nng)
target_compile_definitions(client PRIVATE NNG_ELIDE_DEPRECATED)

50
external/nng/demo/async/README.adoc vendored Normal file
View file

@ -0,0 +1,50 @@
= async
This is a simple asynchronous demo, that demonstrates use of the contexts
and asynchronous message handling and operations, to obtain highly concurrent
processing with minimal fuss.
== Compiling
This is set up for configuration with CMake for ease of use.
You can override the level of concurrency with the `PARALLEL` option.
This determines how many requests the server will accept
at a time, and keep outstanding. Note that for our toy implementation,
we create this many "logical" flows of execution (contexts) (these are
_NOT_ threads), where a request is followed by a reply.
The value of `PARALLEL` must be at least one, and may be as large
as your memory will permit. (The default value is 128.) Probably
you want the value to be small enough to ensure that you have enough
file descriptors. (You can create more contexts than this, but generally
you can't have more than one client per descriptor. Contexts can be used
on the client side to support many thousands of concurrent requests over
even just a single TCP connection, however.)
You can also build this all by hand with Make or whatever.
On UNIX-style systems:
[source, bash]
----
% export CPPFLAGS="-D PARALLEL=32 -I /usr/local/include"
% export LDFLAGS="-L /usr/local/lib -lnng"
% export CC="cc"
% ${CC} ${CPPFLAGS} server.c -o server ${LDFLAGS}
% ${CC} ${CPPFLAGS} client.c -o client ${LDFLAGS}
----
== Running
The easiest thing is to simply use the `run.sh` script, which
sends COUNT (10) random jobs to the server in parallel.
You can of course run the client and server manually instead.
The server takes the address (url) as its only argument.
The client takes the address (url), followed by the number of
milliseconds the server should "wait" before responding (to simulate
an expensive operation.)

95
external/nng/demo/async/client.c vendored Normal file
View file

@ -0,0 +1,95 @@
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitoar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
// This program is just a simple client application for our demo server.
// It is in a separate file to keep the server code clearer to understand.
//
// Our demonstration application layer protocol is simple. The client sends
// a number of milliseconds to wait before responding. The server just gives
// back an empty reply after waiting that long.
// For example:
//
// % ./server tcp://127.0.0.1:5555 &
// % ./client tcp://127.0.0.1:5555 323
// Request took 324 milliseconds.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <nng/nng.h>
#include <nng/protocol/reqrep0/req.h>
#include <nng/supplemental/util/platform.h>
void
fatal(const char *func, int rv)
{
fprintf(stderr, "%s: %s\n", func, nng_strerror(rv));
exit(1);
}
/* The client runs just once, and then returns. */
int
client(const char *url, const char *msecstr)
{
nng_socket sock;
int rv;
nng_msg * msg;
nng_time start;
nng_time end;
unsigned msec;
msec = atoi(msecstr);
if ((rv = nng_req0_open(&sock)) != 0) {
fatal("nng_req0_open", rv);
}
if ((rv = nng_dial(sock, url, NULL, 0)) != 0) {
fatal("nng_dial", rv);
}
start = nng_clock();
if ((rv = nng_msg_alloc(&msg, 0)) != 0) {
fatal("nng_msg_alloc", rv);
}
if ((rv = nng_msg_append_u32(msg, msec)) != 0) {
fatal("nng_msg_append_u32", rv);
}
if ((rv = nng_sendmsg(sock, msg, 0)) != 0) {
fatal("nng_sendmsg", rv);
}
if ((rv = nng_recvmsg(sock, &msg, 0)) != 0) {
fatal("nng_recvmsg", rv);
}
end = nng_clock();
nng_msg_free(msg);
nng_close(sock);
printf("Request took %u milliseconds.\n", (uint32_t)(end - start));
return (0);
}
int
main(int argc, char **argv)
{
int rc;
if (argc != 3) {
fprintf(stderr, "Usage: %s <url> <secs>\n", argv[0]);
exit(EXIT_FAILURE);
}
rc = client(argv[1], argv[2]);
exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}

27
external/nng/demo/async/run.sh vendored Executable file
View file

@ -0,0 +1,27 @@
#!/usr/bin/env bash
ADDR=ipc:///tmp/async_demo
COUNT=10
./server $ADDR &
SERVER_PID=$!
trap "kill $SERVER_PID" 0
typeset -a CLIENT_PID
i=0
sleep 1
while (( i < COUNT ))
do
i=$(( i + 1 ))
rnd=$(( RANDOM % 1000 + 500 ))
echo "Starting client $i: server replies after $rnd msec"
./client $ADDR $rnd &
eval CLIENT_PID[$i]=$!
done
i=0
while (( i < COUNT ))
do
i=$(( i + 1 ))
wait ${CLIENT_PID[$i]}
done
kill $SERVER_PID

178
external/nng/demo/async/server.c vendored Normal file
View file

@ -0,0 +1,178 @@
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitoar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
// This program serves as an example for how to write an async RPC service,
// using the request/reply pattern and contexts (nng_ctx(5)). The server
// allocates a number of contexts up front, which determines the amount of
// parallelism possible. The callbacks are handled asynchronously, so
// this could be done by threads, or something similar. For our uses we
// make use of an event driven architecture that we already have available.
// Our demonstration application layer protocol is simple. The client sends
// a number of milliseconds to wait before responding. The server just gives
// back an empty reply after waiting that long.
// To run this program, start the server as async_demo <url> -s
// Then connect to it with the client as async_client <url> <msec>.
//
// For example:
//
// % ./server tcp://127.0.0.1:5555 &
// % ./client tcp://127.0.0.1:5555 323
// Request took 324 milliseconds.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <nng/nng.h>
#include <nng/protocol/reqrep0/rep.h>
#include <nng/supplemental/util/platform.h>
// Parallel is the maximum number of outstanding requests we can handle.
// This is *NOT* the number of threads in use, but instead represents
// outstanding work items. Select a small number to reduce memory size.
// (Each one of these can be thought of as a request-reply loop.) Note
// that you will probably run into limitations on the number of open file
// descriptors if you set this too high. (If not for that limit, this could
// be set in the thousands, each context consumes a couple of KB.)
#ifndef PARALLEL
#define PARALLEL 128
#endif
// The server keeps a list of work items, sorted by expiration time,
// so that we can use this to set the timeout to the correct value for
// use in poll.
struct work {
enum { INIT, RECV, WAIT, SEND } state;
nng_aio *aio;
nng_msg *msg;
nng_ctx ctx;
};
void
fatal(const char *func, int rv)
{
fprintf(stderr, "%s: %s\n", func, nng_strerror(rv));
exit(1);
}
void
server_cb(void *arg)
{
struct work *work = arg;
nng_msg * msg;
int rv;
uint32_t when;
switch (work->state) {
case INIT:
work->state = RECV;
nng_ctx_recv(work->ctx, work->aio);
break;
case RECV:
if ((rv = nng_aio_result(work->aio)) != 0) {
fatal("nng_ctx_recv", rv);
}
msg = nng_aio_get_msg(work->aio);
if ((rv = nng_msg_trim_u32(msg, &when)) != 0) {
// bad message, just ignore it.
nng_msg_free(msg);
nng_ctx_recv(work->ctx, work->aio);
return;
}
work->msg = msg;
work->state = WAIT;
nng_sleep_aio(when, work->aio);
break;
case WAIT:
// We could add more data to the message here.
nng_aio_set_msg(work->aio, work->msg);
work->msg = NULL;
work->state = SEND;
nng_ctx_send(work->ctx, work->aio);
break;
case SEND:
if ((rv = nng_aio_result(work->aio)) != 0) {
nng_msg_free(work->msg);
fatal("nng_ctx_send", rv);
}
work->state = RECV;
nng_ctx_recv(work->ctx, work->aio);
break;
default:
fatal("bad state!", NNG_ESTATE);
break;
}
}
struct work *
alloc_work(nng_socket sock)
{
struct work *w;
int rv;
if ((w = nng_alloc(sizeof(*w))) == NULL) {
fatal("nng_alloc", NNG_ENOMEM);
}
if ((rv = nng_aio_alloc(&w->aio, server_cb, w)) != 0) {
fatal("nng_aio_alloc", rv);
}
if ((rv = nng_ctx_open(&w->ctx, sock)) != 0) {
fatal("nng_ctx_open", rv);
}
w->state = INIT;
return (w);
}
// The server runs forever.
int
server(const char *url)
{
nng_socket sock;
struct work *works[PARALLEL];
int rv;
int i;
/* Create the socket. */
rv = nng_rep0_open(&sock);
if (rv != 0) {
fatal("nng_rep0_open", rv);
}
for (i = 0; i < PARALLEL; i++) {
works[i] = alloc_work(sock);
}
if ((rv = nng_listen(sock, url, NULL, 0)) != 0) {
fatal("nng_listen", rv);
}
for (i = 0; i < PARALLEL; i++) {
server_cb(works[i]); // this starts them going (INIT state)
}
for (;;) {
nng_msleep(3600000); // neither pause() nor sleep() portable
}
}
int
main(int argc, char **argv)
{
int rc;
if (argc != 2) {
fprintf(stderr, "Usage: %s <url>\n", argv[0]);
exit(EXIT_FAILURE);
}
rc = server(argv[1]);
exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}

View file

@ -0,0 +1,21 @@
#
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
cmake_minimum_required (VERSION 2.8.12)
project(http_client)
# Call this from your own project's makefile.
find_package(nng CONFIG REQUIRED)
find_package(Threads)
add_executable(http_client http_client.c)
target_link_libraries(http_client nng::nng)
target_compile_definitions(http_client PRIVATE NNG_ELIDE_DEPRECATED)

View file

@ -0,0 +1,52 @@
= http_client
This is a very simple HTTP client. It only performs HTTP GET
operations, and does not follow HTTP redirects. Think of it as
a trivialized version of cURL. It is super simple, taking the
URL on the command line, and emitting the results to stdout.
For clarity, we are eliding TLS support.
It may not work on all systems, but it should work anywhere that
both the standard C library and nng itself are available.
We check for errors, but no effort is made to clean up resources,
since this program just exits. In longer running programs or libraries,
callers should take care to clean up things that they allocate.
Unfortunately many famous sites use redirects (usually to HTTPS
sites), so it's not a very useful replacement for cURL.
== Compiling
The following is an example typical of UNIX and similar systems like
Linux and macOS:
[source, bash]
----
% export CPPFLAGS="-I /usr/local/include"
% export LDFLAGS="-L /usr/local/lib -lnng"
% export CC="cc"
% ${CC} ${CPPFLAGS} http_client.c -o http_client ${LDFLAGS}
----
Alternatively, CMake can be used. Here's an example if you have
Ninja build handy (highly recommended):
[source, bash]
----
% mkdir build
% cd build
% cmake -G Ninja ..
% ninja
----
== Running
Make sure you specify the full URL (if the root page include
the simple "/". The URL parser does not add it for you automatically.)
[source, bash]
----
% ./http_client http://httpbin.org/ip
----

View file

@ -0,0 +1,147 @@
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
// This is a very simple HTTP client. It only performs HTTP GET
// operations, and does not follow HTTP redirects. Think of it as
// a trivialized version of CURL. It is super simple, taking the
// URL on the command line, and emitting the results to stdout.
// For clarity, we are eliding TLS support.
// It may not work on all systems, but it should work anywhere that
// both the standard C library and nng itself are available.
// We check for errors, but no effort is made to clean up resources,
// since this program just exits. In longer running programs or libraries,
// callers should take care to clean up things that they allocate.
// Unfortunately many famous sites use redirects, so you won't see that
// emitted.
// Example usage:
//
// % export CPPFLAGS="-I /usr/local/include"
// % export LDFLAGS="-L /usr/local/lib -lnng"
// % export CC="cc"
// % ${CC} ${CPPFLAGS} http_client.c -o http_client ${LDFLAGS}
// % ./http_client http://httpbin.org/ip
//
#include <nng/nng.h>
#include <nng/supplemental/http/http.h>
#include <stdio.h>
#include <stdlib.h>
void
fatal(int rv)
{
fprintf(stderr, "%s\n", nng_strerror(rv));
exit(1);
}
int
main(int argc, char **argv)
{
nng_http_client *client;
nng_http_conn * conn;
nng_url * url;
nng_aio * aio;
nng_http_req * req;
nng_http_res * res;
const char * hdr;
int rv;
int len;
void * data;
nng_iov iov;
if (argc < 2) {
fprintf(stderr, "No URL supplied!\n");
exit(1);
}
if (((rv = nng_url_parse(&url, argv[1])) != 0) ||
((rv = nng_http_client_alloc(&client, url)) != 0) ||
((rv = nng_http_req_alloc(&req, url)) != 0) ||
((rv = nng_http_res_alloc(&res)) != 0) ||
((rv = nng_aio_alloc(&aio, NULL, NULL)) != 0)) {
fatal(rv);
}
// Start connection process...
nng_http_client_connect(client, aio);
// Wait for it to finish.
nng_aio_wait(aio);
if ((rv = nng_aio_result(aio)) != 0) {
fatal(rv);
}
// Get the connection, at the 0th output.
conn = nng_aio_get_output(aio, 0);
// Request is already set up with URL, and for GET via HTTP/1.1.
// The Host: header is already set up too.
// Send the request, and wait for that to finish.
nng_http_conn_write_req(conn, req, aio);
nng_aio_wait(aio);
if ((rv = nng_aio_result(aio)) != 0) {
fatal(rv);
}
// Read a response.
nng_http_conn_read_res(conn, res, aio);
nng_aio_wait(aio);
if ((rv = nng_aio_result(aio)) != 0) {
fatal(rv);
}
if (nng_http_res_get_status(res) != NNG_HTTP_STATUS_OK) {
fprintf(stderr, "HTTP Server Responded: %d %s\n",
nng_http_res_get_status(res),
nng_http_res_get_reason(res));
}
// This only supports regular transfer encoding (no Chunked-Encoding,
// and a Content-Length header is required.)
if ((hdr = nng_http_res_get_header(res, "Content-Length")) == NULL) {
fprintf(stderr, "Missing Content-Length header.\n");
exit(1);
}
len = atoi(hdr);
if (len == 0) {
return (0);
}
// Allocate a buffer to receive the body data.
data = malloc(len);
// Set up a single iov to point to the buffer.
iov.iov_len = len;
iov.iov_buf = data;
// Following never fails with fewer than 5 elements.
nng_aio_set_iov(aio, 1, &iov);
// Now attempt to receive the data.
nng_http_conn_read_all(conn, aio);
// Wait for it to complete.
nng_aio_wait(aio);
if ((rv = nng_aio_result(aio)) != 0) {
fatal(rv);
}
fwrite(data, 1, len, stdout);
return (0);
}

View file

@ -0,0 +1,18 @@
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
cmake_minimum_required(VERSION 3.10)
project(pubsub_forwarder C)
# Find the nng library
find_package(nng REQUIRED)
# Add the executable target
add_executable(pubsub_forwarder pubsub_forwarder.c)
target_compile_options(pubsub_forwarder PRIVATE -Wall -Wextra -Wpedantic -Werror -O2)
# Link against the nng library
target_link_libraries(pubsub_forwarder PRIVATE nng)

View file

@ -0,0 +1,62 @@
= PubSub Forwarder
This is a trivial example of a forwarder/proxy for the pub/sub pattern.
The concept is as follows: the forwarder will listen for connections on
both a front-end port and a back-end port. The front-end will act as a
subscriber so that publishers can publish to it. The back-end will act
as a publisher so that subscribers can subscribe to it. The front-end
then forwards to the back end.
== Compiling
CMake with ninja-build is simplest:
[source, bash]
----
cmake -GNinja -B build
cd build
ninja
----
Or if you prefer a traditional approach,
the following is an example typical of UNIX and similar systems like
Linux and macOS may appeal:
[source, bash]
----
export CPPFLAGS="-I /usr/local/include"
export LDFLAGS="-L /usr/local/lib -lnng"
export CC="cc"
${CC} ${CPPFLAGS} pubsub_forwarder.c -o pubsub_forwarder ${LDFLAGS}
----
== Running
An example setup for running this example would involve the following:
. Step 1: Run this example binary (in the background or a terminal, etc)
. Step 2: In a new terminal, run the following
[source, bash]
----
nngcat --sub --dial "tcp://localhost:3328" --quoted
----
. Step 3: In a second terminal, run the same command again to give us two subscribers
[source, bash]
----
nngcat --sub --dial "tcp://localhost:3328" --quoted
----
. In a third terminal, run the following to publish a counter
[source, bash]
----
for n in $(seq 0 99); do nngcat --pub --dial "tcp://localhost:3327" --data "$n"; done
----

View file

@ -0,0 +1,96 @@
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
//
// Forwarder example based on https://github.com/C-o-r-E/nng_pubsub_proxy
//
// This example shows how to use raw sockets to set up a forwarder or proxy for
// pub/sub.
//
// An example setup for running this example would involve the following:
//
// - Run this example binary (in the background or a terminal, etc)
// - In a new terminal, run
// `nngcat --sub --dial "tcp://localhost:3328" --quoted`
// - In a second terminal, run
// `nngcat --sub --dial "tcp://localhost:3328" --quoted`
// - In a third terminal, run
// `for n in $(seq 0 99);`
// `do nngcat --pub --dial "tcp://localhost:3327" --data "$n";`
// `done`
//
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <nng/nng.h>
#include <nng/protocol/pubsub0/pub.h>
#include <nng/protocol/pubsub0/sub.h>
#define PROXY_FRONT_URL "tcp://localhost:3327"
#define PROXY_BACK_URL "tcp://localhost:3328"
void
panic_on_error(int should_panic, const char *format, ...)
{
if (should_panic) {
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
exit(EXIT_FAILURE);
}
}
int
main()
{
nng_socket sock_front_end = NNG_SOCKET_INITIALIZER;
nng_socket sock_back_end = NNG_SOCKET_INITIALIZER;
int ret = 0;
//
// First we need some nng sockets. Not to be confused with network
// sockets
//
ret = nng_sub0_open_raw(&sock_front_end);
panic_on_error(ret, "Failed to open front end socket\n");
ret = nng_pub0_open_raw(&sock_back_end);
panic_on_error(ret, "Failed to open back end socket\n");
//
// Now we need to set up a listener for each socket so that they have
// addresses
//
nng_listener front_ls = NNG_LISTENER_INITIALIZER;
nng_listener back_ls = NNG_LISTENER_INITIALIZER;
ret = nng_listener_create(&front_ls, sock_front_end, PROXY_FRONT_URL);
panic_on_error(ret, "Failed to create front listener\n");
ret = nng_listener_create(&back_ls, sock_back_end, PROXY_BACK_URL);
panic_on_error(ret, "Failed to create back listener\n");
ret = nng_listener_start(front_ls, 0);
panic_on_error(ret, "Failed to start front listener\n");
ret = nng_listener_start(back_ls, 0);
panic_on_error(ret, "Failed to start back listener\n");
//
// Finally let nng do the forwarding/proxying
//
ret = nng_device(sock_front_end, sock_back_end);
panic_on_error(
ret, "nng_device returned %d: %s\n", ret, nng_strerror(ret));
printf("done");
return 0;
}

22
external/nng/demo/raw/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,22 @@
#
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
cmake_minimum_required (VERSION 2.8.12)
project(raw)
set(PARALLEL 128 CACHE STRING "Parallelism (min 4, max 1000)")
find_package(nng CONFIG REQUIRED)
find_package(Threads)
add_executable(raw raw.c)
target_link_libraries(raw nng::nng)
target_compile_definitions(raw PRIVATE NNG_ELIDE_DEPRECATED PARALLEL=${PARALLEL})

64
external/nng/demo/raw/README.adoc vendored Normal file
View file

@ -0,0 +1,64 @@
= raw
This is a simple asynchronous demo, that demonstrates use of the RAW
sockets with a server, along with async message handling, to obtain a
very high level of asynchronous operation, suitable for use in a highly
concurrent server application.
== Compiling
You can override the level of concurrency with the `PARALLEL` option.
This determines how many requests the server will accept
at a time, and keep outstanding. Note that for our toy
implementation, we create this many "logical" flows of execution
(these are _NOT_ threads), where a request is followed by a reply.
The value of `PARALLEL` must be at least one, and may be as large
as your memory will permit. (The default value is 32.)
The best way to build is using cmake and Ninja build:
[source, bash]
----
% mkdir build
% cd build
% cmake -G Ninja ..
% ninja
----
You can also build the hard way. For example, on UNIX-style systems:
[source, bash]
----
% export CPPFLAGS="-D PARALLEL=32 -I /usr/local/include"
% export LDFLAGS="-L /usr/local/lib -lnng"
% export CC="cc"
% ${CC} ${CPPFLAGS} raw.c -o raw ${LDFLAGS}
----
== Running
To run the server, use the arguments `__url__ -s`.
To run the client, use the arguments `__url__ __msec__`.
The _msec_ is a "delay" time that server will wait before responding.
We have these delays so simulate long running work.
In the following example, all of the clients should complete within
2 seconds. (Assuming `PARALLEL` is defined to be large enough.)
[source,bash]
----
% export URL="tcp://127.0.0.1:55995"
# start the server
% ./raw $URL -s &
# start a bunch of clients
# Note that these all run concurrently!
% ./raw $URL 2 &
% ./raw $URL 2 &
% ./raw $URL 2 &
% ./raw $URL 2 &
% ./raw $URL 2 &
----

220
external/nng/demo/raw/raw.c vendored Normal file
View file

@ -0,0 +1,220 @@
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitoar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
// This program serves as an example for how to write an async RPC service,
// using the RAW request/reply pattern and nn_poll. The server receives
// messages and keeps them on a list, replying to them.
// Our demonstration application layer protocol is simple. The client sends
// a number of milliseconds to wait before responding. The server just gives
// back an empty reply after waiting that long.
// To run this program, start the server as async_demo <url> -s
// Then connect to it with the client as async_client <url> <msec>.
//
// For example:
//
// % ./async tcp://127.0.0.1:5555 -s &
// % ./async tcp://127.0.0.1:5555 323
// Request took 324 milliseconds.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <nng/nng.h>
#include <nng/protocol/reqrep0/rep.h>
#include <nng/protocol/reqrep0/req.h>
#include <nng/supplemental/util/platform.h>
// Parallel is the maximum number of outstanding requests we can handle.
// This is *NOT* the number of threads in use, but instead represents
// outstanding work items. Select a small number to reduce memory size.
// (Each one of these can be thought of as a request-reply loop.)
#ifndef PARALLEL
#define PARALLEL 32
#endif
// The server keeps a list of work items, sorted by expiration time,
// so that we can use this to set the timeout to the correct value for
// use in poll.
struct work {
enum { INIT, RECV, WAIT, SEND } state;
nng_aio * aio;
nng_socket sock;
nng_msg * msg;
};
void
fatal(const char *func, int rv)
{
fprintf(stderr, "%s: %s\n", func, nng_strerror(rv));
exit(1);
}
void
server_cb(void *arg)
{
struct work *work = arg;
nng_msg * msg;
int rv;
uint32_t when;
switch (work->state) {
case INIT:
work->state = RECV;
nng_recv_aio(work->sock, work->aio);
break;
case RECV:
if ((rv = nng_aio_result(work->aio)) != 0) {
fatal("nng_recv_aio", rv);
}
msg = nng_aio_get_msg(work->aio);
if ((rv = nng_msg_trim_u32(msg, &when)) != 0) {
// bad message, just ignore it.
nng_msg_free(msg);
nng_recv_aio(work->sock, work->aio);
return;
}
work->msg = msg;
work->state = WAIT;
nng_sleep_aio(when, work->aio);
break;
case WAIT:
// We could add more data to the message here.
nng_aio_set_msg(work->aio, work->msg);
work->msg = NULL;
work->state = SEND;
nng_send_aio(work->sock, work->aio);
break;
case SEND:
if ((rv = nng_aio_result(work->aio)) != 0) {
nng_msg_free(work->msg);
fatal("nng_send_aio", rv);
}
work->state = RECV;
nng_recv_aio(work->sock, work->aio);
break;
default:
fatal("bad state!", NNG_ESTATE);
break;
}
}
struct work *
alloc_work(nng_socket sock)
{
struct work *w;
int rv;
if ((w = nng_alloc(sizeof(*w))) == NULL) {
fatal("nng_alloc", NNG_ENOMEM);
}
if ((rv = nng_aio_alloc(&w->aio, server_cb, w)) != 0) {
fatal("nng_aio_alloc", rv);
}
w->state = INIT;
w->sock = sock;
return (w);
}
// The server runs forever.
int
server(const char *url)
{
nng_socket sock;
struct work *works[PARALLEL];
int rv;
int i;
/* Create the socket. */
rv = nng_rep0_open_raw(&sock);
if (rv != 0) {
fatal("nng_rep0_open", rv);
}
for (i = 0; i < PARALLEL; i++) {
works[i] = alloc_work(sock);
}
if ((rv = nng_listen(sock, url, NULL, 0)) != 0) {
fatal("nng_listen", rv);
}
for (i = 0; i < PARALLEL; i++) {
server_cb(works[i]); // this starts them going (INIT state)
}
for (;;) {
nng_msleep(3600000); // neither pause() nor sleep() portable
}
}
/* The client runs just once, and then returns. */
int
client(const char *url, const char *msecstr)
{
nng_socket sock;
int rv;
nng_msg * msg;
nng_time start;
nng_time end;
unsigned msec;
msec = atoi(msecstr) * 1000;
if ((rv = nng_req0_open(&sock)) != 0) {
fatal("nng_req0_open", rv);
}
if ((rv = nng_dial(sock, url, NULL, 0)) != 0) {
fatal("nng_dial", rv);
}
start = nng_clock();
if ((rv = nng_msg_alloc(&msg, 0)) != 0) {
fatal("nng_msg_alloc", rv);
}
if ((rv = nng_msg_append_u32(msg, msec)) != 0) {
fatal("nng_msg_append_u32", rv);
}
if ((rv = nng_sendmsg(sock, msg, 0)) != 0) {
fatal("nng_send", rv);
}
if ((rv = nng_recvmsg(sock, &msg, 0)) != 0) {
fatal("nng_recvmsg", rv);
}
end = nng_clock();
nng_msg_free(msg);
nng_close(sock);
printf("Request took %u milliseconds.\n", (uint32_t)(end - start));
return (0);
}
int
main(int argc, char **argv)
{
int rc;
if (argc < 3) {
fprintf(stderr, "Usage: %s <url> [-s|<secs>]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (strcmp(argv[2], "-s") == 0) {
rc = server(argv[1]);
} else {
rc = client(argv[1], argv[2]);
}
exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}

23
external/nng/demo/reqrep/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,23 @@
#
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
cmake_minimum_required (VERSION 2.8.12)
project(reqrep)
find_package(nng CONFIG REQUIRED)
find_package(Threads)
# Uncomment to enable ZeroTier transport
# find_package(zerotiercore)
add_executable(reqrep reqrep.c)
target_link_libraries(reqrep nng::nng)
target_compile_definitions(reqrep PRIVATE NNG_ELIDE_DEPRECATED)

59
external/nng/demo/reqrep/README.adoc vendored Normal file
View file

@ -0,0 +1,59 @@
= reqrep
This is a very simple RPC service using the REQ/REP method.
It is derived in part from Tim Dysinger's
http://nanomsg.org/gettingstarted/[Getting Started With Nanomsg]
examples, but we have updated for _nng_, and converted to use binary
frames across the wire instead of string data.
The protocol is simple:
* Client will send a 64-bit command (network byte order, i.e. big endian).
* Server sends a 64-bit response (also network byte order.)
The only command is "DATE", which has value 0x1. The value returned is
a UNIX timestamp (seconds since Jan 1, 1970.)
(We used 64-bit values for simplicity, and to avoid the Y2038 bug when
compiled on 64-bit systems.)
== Compiling
CMake with ninja-build is simplest:
[source, bash]
----
% mkdir build
% cd build
% cmake -G Ninja ..
% ninja
----
Or if you prefer a traditional approach,
the following is an example typical of UNIX and similar systems like
Linux and macOS may appeal:
[source, bash]
----
% export CPPFLAGS="-I /usr/local/include"
% export LDFLAGS="-L /usr/local/lib -lnng"
% export CC="cc"
% ${CC} ${CPPFLAGS} reqrep.c -o reqrep ${LDFLAGS}
----
== Running
You can run either the client or the server, and use whatever legal
_nng_ URL you like:
[source, bash]
----
% ./reqrep server tcp://127.0.0.1:8899 &
% ./reqrep client tcp://127.0.0.1:8899
CLIENT: SENDING DATE REQUEST
SERVER: RECEIVED DATE REQUEST
SERVER: SENDING DATE: Thu Feb 8 10:26:18 2018
CLIENT: RECEIVED DATE: Thu Feb 8 10:26:18 2018
----

216
external/nng/demo/reqrep/reqrep.c vendored Normal file
View file

@ -0,0 +1,216 @@
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2021 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
//
// This is just a simple REQ/REP demonstration application. It is derived
// from the legacy nanomsg demonstration program of the same name, written
// by Tim Dysinger, but updated for nng. I've also updated it to pass simpler
// binary data rather than strings over the network.
//
// The program implements a simple RPC style service, which just returns
// the date in UNIX time (seconds since 1970).
//
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <nng/nng.h>
#include <nng/protocol/reqrep0/rep.h>
#include <nng/protocol/reqrep0/req.h>
#include <nng/transport/zerotier/zerotier.h>
#include <nng/supplemental/util/platform.h>
#define CLIENT "client"
#define SERVER "server"
#define DATECMD 1
#define PUT64(ptr, u) \
do { \
(ptr)[0] = (uint8_t)(((uint64_t)(u)) >> 56); \
(ptr)[1] = (uint8_t)(((uint64_t)(u)) >> 48); \
(ptr)[2] = (uint8_t)(((uint64_t)(u)) >> 40); \
(ptr)[3] = (uint8_t)(((uint64_t)(u)) >> 32); \
(ptr)[4] = (uint8_t)(((uint64_t)(u)) >> 24); \
(ptr)[5] = (uint8_t)(((uint64_t)(u)) >> 16); \
(ptr)[6] = (uint8_t)(((uint64_t)(u)) >> 8); \
(ptr)[7] = (uint8_t)((uint64_t)(u)); \
} while (0)
#define GET64(ptr, v) \
v = (((uint64_t)((uint8_t)(ptr)[0])) << 56) + \
(((uint64_t)((uint8_t)(ptr)[1])) << 48) + \
(((uint64_t)((uint8_t)(ptr)[2])) << 40) + \
(((uint64_t)((uint8_t)(ptr)[3])) << 32) + \
(((uint64_t)((uint8_t)(ptr)[4])) << 24) + \
(((uint64_t)((uint8_t)(ptr)[5])) << 16) + \
(((uint64_t)((uint8_t)(ptr)[6])) << 8) + \
(((uint64_t)(uint8_t)(ptr)[7]))
void
fatal(const char *func, int rv)
{
fprintf(stderr, "%s: %s\n", func, nng_strerror(rv));
exit(1);
}
void
showdate(time_t now)
{
struct tm *info = localtime(&now);
printf("%s", asctime(info));
}
int
server(const char *url)
{
nng_socket sock;
nng_listener listener;
int rv;
int count = 0;
if ((rv = nng_rep0_open(&sock)) != 0) {
fatal("nng_rep0_open", rv);
}
if ((rv = nng_listener_create(&listener, sock, url)) != 0) {
fatal("nng_listener_create", rv);
}
if (strncmp(url, "zt://", 5) == 0) {
printf("ZeroTier transport will store its keys in current working directory.\n");
printf("The server and client instances must run in separate directories.\n");
nng_listener_set_string(listener, NNG_OPT_ZT_HOME, ".");
nng_listener_set_ms(listener, NNG_OPT_RECONNMINT, 1);
nng_listener_set_ms(listener, NNG_OPT_RECONNMAXT, 1000);
nng_socket_set_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000);
nng_socket_set_ms(sock, NNG_OPT_RECVMAXSZ, 0);
nng_listener_set_ms(listener, NNG_OPT_ZT_PING_TIME, 10000);
nng_listener_set_ms(listener, NNG_OPT_ZT_CONN_TIME, 1000);
} else {
nng_socket_set_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000);
}
nng_listener_start(listener, 0);
for (;;) {
char * buf = NULL;
size_t sz;
uint64_t val;
count++;
if ((rv = nng_recv(sock, &buf, &sz, NNG_FLAG_ALLOC)) != 0) {
fatal("nng_recv", rv);
}
if ((sz == sizeof(uint64_t)) &&
((GET64(buf, val)) == DATECMD)) {
time_t now;
printf("SERVER: RECEIVED DATE REQUEST\n");
now = time(&now);
if (count == 6) {
printf("SERVER: SKIP SENDING REPLY\n");
nng_free(buf, sz);
continue;
}
printf("SERVER: SENDING DATE: ");
showdate(now);
// Reuse the buffer. We know it is big enough.
PUT64(buf, (uint64_t) now);
rv = nng_send(sock, buf, sz, NNG_FLAG_ALLOC);
if (rv != 0) {
fatal("nng_send", rv);
}
continue;
}
// Unrecognized command, so toss the buffer.
nng_free(buf, sz);
}
}
int
client(const char *url)
{
nng_socket sock;
nng_dialer dialer;
int rv;
size_t sz;
char * buf = NULL;
uint8_t cmd[sizeof(uint64_t)];
int sleep = 0;
PUT64(cmd, DATECMD);
if ((rv = nng_req0_open(&sock)) != 0) {
fatal("nng_socket", rv);
}
if ((rv = nng_dialer_create(&dialer, sock, url)) != 0) {
fatal("nng_dialer_create", rv);
}
if (strncmp(url, "zt://", 5) == 0) {
printf("ZeroTier transport will store its keys in current working directory\n");
printf("The server and client instances must run in separate directories.\n");
nng_dialer_set_string(dialer, NNG_OPT_ZT_HOME, ".");
nng_dialer_set_ms(dialer, NNG_OPT_RECONNMINT, 1);
nng_dialer_set_ms(dialer, NNG_OPT_RECONNMAXT, 1000);
nng_socket_set_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000);
nng_socket_set_ms(sock, NNG_OPT_RECVMAXSZ, 0);
nng_dialer_set_ms(dialer, NNG_OPT_ZT_PING_TIME, 10000);
nng_dialer_set_ms(dialer, NNG_OPT_ZT_CONN_TIME, 1000);
} else {
nng_socket_set_ms(sock, NNG_OPT_REQ_RESENDTIME, 2000);
}
nng_dialer_start(dialer, NNG_FLAG_NONBLOCK);
while (1) {
printf("CLIENT: SENDING DATE REQUEST\n");
if ((rv = nng_send(sock, cmd, sizeof(cmd), 0)) != 0) {
fatal("nng_send", rv);
}
if ((rv = nng_recv(sock, &buf, &sz, NNG_FLAG_ALLOC)) != 0) {
fatal("nng_recv", rv);
}
if (sz == sizeof(uint64_t)) {
uint64_t now;
GET64(buf, now);
printf("CLIENT: RECEIVED DATE: ");
showdate((time_t) now);
} else {
printf("CLIENT: GOT WRONG SIZE!\n");
}
nng_msleep(sleep);
sleep++;
if (sleep == 4) {
sleep = 4000;
}
}
// This assumes that buf is ASCIIZ (zero terminated).
nng_free(buf, sz);
nng_close(sock);
return (0);
}
int
main(const int argc, const char **argv)
{
if ((argc > 1) && (strcmp(CLIENT, argv[1]) == 0))
return (client(argv[2]));
if ((argc > 1) && (strcmp(SERVER, argv[1]) == 0))
return (server(argv[2]));
fprintf(stderr, "Usage: reqrep %s|%s <URL> ...\n", CLIENT, SERVER);
return (1);
}

20
external/nng/demo/rest/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,20 @@
#
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
cmake_minimum_required (VERSION 2.8.12)
project(rest)
find_package(nng CONFIG REQUIRED)
find_package(Threads)
add_executable(rest-server server.c)
target_link_libraries(rest-server nng::nng)
target_compile_definitions(rest-server PRIVATE NNG_ELIDE_DEPRECATED)

45
external/nng/demo/rest/README.adoc vendored Normal file
View file

@ -0,0 +1,45 @@
= REST API Gateway demo
This is a somewhat contrived demonstration, but may be useful
in a pattern for solving real world problems.
There is a single "server" (rest-server) program, that does these:
. REST API at /api/rest/rot13 - this API takes data from HTTP POST commands,
and forwards them to an NNG REQ socket. When the REQ response comes,
the reply is redirected back to the server. (For the purposes of the
demonstration, our server just performs ROT13 on input.)
. REP server (implemented in the same program using inproc, for demonstration
purposes. In a real world scenario this might instead go to another
process on another computer.)
[source, bash]
----
% env PORT=8888 # default
% ./rest-server &
% curl -d ABC http://127.0.0.1:8888/api/rest/rot13; echo
NOP
% curl -d NOP http://127.0.0.1:8888/api/rest/rot13; echo
ABC
----
== Compiling
To build the program, we recommend CMake and Ninja-Build.
[source, bash]
----
% mkdir build
% cd build
% cmake -G Ninja ..
% ninja
----
Alternatively, you can go old-school.
Here's the simplest option for Linux:
[source, bash]
----
% cc server.c -o rest-server -I /usr/local/include -lnng
----

372
external/nng/demo/rest/server.c vendored Normal file
View file

@ -0,0 +1,372 @@
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
#define INPROC_URL "inproc://rot13"
#define REST_URL "http://127.0.0.1:%u/api/rest/rot13"
// REST API -> NNG REP server demonstration.
// This is a silly demo -- it listens on port 8888 (or $PORT if present),
// and accepts HTTP POST requests at /api/rest/rot13
//
// These requests are converted into an NNG REQ message, and sent to an
// NNG REP server (builtin inproc_server, for demonstration purposes only).
// The reply is obtained from the server, and sent back to the client via
// the HTTP server framework.
// Example usage:
//
// % export CPPFLAGS="-I /usr/local/include"
// % export LDFLAGS="-L /usr/local/lib -lnng"
// % export CC="cc"
// % ${CC} ${CPPFLAGS} server.c -o server ${LDFLAGS}
// % ./server &
// % curl -d TEST http://127.0.0.1:8888/api/rest/rot13
// GRFG
//
#include <nng/nng.h>
#include <nng/protocol/reqrep0/rep.h>
#include <nng/protocol/reqrep0/req.h>
#include <nng/supplemental/http/http.h>
#include <nng/supplemental/util/platform.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// utility function
void
fatal(const char *what, int rv)
{
fprintf(stderr, "%s: %s\n", what, nng_strerror(rv));
exit(1);
}
// This server acts as a proxy. We take HTTP POST requests, convert them to
// REQ messages, and when the reply is received, send the reply back to
// the original HTTP client.
//
// The state flow looks like:
//
// 1. Receive HTTP request & headers
// 2. Receive HTTP request (POST) data
// 3. Send POST payload as REQ body
// 4. Receive REP reply (including payload)
// 5. Return REP message body to the HTTP server (which forwards to client)
// 6. Restart at step 1.
//
// The above flow is pretty linear, and so we use contexts (nng_ctx) to
// obtain parallelism.
typedef enum {
SEND_REQ, // Sending REQ request
RECV_REP, // Receiving REQ reply
} job_state;
typedef struct rest_job {
nng_aio * http_aio; // aio from HTTP we must reply to
nng_http_res * http_res; // HTTP response object
job_state state; // 0 = sending, 1 = receiving
nng_msg * msg; // request message
nng_aio * aio; // request flow
nng_ctx ctx; // context on the request socket
struct rest_job *next; // next on the freelist
} rest_job;
nng_socket req_sock;
// We maintain a queue of free jobs. This way we don't have to
// deallocate them from the callback; we just reuse them.
nng_mtx * job_lock;
rest_job *job_freelist;
static void rest_job_cb(void *arg);
static void
rest_recycle_job(rest_job *job)
{
if (job->http_res != NULL) {
nng_http_res_free(job->http_res);
job->http_res = NULL;
}
if (job->msg != NULL) {
nng_msg_free(job->msg);
job->msg = NULL;
}
if (nng_ctx_id(job->ctx) != 0) {
nng_ctx_close(job->ctx);
}
nng_mtx_lock(job_lock);
job->next = job_freelist;
job_freelist = job;
nng_mtx_unlock(job_lock);
}
static rest_job *
rest_get_job(void)
{
rest_job *job;
nng_mtx_lock(job_lock);
if ((job = job_freelist) != NULL) {
job_freelist = job->next;
nng_mtx_unlock(job_lock);
job->next = NULL;
return (job);
}
nng_mtx_unlock(job_lock);
if ((job = calloc(1, sizeof(*job))) == NULL) {
return (NULL);
}
if (nng_aio_alloc(&job->aio, rest_job_cb, job) != 0) {
free(job);
return (NULL);
}
return (job);
}
static void
rest_http_fatal(rest_job *job, const char *fmt, int rv)
{
char buf[128];
nng_aio * aio = job->http_aio;
nng_http_res *res = job->http_res;
job->http_res = NULL;
job->http_aio = NULL;
snprintf(buf, sizeof(buf), fmt, nng_strerror(rv));
nng_http_res_set_status(res, NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR);
nng_http_res_set_reason(res, buf);
nng_aio_set_output(aio, 0, res);
nng_aio_finish(aio, 0);
rest_recycle_job(job);
}
static void
rest_job_cb(void *arg)
{
rest_job *job = arg;
nng_aio * aio = job->aio;
int rv;
switch (job->state) {
case SEND_REQ:
if ((rv = nng_aio_result(aio)) != 0) {
rest_http_fatal(job, "send REQ failed: %s", rv);
return;
}
job->msg = NULL;
// Message was sent, so now wait for the reply.
nng_aio_set_msg(aio, NULL);
job->state = RECV_REP;
nng_ctx_recv(job->ctx, aio);
break;
case RECV_REP:
if ((rv = nng_aio_result(aio)) != 0) {
rest_http_fatal(job, "recv reply failed: %s", rv);
return;
}
job->msg = nng_aio_get_msg(aio);
// We got a reply, so give it back to the server.
rv = nng_http_res_copy_data(job->http_res,
nng_msg_body(job->msg), nng_msg_len(job->msg));
if (rv != 0) {
rest_http_fatal(job, "nng_http_res_copy_data: %s", rv);
return;
}
// Set the output - the HTTP server will send it back to the
// user agent with a 200 response.
nng_aio_set_output(job->http_aio, 0, job->http_res);
nng_aio_finish(job->http_aio, 0);
job->http_aio = NULL;
job->http_res = NULL;
// We are done with the job.
rest_recycle_job(job);
return;
default:
fatal("bad case", NNG_ESTATE);
break;
}
}
// Our rest server just takes the message body, creates a request ID
// for it, and sends it on. This runs in raw mode, so
void
rest_handle(nng_aio *aio)
{
struct rest_job *job;
nng_http_req * req = nng_aio_get_input(aio, 0);
nng_http_conn * conn = nng_aio_get_input(aio, 2);
const char * clen;
size_t sz;
nng_iov iov;
int rv;
void * data;
if ((job = rest_get_job()) == NULL) {
nng_aio_finish(aio, NNG_ENOMEM);
return;
}
if (((rv = nng_http_res_alloc(&job->http_res)) != 0) ||
((rv = nng_ctx_open(&job->ctx, req_sock)) != 0)) {
rest_recycle_job(job);
nng_aio_finish(aio, rv);
return;
}
nng_http_req_get_data(req, &data, &sz);
job->http_aio = aio;
if ((rv = nng_msg_alloc(&job->msg, sz)) != 0) {
rest_http_fatal(job, "nng_msg_alloc: %s", rv);
return;
}
memcpy(nng_msg_body(job->msg), data, sz);
nng_aio_set_msg(job->aio, job->msg);
job->state = SEND_REQ;
nng_ctx_send(job->ctx, job->aio);
}
void
rest_start(uint16_t port)
{
nng_http_server * server;
nng_http_handler *handler;
char rest_addr[128];
nng_url * url;
int rv;
if ((rv = nng_mtx_alloc(&job_lock)) != 0) {
fatal("nng_mtx_alloc", rv);
}
job_freelist = NULL;
// Set up some strings, etc. We use the port number
// from the argument list.
snprintf(rest_addr, sizeof(rest_addr), REST_URL, port);
if ((rv = nng_url_parse(&url, rest_addr)) != 0) {
fatal("nng_url_parse", rv);
}
// Create the REQ socket, and put it in raw mode, connected to
// the remote REP server (our inproc server in this case).
if ((rv = nng_req0_open(&req_sock)) != 0) {
fatal("nng_req0_open", rv);
}
if ((rv = nng_dial(req_sock, INPROC_URL, NULL, NNG_FLAG_NONBLOCK)) !=
0) {
fatal("nng_dial(" INPROC_URL ")", rv);
}
// Get a suitable HTTP server instance. This creates one
// if it doesn't already exist.
if ((rv = nng_http_server_hold(&server, url)) != 0) {
fatal("nng_http_server_hold", rv);
}
// Allocate the handler - we use a dynamic handler for REST
// using the function "rest_handle" declared above.
rv = nng_http_handler_alloc(&handler, url->u_path, rest_handle);
if (rv != 0) {
fatal("nng_http_handler_alloc", rv);
}
if ((rv = nng_http_handler_set_method(handler, "POST")) != 0) {
fatal("nng_http_handler_set_method", rv);
}
// We want to collect the body, and we (arbitrarily) limit this to
// 128KB. The default limit is 1MB. You can explicitly collect
// the data yourself with another HTTP read transaction by disabling
// this, but that's a lot of work, especially if you want to handle
// chunked transfers.
if ((rv = nng_http_handler_collect_body(handler, true, 1024 * 128)) !=
0) {
fatal("nng_http_handler_collect_body", rv);
}
if ((rv = nng_http_server_add_handler(server, handler)) != 0) {
fatal("nng_http_handler_add_handler", rv);
}
if ((rv = nng_http_server_start(server)) != 0) {
fatal("nng_http_server_start", rv);
}
nng_url_free(url);
}
//
// inproc_server - this just is a simple REP server that listens for
// messages, and performs ROT13 on them before sending them. This
// doesn't have to be in the same process -- it is hear for demonstration
// simplicity only. (Most likely this would be somewhere else.) Note
// especially that this uses inproc, so nothing can get to it directly
// from outside the process.
//
void
inproc_server(void *arg)
{
nng_socket s;
int rv;
nng_msg * msg;
if (((rv = nng_rep0_open(&s)) != 0) ||
((rv = nng_listen(s, INPROC_URL, NULL, 0)) != 0)) {
fatal("unable to set up inproc", rv);
}
// This is simple enough that we don't need concurrency. Plus it
// makes for an easier demo.
for (;;) {
char *body;
if ((rv = nng_recvmsg(s, &msg, 0)) != 0) {
fatal("inproc recvmsg", rv);
}
body = nng_msg_body(msg);
for (int i = 0; i < nng_msg_len(msg); i++) {
// Table lookup would be faster, but this works.
if (isupper(body[i])) {
char base = body[i] - 'A';
base = (base + 13) % 26;
body[i] = base + 'A';
} else if (islower(body[i])) {
char base = body[i] - 'a';
base = (base + 13) % 26;
body[i] = base + 'a';
}
}
if ((rv = nng_sendmsg(s, msg, 0)) != 0) {
fatal("inproc sendmsg", rv);
}
}
}
int
main(int argc, char **argv)
{
int rv;
nng_thread *inproc_thr;
uint16_t port = 0;
rv = nng_thread_create(&inproc_thr, inproc_server, NULL);
if (rv != 0) {
fatal("cannot start inproc server", rv);
}
if (getenv("PORT") != NULL) {
port = (uint16_t) atoi(getenv("PORT"));
}
port = port ? port : 8888;
rest_start(port);
// This runs forever. The inproc_thr never exits, so we
// just block behind its condition variable.
nng_thread_destroy(inproc_thr);
}

27
external/nng/demo/stream/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,27 @@
#
# Copyright 2020 Hugo Lindström <hugolm84@gmail.com>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
cmake_minimum_required (VERSION 2.8.7)
project(stream)
find_package(nng CONFIG REQUIRED)
add_executable(${PROJECT_NAME})
target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/stream.c)
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/platform/posix/server.c)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/platform/windows/server.c)
endif()
target_link_libraries(stream nng::nng)

View file

@ -0,0 +1,53 @@
// Copyright 2020 Hugo Lindström <hugolm84@gmail.com>
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <unistd.h>
void
error(const char *msg)
{
perror(msg);
exit(1);
}
int
server(int portno)
{
int sockfd, newsockfd;
socklen_t clilen;
struct sockaddr_in serv_addr, cli_addr;
int n;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
error("ERROR opening socket");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) <
0) {
error("ERROR on binding");
}
listen(sockfd, 5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
error("ERROR on accept");
}
n = write(newsockfd, "Hello Client!", 13);
if (n < 0)
error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
}

View file

@ -0,0 +1,87 @@
// Copyright 2020 Hugo Lindström <hugolm84@gmail.com>
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
void
wsa_fatal(const char *func)
{
fprintf(stderr, "%s: %d\n", func, WSAGetLastError());
exit(1);
}
int
server(int portno)
{
WSADATA wsa;
SOCKET s, new_socket;
struct sockaddr_in server, client;
int c;
char * message;
printf("Initialising Winsock...\n");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
wsa_fatal("Failed to call WSAStartup");
}
printf("Initialised WSA.\n");
// Create a socket
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
wsa_fatal("Could not create socket");
}
printf("Socket created.\n");
// Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(portno);
// Bind
if (bind(s, (struct sockaddr *) &server, sizeof(server)) ==
SOCKET_ERROR) {
wsa_fatal("Bind failed");
}
printf("Bind done\n");
// Listen to incoming connections
listen(s, 3);
// Accept and incoming connection
printf("Waiting for incoming connections...\n");
c = sizeof(struct sockaddr_in);
while ((new_socket = accept(s, (struct sockaddr *) &client, &c)) !=
INVALID_SOCKET) {
printf("Connection accepted\n");
// Reply to the client
message = "Hello Client!";
if (send(new_socket, message, (int) strlen(message), 0) ==
SOCKET_ERROR) {
wsa_fatal("Failed to send message to client!");
}
}
if (new_socket == INVALID_SOCKET) {
wsa_fatal("accept failed");
}
if (closesocket(s) == SOCKET_ERROR) {
wsa_fatal("Failed to close socket");
}
if (WSACleanup() == SOCKET_ERROR) {
wsa_fatal("Failed to WSACleanup");
}
return 0;
}

109
external/nng/demo/stream/stream.c vendored Normal file
View file

@ -0,0 +1,109 @@
// Copyright 2020 Hugo Lindström <hugolm84@gmail.com>
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
// This program serves as an example for how to write async communication with
// an arbitrary socket using nng_stream. The server receives a connection and
// sends a hello message to the nng_stream iov.
// To run this program, start the server as stream -s <portnumber>
// Then connect to it with the client as stream -c <url>
//
// For example:
//
// % ./stream -s 5555 &
// % ./stream -c tcp://127.0.0.1:5555
#include <nng/nng.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void
nng_fatal(const char *func, int rv)
{
fprintf(stderr, "%s: %s\n", func, nng_strerror(rv));
exit(1);
}
int server(int port);
int client(const char *url);
int
main(int argc, char **argv)
{
int rc;
if (argc < 3) {
fprintf(stderr, "Usage: %s [-s port|-c url]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (strcmp(argv[1], "-s") == 0) {
rc = server(atoi(argv[2]));
} else {
rc = client(argv[2]);
}
exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
int
client(const char *url)
{
nng_stream_dialer *dialer;
nng_aio * aio;
nng_iov iov;
int rv;
// Allocatate dialer and aio assoicated with this connection
if ((rv = nng_stream_dialer_alloc(&dialer, url)) != 0) {
nng_fatal("call to nng_stream_dialer_alloc failed", rv);
}
if ((rv = nng_aio_alloc(&aio, NULL, NULL)) != 0) {
nng_fatal("call to nng_aio_alloc", rv);
}
nng_aio_set_timeout(aio, 5000); // 5 sec
// Allocatate a buffer to recv
iov.iov_len = 100;
iov.iov_buf = (char *) malloc(sizeof(char) * iov.iov_len);
if ((rv = nng_aio_set_iov(aio, 1, &iov)) != 0) {
nng_fatal("call to nng_aio_alloc", rv);
}
// Connect to the socket via url provided to alloc
nng_stream_dialer_dial(dialer, aio);
// Wait for connection
nng_aio_wait(aio);
if ((rv = nng_aio_result(aio)) != 0) {
nng_fatal("waiting for ng_stream_dialer_dial failed", rv);
}
// Get the stream (connection) at position 0
nng_stream *c1 = (nng_stream *) nng_aio_get_output(aio, 0);
nng_stream_recv(c1, aio);
nng_aio_wait(aio);
if ((rv = nng_aio_result(aio)) != 0) {
nng_fatal("waiting for nng_stream_recv failed", rv);
}
size_t recv_count = nng_aio_count(aio);
if (recv_count <= 0) {
nng_fatal("Recv count was 0!", NNG_ECONNABORTED);
} else {
printf("received %zu bytes, message: '%s'\n", recv_count,
(char *) iov.iov_buf);
}
// Send ELCOSE to send/recv associated wit this stream
free(iov.iov_buf);
nng_stream_free(c1);
nng_aio_free(aio);
nng_stream_dialer_free(dialer);
return 0;
}

84
external/nng/docs/BUILD_ANDROID.adoc vendored Normal file
View file

@ -0,0 +1,84 @@
ifdef::env-github[]
:note-caption: :information_source:
endif::[]
= Building for Android
NOTE: This work has received only cursory testing. As always, _caveat emptor_.
== Pre-Requisites
Android Studio:::
There are probably other ways to cross-build for Android, but if you're
not using Android Studio, then you probably don't need much help here.
Android NDK::
A copy of the Android NDK is required to build native code applications.
Android Studio has information for downloading it within the app.
== Steps
You need to use the CMake that is included with Android Studio, because
it knows how to build the Gradle targets. (At least on macOS, the system
default cmake does not have the right generator support.)
You will also use the Android toolchain file for CMake that is included
with the NDK.
NOTE: You *must* use the _NDK_ toolchain, not the one that came with the _SDK_.
The _SDK_ toolchain file is too old and will not work with modern NDKs!
When building for Android, by default we build static libraries, and
we do not build tools or tests. The tools and tests won't work since
they assume a shell environment, and you don't want to deal with the
dependency nightmare that is dynamic libraries anyway. Trust us.
The Android NDK includes documentation for how to run
CMake including the options that can be set. Details are located
here: https://developer.android.com/ndk/guides/cmake
TIP: It is *highly* recommended you review the NDK documentation,
because you will most likely want to change some of the default values
for the ABI or API level.
For the sake of clarity, we are assuming only the defaults here.
Set the following environment variables:
`CMAKE`::
Path to the Android SDK supplied CMake binary. For example, on
our macOS install of Android Studio, we have it located in
`$HOME/Library/Android/sdk/cmake/3.6.4111459/bin/cmake`.
`NDK`::
Path to the Android NDK. In the same installation, on our system,
it is in `$HOME/Library/Android/sdk/ndk-bundle`
Using the above toolchain file, we can build for Android using
the CMake standard `CMAKE_TOOLCHAIN_FILE` macro, and using the
Android supplied CMake:
If you have checked out this repository in `$SRC`, and your copy of the
Android SDK is located in `$SDK`, the following should work:
[source, sh]
----
% cd $SRC
% mkdir android-build
% cd android-build
% ${CMAKE} -DCMAKE_TOOLCHAIN_FILE=${NDK}/build/cmake/android.toolchain.cmake ..
----
Then you can build using Xcode, or simply use cmake to drive the build:
[source, sh]
----
% ${CMAKE} --build .
----
Extra effort may be required to enable the use of mbedTLS; you will
need to review the mbedTLS documentation for configuring that for use
in Android.

View file

@ -0,0 +1,49 @@
ifdef::env-github[]
:note-caption: :information_source:
endif::[]
= Building for Cross Compilation
TIP: Cross-compiling is used when the operating system or process architecure
the software is being built for is different than the system where the software
is being compiled. If you don't know what this means, this does not apply to
and you should ignore this file.
When building for cross-compilation, you can use CMake's native support
`CMAKE_TOOLCHAIN_FILE` to configure the location of the toolchain.
You'll need that toolchain to have your compiler, linker, header files,
and possibly any other libraries that need to be linked at build time.
This is all relatively standard stuff for CMake.
A lot more detail is located here: https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/CrossCompiling
NOTE: When _NNG_ detects that it is being built in a Cross-Compile
situation (i.e. when `CMAKE_CROSSCOMPILING` is true), it will default
to disabling the building of the test suite and tools.
This is normally preferable, since many embedded environments cannot host
command line applications or shell environments. +
+
To enable tools or tests to build anyway, the values of either
`NNG_TOOLS` or `NNG_TESTS` (or both) may be set to `ON`.
== Cross-compiling for Android
More details for Android are located in the <<BUILD_ANDROID.adoc>> file.
== Cross-compiling for iOS
More details for iOS (and tvOS, etc.) are located in the <<BUILD_IOS.adoc>> file.
== Cross-compiling for Windows or Linux or MACOS - Using vcpkg
You can download and install nng using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install nng
The nng port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.

65
external/nng/docs/BUILD_IOS.adoc vendored Normal file
View file

@ -0,0 +1,65 @@
ifdef::env-github[]
:note-caption: :information_source:
endif::[]
= Building for iOS (and tvOS, watchOS)
NOTE: This work has had only minimal validation. As always, _caveat emptor_.
== Pre-Requisites
macOS::
As far as we know, the only way to build iOS applications is on a
macOS host system.
Xcode::
You will need Xcode. We tested this with Xcode 9.3.
CMake::
We tested this with CMake 3.9. Other versions may work.
iOS cmake toolchain file::
At the time of this writing (May 28, 2018), the toolchain file
located at https://github.com/leetal/ios-cmake is appears to work
reasonably well.
== Steps
When building for iOS and similar targets, only static libraries may be built.
(This is good for avoiding dependency nightmares anyway.)
Using the above toolchain file, we can build for iOS using
the CMake standard CMAKE_TOOLCHAIN_FILE macro, and using
the IOS_PLATFORM macro to set the target. (See the iOS CMake
toolchain README for valid options; we select "OS" for iOS.)
The test suite and command line tools will automatically be removed
from the build, since they aren't interesting or useful in cross-compile
environment. (There is no way to run them.)
If you have checked out this repository in $SRC, the following should work:
[source, sh]
----
% cd $SRC
% mkdir ios-build
% cd ios-build
% git clone https://github.com/leetal/ios-cmake
% cmake -G Xcode \
-DCMAKE_TOOLCHAIN_FILE=`pwd`/ios-cmake/ios.toolchain.cmake \
-DIOS_PLATFORM=OS ..
----
Then you can build using Xcode, or simply use cmake to drive the build:
[source, sh]
----
% cmake --build .
----
Extra effort may be required to enable the use of mbedTLS (NNG does not
at the time of writing support Secure Transport. See issue #497 for status.)

60
external/nng/docs/BUILD_TLS.adoc vendored Normal file
View file

@ -0,0 +1,60 @@
ifdef::env-github[]
:important-caption: :heavy_exclamation_mark:
endif::[]
= Building for TLS Support
If you want to include support for Transport Layer Security
(tls+tcp:// and wss:// URLs) you should follow these directions.
At this time, TLS support depends on the https://tls.mbed.org/[Mbed TLS]
library.
IMPORTANT: Mbed TLS is licensed under different terms than NNG.
You are responsible for reading those license terms, and ensuring
that your use conforms to them.
On many distributions you may be able to install a pre-packaged version
of Mbed TLS. We recommend doing so if this is an option for you.
For example, Ubuntu users can install the `libmbedtls-dev` package.
You can also build Mbed TLS from source; if you choose to do so,
please make sure you also *install* it somewhere (even a temporary
staging directory).
== Configuring NNG with Mbed TLS
TLS support is not enabled by default, but can be enabled by configuring
with the CMake option `NNG_ENABLE_TLS=ON`.
By default NNG searches for an installed copy of Mbed TLS in `/usr/local`,
as well as the normal installation directories for libraries on your system.
If you have installed Mbed TLS elsewhere, you can direct the NNG configuration
to it by setting the `MBEDTLS_ROOT_DIR` CMake variable.
== Example
The following example would work on either Linux or macOS, and assumes
that we have checked out github source trees into `$HOME/work`.
It also assumes that Mbed TLS is already installed in /usr/local or
a standard search path.
[source, sh]
----
$ export NNGDIR=$HOME/work/nng
$ mkdir build
$ cd build
$ cmake -DNNG_ENABLE_TLS=ON ..
... (lots of lines of output from cmake...)
$ make
... (lots of lines of output from make...)
$ ./tests/tls
ok ./tests/tls 1.503s
----

80
external/nng/docs/BUILD_ZEROTIER.adoc vendored Normal file
View file

@ -0,0 +1,80 @@
ifdef::env-github[]
:important-caption: :heavy_exclamation_mark:
endif::[]
= Building for ZeroTier Support
If you want to include support for the experimental ZeroTier
transport (`zt://` URLs), you should follow these directions.
Staysail has created a package that builds a clean CMake project
that you can import.
Download this from https://github.com/staysail/libzerotiercore[GitHub].
IMPORTANT: ZeroTierOne is licensed under different terms than NNG.
You are responsible for reading those license terms, and ensuring that
your use conforms to them.
IMPORTANT: The ZeroTier transport, and these build instructions,
are experimental.
We expect both to change over time as ZeroTier and the NNG `zt://` transport
both mature.
As always, _caveat emptor_.
== Building libzerotiercore
Using "CMake", you can build libzerotiercore
using any normal CMake generator.
You should install it as well.
Normally it will install into `/usr/local` on
Linux and UNIX systems.
== Configuring NNG with ZT
You will need to enable ZeroTier within NNG using the CMake option `NNG_TRANSPORT_ZEROTIER=ON`.
If you have installed the libzerotiercore in
one of the default locations, then that should be all
that is needed.
If you have specified a different location, you will
need to inform CMake of this by setting the CMake
variable `-Dzerotier_DIR=<where you installed it>`
== Example
The following example would work on either Linux or macOS, and assumes
that we have checked out github source trees into `$HOME/work`.
[source, sh]
----
$ export NNGDIR=$HOME/work/nng
$ export ZTDIR=$HOME/work/libzerotiercore
$ git clone https://github.com/staysail/libzerotiercore $ZTDIR
$ cd $ZTDIR
$ mkdir build
$ cd build
$ cmake ..
... (lots of lines of output from cmake...)
$ make
... (lots of lines of output from make...)
$ make install
$ cd $NNGDIR
$ mkdir build
$ cd build
$ cmake -DNNG_TRANSPORT_ZEROTIER=ON ..
... (lots of lines of output from cmake...)
$ make
... (lots of lines of output from make...)
$ ./tests/zt
ok ./tests/zt 22.837s
----

129
external/nng/docs/CONTRIBUTING.adoc vendored Normal file
View file

@ -0,0 +1,129 @@
= NNG Contributing Guidelines
Legal stuff:
For any submission you make to us, either by filing an issue, or submitting a
defect, or sending us a message, you agree and certify that:
** You are the author or legal owner of the content submitted, or
you have authorization to submit the content by the owner
(such as your employer).
** Unless the submission is otherwise labeled, you or the owner
are granting the NNG Project, its contributors, and licensees,
a non-exclusive license to your use submission under the terms of
MIT License (as documented in the <<LICENSE#,LICENSE>> file in this
repository.) This grant shall include a right to use for any
patents covering content in the submission.
** You are not aware of any legal encumbrances to the use of the
submission (such as patents held by others) unless explicitly
stated otherwise.
** You have read, and agree to abide by, our
<<CODE_OF_CONDUCT#,Code of Conduct>>.
** You understand that participation in this project is voluntary,
and at no point shall any of the project members or leadership
be obligated to review, merge, or handle any submission.
== Filing Issues
We use github issues for NNG. We ask that you keep in mind the following
when filing issues:
* First look to see if your issue is already covered by an existing issue.
* Synopsis should be brief, but descriptive. (We may alter the synopsis
to correct its accuracy or improve its brevity.)
* Include details about the platform (operating system, language).
* Include CMake configuration used to build NNG.
* Include expected results or behavior, and observed results or behavior.
* If at all possible, a reproducible test case is helpful. We prefer test
cases as the minimal amount of C code to demonstrate the defect.
* Please file issues only when filing things that should be fixed by
changes to the source or documentation in the repository (such as bugs
or feature requests). For support questions and other discussion, please
instead use the mailing list
https://www.freelists.org/list/nanomsg
or Gitter chat
https://gitter.im/nanomsg/nanomsg .
== Pull Requests
* We use Github PRs
* Please follow the existing coding style.
** See the `.clang-format` for whitespace rules.
** Return values should be enclosed in parenthesis.
** Conditional clauses are always enclosed in braces, and thus
span multiple lines.
TIP: The `.clang-format` file and `clang-format` may be helpful, but
is not necessarily complete. Also you may need to use a recent version
of `clang-format` as older versions can differ in their output.
* If you submit a PR, we would appreciate it if you would respond to review
feedback, rather than just leaving your baby on our doorstep. Abandoned
PRs or issues may be closed without further action.
* Commits should have comments formatted like this:
----
fixes #<issue#1> <issue#1-synopsis>
fixes #<issue#2> <issue#2-synopsis>
<Comments describing the issues, or fix, that you want to have
in the commit history. Not every issue needs such comments.>
----
* We have an "always release ready" policy for our tree, meaning we should
be able to build a functional release at any commit boundary. This ensures
that others taking the work can use git bisect and similar approaches when
hunting down regressions, or when cherry-picking changes for their own
forked copies. This has a few consequences:
** PRs should be functionally complete (that is, don't submit a
PR with partial work in progress, unless you have reached a
milestone that can stand on its own merit.)
** Each commit in a PR should also be "complete", so that
a release could be cut in between your commits without
leaving the tree in a broken or dysfunctional state.
** Usually this means its best to address only one issue in a PR,
with just one commit (squashed).
** Please have already merged and tested your code against the
latest changes in master. (If your code has merge conflicts,
your PR will be rejected until you have fixed the conflicts.)
* As a special exception, you may submit a PR for handling by our test
infrastructure; in that case please clearly identify that the PR is
submitted for that purpose, and should not considered for integration
yet. When that testing is done, please close the PR, and submit a new
one when you are ready for final review and integration.
* Code submitted should contain updates to any copyright files to add
your copyright to the license. We prefer you follow the existing
style of copyright, `// Copyright <year> <owner> <email or url>`
NOTE: We only use the most recent year, and we do not use `\(C)` which has
no legal value when the word "`Copyright`" is already present. We also
do not use the old "`All rights reserved.`" statement, which is equally
meaningless under current international copyright law.
* When updating an existing file, any new Copyright notice should be
added immediately below the pre-existing one, just before the license
boilerplate.
* All new files should use the MIT license and the same boilerplate
from one of the other files. We do not normally approve submissions
with different license or boilerplates -- please contact us if you
have a compelling reason for wanting to do that.

22
external/nng/docs/LICENSE.adoc vendored Normal file
View file

@ -0,0 +1,22 @@
= The MIT License
Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +
Copyright 2018 Capitar IT Group BV <info@capitar.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

340
external/nng/docs/RATIONALE.adoc vendored Normal file
View file

@ -0,0 +1,340 @@
= Rationale: Or why am I bothering to rewrite nanomsg?
Garrett D'Amore <garrett@damore.org>
v0.3, April 10, 2018
NOTE: You might want to review
http://nanomsg.org/documentation-zeromq.html[Martin Sustrik's rationale]
for nanomsg vs. ZeroMQ.
== Background
I became involved in the
http://www.nanomsg.org[nanomsg] community back in 2014, when
I wrote https://github.com/go-mangos/mangos[mangos] as a pure
http://www.golang.org[Go] implementation of the wire protocols behind
_nanomsg_. I did that work because I was dissatisfied with the
http://zeromq.org[_ZeroMQ_] licensing model
and the {cpp} baggage that came with it. I also needed something that would
work with _Go_ on http://www.illumos.org[illumos], which at the time
lacked support for `cgo` (so I could not just use an FFI binding.)
At the time, it was the only alternate implementation those protocols.
Writing _mangos_ gave me a lot of detail about the internals of _nanomsg_ and
the SP protocols.
It would not be wrong to say that one of the goals of _mangos_ was to teach
me about _Go_. It was my first non-trivial _Go_ project.
While working with _mangos_, I wound up implementing a number of additional
features, such as a TLS transport, the ability to bind to wild card ports,
and the ability to determine more information about the sender of a message.
This was incredibly useful in a number of projects.
I initially looked at _nanomsg_ itself, as I wanted to add a TLS transport
to it, and I needed to make some bug fixes (for protocol bugs for example),
and so forth.
== Lessons Learned
Perhaps it might be better to state that there were a number of opportunities
to learn from the lessons of _nanomsg_, as well as lessons we learned while
building _nng_ itself.
=== State Machine Madness
What I ran into in _nanomsg_, when attempting to improve it, was a
challenging mess of state machines. _nanomsg_ has dozens of state machines,
many of which feed into others, such that tracking flow through the state
machines is incredibly painful.
Worse, these state machines are designed to be run from a single worker
thread. This means that a given socket is entirely single theaded; you
could in theory have dozens, hundreds, or even thousands of connections
open, but they would be serviced only by a single thread. (Admittedly
non-blocking I/O is used to let the OS kernel calls run asynchronously
perhaps on multiple cores, but nanomsg itself runs all socket code on
a single worker thread.)
There is another problem too -- the `inproc` code that moves messages
between one socket and another was incredibly racy. This is because the
two sockets have different locks, and so dealing with the different
contexts was tricky (and consequently buggy). (I've since, I think, fixed
the worst of the bugs here, but only after many hours of pulling out hair.)
The state machines also make fairly linear flow really difficult to follow.
For example, there is a state machine to read the header information. This
may come a byte a time, and the state machine has to add the bytes, check
for completion, and possibly change state, even if it is just reading a
single 32-bit word. This is a lot more complex than most programmers are
used to, such as `read(fd, &val, 4)`.
Now to be fair, Martin Sustrik had the best intentions when he created the
state machine model around which _nanomsg_ is built. I do think that from
experience this is one of the most dense and unapproachable parts of _nanomsg_,
in spite of the fact that Martin's goal was precisely the opposite. I
consider this a "failed experiment" -- but hey failed experiments are the
basis of all great science.
=== Thread Challenges
While _nanomsg_ is mostly internally single threaded, I decided to try to
emulate the simple architecture of _mangos_ using system threads. (_mangos_
benefits greatly from _Go_'s excellent coroutine facility.) Having been well
and truly spoiled by _illumos_ threading (and especially _illumos_ kernel
threads), I thought this would be a reasonable architecture.
Sadly, this initial effort, while it worked, scaled incredibly poorly --
even so-called "modern" operating systems like _macOS_ 10.12 and _Windows_ 8.1
simply melted or failed entirely when creating any non-trivial number of
threads. (To me, creating 100 threads should be a no-brainer, especially if
one limits the stack size appropriately. I'm used to be able to create
thousands of threads without concern. As I said, I've been spoiled.
If your system falls over at a mere 200 threads I consider it a toy
implementation of threading. Unfortunately most of the mainstream operating
systems are therefore toy implementations.)
Chalk up another failed experiment.
I did find another approach which is discussed further.
=== File Descriptor Driven
Most of the underlying I/O in _nanomsg_ is built around file descriptors,
and it's internal usock structure, which is also state machine driven.
This means that implementing new transports which might need something
other than a file descriptor, is really non-trivial. This stymied my
first attempt to add http://www.openssl.org[OpenSSL] support to get TLS
added -- _OpenSSL_ has it's own `struct BIO` for this stuff, and I could
not see an easy way to convert _nanomsg_'s `usock` stuff to accomodate the
`struct BIO`.
In retrospect, _OpenSSL_ wasn't the ideal choice for an SSL/TLS library,
and we have since chosen another (https://tls.mbed.org[mbed TLS]).
Still, we needed an abstraction model that was better than just file
descriptors for I/O.
=== Poll
In order to support use in event driven programming, asynchronous
situations, etc. _nanomsg_ offers non-blocking I/O. In order to make
this work for end-users, a notification mechanism is required, and
nanomsg, in the spirit of following POSIX, offers a notification method
based on `poll(2)` or `select(2)`.
In order for this to work, it offers up a selectable file descriptor
for send and another one for receive. When events occur, these are
written to, and the user application "clears" these by reading from
them. (This is done on behalf of the application by _nanomsg_'s API calls.)
This means that in addition to the context switch code, there are not
fewer than 2 extra system calls executed per message sent or received, and
on a mostly idle system as many as 3. This means that to send a message
from one process to another you may have to execute up to 6 extra system
calls, beyond the 2 required to actually send and receive the message.
NOTE: Its even more hideous to support this on Windows, where there is no
`pipe(2)` system call, so we have to cobble up a loopback TCP connection
just for this event notification, in addition to the system call
explosion.
There are cases where this file descriptor logic is easier for existing
applications to integrate into event loops (e.g. they already have a thread
blocked in `poll()`.)
But for many cases this is not necessary. A simple callback mechanism
would be far better, with the FDs available only as an option for code
that needs them. This is the approach that we have taken with _nng_.
As another consequence of our approach, we do not require file descriptors
for sockets at all, so it is possible to create applications containing
_many_ thousands of `inproc` sockets with no files open at all. (Obviously
if you're going to perform real I/O to other processes or other systems,
you're going to need to have the underlying transport file descriptors
open, but then the only real limit should be the number of files that you
can open on your system. And the number of active connections you can maintain
should ideally approach that system limit closely.)
=== POSIX APIs
Another of Martin's goals, which seems worthwhile at first, was the
attempt to provide a familiar POSIX API (based upon the BSD socket API).
As a C programmer coming from UNIX systems, this really attracted me.
The problem is that the POSIX APIs are actually really horrible. In
particular the semantics around `cmsg` are about as arcane and painful as
one can imagine. Largely, this has meant that extensions to the `cmsg`
API simply have not occurred in _nanomsg_.
The `cmsg` API specified by POSIX is as bad as it is because POSIX had
requirements not to break APIs that already existed, and they needed to
shim something that would work with existing implementations, including
getting across a system call boundary. _nanomsg_ has never had such
constraints.
Oh, and there was that whole "design by committee" aspect.
Attempting to retain low numbered "socket descriptors" had its own
problems -- a huge source of use-after-close bugs, which made the
use of `nn_close()` incredibly dangerous for multithreaded sockets.
(If one thread closes and opens a new socket, other threads still using
the old socket might wind up accessing the "new" socket without realizing
it.)
The other thing is that BSD socket APIs are super familiar to UNIX C
programmers -- but experience with _nanomsg_ has taught us already that these
are actually in the minority of _nanomsg_'s users. Most of our users are
coming to us from {cpp} (object oriented), _Java_, and _Python_ backgrounds.
For them the BSD sockets API is frankly somewhat bizarre and alien.
With _nng_, we realized that constraining ourselves to the mistakes of the
POSIX API was hurting rather than helping. So _nng_ provides a much friendlier
interface for getting properties associated with messages.
In _nng_ we also generally try hard to avoid reusing
an identifier until no other option exists. This generally means most
applications won't see socket reuse until billions of other sockets
have been opened. There is little chance for accidental reuse.
== Compatibility
Of course, there are a number of existing _nanomsg_ consumers "in the wild"
already. It is important to continue to support them. So I decided from
the get go to implement a "compatibility" layer, that provides the same
API, and as much as possible the same ABI, as legacy _nanomsg_. However,
new features and capabilities would not necessarily be exposed to the
the legacy API.
Today _nng_ offers this. You can relink an existing _nanomsg_ binary against
_libnng_ instead of _libnn_, and it usually Just Works(TM). Source
compatibility is almost as easy, although the application code needs to be
modified to use different header files.
NOTE: I am considering changing the include file in the future so that
it matches exactly the _nanomsg_ include path, so that only a compiler
flag change would be needed.
== Asynchronous IO
As a consequence of our experience with threads being so unscalable,
we decided to create a new underlying abstraction modeled largely on
Windows IO completion ports. (As bad as so many of the Windows APIs
are, the IO completion port stuff is actually pretty nice.) Under the
hood in _nng_ all I/O is asynchronous, and we have `nni_aio` objects
for each pending I/O. These have an associated completion routine.
The completion routines are _usually_ run on a separate worker thread
(we have many such workers; in theory the number should be tuned to the
available number of CPU cores to ensure that we never wait while a CPU
core is available for work), but they can be run "synchronously" if
the I/O provider knows it is safe to do so (for example the completion
is occuring in a context where no locks are held.)
The `nni_aio` structures are accessible to user applications as well, which can
lead to much more efficient and easier to write asynchronous applications,
and can aid integration into event-driven systems and runtimes, without
requiring extra system calls required by the legacy _nanomsg_ approach.
There is still performance tuning work to do, especially optimization for
specific pollers like `epoll()` and `kqueue()` to address the C10K problem,
but that work is already in progress.
== Portability & Embeddability
A significant goal of _nng_ is to be portable to many kinds of different
kinds of systems, and embedded in systems that do not support POSIX or Win32
APIs. To that end we have a clear platform portability layer. We do require
that platforms supply entry points for certain networking, synchronization,
threading, and timekeeping functions, but these are fairly straight-forward
to implement on any reasonable 32-bit or 64-bit system, including most
embedded operating systems.
Additionally, this portability layer may be used to build other kinds of
experiments -- for example it should be relatively straight-forward to provide
a "platform" based on one of the various coroutine libraries such as Martin's
http://libdill.org[libdill] or https://swtch.com/libtask/[libtask].
TIP: If you want to write a coroutine-based platform, let me know!
== New Transports
The other, most critical, motivation behind _nng_ was to enable an easier
creation of new transports. In particular, one client (
http://www.capitar.com[Capitar IT Group BV])
contracted the creation of a http://www.zerotier.com[ZeroTier] transport for
_nanomsg_.
After beating my head against the state machines some more, I finally asked
myself if it would not be easier just to rewrite _nanomsg_ using the model
I had created for _mangos_.
In retrospect, I'm not sure that the answer was a clear and definite yes
in favor of _nng_, but for the other things I want to do, it has enabled a
lot of new work. The ZeroTier transport was created with a relatively
modest amount of effort, in spite of being based upon a connectionless
transport. I do not believe I could have done this easily in the existing
_nanomsg_.
I've since added a rich TLS transport, and have implemented a WebSocket
transport that is far more capable than that in _nanomsg_, as it can
support TLS and sharing the TCP port across multiple _nng_ sockets (using
the path to discriminate) or even other HTTP services.
There are already plans afoot for other kinds of transports using QUIC
or KCP or SSH, as well as a pure UDP transport. The new _nng_ transport
layer makes implementation of these all fairly straight-forward.
== HTTP and Other services
As part of implementing a real WebSocket transport, it was necessary to
implement at least some HTTP capabilities. Rather than just settle for a toy
implementation, _nng_ has a very capable HTTP server and client framework.
The server can be used to build real web services, so it becomes possible
for example to serve static content, REST API, and _nng_ based services
all from the same TCP port using the same program.
We've also made the WebSocket services fairly generic, which may support
a plethora of other kinds of transports and services.
There is also a portability layer -- so some common services (threading,
timing, etc.) are provided in the _nng_ library to help make writing
portable _nng_ applications easier.
It will not surprise me if developers start finding uses for _nng_ that
have nothing to do with Scalability Protocols.
== Separate Contexts
As part of working on a demo suite of applications, I realized that the
requirement to use raw mode sockets for concurrent applications was rather
onerous, forcing application developers to re-implement much of the
same logic that is already in _nng_.
Thus was the born the idea of separating the context for protocols from
the socket, allowing multiple contexts (each of which managing it's own
REQ/REP state machinery) to be allocated and used on a single socket.
This was a large change indeed, but we believe application developers
are going to find it *much* easier to write scalable applications,
and hopefully the uses of raw mode and applications needing to inspect
or generate their own application headers will vanish.
Note that these contexts are entirely optional -- an application can
still use the implicit context associated with the socket just like
always, if it has no need for extra concurrency.
One side benefit of this work was that we identified several places
to make _nng_ perform more efficiently, reducing the number of context
switches and extra raw vs. cooked logic.
== Towards _nanomsg_ 2.0
It is my intention that _nng_ ultimately replace _nanomsg_. I do think of it
as "nanomsg 2.0". In fact "nng" stands for "nanomsg next generation" in
my mind. Some day soon I'm hoping that the various website
references to nanomsg my simply be updated to point at _nng_. It is not
clear to me whether at that time I will simply rename the existing
code to _nanomsg_, nanomsg2, or leave it as _nng_.

11
external/nng/docs/README.txt vendored Normal file
View file

@ -0,0 +1,11 @@
This contains the nng documentation for API users.
The documentation is written in asciidoc in the form of man pages. It is
automatically formatted for display on the website.
It is possible to emit TROFF sources for use by the UNIX man page, and HTML
for online viewing. asciidoctor supports PDF and EPUB formats via plugins,
so there are still more options available.
The man pages are in the "man" directory. The reason those are separate
is that they get special treatment. Other documentation is located here.

446
external/nng/docs/man/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,446 @@
#
# Copyright 2024 Staysail Systems, Inc. <info@staysail.tech>
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
# Copyright 2019 Devolutions <info@devolutions.net>
#
# This software is supplied under the terms of the MIT License, a
# copy of which should be located in the distribution where this
# file was obtained (LICENSE.txt). A copy of the license may also be
# found online at https://opensource.org/licenses/MIT.
# We default to off here.
option(NNG_ENABLE_DOC "Enable building documentation." OFF)
if (NNG_ENABLE_DOC)
find_program(ASCIIDOCTOR asciidoctor)
if (NOT ASCIIDOCTOR)
message(WARNING "Could not find asciidoctor: skipping docs")
set(NNG_ENABLE_DOC OFF)
else ()
message(STATUS "Using asciidoctor at ${ASCIIDOCTOR}")
endif ()
endif ()
if (NNG_ENABLE_DOC)
set(NNG_DOCDIR ${CMAKE_CURRENT_SOURCE_DIR})
set(NNG_A2M ${ASCIIDOCTOR} -b manpage -amanmanual='NNG Reference Manual')
set(NNG_A2H ${ASCIIDOCTOR} -a nofooter -atoc=left -aicons=font -d manpage -b html5)
macro(nng_man NAME SECT)
add_custom_command(
OUTPUT ${NAME}.${SECT}
COMMAND ${NNG_A2M} -o ${NAME}.${SECT} ${NNG_DOCDIR}/${NAME}.${SECT}.adoc
MAIN_DEPENDENCY ${NNG_DOCDIR}/${NAME}.${SECT}.adoc
)
add_custom_command(
OUTPUT ${NAME}.${SECT}.html
COMMAND ${NNG_A2H} -o ${NAME}.${SECT}.html ${NNG_DOCDIR}/${NAME}.${SECT}.adoc
MAIN_DEPENDENCY ${NNG_DOCDIR}/${NAME}.${SECT}.adoc
)
set(NNG_MANS ${NNG_MANS} ${NAME}.${SECT})
set(NNG_HTMLS ${NNG_HTMLS} ${NAME}.${SECT}.html)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.${SECT}.html
DESTINATION ${CMAKE_INSTALL_DOCDIR}
)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.${SECT}
DESTINATION ${CMAKE_INSTALL_MANDIR}/man${SECT}
)
endmacro(nng_man)
set(NNG_MAN1
nngcat
)
set(NNG_MAN3
libnng
nng_aio_abort
nng_aio_alloc
nng_aio_begin
nng_aio_cancel
nng_aio_count
nng_aio_defer
nng_aio_finish
nng_aio_free
nng_aio_get_input
nng_aio_get_msg
nng_aio_get_output
nng_aio_result
nng_aio_set_input
nng_aio_set_iov
nng_aio_set_msg
nng_aio_set_output
nng_aio_set_timeout
nng_aio_stop
nng_aio_wait
nng_alloc
nng_bus_open
nng_close
nng_ctx_close
nng_ctx_get
nng_ctx_getopt
nng_ctx_id
nng_ctx_open
nng_ctx_recv
nng_ctx_send
nng_ctx_set
nng_ctx_setopt
nng_device
nng_dial
nng_dialer_close
nng_dialer_create
nng_dialer_get
nng_dialer_getopt
nng_dialer_id
nng_dialer_set
nng_dialer_setopt
nng_dialer_start
nng_free
nng_getopt
nng_inproc_register
nng_ipc_register
nng_listen
nng_listener_close
nng_listener_create
nng_listener_get
nng_listener_getopt
nng_listener_id
nng_listener_set
nng_listener_setopt
nng_listener_start
nng_log
nng_log_get_level
nng_log_set_facility
nng_log_set_level
nng_log_set_logger
nng_msg_alloc
nng_msg_append
nng_msg_body
nng_msg_chop
nng_msg_clear
nng_msg_dup
nng_msg_free
nng_msg_get_pipe
nng_msg_header
nng_msg_header_append
nng_msg_header_chop
nng_msg_header_clear
nng_msg_header_insert
nng_msg_header_len
nng_msg_header_trim
nng_msg_insert
nng_msg_len
nng_msg_realloc
nng_msg_set_pipe
nng_msg_trim
nng_pair_open
nng_pipe_close
nng_pipe_dialer
nng_pipe_get
nng_pipe_getopt
nng_pipe_id
nng_pipe_listener
nng_pipe_notify
nng_pipe_socket
nng_pub_open
nng_pull_open
nng_push_open
nng_recv
nng_recv_aio
nng_recvmsg
nng_rep_open
nng_req_open
nng_respondent_open
nng_send
nng_send_aio
nng_sendmsg
nng_setopt
nng_sleep_aio
nng_socket_id
nng_socket_get
nng_socket_set
nng_stats_free
nng_stats_get
nng_stat_bool
nng_stat_child
nng_stat_desc
nng_stat_find
nng_stat_find_dialer
nng_stat_find_listener
nng_stat_find_socket
nng_stat_name
nng_stat_next
nng_stat_string
nng_stat_timestamp
nng_stat_type
nng_stat_unit
nng_stat_value
nng_str_sockaddr
nng_strdup
nng_strerror
nng_strfree
nng_sub_open
nng_surveyor_open
nng_tcp_register
nng_tls_register
nng_url_clone
nng_url_free
nng_url_parse
nng_version
nng_ws_register
nng_wss_register
nng_zt_register
)
set(NNG_MAN3COMPAT
nn_allocmsg
nn_bind
nn_close
nn_cmsg
nn_connect
nn_device
nn_errno
nn_freemsg
nn_get_statistic
nn_getsockopt
nn_poll
nn_reallocmsg
nn_recv
nn_recvmsg
nn_send
nn_sendmsg
nn_setsockopt
nn_shutdown
nn_socket
nn_strerror
nn_term
nng_compat
)
set(NNG_MAN3HTTP
nng_http_client_alloc
nng_http_client_connect
nng_http_client_free
nng_http_client_get_tls
nng_http_client_set_tls
nng_http_client_transact
nng_http_conn_close
nng_http_conn_read
nng_http_conn_read_all
nng_http_conn_read_req
nng_http_conn_read_res
nng_http_conn_transact
nng_http_conn_write
nng_http_conn_write_all
nng_http_conn_write_req
nng_http_conn_write_res
nng_http_handler_alloc
nng_http_handler_free
nng_http_handler_get_data
nng_http_handler_set_data
nng_http_handler_set_host
nng_http_handler_set_method
nng_http_handler_set_tree
nng_http_hijack
nng_http_req_add_header
nng_http_req_alloc
nng_http_req_copy_data
nng_http_req_del_header
nng_http_req_free
nng_http_req_get_data
nng_http_req_get_header
nng_http_req_get_method
nng_http_req_get_uri
nng_http_req_get_version
nng_http_req_reset
nng_http_req_set_data
nng_http_req_set_header
nng_http_req_set_method
nng_http_req_set_uri
nng_http_req_set_version
nng_http_res_add_header
nng_http_res_alloc
nng_http_res_alloc_error
nng_http_res_copy_data
nng_http_res_del_header
nng_http_res_free
nng_http_res_get_data
nng_http_res_get_header
nng_http_res_get_reason
nng_http_res_get_status
nng_http_res_get_version
nng_http_res_reset
nng_http_res_set_data
nng_http_res_set_header
nng_http_res_set_reason
nng_http_res_set_status
nng_http_res_set_version
nng_http_server_add_handler
nng_http_server_del_handler
nng_http_server_get_addr
nng_http_server_get_tls
nng_http_server_hold
nng_http_server_release
nng_http_server_set_tls
nng_http_server_start
nng_http_server_stop
)
set(NNG_MAN3SUPP
nng_clock
nng_cv_alloc
nng_cv_free
nng_cv_until
nng_cv_wait
nng_cv_wake
nng_cv_wake1
nng_id_map
nng_msleep
nng_mtx_alloc
nng_mtx_free
nng_mtx_lock
nng_mtx_unlock
nng_opts_parse
nng_random
nng_socket_pair
nng_thread_create
nng_thread_destroy
nng_thread_set_name
)
set(NNG_MAN3STR
nng_stream_close
nng_stream_free
nng_stream_get
nng_stream_recv
nng_stream_send
nng_stream_set
nng_stream_dialer_alloc
nng_stream_dialer_close
nng_stream_dialer_dial
nng_stream_dialer_free
nng_stream_dialer_get
nng_stream_dialer_set
nng_stream_listener_accept
nng_stream_listener_alloc
nng_stream_listener_close
nng_stream_listener_free
nng_stream_listener_get
nng_stream_listener_listen
nng_stream_listener_set
)
set(NNG_MAN3TLS
nng_tls_config_alloc
nng_tls_config_auth_mode
nng_tls_config_ca_chain
nng_tls_config_ca_file
nng_tls_config_cert_key_file
nng_tls_config_free
nng_tls_config_hold
nng_tls_config_own_cert
nng_tls_config_server_name
nng_tls_engine_description
nng_tls_engine_fips_mode
nng_tls_engine_name
)
set(NNG_MAN5
nng_aio
nng_ctx
nng_dialer
nng_duration
nng_iov
nng_listener
nng_msg
nng_options
nng_pipe
nng_sockaddr
nng_sockaddr_abstract
nng_sockaddr_in
nng_sockaddr_in6
nng_sockaddr_inproc
nng_sockaddr_ipc
nng_sockaddr_zt
nng_socket
nng_stat
nng_url
nng_stream
nng_stream_dialer
nng_stream_listener
nng_tcp_options
nng_ipc_options
nng_tls_config
nng_tls_engine
nng_tls_options
)
set(NNG_MAN7
nng
nng_bus
nng_inproc
nng_ipc
nng_pair
nng_pub
nng_pull
nng_push
nng_rep
nng_req
nng_respondent
nng_socket
nng_sub
nng_surveyor
nng_tcp
nng_tls
nng_ws
nng_zerotier
)
foreach (F ${NNG_MAN1})
nng_man(${F} 1)
endforeach ()
foreach (F ${NNG_MAN3})
nng_man(${F} 3)
endforeach ()
foreach (F ${NNG_MAN3COMPAT})
nng_man(${F} 3compat)
endforeach ()
foreach (F ${NNG_MAN3HTTP})
nng_man(${F} 3http)
endforeach ()
foreach (F ${NNG_MAN3STR})
nng_man(${F} 3str)
endforeach ()
foreach (F ${NNG_MAN3SUPP})
nng_man(${F} 3supp)
endforeach ()
foreach (F ${NNG_MAN3TLS})
nng_man(${F} 3tls)
endforeach ()
foreach (F ${NNG_MAN5})
nng_man(${F} 5)
endforeach ()
foreach (F ${NNG_MAN7})
nng_man(${F} 7)
endforeach ()
add_custom_target(man ALL DEPENDS ${NNG_MANS})
add_custom_target(html ALL DEPENDS ${NNG_HTMLS})
endif ()

484
external/nng/docs/man/libnng.3.adoc vendored Normal file
View file

@ -0,0 +1,484 @@
= libnng(3)
//
// Copyright 2023 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
// Copyright 2019 Devolutions <info@devolutions.net>
// Copyright 2020 Dirac Research <robert.bielik@dirac.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
libnng - nanomsg next generation library
== SYNOPSIS
*cc* [_flags_] _files_ *-lnng* [_libraries_]
== DESCRIPTION
xref:nng.7.adoc[_NNG_] provides a common messaging framework
intended to solve common communication problems in distributed applications.
It provides a C language API.
=== Common Functions
The following common functions exist in _libnng_.
|===
|xref:nng_alloc.3.adoc[nng_alloc()]|allocate memory
|xref:nng_free.3.adoc[nng_free()]|free memory
|xref:nng_strdup.3.adoc[nng_strdup()]|duplicate string
|xref:nng_strerror.3.adoc[nng_strerror()]|return an error description
|xref:nng_strfree.3.adoc[nng_strfree()]|free string
|xref:nng_version.3.adoc[nng_version()]|report library version
|===
=== Socket Functions
The following functions operate on sockets.
|===
|xref:nng_close.3.adoc[nng_close()]|close socket
|xref:nng_dial.3.adoc[nng_dial()]|create and start dialer
|xref:nng_getopt.3.adoc[nng_getopt()]|get socket option
|xref:nng_listen.3.adoc[nng_listen()]|create and start listener
|xref:nng_recv.3.adoc[nng_recv()]|receive data
|xref:nng_send.3.adoc[nng_send()]|send data
|xref:nng_setopt.3.adoc[nng_setopt()]|set socket option
|xref:nng_socket_get.3.adoc[nng_socket_get()]|get socket option
|xref:nng_socket_id.3.adoc[nng_socket_id()]|get numeric socket identifier
|xref:nng_socket_set.3.adoc[nng_socket_set()]|set socket option
|===
=== Connection Management
The following functions are used with either listeners, or dialers.
Listeners accept incoming connection requests, and dialers make them.
|===
|xref:nng_dial.3.adoc[nng_dial()]|create and start dialer
|xref:nng_dialer_close.3.adoc[nng_dialer_close()]|close dialer
|xref:nng_dialer_create.3.adoc[nng_dialer_create()]|create dialer
|xref:nng_dialer_get.3.adoc[nng_dialer_get()]|get dialer option
|xref:nng_dialer_getopt.3.adoc[nng_dialer_getopt()]|get dialer option
|xref:nng_dialer_id.3.adoc[nng_dialer_id()]|get numeric dialer identifier
|xref:nng_dialer_set.3.adoc[nng_dialer_set()]|set dialer option
|xref:nng_dialer_setopt.3.adoc[nng_dialer_setopt()]|set dialer option
|xref:nng_dialer_start.3.adoc[nng_dialer_start()]|start dialer
|xref:nng_listen.3.adoc[nng_listen()]|create and start listener
|xref:nng_listener_close.3.adoc[nng_listener_close()]|close listener
|xref:nng_listener_create.3.adoc[nng_listener_create()]|create listener
|xref:nng_listener_get.3.adoc[nng_listener_get()]|get listener option
|xref:nng_listener_getopt.3.adoc[nng_listener_getopt()]|get listener option
|xref:nng_listener_id.3.adoc[nng_listener_id()]|get numeric listener identifier
|xref:nng_listener_set.3.adoc[nng_listener_set()]|set listener option
|xref:nng_listener_setopt.3.adoc[nng_listener_setopt()]|set listener option
|xref:nng_listener_start.3.adoc[nng_listener_start()]|start listener
|xref:nng_pipe_close.3.adoc[nng_pipe_close()]|close pipe
|xref:nng_pipe_dialer.3.adoc[nng_pipe_dialer()]|return dialer that created pipe
|xref:nng_pipe_get.3.adoc[nng_pipe_get()]|get pipe option
|xref:nng_pipe_getopt.3.adoc[nng_pipe_getopt()]|get pipe option
|xref:nng_pipe_id.3.adoc[nng_pipe_id()]|get numeric pipe identifier
|xref:nng_pipe_listener.3.adoc[nng_pipe_listener()]|return listener that created pipe
|xref:nng_pipe_notify.3.adoc[nng_pipe_notify()]|register pipe notification callback
|xref:nng_pipe_socket.3.adoc[nng_pipe_socket()]|return owning socket for pipe
|===
=== Message Handling Functions
Applications desiring to use the richest part of _libnng_ will want to
use the message API, where a message structure is passed between functions.
This API provides the most power support for zero-copy.
Messages are divided into a header and body, where the body generally carries
user-payload and the header carries protocol specific header information.
Most applications will only interact with the body.
|===
|xref:nng_msg_alloc.3.adoc[nng_msg_alloc()]|allocate a message
|xref:nng_msg_append.3.adoc[nng_msg_append()]|append to message body
|xref:nng_msg_body.3.adoc[nng_msg_body()]|return message body
|xref:nng_msg_capacity.3.adoc[nng_msg_capacity()]|return capacity allocated for message body
|xref:nng_msg_chop.3.adoc[nng_msg_chop()]|remove data from end of message body
|xref:nng_msg_clear.3.adoc[nng_msg_clear()]|clear message body
|xref:nng_msg_dup.3.adoc[nng_msg_dup()]|duplicate a message
|xref:nng_msg_free.3.adoc[nng_msg_free()]|free a message
|xref:nng_msg_get_pipe.3.adoc[nng_msg_get_pipe()]|get pipe for message
|xref:nng_msg_insert.3.adoc[nng_msg_insert()]|prepend to message body
|xref:nng_msg_len.3.adoc[nng_msg_len()]|return the message body length
|xref:nng_msg_realloc.3.adoc[nng_msg_realloc()]|reallocate a message
|xref:nng_msg_reserve.3.adoc[nng_msg_reserve()]|reserve storage for message body
|xref:nng_msg_set_pipe.3.adoc[nng_msg_set_pipe()]|set pipe for message
|xref:nng_msg_trim.3.adoc[nng_msg_trim()]|remove data from start of message body
|xref:nng_recvmsg.3.adoc[nng_recvmsg()]|receive a message
|xref:nng_sendmsg.3.adoc[nng_sendmsg()]|send a message
|===
==== Message Header Handling
TIP: Few applications will need these functions, as message headers are only
used to carry protocol-specific content. However, applications which use raw
mode may need to access the header of messages.
|===
|xref:nng_msg_header.3.adoc[nng_msg_header()]|return message header
|xref:nng_msg_header_append.3.adoc[nng_msg_header_append()]|append to message header
|xref:nng_msg_header_chop.3.adoc[nng_msg_header_chop()]|remove data from end of message header
|xref:nng_msg_header_clear.3.adoc[nng_msg_header_clear()]|clear message header
|xref:nng_msg_header_insert.3.adoc[nng_msg_header_insert()]|prepend to message header
|xref:nng_msg_header_len.3.adoc[nng_msg_header_len()]|return the message header length
|xref:nng_msg_header_trim.3.adoc[nng_msg_header_trim()]|remove data from start of message header
|===
=== Asynchronous Operations
Most applications will interact with _NNG_ synchronously; that is that
functions such as xref:nng_send.3.adoc[`nng_send()`] will block the calling
thread until the operation has completed.
NOTE: Synchronous operations which send messages may return before the
message has actually been received, or even transmitted. Instead, These
functions return as soon as the message was successfully queued for
delivery.
Asynchronous operations behave differently. These operations are
initiated by the calling thread, but control returns immediately to
the calling thread. When the operation is subsequently completed (regardless
of whether this was successful or not), then a user supplied function
is executed.
A context structure, an xref:nng_aio.5.adoc[`nng_aio`], is allocated and
associated with each asynchronous operation.
Only a single asynchronous operation may be associated with an
`nng_aio` at any time.
The following functions are used in the asynchronous model:
|===
|xref:nng_aio_abort.3.adoc[nng_aio_abort()]|abort asynchronous I/O operation
|xref:nng_aio_alloc.3.adoc[nng_aio_alloc()]|allocate asynchronous I/O handle
|xref:nng_aio_begin.3.adoc[nng_aio_begin()]|begin asynchronous I/O operation
|xref:nng_aio_busy.3.adoc[nng_aio_busy()]|test if asynchronous I/O is busy
|xref:nng_aio_cancel.3.adoc[nng_aio_cancel()]|cancel asynchronous I/O operation
|xref:nng_aio_count.3.adoc[nng_aio_count()]|return number of bytes transferred
|xref:nng_aio_defer.3.adoc[nng_aio_defer()]|defer asynchronous I/O operation
|xref:nng_aio_finish.3.adoc[nng_aio_finish()]|finish asynchronous I/O operation
|xref:nng_aio_free.3.adoc[nng_aio_free()]|free asynchronous I/O handle
|xref:nng_aio_get_input.3.adoc[nng_aio_get_input()]|return input parameter
|xref:nng_aio_get_msg.3.adoc[nng_aio_get_msg()]|get message from an asynchronous receive
|xref:nng_aio_get_output.3.adoc[nng_aio_get_output()]|return output result
|xref:nng_aio_free.3.adoc[nng_aio_reap()]|reap asynchronous I/O handle
|xref:nng_aio_result.3.adoc[nng_aio_result()]|return result of asynchronous operation
|xref:nng_aio_set_input.3.adoc[nng_aio_set_input()]|set input parameter
|xref:nng_aio_set_iov.3.adoc[nng_aio_set_iov()]|set scatter/gather vector
|xref:nng_aio_set_msg.3.adoc[nng_aio_set_msg()]|set message for an asynchronous send
|xref:nng_aio_set_output.3.adoc[nng_aio_set_output()]|set output result
|xref:nng_aio_set_timeout.3.adoc[nng_aio_set_timeout()]|set asynchronous I/O timeout
|xref:nng_aio_stop.3.adoc[nng_aio_stop()]|stop asynchronous I/O operation
|xref:nng_aio_wait.3.adoc[nng_aio_wait()]|wait for asynchronous I/O operation
|xref:nng_recv_aio.3.adoc[nng_recv_aio()]|receive message asynchronously
|xref:nng_send_aio.3.adoc[nng_send_aio()]|send message asynchronously
|xref:nng_sleep_aio.3.adoc[nng_sleep_aio()]|sleep asynchronously
|===
=== Protocols
The following functions are used to construct a socket with a specific protocol:
|===
|xref:nng_bus_open.3.adoc[nng_bus_open()]|open a bus socket
|xref:nng_pair_open.3.adoc[nng_pair_open()]|open a pair socket
|xref:nng_pub_open.3.adoc[nng_pub_open()]|open a pub socket
|xref:nng_pull_open.3.adoc[nng_pull_open()]|open a pull socket
|xref:nng_push_open.3.adoc[nng_push_open()]|open a push socket
|xref:nng_rep_open.3.adoc[nng_rep_open()]|open a rep socket
|xref:nng_req_open.3.adoc[nng_req_open()]|open a req socket
|xref:nng_respondent_open.3.adoc[nng_respondent_open()]|open a respondent socket
|xref:nng_sub_open.3.adoc[nng_sub_open()]|open a sub socket
|xref:nng_surveyor_open.3.adoc[nng_surveyor_open()]|open a surveyor socket
|===
=== Transports
The following functions are used to register a transport for use.
|===
| xref:nng_inproc_register.3.adoc[nng_inproc_register()]|register inproc transport
| xref:nng_ipc_register.3.adoc[nng_ipc_register()]|register IPC transport
| xref:nng_tcp_register.3.adoc[nng_tcp_register()]|register TCP transport
| xref:nng_tls_register.3.adoc[nng_tls_register()]|register TLS transport
| xref:nng_ws_register.3.adoc[nng_ws_register()]|register WebSocket transport
| xref:nng_wss_register.3.adoc[nng_wss_register()]|register WebSocket Secure transport
| xref:nng_zt_register.3.adoc[nng_zt_register()]|register ZeroTier transport
|===
=== Protocol Contexts
The following functions are useful to separate the protocol processing
from a socket object, into a separate context.
This can allow multiple contexts to be created on a single socket for
concurrent applications.
|===
|xref:nng_ctx_close.3.adoc[nng_ctx_close()]|close context
|xref:nng_ctx_get.3.adoc[nng_ctx_get()]|get context option
|xref:nng_ctx_getopt.3.adoc[nng_ctx_getopt()]|get context option
|xref:nng_ctx_id.3.adoc[nng_ctx_id()]|get numeric context identifier
|xref:nng_ctx_open.3.adoc[nng_ctx_open()]|create context
|xref:nng_ctx_recv.3.adoc[nng_ctx_recv()]|receive message using context asynchronously
|xref:nng_ctx_recvmsg.3.adoc[nng_ctx_recvmsg()]|receive a message using context
|xref:nng_ctx_send.3.adoc[nng_ctx_send()]|send message using context asynchronously
|xref:nng_ctx_sendmsg.3.adoc[nng_ctx_sendmsg()]|send a message using context
|xref:nng_ctx_set.3.adoc[nng_ctx_set()]|set context option
|xref:nng_ctx_setopt.3.adoc[nng_ctx_setopt()]|set context option
|===
=== Devices, Relays
The following function family is used to create forwarders or relayers
that route messages from one socket to another.
|===
|xref:nng_device.3.adoc[nng_device()]|message forwarding device
|===
=== Statistics
The following functions provide access to statistics which can be used
to observe program behaviors and as an aid in troubleshooting.
|===
|xref:nng_stat_bool.3.adoc[nng_stat_bool()]|get statistic Boolean value
|xref:nng_stat_child.3.adoc[nng_stat_child()]|get child statistic
|xref:nng_stat_desc.3.adoc[nng_stat_name()]|get statistic description
|xref:nng_stat_find.3.adoc[nng_stat_find()]|find statistic by name
|xref:nng_stat_find_dialer.3.adoc[nng_stat_find_dialer()]|find dialer statistics
|xref:nng_stat_find_listener.3.adoc[nng_stat_find_listener()]|find listener statistics
|xref:nng_stat_find_socket.3.adoc[nng_stat_find_socket()]|find socket statistics
|xref:nng_stat_name.3.adoc[nng_stat_name()]|get statistic name
|xref:nng_stat_next.3.adoc[nng_stat_next()]|get next statistic
|xref:nng_stat_string.3.adoc[nng_stat_string()]|get statistic string value
|xref:nng_stat_timestamp.3.adoc[nng_stat_timestamp()]|get statistic timestamp
|xref:nng_stat_type.3.adoc[nng_stat_type()]|get statistic type
|xref:nng_stat_unit.3.adoc[nng_stat_unit()]|get statistic unit
|xref:nng_stat_value.3.adoc[nng_stat_value()]|get statistic numeric value
|xref:nng_stats_free.3.adoc[nng_stats_free()]|free statistics
|xref:nng_stats_get.3.adoc[nng_stats_get()]|get statistics
|===
=== URL Object
Common functionality is supplied for parsing and handling
universal resource locators (URLS).
|===
|xref:nng_url_clone.3.adoc[nng_url_clone()]|clone URL structure
|xref:nng_url_free.3.adoc[nng_url_free()]|free URL structure
|xref:nng_url_parse.3.adoc[nng_url_parse()]|create URL structure from string
|===
=== Logging Support
Common functionality for message logging.
|===
|xref:nng_log.3.adoc[nng_log()]|log a message
|xref:nng_log_facility.3.adoc[nng_log_set_facility()]|set log facility
|xref:nng_log_level.3.adoc[nng_log_set_level()]|set log level
|xref:nng_log_logger.3.adoc[nng_log_set_logger()]|set logging handler
|===
=== Supplemental API
These supplemental functions are not intrinsic to building
network applications with _NNG_, but they are made available
as a convenience to aid in creating portable applications.
|===
|xref:nng_clock.3supp.adoc[nng_clock()]|get time
|xref:nng_cv_alloc.3supp.adoc[nng_cv_alloc()]|allocate condition variable
|xref:nng_cv_free.3supp.adoc[nng_cv_free()]|free condition variable
|xref:nng_cv_until.3supp.adoc[nng_cv_until()]|wait for condition or timeout
|xref:nng_cv_wait.3supp.adoc[nng_cv_wait()]|wait for condition
|xref:nng_cv_wake.3supp.adoc[nng_cv_wake()]|wake all waiters
|xref:nng_cv_wake1.3supp.adoc[nng_cv_wake1()]|wake one waiter
|xref:nng_id_map.3supp.adoc[nng_id_map]|identifier based mapping table
|xref:nng_msleep.3supp.adoc[nng_msleep()]|sleep for milliseconds
|xref:nng_mtx_alloc.3supp.adoc[nng_mtx_alloc()]|allocate mutex
|xref:nng_mtx_free.3supp.adoc[nng_mtx_free()]|free mutex
|xref:nng_mtx_lock.3supp.adoc[nng_mtx_lock()]|lock mutex
|xref:nng_mtx_unlock.3supp.adoc[nng_mtx_unlock()]|unlock mutex
|xref:nng_opts_parse.3supp.adoc[nng_opts_parse()]|parse command line options
|xref:nng_random.3supp.adoc[nng_random()]|get random number
|xref:nng_socket_pair.3supp.adoc[nng_socket_pair()]|create connected pair of BSD sockets
|xref:nng_thread_create.3supp.adoc[nng_thread_create()]|create thread
|xref:nng_thread_destroy.3supp.adoc[nng_thread_destroy()]|reap thread
|xref:nng_thread_set_name.3supp.adoc[nng_thread_set_name()]|set thread name
|===
=== Byte Streams
These functions are available for use with byte streams.
They are considered low-level, for uses where the higher level functions
using Scalability Protocols are inappropriate.
Byte streams, represented by
xref:nng_stream.5.adoc[`nng_stream`] objects, correspond to underlying
connections such as TCP connections or named pipes.
They are created by either
xref:nng_stream_dialer.5.adoc[`nng_stream_dialer`] or
xref:nng_stream_listener.5.adoc[`nng_stream_listener`] objects.
|===
|xref:nng_stream_close.3str.adoc[nng_stream_close()]|close byte stream
|xref:nng_stream_dialer_alloc.3str.adoc[nng_stream_dialer_alloc()]|allocate byte stream dialer
|xref:nng_stream_dialer_close.3str.adoc[nng_stream_dialer_close()]|close byte stream dialer
|xref:nng_stream_dialer_dial.3str.adoc[nng_stream_dialer_dial()]|initiate outgoing byte stream
|xref:nng_stream_dialer_free.3str.adoc[nng_stream_dialer_free()]|free byte stream dialer
|xref:nng_stream_dialer_get.3str.adoc[nng_stream_dialer_get()]|get option from byte stream dialer
|xref:nng_stream_dialer_set.3str.adoc[nng_stream_dialer_set()]|set option on byte stream dialer
|xref:nng_stream_free.3str.adoc[nng_stream_free()]|free byte stream
|xref:nng_stream_get.3str.adoc[nng_stream_get()]|get option from byte stream
|xref:nng_stream_listener_accept.3str.adoc[nng_stream_listener_accept()]|accept incoming byte stream
|xref:nng_stream_listener_alloc.3str.adoc[nng_stream_listener_alloc()]|allocate byte stream listener
|xref:nng_stream_listener_close.3str.adoc[nng_stream_listener_close()]|close byte stream listener
|xref:nng_stream_listener_free.3str.adoc[nng_stream_listener_free()]|free byte stream listener
|xref:nng_stream_listener_get.3str.adoc[nng_stream_listener_get()]|get option from byte stream listener
|xref:nng_stream_listener_listen.3str.adoc[nng_stream_listener_listen()]|bind byte stream listener to address
|xref:nng_stream_listener_set.3str.adoc[nng_stream_listener_set()]|set option on byte stream listener
|xref:nng_stream_recv.3str.adoc[nng_stream_recv()]|receive from byte stream
|xref:nng_stream_send.3str.adoc[nng_stream_send()]|send to byte stream
|xref:nng_stream_set.3str.adoc[nng_stream_set()]|set option on byte stream
|===
=== HTTP Support
The library may be configured with support for HTTP, and this will
be the case if WebSocket support is configured as well.
In this case, it is possible to access functionality to support the creation of
HTTP (and HTTP/S if TLS support is present) servers and clients.
==== Common HTTP Functions
The following functions are used to work with HTTP requests, responses,
and connections.
|===
|xref:nng_http_conn_close.3http.adoc[nng_http_conn_close()]|close HTTP connection
|xref:nng_http_conn_read.3http.adoc[nng_http_conn_read()]|read from HTTP connection
|xref:nng_http_conn_read_all.3http.adoc[nng_http_conn_read_all()]|read all from HTTP connection
|xref:nng_http_conn_read_req.3http.adoc[nng_http_conn_read_req()]|read HTTP request
|xref:nng_http_conn_read_res.3http.adoc[nng_http_conn_read_res()]|read HTTP response
|xref:nng_http_conn_write.3http.adoc[nng_http_conn_write()]|write to HTTP connection
|xref:nng_http_conn_write_all.3http.adoc[nng_http_conn_write_all()]|write all to HTTP connection
|xref:nng_http_conn_write_req.3http.adoc[nng_http_conn_write_req()]|write HTTP request
|xref:nng_http_conn_write_res.3http.adoc[nng_http_conn_write_res()]|write HTTP response
|xref:nng_http_req_add_header.3http.adoc[nng_http_req_add_header()]|add HTTP request header
|xref:nng_http_req_alloc.3http.adoc[nng_http_req_alloc()]|allocate HTTP request structure
|xref:nng_http_req_copy_data.3http.adoc[nng_http_req_copy_data()]|copy HTTP request body
|xref:nng_http_req_del_header.3http.adoc[nng_http_req_del_header()]|delete HTTP request header
|xref:nng_http_req_free.3http.adoc[nng_http_req_free()]|free HTTP request structure
|xref:nng_http_req_get_data.3http.adoc[nng_http_req_get_data()]|get HTTP request body
|xref:nng_http_req_get_header.3http.adoc[nng_http_req_get_header()]|return HTTP request header
|xref:nng_http_req_get_method.3http.adoc[nng_http_req_get_method()]|return HTTP request method
|xref:nng_http_req_get_uri.3http.adoc[nng_http_req_get_uri()]|return HTTP request URI
|xref:nng_http_req_get_version.3http.adoc[nng_http_req_get_version()]|return HTTP request protocol version
|xref:nng_http_req_reset.3http.adoc[nng_http_req_reset()]|reset HTTP request structure
|xref:nng_http_req_set_data.3http.adoc[nng_http_req_set_data()]|set HTTP request body
|xref:nng_http_req_set_header.3http.adoc[nng_http_req_set_header()]|set HTTP request header
|xref:nng_http_req_set_method.3http.adoc[nng_http_req_set_method()]|set HTTP request method
|xref:nng_http_req_set_uri.3http.adoc[nng_http_req_set_uri()]|set HTTP request URI
|xref:nng_http_req_set_version.3http.adoc[nng_http_req_set_version()]|set HTTP request protocol version
|xref:nng_http_res_add_header.3http.adoc[nng_http_res_add_header()]|add HTTP response header
|xref:nng_http_res_alloc.3http.adoc[nng_http_res_alloc()]|allocate HTTP response structure
|xref:nng_http_res_alloc_error.3http.adoc[nng_http_res_alloc_error()]|allocate HTTP error response
|xref:nng_http_res_copy_data.3http.adoc[nng_http_res_copy_data()]|copy HTTP response body
|xref:nng_http_res_del_header.3http.adoc[nng_http_res_del_header()]|delete HTTP response header
|xref:nng_http_res_free.3http.adoc[nng_http_res_free()]|free HTTP response structure
|xref:nng_http_res_get_data.3http.adoc[nng_http_res_get_data()]|get HTTP response body
|xref:nng_http_res_get_header.3http.adoc[nng_http_res_get_header()]|return HTTP response header
|xref:nng_http_res_get_reason.3http.adoc[nng_http_res_get_reason()]|return HTTP response reason
|xref:nng_http_res_get_status.3http.adoc[nng_http_res_get_status()]|return HTTP response status
|xref:nng_http_res_get_version.3http.adoc[nng_http_res_get_version()]|return HTTP response protocol version
|xref:nng_http_res_reset.3http.adoc[nng_http_res_reset()]|reset HTTP response structure
|xref:nng_http_res_set_data.3http.adoc[nng_http_res_set_data()]|set HTTP response body
|xref:nng_http_res_set_header.3http.adoc[nng_http_res_set_header()]|set HTTP response header
|xref:nng_http_res_set_reason.3http.adoc[nng_http_res_set_reason()]|set HTTP response reason
|xref:nng_http_res_set_status.3http.adoc[nng_http_res_set_status()]|set HTTP response status
|xref:nng_http_res_set_version.3http.adoc[nng_http_res_set_version()]|set HTTP response protocol version
|===
==== HTTP Client Functions
These functions are intended for use with HTTP client applications.
|===
|xref:nng_http_client_alloc.3http.adoc[nng_http_client_alloc()]|allocate HTTP client
|xref:nng_http_client_connect.3http.adoc[nng_http_client_connect()]|establish HTTP client connection
|xref:nng_http_client_free.3http.adoc[nng_http_client_free()]|free HTTP client
|xref:nng_http_client_get_tls.3http.adoc[nng_http_client_get_tls()]|get HTTP client TLS configuration
|xref:nng_http_client_set_tls.3http.adoc[nng_http_client_set_tls()]|set HTTP client TLS configuration
|xref:nng_http_client_transact.3http.adoc[nng_http_client_transact()]|perform one HTTP transaction
|xref:nng_http_conn_transact.3http.adoc[nng_http_conn_transact()]|perform one HTTP transaction on connection
|===
==== HTTP Server Functions
These functions are intended for use with HTTP server applications.
|===
|xref:nng_http_handler_alloc.3http.adoc[nng_http_handler_alloc()]|allocate HTTP server handler
|xref:nng_http_handler_collect_body.3http.adoc[nng_http_handler_collect_body()]|set HTTP handler to collect request body
|xref:nng_http_handler_free.3http.adoc[nng_http_handler_free()]|free HTTP server handler
|xref:nng_http_handler_get_data.3http.adoc[nng_http_handler_get_data()]|return extra data for HTTP handler
|xref:nng_http_handler_set_data.3http.adoc[nng_http_handler_set_data()]|set extra data for HTTP handler
|xref:nng_http_handler_set_host.3http.adoc[nng_http_handler_set_host()]|set host for HTTP handler
|xref:nng_http_handler_set_method.3http.adoc[nng_http_handler_set_method()]|set HTTP handler method
|xref:nng_http_handler_set_tree.3http.adoc[nng_http_handler_set_tree()]|set HTTP handler to match trees
|xref:nng_http_hijack.3http.adoc[nng_http_hijack()]|hijack HTTP server connection
|xref:nng_http_server_add_handler.3http.adoc[nng_http_server_add_handler()]|add HTTP server handler
|xref:nng_http_server_del_handler.3http.adoc[nng_http_server_del_handler()]|delete HTTP server handler
|xref:nng_http_server_get_addr.3http.adoc[nng_http_server_get_addr()]|get HTTP server address
|xref:nng_http_server_get_tls.3http.adoc[nng_http_server_get_tls()]|get HTTP server TLS configuration
|xref:nng_http_server_hold.3http.adoc[nng_http_server_hold()]|get and hold HTTP server instance
|xref:nng_http_server_release.3http.adoc[nng_http_server_release()]|release HTTP server instance
|xref:nng_http_server_set_error_file.3http.adoc[nng_http_server_set_error_file()]|set custom HTTP error file
|xref:nng_http_server_set_error_page.3http.adoc[nng_http_server_set_error_page()]|set custom HTTP error page
|xref:nng_http_server_set_tls.3http.adoc[nng_http_server_set_tls()]|set HTTP server TLS configuration
|xref:nng_http_server_res_error.3http.adoc[nng_http_server_res_error()]|use HTTP server error page
|xref:nng_http_server_start.3http.adoc[nng_http_server_start()]|start HTTP server
|xref:nng_http_server_stop.3http.adoc[nng_http_server_stop()]|stop HTTP server
|===
=== TLS Configuration Objects
The following functions are used to manipulate transport layer security
(TLS) configuration objects. Most of these functions will not be used even
by TLS applications.
NOTE: These functions will only be present if the library has been built
with TLS support.
|===
|xref:nng_tls_config_alloc.3tls.adoc[nng_tls_config_alloc()]|allocate TLS configuration
|xref:nng_tls_config_auth_mode.3tls.adoc[nng_tls_config_auth_mode()]|set authentication mode
|xref:nng_tls_config_ca_chain.3tls.adoc[nng_tls_config_ca_chain()]|set certificate authority chain
|xref:nng_tls_config_ca_file.3tls.adoc[nng_tls_config_ca_file()]|load certificate authority from file
|xref:nng_tls_config_cert_key_file.3tls.adoc[nng_tls_config_cert_key_file()]|load own certificate and key from file
|xref:nng_tls_config_own_cert.3tls.adoc[nng_tls_config_own_cert()]|set own certificate and key
|xref:nng_tls_config_free.3tls.adoc[nng_tls_config_free()]|free TLS configuration
|xref:nng_tls_config_server_name.3tls.adoc[nng_tls_config_server_name()]|set remote server name
|===
== SEE ALSO
[.text-left]
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

2
external/nng/docs/man/man1.desc vendored Normal file
View file

@ -0,0 +1,2 @@
This section documents utilities and programs that are included
with the distribution.

1
external/nng/docs/man/man1.sect vendored Normal file
View file

@ -0,0 +1 @@
Commands and Utilities

6
external/nng/docs/man/man3.desc vendored Normal file
View file

@ -0,0 +1,6 @@
This section documents core libary functions supporting Scalability
Protocols.
Most Scalability Protocols applications can be written using just
the functions documented in this section, as this represents the
primary API for building such applications.

1
external/nng/docs/man/man3.sect vendored Normal file
View file

@ -0,0 +1 @@
Library Functions

13
external/nng/docs/man/man3compat.desc vendored Normal file
View file

@ -0,0 +1,13 @@
This section documents the _nanomsg_ 1.0 libary compatible functions.
These functions are provided as a transition aid, for application
developers coming to _NNG_ from _libnanomsg_, and are discouraged
from use in new applications.
TIP: While this is discouraged for long term use, as a transition aid
applications may use the value returned by the
xref:nng_socket_id.3.adoc[`nng_socket_id()`] in these functions just like a
socket descriptor (as if the socket were opened via
xref:nn_socket.3compat.adoc[`nn_socket()`]).
This sort of API intermixing should only be used during transition from
the legacy API to the new API.

1
external/nng/docs/man/man3compat.sect vendored Normal file
View file

@ -0,0 +1 @@
Compatible Library Functions

13
external/nng/docs/man/man3http.desc vendored Normal file
View file

@ -0,0 +1,13 @@
This section documents supplemental HTTP (HyperText Transport Protocol)
support functions that are available.
These functions can be used in conjunction with the
xref:nng_ws.7.adoc[WebSocket] transport for Scalability Protocols, or they
may be used to construct other types of applications that communicate
using HTTP.
It is also possible to combine the two, such that an HTTP server providing
static or dynamic content can also be used to host one or more Scalability
Protocols sockets.
NOTE: At present NNG only supports HTTP/1.0 and HTTP/1.1.

1
external/nng/docs/man/man3http.sect vendored Normal file
View file

@ -0,0 +1 @@
Supplemental HTTP Functions

7
external/nng/docs/man/man3str.desc vendored Normal file
View file

@ -0,0 +1,7 @@
This section documents supplemental byte stream functions that
are available.
These functions are made available to facilitate using raw byte stream
connections with the NNG asynchronous I/O API.
These byte streams may be useful for applications that need to
communicate with raw TCP/IP or IPC streams instead of Scalability Protocols.

1
external/nng/docs/man/man3str.sect vendored Normal file
View file

@ -0,0 +1 @@
Supplemental TCP Functions

7
external/nng/docs/man/man3supp.desc vendored Normal file
View file

@ -0,0 +1,7 @@
This section documents supplemental functions that are available.
These functions are not intrinsic to building Scalability Protocols
applications with this library.
However, their use may facilitate writing portable applications by
providing uniform functions for common application needs such as
mutual exclusion locks, threading, time keeping, and similar needs.

1
external/nng/docs/man/man3supp.sect vendored Normal file
View file

@ -0,0 +1 @@
Supplemental Functions

17
external/nng/docs/man/man3tls.desc vendored Normal file
View file

@ -0,0 +1,17 @@
This section documents supplemental TLS (Transport Layer Security)
functions that are available.
TLS support is available when using Scalability Protocols with
the xref:nng_tls.7.adoc[TLS] transport, or when using WebSocket, either
with the xref:nng_ws.7.adoc[WebSocket] transport for Scalability Protocols,
or combined with other HTTP capabilities.
These functions depend on library support that is not included directly
with _NNG_ however, so their presence will depend on whether this
additional support was present and enabled with _libnng_ was built.
Currently, this extra support can be provided by the
https://tls.mbed.org[mbedTLS library] or by external plug-ins.
TIP: Contact https://staysail.tech[Staysail Systems, Inc.] for
details about commercially available options, including support for
FIPS 140-2 validated cryptography and TLS v1.3.

1
external/nng/docs/man/man3tls.sect vendored Normal file
View file

@ -0,0 +1 @@
Supplemental TLS Functions

4
external/nng/docs/man/man5.desc vendored Normal file
View file

@ -0,0 +1,4 @@
This section documents core macros and types that are available.
These are the core types and macros that most Scalabilty Protocols
applications need will use.

1
external/nng/docs/man/man5.sect vendored Normal file
View file

@ -0,0 +1 @@
Macros and Types

14
external/nng/docs/man/man7.desc vendored Normal file
View file

@ -0,0 +1,14 @@
This sections documents various protocols and transports that are
available in the distribution.
(((protocol)))
Protocols implement communication patterns, such as
request/reply, publish/subscribe, and so forth.
A given xref:nng_socket.5.adoc[socket] is created with exactly one protocol, and that
protocol defines the key behavior of the socket.
(((transport)))
Conversely, transports are the underlying mechansims by which messages
are moved between participants, such as TCP/IP or UNIX domain IPC.
A given xref:nng_socket.5.adoc[socket] may be using several transports at the same
time.

1
external/nng/docs/man/man7.sect vendored Normal file
View file

@ -0,0 +1 @@
Protocols and Transports

View file

@ -0,0 +1,67 @@
= nn_allocmsg(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_allocmsg - allocate message (compatible API)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
void *nn_allocmsg(size_t size, int type);
----
== DESCRIPTION
The `nn_allocmsg()` allocates a message structure of size _size_, and is
primarily used to support zero-copy send operations, making use of the
`NNG_MSG` special size indicator.
The value returned is a pointer to the start of the message payload buffer.
The value of _size_ must be positive, and small enough to hold reasonable
message data plus book-keeping information.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
The value of _type_ *must* be zero.
(This argument was reserved to support different kinds of memory spaces
for RDMA devices, but this was never developed in the legacy API.)
The returned message must be disposed of by either
xref:nn_freemsg.3compat.adoc[`nn_freemsg()`] or
xref:nn_send.3compat.adoc[`nn_send()`] when the caller is finished with it.
== RETURN VALUES
This function returns a pointer to message buffer space, or `NULL`
on failure.
== ERRORS
[horizontal]
`ENOMEM`:: Insufficient memory is available.
`EINVAL`:: An invalid _size_ or _type_ was specified.
`ETERM`:: The library is shutting down.
== SEE ALSO
[.text-left]
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_freemsg.3compat.adoc[nn_freemsg(3compat)],
xref:nn_reallocmsg.3compat.adoc[nn_reallocmsg(3compat)],
xref:nn_send.3compat.adoc[nn_send(3compat)],
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,68 @@
= nn_bind(3compat)
//
// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_bind - accept connections from remote peers (compatible API)
== SYNOPSIS
[source, c]
----
#include <nanomsg/nn.h>
int nn_bind(int sock, const char *url)
----
== DESCRIPTION
The `nn_bind()` function arranges for the socket _sock_ to
accept connections at the address specified by _url_.
An identifier for this socket's association with the _url_ is
returned to the caller on success.
This identfier can be used with
xref:nn_shutdown.3compat.adoc[`nn_shutdown()`] to
remove the association later.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
NOTE: The bind operation is performed asynchronously, and may not have
completed before this function returns control to the caller.
IMPORTANT: Only transports supported by legacy _libnanomsg_ may be
used with this function.
In particular, only the schemes `tcp://`, `ipc://`, `inproc://`, and `ws://` are
supported with this function.
(Use the xref:libnng.3.adoc[modern API] to use other schemes.)
== RETURN VALUES
This function returns a positive identifier on success, and -1 on error.
== ERRORS
[horizontal]
`EADDRINUSE`:: The address specified by _url_ is already in use.
`EADDRNOTAVAIL`:: The address specified by _url_ is not available.
`EBADF`:: The socket _sock_ is not open.
`EINVAL`:: An invalid _url_ was supplied.
== SEE ALSO
[.text-left]
xref:nn_connect.3compat.adoc[nn_connect(3compat)],
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_shutdown.3compat.adoc[nn_shutdown(3compat)],
xref:nn_socket.3compat.adoc[nn_socket(3compat)],
xref:nng_compat.3compat.adoc[nn_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,51 @@
= nn_close(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_close - close socket (compatible API)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
int nn_close(int sock);
----
== DESCRIPTION
The `nn_close()` function closes the socket _sock_.
Any operations that are currently in progress will be terminated, and will
fail with error `EBADF`.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
== RETURN VALUES
This function returns zero on success, and -1 on failure.
== ERRORS
[horizontal]
`EBADF`:: The socket is not open.
`ETERM`:: The library is shutting down.
== SEE ALSO
[.text-left]
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_socket.3compat.adoc[nn_socket(3compat)],
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,78 @@
= nn_cmsg(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_cmsg - message control data (compatible API)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
struct nn_cmsghdr {
size_t cmsg_len;
int cmsg_level;
int cmsg_type;
};
----
== DESCRIPTION
The `nn_cmsghdr` structure describes a block of control data that is
associated with a message either sent by xref:nn_sendmsg.3compat.adoc[`nn_sendmsg()`]
or received by xref:nn_recvmsg.3compat.adoc[`nn_recvmsg()`].
NOTE: This structure and supporting macros are provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
Each header is followed by `cmsg_len` bytes of data, plus any padding required
to align the structure.
The only defined ancillary data at this time is the protocol headers used by
the protocols.
This uses `cmsg_level` set to `PROTO_SP` and the `cmsg_type` set to
`SP_HDR`.
The actual data for this will vary from depending on the protocol used.
Convenience macros are provided to make working with these fields easier.
`struct nn_cmsghdr *NN_CMSG_FIRSTHDR(struct nn_msghdr *__hdr__)`::
This macro returns the first `struct nn_cmsghdr` header in _hdr_.
`struct nn_cmsghdr *NN_CMSG_NXTHDR(struct nn_msghdr *__hdr__, struct nn_cmsghdr *__ch__)`::
This macro returns a pointer to the next `struct nn_cmsghdr` in _hdr_ after _ch_.
`void *NN_CMSG_DATA(struct nn_cmsghdr *__ch__)`::
This macro returns a pointer to the header-specific data for _ch_.
`size_t NN_CMSG_ALIGN(size_t __len__)`::
This macro returns the length specified by _len_, plus any padding required to
provide the necessary alignment for another structure.
`size_t NN_CMSG_SPACE(size_t __len__)`::
This macro returns the amount of space required for a header, with _len_
bytes of following data, and any necessary padding.
`size_t NN_CMSG_LEN(size_t __len__)`::
This macro evaluates to the length of the header (including alignment),
and the associated data of length _len_, but without any trailing padding
to align for another header.
== SEE ALSO
[.text-left]
xref:nn_recvmsg.3compat.adoc[nn_recvmsg(3compat)],
xref:nn_sendmsg.3compat.adoc[nn_sendmsg(3compat)],
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,67 @@
= nn_connect(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_connect - connect to remote peer (compatible API)
== SYNOPSIS
[source, c]
----
#include <nanomsg/nn.h>
int nn_connect(int sock, const char *url)
----
== DESCRIPTION
The `nn_connect()` function arranges for the socket _sock_ to
initiate connection to a peer at the address specified by _url_.
An identifier for this socket's association with the _url_ is
returned to the caller on success.
This identifier can be used with
xref:nn_shutdown.3compat.adoc[`nn_shutdown()`] to
remove the association later.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
NOTE: The connect operation is performed asynchronously, and may not have
completed before this function returns control to the caller.
IMPORTANT: Only transports supported by legacy _libnanomsg_ may be
used with this function.
In particular, only the schemes `tcp://`, `ipc://`, `inproc://`, and `ws://` are
supported with this function.
(Use the xref:libnng.3.adoc[modern API] to use other schemes.)
== RETURN VALUES
This function returns a positive identifier success, and -1 on error.
== ERRORS
[horizontal]
`ECONNREFUSED`:: The connection attempt was refused.
`EBADF`:: The socket _sock_ is not open.
`EINVAL`:: An invalid _url_ was supplied.
== SEE ALSO
[.text-left]
xref:nn_bind.3compat.adoc[nn_bind(3compat)],
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_shutdown.3compat.adoc[nn_shutdown(3compat)],
xref:nn_socket.3compat.adoc[nn_socket(3compat)],
xref:nng_compat.3compat.adoc[nn_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,59 @@
= nn_device(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_device - create forwarding device (compatible API)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
int nn_device(int sock1, int sock2);
----
== DESCRIPTION
The `nn_device()` function is used to create a forwarder, where messages
received on one of the two sockets _sock1_ and _sock2_ are forwarded to
the other.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
The two sockets must be compatible, and must be
xref:nng.7.adoc#raw_mode[raw mode]
sockets.
More detail about devices and how they can be used is available in the
new style xref:nng_device.3.adoc[nng_device()] documentation.
== RETURN VALUES
This function blocks forever, and will return -1 only when
one of the sockets is closed or an error occurs.
== ERRORS
[horizontal]
`EBADF`:: One of the two sockets is invalid or not open, or has
`EINVAL`:: The sockets are not compatible with each other, or not both raw.
`ENOMEM`:: Insufficient memory is available.
== SEE ALSO
[.text-left]
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_socket.3compat.adoc[nn_socket(3compat)],
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,79 @@
= nn_errno(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_errno - return most recent error (compatible API)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
int nn_errno(void);
----
== DESCRIPTION
The `nn_errno()` function returns the error number corresponding to the
most recent failed operation by the calling thread.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
IMPORTANT: The error numbers returned from this function may include
errors caused by system functions, which overlap the usual `errno` variable,
and this function simply returns the value of `errno`.
However, the values returned may include numeric values that are not
defined by the system, but are unique to _libnanomsg_, such as `EFSM`.
This library implements the following error numbers, in addition to any others
that might be set for `errno` by the underlying system:
== RETURN VALUES
This function returns the value of `errno`.
If no operation has failed, then this will be zero.
== ERRORS
[horizontal]
`EINTR`:: Operation interrupted.
`ENOMEM`:: Insufficient memory.
`EINVAL`:: Invalid argument.
`EBUSY`:: Resource is busy.
`ETIMEDOUT`:: Operation timed out.
`ECONNREFUSED`:: Connection refused by peer.
`EBADF`:: Invalid or closed socket.
`EAGAIN`:: Operation would block.
`ENOTSUP`:: Protocol or option not supported.
`EADDRINUSE`:: Requested address is already in use.
`EFSM`:: Protocol state incorrect.
`EPROTO`:: Protocol error.
`EHOSTUNREACH`:: Remote peer is unreachable.
`EADDRNOTAVAIL`:: Requested address is not available.
`EACCES`:: Permission denied.
`EMSGSIZE`:: Message is too large.
`ECONNABORTED`:: Connection attempt aborted.
`ECONNRESET`:: Connection reset by peer.
`EEXIST`:: Resource already exists.
`EMFILE`:: Too many open files.
`ENOSPC`:: Insufficient persistent storage.
== SEE ALSO
[.text-left]
xref:nn_strerror.3compat.adoc[nn_strerror(3compat)],
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,49 @@
= nn_freemsg(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_freemsg - free message (compatible API)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
int nn_freemsg(void *msg);
----
== DESCRIPTION
The `nn_freemsg()` deallocates a message previously allocated with
xref:nn_allocmsg.3compat.adoc[`nn_allocmsg()`] or similar functions.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
== RETURN VALUES
This function always returns 0.
== ERRORS
None.
== SEE ALSO
[.text-left]
xref:nn_allocmsg.3compat.adoc[nn_allocmsg(3compat)],
xref:nn_freemsg.3compat.adoc[nn_freemsg(3compat)],
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,46 @@
= nn_get_statistic(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_get_statistic - get statistic (stub)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
uint64_t nn_get_statistic(int sock, int stat);
----
== DESCRIPTION
The `nn_get_statistic()` function exists only as a stub, and always returns
zero.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
== RETURN VALUES
Zero.
== ERRORS
None.
== SEE ALSO
[.text-left]
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,228 @@
= nn_getsockopt(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_getsockopt - get socket option (compatible API)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
int nn_getsockopt(int sock, int level, int option, void *val, size_t *szp);
----
== DESCRIPTION
The `nn_getsockopt()` function gets a socket option on socket _sock_.
The option retrieved is determined by the _level_ and _option_.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
The value pointed to by _szp_ must be initialized to the size of the buffer
pointed to by _val_.
No more than this many bytes of the option will be copied into the destination
buffer on success.
On success, the value pointed to by _szp_ will be updated with the actual
size of the option.
TIP: To determine the size to receive an option, first call this function
with _val_ set to `NULL` and the value addressed by _szp_ initialized to zero.
The _level_ determines whether the option is a generic socket option,
or is transport-specific.
The values possible for level are as follows:
[horizontal]
`NN_SOL_SOCKET`:: Generic socket option
`NN_IPC`:: Transport specific option for IPC.
`NN_TCP`:: Transport specific option for TCP.
`NN_WS`:: Transport specific option for WebSocket.
The following generic socket options are possible (all are of type `int` and
thus size 4, unless otherwise indicated.)
`NN_SNDBUF`::
Send buffer size in bytes.
NOTE: In _NNG_ buffers are sized as a count of messages rather than
bytes; accordingly this value is the queue depth multiplied by 1024
(representing an estimate that the average message size is 1kB).
Applications that have unusual message sizes may wish to adjust the value
used here accordingly.
`NN_RCVBUF`::
Receive buffer size in bytes.
NOTE: The same caveats for `NN_SNDBUF` apply here as well.
`NN_SNDTIMEO`::
Send time-out in milliseconds.
Send operations will fail with `ETIMEDOUT` if no message can be received
after this many milliseconds have transpired since the operation was started.
A value of -1 means that no timeout is applied.
`NN_RCVTIMEO`::
Receive time-out in milliseconds.
Receive operations will fail with `ETIMEDOUT` if no message can be received
after this many milliseconds have transpired since the operation was started.
A value of -1 means that no timeout is applied.
`NN_RCVMAXSIZE`::
Maximum receive size in bytes.
The socket will discard messages larger than this on receive.
The default, 1MB, is intended to prevent denial-of-service attacks.
The value -1 removes any limit.
`NN_RECONNECT_IVL`::
Reconnect interval in milliseconds.
After an outgoing connection is closed or fails, the socket will
automatically attempt to reconnect after this many milliseconds.
This is the starting value for the time, and is used in the first
reconnection attempt after a successful connection is made.
The default is 100.
`NN_RECONNECT_IVL_MAX`::
Maximum reconnect interval in milliseconds.
Subsequent reconnection attempts after a failed attempt are made at
exponentially increasing intervals (back-off), but the interval is
capped by this value.
If this value is smaller than `NN_RECONNECT_IVL`, then no exponential
back-off is performed, and each reconnect interval will be determined
solely by `NN_RECONNECT_IVL`.
The default is zero.
`NN_LINGER`::
This option is always zero and exists only for compatibility.
NOTE: This option was unreliable in early releases of _libnanomsg_, and
is unsupported in _NNG_ and recent _libnanomsg_ releases.
Applications needing assurance of message delivery should either include an
explicit notification (automatic with the `NN_REQ` protocol) or allow
sufficient time for the socket to drain before closing the socket or exiting.
`NN_SNDPRIO`::
This option is not implemented at this time.
`NN_RCVPRIO`::
This option is not implemented at this time.
`NN_IPV4ONLY`::
This option is not implemented at this time.
`NN_SOCKET_NAME`::
This option is a string, and represents the socket name.
It can be changed to help with identifying different sockets with
their different application-specific purposes.
`NN_MAXTTL`::
Maximum number of times a message may traverse devices or proxies.
This value, if positive, provides some protection against forwarding loops in
xref:nng_device.3.adoc[device] chains.
NOTE: Not all protocols offer this protection, so care should still be used
in configuring device forwarding.
`NN_DOMAIN`::
This option of type `int` represents either the value `AF_SP` or `AF_SP_RAW`,
corresponding to the value that the socket was created with.
`NN_PROTOCOL`::
This option option of type `int` contains the numeric protocol number
that the socket is used with.
`NN_RCVFD`::
This option returns a file descriptor suitable for use in with `poll()` or
`select()` (or other system-specific polling functions).
This descriptor will be readable when a message is available for receiving
at the socket.
This option is of type `int` on all systems except Windows, where it is of
type `SOCKET`.
NOTE: The file descriptor should not be read or written by the application,
and is not the same as any underlying descriptor used for network sockets.
`NN_SNDFD`::
This option returns a file descriptor suitable for use in with `poll()` or
`select()` (or other system-specific polling functions).
This descriptor will be readable when the socket is able to accept a message
for sending.
This option is of type `int` on all systems except Windows, where it is of
type `SOCKET`.
NOTE: The file descriptor should not be read or written by the application,
and is not the same as any underlying descriptor used for network sockets.
Furthermore, the file descriptor should only be polled for _readability_.
The following option is available for `NN_REQ` sockets
using the `NN_REQ` level:
`NN_REQ_RESEND_IVL`::
Request retry interval in milliseconds.
If an `NN_REQ` socket does not receive a reply to a request within this
period of time, the socket will automatically resend the request.
The default value is 60000 (one minute).
The following option is available for `NN_SURVEYOR` sockets
using the `NN_SURVEYOR` level:
`NN_SURVEYOR_DEADLINE`::
Survey deadline in milliseconds for `NN_SURVEYOR` sockets.
After sending a survey message, the socket will only accept responses
from respondents for this long.
Any responses arriving after this expires are silently discarded.
In addition, the following transport specific options are offered:
`NN_IPC_SEC_ATTR`::
This `NN_IPC` option is not supported at this time.
`NN_IPC_OUTBUFSZ`::
This `NN_IPC` option is not supported at this time.
`NN_IPC_INBUFSZE`::
This `NN_IPC` option is not supported at this time.
`NN_TCP_NODELAY`::
This `NN_TCP` option is not supported at this time.
`NN_WS_MSG_TYPE`::
This `NN_WS` option is not supported, as _NNG_ only supports binary messages
in this implementation.
== RETURN VALUES
This function returns zero on success, and -1 on failure.
== ERRORS
[horizontal]
`EBADF`:: The socket _sock_ is not an open socket.
`ENOMEM`:: Insufficient memory is available.
`ENOPROTOOPT`:: The level and/or option is invalid.
`EINVAL`:: The option, or the value passed, is invalid.
`ETERM`:: The library is shutting down.
`EACCES`:: The option cannot be changed.
== SEE ALSO
[.text-left]
xref:nng_socket.5.adoc[nng_socket(5)],
xref:nn_close.3compat.adoc[nn_close(3compat)],
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_getsockopt.3compat.adoc[nn_getsockopt(3compat)],
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,102 @@
= nn_poll(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_poll - poll sockets (compatible API)
== SYNOPSIS
[source, c]
----
#include <nanomsg/nn.h>
#define NN_POLLIN 1
#define NN_POLLOUT 2
struct nn_pollfd {
int fd;
uint16_t events;
uint16_t revents;
};
int nn_poll(struct nn_pollfd *pfds, int npfd, int timeout);
----
== DESCRIPTION
The `nn_poll()` function polls a group of sockets for readiness to send or receive.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
The array of _nfds_ sockets to poll for are passed into _pfds_.
Each member of this array is initialized with the `fd` field set to
the socket, and the `events` field set to a mask that can contain either or both
of the flags `NN_POLLIN` and `NN_POLLOUT`.
The flag `NN_POLLIN` indicates that a socket is ready for receiving without
blocking (a message is available on the socket), and the flag `NN_POLLOUT`
indicates that a socket is ready for sending without blocking.
Upon success, the function returns the number of updates the `revents`
field of each member of the _pfds_ array, setting it to indicate
whether the requested status is true or not.
NOTE: The `revents` field will only have a flag set if the corresponding
flag was also set in the `events` field.
If the _timeout_ field is positive, then this function will wait for
up the that many milliseconds.
If none of the requested events occurs before that timeout occurs, then
the function will return -1 and set the error to `ETIMEDOUT`.
If the _timeout_ is zero, then this function will return immediately,
after updating the current status of the sockets.
If the _timeout_ is -1, then the function waits forever, or until one of the
requested events occurs.
IMPORTANT: This function is only suitable for use with sockets obtained with the
xref:nn_socket.3compat.adoc[`nn_socket()`] function, and is not compatible
with file descriptors obtained via any other means.
This includes file descriptors obtained using the `NN_SNDFD` or `NN_RCVFD`
options with xref:nn_getsockopt.3compat.adoc[`nn_getsockopt()`]
NOTE: This function is significantly less efficient than other polling
or asynchronous I/O mechanisms, and is provided for API compatibility only.
It's use is discouraged.
NOTE: This function is *not* supported on systems other than POSIX derived
platforms and Windows.
== RETURN VALUES
This function returns the number of sockets with events on success, or -1 on error.
== ERRORS
[horizontal]
`ENOMEM`:: Insufficient memory available.
`EBADF`:: One of the sockets is not open.
`ETIMEDOUT`:: Operation timed out.
`ENOTSUP`:: This function is not supported on this platform.
== SEE ALSO
[.text-left]
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_recv.3compat.adoc[nn_recv(3compat)],
xref:nn_send.3compat.adoc[nn_send(3compat)],
xref:nn_socket.3compat.adoc[nn_socket(3compat)],
xref:nng_compat.3compat.adoc[nn_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,59 @@
= nn_reallocmsg(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_reallocmsg - reallocate message (compatible API)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
void *nn_reallocmsg(void *old, size_t size);
----
== DESCRIPTION
The `nn_reallocmsg()` reallocates the message _old_, making it of size _size_.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
On success, the contents of _old_ are copied into the new message
(truncating if appropriate), then _old_ is deallocated, and a pointer
to the new message payload is returned.
On failure, the _old_ message is unchanged, and the value `NULL` is returned
to the caller.
== RETURN VALUES
This function returns a pointer to message buffer space, or `NULL`
on failure.
== ERRORS
[horizontal]
`ENOMEM`:: Insufficient memory is available.
`EINVAL`:: An invalid _size_ was specified.
`ETERM`:: The library is shutting down.
== SEE ALSO
[.text-left]
xref:nn_allocmsg.3compat.adoc[nn_allocmsg(3compat)],
xref:nn_freemsg.3compat.adoc[nn_freemsg(3compat)],
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,75 @@
= nn_recv(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_recv - receive data (compatible API)
== SYNOPSIS
[source, c]
----
#include <nanomsg/nn.h>
int nn_recv(int sock, void *data, size_t size, int flags)
----
== DESCRIPTION
The `nn_recv()` function receives a message from the socket _sock_.
The message body must fit within _size_ bytes, and will be stored
at the location specified by _data_, unless _size_ is the
special value `NN_MSG`, indicating a zero-copy operation.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
If _size_ has the special value `NN_MSG`, then a zero-copy operation
is performed.
In this case, instead of copying the message data into the address
specified by _data_, a new message large enough to hold the message data
will be allocated (as if by the
function xref:nn_allocmsg.3compat.adoc[`nn_allocmsg()`]), and the message
payload will be stored accordingly.
In this case, the value stored at _data_ will not be message data,
but a pointer to the message itself.
In this case, on success, the caller shall take responsibility for
the final disposition of the message (such as by sending it to
another peer using xref:nn_send.3compat.adoc[`nn_send()`]) or
xref:nn_freemsg.3compat.adoc[`nn_freemsg()`].
The _flags_ field may contain the special flag `NN_DONTWAIT`.
In this case, if the no message is available for immediate receipt,
the operation shall not block, but instead will fail with the error `EAGAIN`.
== RETURN VALUES
This function returns the number of bytes sent on success, and -1 on error.
== ERRORS
[horizontal]
`EAGAIN`:: The operation would block.
`EBADF`:: The socket _sock_ is not open.
`EFSM`:: The socket cannot receive in this state.
`ENOTSUP`:: This protocol cannot receive.
`ETIMEDOUT`:: Operation timed out.
== SEE ALSO
[.text-left]
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_recvmsg.3compat.adoc[nn_recvmsg(3compat)],
xref:nn_send.3compat.adoc[nn_send(3compat)],
xref:nn_socket.3compat.adoc[nn_socket(3compat)],
xref:nng_compat.3compat.adoc[nn_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,99 @@
= nn_recvmsg(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_recvmsg - receive message (compatible API)
== SYNOPSIS
[source, c]
----
#include <nanomsg/nn.h>
int nn_recvmsg(int sock, struct nn_msghdr *hdr, int flags);
----
== DESCRIPTION
The `nn_recvmsg()` function receives a message into the header described by
_hdr_ using the socket _sock_.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
The _flags_ field may contain the special flag `NN_DONTWAIT`.
In this case, if no message is ready for receiving on _sock_,
the operation shall not block, but instead will fail with the error `EAGAIN`.
The _hdr_ points to a structure of type `struct nn_msghdr`, which has the
following definition:
[source, c]
----
struct nn_iovec {
void * iov_base;
size_t iov_len;
};
struct nn_msghdr {
struct nn_iovec *msg_iov;
int msg_iovlen;
void * msg_control;
size_t msg_controllen;
};
----
The `msg_iov` is an array of scatter items, permitting the message
to be spread into different memory blocks.
There are `msg_iovlen` elements in this array, each of which
has the base address (`iov_base`) and length (`iov_len`) indicated.
The last member of this array may have the `iov_len` field set to `NN_MSG`,
in which case the function shall allocate a message buffer, and store the
pointer to it at the address indicated by `iov_base`.
This can help save an extra copy operation.
The buffer should be deallocated by xref:nn_freemsg.3compat.adoc[`nn_freemsg()`]
or similar when it is no longer needed.
The values of `msg_control` and `msg_controllen` describe a buffer
of ancillary data associated with the message.
This is currently only useful to obtain the message headers
used with xref:nng.7.adoc#raw_mode[raw mode] sockets.
In all other circumstances these fields should be zero.
Details about this structure are covered in
xref:nn_cmsg.3compat.adoc[`nn_cmsg(3compat)`].
== RETURN VALUES
This function returns the number of bytes received on success, and -1 on error.
== ERRORS
[horizontal]
`EAGAIN`:: The operation would block.
`EBADF`:: The socket _sock_ is not open.
`EFSM`:: The socket cannot receive in this state.
`EINVAL`:: The _hdr_ is invalid.
`ENOTSUP`:: This protocol cannot receive.
`ETIMEDOUT`:: Operation timed out.
== SEE ALSO
[.text-left]
xref:nn_cmsg.3compat.adoc[nn_cmsg(3compat)],
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_recv.3compat.adoc[nn_recv(3compat)],
xref:nn_send.3compat.adoc[nn_send(3compat)],
xref:nn_socket.3compat.adoc[nn_socket(3compat)],
xref:nng_compat.3compat.adoc[nn_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,74 @@
= nn_send(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_send - send data (compatible API)
== SYNOPSIS
[source, c]
----
#include <nanomsg/nn.h>
int nn_send(int sock, const void *data, size_t size, int flags)
----
== DESCRIPTION
The `nn_send()` function creates a message containing _data_ (of size _size_),
and sends using the socket _sock_.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
If _size_ has the special value `NN_MSG`, then a zero-copy operation
is performed.
In this case, _data_ points not to the message content itself, but instead
is a pointer to the pointer, an extra level of pointer indirection.
The message must have been previously allocated by
xref:nn_allocmsg.3compat.adoc[`nn_allocmsg()`] or
xref:nn_recvmsg.3compat.adoc[`nn_recvmsg()`]`, using the same `NN_MSG` size.
In this case, the ownership of the message shall remain with
the caller, unless the function returns 0, indicating that the
function has taken responsibility for delivering or disposing of the
message.
The _flags_ field may contain the special flag `NN_DONTWAIT`.
In this case, if the socket is unable to accept more data for sending,
the operation shall not block, but instead will fail with the error `EAGAIN`.
NOTE: The send operation is performed asynchronously, and may not have
completed before this function returns control to the caller.
== RETURN VALUES
This function returns the number of bytes sent on success, and -1 on error.
== ERRORS
[horizontal]
`EAGAIN`:: The operation would block.
`EBADF`:: The socket _sock_ is not open.
`EFSM`:: The socket cannot send in this state.
`ENOTSUP`:: This protocol cannot send.
`ETIMEDOUT`:: Operation timed out.
== SEE ALSO
[.text-left]
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_recv.3compat.adoc[nn_recv(3compat)],
xref:nn_sendmsg.3compat.adoc[nn_sendmsg(3compat)],
xref:nn_socket.3compat.adoc[nn_socket(3compat)],
xref:nng_compat.3compat.adoc[nn_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,107 @@
= nn_sendmsg(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_sendmsg - send message (compatible API)
== SYNOPSIS
[source, c]
----
#include <nanomsg/nn.h>
int nn_sendmsg(int sock, const struct nn_msghdr *hdr, int flags);
----
== DESCRIPTION
The `nn_sendmsg()` function sends the message described by _hdr_ using the
socket _sock_.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
The _flags_ field may contain the special flag `NN_DONTWAIT`.
In this case, if the socket is unable to accept more data for sending,
the operation shall not block, but instead will fail with the error `EAGAIN`.
The _hdr_ points to a structure of type `struct nn_msghdr`, which has the
following definition:
[source, c]
----
struct nn_iovec {
void * iov_base;
size_t iov_len;
};
struct nn_msghdr {
struct nn_iovec *msg_iov;
int msg_iovlen;
void * msg_control;
size_t msg_controllen;
};
----
The `msg_iov` is an array of gather items, permitting the message
to be spread into different memory blocks.
There are `msg_iovlen` elements in this array, each of which
has the base address (`iov_base`) and length (`iov_len`) indicated.
For buffers allocated for zero copy
(such as by xref:nn_allocmsg.3compat.adoc[`nn_allocmsg()`]), the value
of `iov_base` should be the address of the pointer to the buffer,
rather than the address of the buffer itself.
In this case, the value of `iov_len` should be `NN_MSG`,
as the length is inferred from the allocated message.
If the `msg_iovlen` field is `NN_MSG`, then this function will free
the associated buffer after it is done with it, if it returns successfully.
(If the function returns with an error, then the caller retains ownership
of the associated buffer and may retry the operation or free the buffer
at its choice.)
The values of `msg_control` and `msg_controllen` describe a buffer
of ancillary data to send the message.
This is currently only useful to provide the message headers
used with xref:nng.7.adoc#raw_mode[raw mode] sockets.
In all other circumstances these fields should be zero.
Details about this structure are covered in
xref:nn_cmsg.3compat.adoc[`nn_cmsg(3compat)`].
NOTE: The send operation is performed asynchronously, and may not have
completed before this function returns control to the caller.
== RETURN VALUES
This function returns the number of bytes sent on success, and -1 on error.
== ERRORS
[horizontal]
`EAGAIN`:: The operation would block.
`EBADF`:: The socket _sock_ is not open.
`EFSM`:: The socket cannot send in this state.
`EINVAL`:: The _hdr_ is invalid.
`ENOTSUP`:: This protocol cannot send.
`ETIMEDOUT`:: Operation timed out.
== SEE ALSO
[.text-left]
xref:nn_cmsg.3compat.adoc[nn_cmsg(3compat)],
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_recv.3compat.adoc[nn_recv(3compat)],
xref:nn_send.3compat.adoc[nn_send(3compat)],
xref:nn_socket.3compat.adoc[nn_socket(3compat)],
xref:nng_compat.3compat.adoc[nn_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,205 @@
= nn_setsockopt(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_setsockopt - set socket option (compatible API)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
int nn_setsockopt(int sock, int level, int option, const void *val, size_t sz);
----
== DESCRIPTION
The `nn_setsockopt()` function sets a socket option on socket _sock_,
affecting the behavior of the socket.
The option set is determined by the _level_ and _option_.
The value of the option is set by _val_, and _sz_, which are pointers to
the actual value and the size of the value, respectively.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
The _level_ determines whether the option is a generic socket option,
or is transport-specific.
The values possible for level are as follows:
[horizontal]
`NN_SOL_SOCKET`:: Generic socket option
`NN_IPC`:: Transport specific option for IPC.
`NN_TCP`:: Transport specific option for TCP.
`NN_WS`:: Transport specific option for WebSocket.
The following generic socket options are possible (all are of type `int` and
thus size 4, unless otherwise indicated.)
`NN_SNDBUF`::
Send buffer size in bytes.
NOTE: In _NNG_ buffers are sized as a count of messages rather than
bytes, and so an attempt to estimate a conversion based upon a predetermined
message size of 1kB is made.
The value supplied is rounded up to the nearest value divisible by 1024, and
then divided by 1024 to convert to a message count.
Applications that have unusual message sizes may wish to adjust the value
used here accordingly.
`NN_RCVBUF`::
Receive buffer size in bytes.
NOTE: The same caveats for `NN_SNDBUF` apply here as well.
`NN_SNDTIMEO`::
Send time-out in milliseconds.
Send operations will fail with `ETIMEDOUT` if no message can be received
after this many milliseconds have transpired since the operation was started.
A value of -1 means that no timeout is applied.
`NN_RCVTIMEO`::
Receive time-out in milliseconds.
Receive operations will fail with `ETIMEDOUT` if no message can be received
after this many milliseconds have transpired since the operation was started.
A value of -1 means that no timeout is applied.
`NN_RCVMAXSIZE`::
Maximum receive size in bytes.
The socket will discard messages larger than this on receive.
The default, 1MB, is intended to prevent denial-of-service attacks.
The value -1 removes any limit.
`NN_RECONNECT_IVL`::
Reconnect interval in milliseconds.
After an outgoing connection is closed or fails, the socket will
automatically attempt to reconnect after this many milliseconds.
This is the starting value for the time, and is used in the first
reconnection attempt after a successful connection is made.
The default is 100.
`NN_RECONNECT_IVL_MAX`::
Maximum reconnect interval in milliseconds.
Subsequent reconnection attempts after a failed attempt are made at
exponentially increasing intervals (back-off), but the interval is
capped by this value.
If this value is smaller than `NN_RECONNECT_IVL`, then no exponential
back-off is performed, and each reconnect interval will be determined
solely by `NN_RECONNECT_IVL`.
The default is zero.
`NN_LINGER`::
This option is ignored, and exists only for compatibility.
NOTE: This option was unreliable in early releases of _libnanomsg_, and
is unsupported in _NNG_ and recent _libnanomsg_ releases.
Applications needing assurance of message delivery should either include an
explicit notification (automatic with the `NN_REQ` protocol) or allow
sufficient time for the socket to drain before closing the socket or exiting.
`NN_SNDPRIO`::
This option is not implemented at this time.
`NN_RCVPRIO`::
This option is not implemented at this time.
`NN_IPV4ONLY`::
This option is not implemented at this time.
`NN_SOCKET_NAME`::
This option is a string, and represents the socket name.
It can be changed to help with identifying different sockets with
their different application-specific purposes.
`NN_MAXTTL`::
Maximum number of times a message may traverse devices or proxies.
This value, if positive, provides some protection against forwarding loops in
xref:nng_device.3.adoc[device] chains.
NOTE: Not all protocols offer this protection, so care should still be used
in configuring device forwarding.
The following option is available for `NN_REQ` sockets
using the `NN_REQ` level:
`NN_REQ_RESEND_IVL`::
Request retry interval in milliseconds.
If an `NN_REQ` socket does not receive a reply to a request within this
period of time, the socket will automatically resend the request.
The default value is 60000 (one minute).
The following options are available for `NN_SUB` sockets using the `NN_SUB` level:
`NN_SUB_SUBSCRIBE`::
Subscription topic, for `NN_SUB` sockets.
This sets a subscription topic.
When a message from a publisher arrives, it is compared against all
subscriptions.
If the first _sz_ bytes of the message are not identical to _val_,
then the message is silently discarded.
TIP: To receive all messages, subscribe to an empty topic (_sz_ equal to zero).
`NN_SUB_UNSUBSCRIBE`::
Removes a subscription topic that was earlier established.
The following option is available for `NN_SURVEYOR` sockets
using the `NN_SURVEYOR` level:
`NN_SURVEYOR_DEADLINE`::
Survey deadline in milliseconds for `NN_SURVEYOR` sockets.
After sending a survey message, the socket will only accept responses
from respondents for this long.
Any responses arriving after this expires are silently discarded.
In addition, the following transport specific options are offered:
`NN_IPC_SEC_ATTR`::
This `NN_IPC` option is not supported at this time.
`NN_IPC_OUTBUFSZ`::
This `NN_IPC` option is not supported at this time.
`NN_IPC_INBUFSZE`::
This `NN_IPC` option is not supported at this time.
`NN_TCP_NODELAY`::
This `NN_TCP` option is not supported at this time.
`NN_WS_MSG_TYPE`::
This `NN_WS` option is not supported at this time.
== RETURN VALUES
This function returns zero on success, and -1 on failure.
== ERRORS
[horizontal]
`EBADF`:: The socket _sock_ is not an open socket.
`ENOMEM`:: Insufficient memory is available.
`ENOPROTOOPT`:: The level and/or option is invalid.
`EINVAL`:: The option, or the value passed, is invalid.
`ETERM`:: The library is shutting down.
`EACCES`:: The option cannot be changed.
== SEE ALSO
[.text-left]
xref:nng_socket.5.adoc[nng_socket(5)],
xref:nn_close.3compat.adoc[nn_close(3compat)],
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_getsockopt.3compat.adoc[nn_getsockopt(3compat)],
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,55 @@
= nn_shutdown(3compat)
//
// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_shutdown - shut down endpoint (compatible API)
== SYNOPSIS
[source, c]
----
#include <nanomsg/nn.h>
int nn_shutdown(int sock, int ep)
----
== DESCRIPTION
The `nn_shutdown()` shuts down the endpoint _ep_, which is either a listener or
a dialer) on the socket _sock_.
This will stop the socket from either accepting new connections, or establishing
old ones.
Additionally, any established connections associated with _ep_ will be closed.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
== RETURN VALUES
This function returns zero on success, and -1 on error.
== ERRORS
[horizontal]
`EBADF`:: The socket _sock_ is not open.
`EINVAL`:: An invalid _ep_ was supplied.
== SEE ALSO
[.text-left]
xref:nn_bind.3compat.adoc[nn_bind(3compat)],
xref:nn_connect.3compat.adoc[nn_connect(3compat)],
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nn_socket.3compat.adoc[nn_socket(3compat)],
xref:nng_compat.3compat.adoc[nn_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,78 @@
= nn_socket(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_socket - create socket (compatible API)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
int nn_socket(int af, int proto);
----
== DESCRIPTION
The `nn_socket()` function creates socket using the address family _af_ and
protocol _proto_ and returns it.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
IMPORTANT: Mixing the compatibility API and the modern API is not supported
on a given socket.
NOTE: Some protocols, transports, and features are only available in the modern API.
The address family _af_ can be one of two values:
[horizontal]
`AF_SP`:: Normal socket.
`AF_SP_RAW`:: xref:nng.7.adoc#raw_mode[Raw mode] socket.
The protocol indicates the protocol to be used when creating the socket.
The following protocols are defined:
[horizontal]
`NN_PAIR`:: xref:nng_pair.7.adoc[Pair] protocol.
`NN_PUB`:: xref:nng_pub.7.adoc[Publisher] protocol.
`NN_SUB`:: xref:nng_sub.7.adoc[Subscriber] protocol.
`NN_REQ`:: xref:nng_req.7.adoc[Requestor] protocol.
`NN_REP`:: xref:nng_rep.7.adoc[Replier] protocol.
`NN_PUSH`:: xref:nng_push.7.adoc[Push] protocol.
`NN_PULL`:: xref:nng_pull.7.adoc[Pull] protocol.
`NN_SURVEYOR`:: xref:nng_surveyor.7.adoc[Surveyor] protocol.
`NN_RESPONDENT`:: xref:nng_respondent.7.adoc[Respondent] protocol.
`NN_BUS`:: xref:nng_bus.7.adoc[Bus] protocol.
== RETURN VALUES
This function returns a valid socket number on success, and -1 on failure.
== ERRORS
[horizontal]
`ENOMEM`:: Insufficient memory is available.
`ENOTSUP`:: The protocol is not supported.
`ETERM`:: The library is shutting down.
== SEE ALSO
[.text-left]
xref:nng_socket.5.adoc[nng_socket(5)],
xref:nn_close.3compat.adoc[nn_close(3compat)],
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

View file

@ -0,0 +1,47 @@
= nn_strerror(3compat)
//
// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This document is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt). A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//
== NAME
nn_strerror - return message for error (compatible API)
== SYNOPSIS
[source,c]
----
#include <nanomsg/nn.h>
const char *nn_strerror(int err);
----
== DESCRIPTION
The `nn_strerror()` function returns a human readable message corresponding
to the given error number _err_.
NOTE: This function is provided for API
xref:nng_compat.3compat.adoc[compatibility] with legacy _libnanomsg_.
Consider using the relevant xref:libnng.3.adoc[modern API] instead.
== RETURN VALUES
This function returns the message corresponding to _err_.
== ERRORS
None.
== SEE ALSO
[.text-left]
xref:nn_errno.3compat.adoc[nn_errno(3compat)],
xref:nng_compat.3compat.adoc[nng_compat(3compat)],
xref:nng.7.adoc[nng(7)]

Some files were not shown because too many files have changed in this diff Show more