nanomsg-1.1.5/000077500000000000000000000000001336111550300131565ustar00rootroot00000000000000nanomsg-1.1.5/.appveyor.yml000066400000000000000000000033551336111550300156320ustar00rootroot00000000000000version: 0.8.{build} environment: global: ASCIIDOCTOR_VER: 1.5.4 CFLAGS: /MP matrix: # array of all environments used to test builds - GENERATOR: NMake Makefiles CFG: Debug VS_VERSION: 12.0 - GENERATOR: Visual Studio 14 2015 VS_VERSION: 14.0 CFG: Debug - GENERATOR: Visual Studio 12 2013 VS_VERSION: 12.0 CFG: Debug - GENERATOR: Visual Studio 14 2015 Win64 CFG: Debug VS_VERSION: 14.0 - GENERATOR: Visual Studio 12 2013 Win64 CFG: Debug VS_VERSION: 12.0 cache: - '%USERPROFILE%\asciidoctor-%ASCIIDOCTOR_VER%.gem -> .appveyor.yml' install: # Gem fetching can sometimes be excruciatingly slow due to the rubygems database, # so we have to manually download our target gem. - ps: | $asciidoctor = "$($env:USERPROFILE)\asciidoctor-$($env:ASCIIDOCTOR_VER).gem" if (-not (Test-Path $asciidoctor)) { $url = "https://rubygems.org/downloads/asciidoctor-$($env:ASCIIDOCTOR_VER).gem" Write-Output "Downloading asciidoctor $env:ASCIIDOCTOR_VER from $url" (New-Object Net.WebClient).DownloadFile($url, $asciidoctor) } gem install --no-document --local $asciidoctor # This section is a workaround for: https://github.com/nanomsg/nanomsg/issues/683 before_build: - del "C:\Program Files (x86)\MSBuild\%VS_VERSION%\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets" build: parallel: true build_script: - cmd: IF NOT %VS_VERSION% == NONE call "C:/Program Files (x86)/Microsoft Visual Studio %VS_VERSION%/Common7/Tools/vsvars32.bat" - cmd: cmake --version - cmd: md build - cmd: cd build - cmd: cmake -G "%GENERATOR%" .. - cmd: cmake --build . test_script: - cmd: ctest --output-on-failure -C "%CFG%" nanomsg-1.1.5/.circleci/000077500000000000000000000000001336111550300150115ustar00rootroot00000000000000nanomsg-1.1.5/.circleci/build-and-test.sh000077500000000000000000000004161336111550300201650ustar00rootroot00000000000000#!/bin/bash # # common build & test steps for CircleCI jobs # uname -a cmake --version ninja --version mkdir build cd build cmake -G Ninja -DCMAKE_BUILD_TYPE=${BUILD_TYPE:-Debug} -DNN_ENABLE_COVERAGE=${COVERAGE:-OFF} .. ninja env CTEST_OUTPUT_ON_FAILURE=1 ninja test nanomsg-1.1.5/.circleci/codecov.sh000077500000000000000000000011061336111550300167700ustar00rootroot00000000000000#!/bin/bash # Copyright 2018 Garrett D'Amore # Copyright 2018 Capitar IT Group BV # # 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. if [ "${COVERAGE}" != ON ] then echo "Code coverage not enabled." exit 0 fi GCOV=${GCOV:-gcov} bash <(curl -s https://codecov.io/bash) -x ${GCOV} || echo "Codecov did not collect coverage" echo 0 nanomsg-1.1.5/.circleci/config.yml000066400000000000000000000043001336111550300167760ustar00rootroot00000000000000# # CircleCI 2.0 configuration. This was borrowed from NNG, but is adjusted # for libnanomsg. (We don't need mbedTLS or use clang-format, for example.) # version: 2.0 jobs: "clang6 - build, test": docker: - image: ubuntu:16.04 environment: CC: clang-6.0 CXX: clang++-6.0 CTEST_OUTPUT_ON_FAILURE: 1 steps: - checkout - run: apt-get update -qq - run: apt-get install -y software-properties-common - run: apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-6.0 main" - run: apt-get update -qq - run: > apt-get install -y --allow-unauthenticated build-essential asciidoctor cmake ninja-build clang-6.0 - run: ./.circleci/build-and-test.sh "gcc8 - build, test": docker: - image: ubuntu:16.04 environment: CC: gcc-8 CXX: g++-8 GCOV: gcov-8 CTEST_OUTPUT_ON_FAILURE: 1 steps: - checkout - run: apt-get update -qq - run: apt-get install -y software-properties-common - run: add-apt-repository ppa:ubuntu-toolchain-r/test - run: apt-get update -qq - run: > apt-get install -y --allow-unauthenticated build-essential asciidoctor cmake ninja-build gcc-8 g++-8 - run: ./.circleci/build-and-test.sh "gcc - coverage": docker: - image: ubuntu:16.04 environment: CC: gcc CXX: g++ COVERAGE: "ON" GCOV: gcov CTEST_OUTPUT_ON_FAILURE: 1 steps: - checkout - run: apt-get update -qq - run: apt-get install -y software-properties-common - run: add-apt-repository ppa:ubuntu-toolchain-r/test - run: apt-get update -qq - run: > apt-get install -y --allow-unauthenticated build-essential curl asciidoctor cmake ninja-build - run: ./.circleci/build-and-test.sh - run: ./.circleci/codecov.sh workflows: version: 2 build_and_test: jobs: - "clang6 - build, test" - "gcc8 - build, test" - "gcc - coverage" nanomsg-1.1.5/.gitignore000066400000000000000000000015121336111550300151450ustar00rootroot00000000000000.*/ build/ *.a *.deps *.la *.libs *.lo *.o *.swo *.swp *.out *Makefile .dirstamp doc/asciidoc.conf nanocat tcpmuxd *.tar.gz *.zip perf/inproc_lat perf/inproc_thr perf/local_lat perf/local_thr perf/remote_lat perf/remote_thr doc/*.1 doc/*.7 doc/*.3 doc/*.html doc/diagrams *.log tests/*.trs tests/block tests/bus tests/device tests/domain tests/emfile tests/pipeline tests/hash tests/inproc tests/inproc_shutdown tests/iovec tests/ipc tests/ipc_shutdown tests/ipc_stress tests/list tests/msg tests/pair tests/poll tests/prio tests/pubsub tests/reqrep tests/separation tests/shutdown tests/survey tests/symbol tests/tcp tests/tcp_shutdown tests/timeo tests/trie tests/zerocopy tests/term tests/cmsg tests/ws tests/tcpmux *.dir *.vcxproj *.vcxproj.filters *.vcxproj.user Debug Release CMakeFiles .cproject .project .pydevproject *.sdf *.opensdf nanomsg-1.1.5/.version000066400000000000000000000000061336111550300146400ustar00rootroot000000000000001.1.5 nanomsg-1.1.5/AUTHORS000066400000000000000000000051611336111550300142310ustar00rootroot00000000000000Complete list of copyright holders to nanomsg codebase: Achille Roussel Aleksandar Fabijanic Alex Brem Andre Jonsson Andrew Starks Aram Santogidis Ark Degtiarov Bill McCroskey Boris Zentner Bruce Mitchener Bruno Bigras Chip Salzenberg David Beck Dennis Klein Dirkjan Ochtman Dong Fang Drew Crawford Dylan Socolobsky Emeric Chevalier Emil Renner Berthing Evan Wies Franklin "Snaipe" Mathieu Gareth Roberts Garrett D'Amore Gonzalo Diethelm Gaurav Gupta Hajime Saito Harlan Lieberman-Berg Immanuel Weber Ivan Pechorin Ivo Vachkov Jack R. Dunaway Joshua Foster Julien Ammous Kaspar Schiess Kristian Lein-Mathisen Luca Barbato Manuel Mendez Mark Ellzey Martin Sustrik Matt Howlett Max Drechsler Michael John Mikko Koppanen Nick Desaulniers Nicolas Hillegeer Nir Soffer Örjan Persson Oskari Timperi Paul Colomiets Pavlo Kapyshin Remy Brunno Rob Sciuk Ryan Killea Robert G. Jakabosky Sergey Avseyev Sergey Kovalevich Sergei Nikulov Shivanand Velmurugan Simon Strandgaard Stan Mihai Steve Atkins Steve McKay Stuart Wallace Timothee Besset Tobias Peters Victor Guerra Yonggang Luo Zoltan Boszormenyi nanomsg-1.1.5/CMakeLists.txt000066400000000000000000000435371336111550300157320ustar00rootroot00000000000000# # 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 # Copyright 2017 Garrett D'Amore # # 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 2.8.12) project (nanomsg C) include (CheckFunctionExists) include (CheckSymbolExists) include (CheckStructHasMember) include (CheckLibraryExists) include (CheckCSourceCompiles) include (GNUInstallDirs) if (POLICY CMP0042) # Newer cmake on MacOS should use @rpath cmake_policy (SET CMP0042 NEW) endif () 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 (NN_DESCRIPTION "High-Performance Scalability Protocols") set (ISSUE_REPORT_MSG "Please consider opening an issue at https://github.com/nanomsg/nanomsg") # Determine library versions. file (READ src/nn.h NN_HDR_STR) string (REGEX REPLACE ".*#define +NN_VERSION_CURRENT +([0-9]+).*" "\\1" NN_VERSION_CURRENT "${NN_HDR_STR}") string (REGEX REPLACE ".*#define +NN_VERSION_REVISION +([0-9]+).*" "\\1" NN_VERSION_REVISION "${NN_HDR_STR}") string (REGEX REPLACE ".*#define +NN_VERSION_AGE +([0-9]+).*" "\\1" NN_VERSION_AGE "${NN_HDR_STR}") if ((NN_VERSION_CURRENT STREQUAL "") OR (NN_VERSION_REVISION STREQUAL "") OR (NN_VERSION_AGE STREQUAL "")) message (FATAL_ERROR "Could not read ABI version from nn.h") else () set (NN_ABI_VERSION "${NN_VERSION_CURRENT}") set (NN_LIB_VERSION "${NN_VERSION_CURRENT}.${NN_VERSION_REVISION}.${NN_VERSION_AGE}") message (STATUS "Detected nanomsg ABI v${NN_ABI_VERSION} (v${NN_LIB_VERSION})") endif () # Determine package version. find_package (Git QUIET) if (DEFINED ENV{TRAVIS_TAG}) set (NN_PACKAGE_VERSION "$ENV{TRAVIS_TAG}") elseif (GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") # Working off a git repo, using git versioning # Get version from last tag execute_process ( COMMAND "${GIT_EXECUTABLE}" describe --always# | sed -e "s:v::" WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" OUTPUT_VARIABLE NN_PACKAGE_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) # If the sources have been changed locally, add -dirty to the version. execute_process ( COMMAND "${GIT_EXECUTABLE}" diff --quiet WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" RESULT_VARIABLE res) if (res EQUAL 1) set (NN_PACKAGE_VERSION "${NN_PACKAGE_VERSION}-dirty") endif() elseif (EXISTS ${PROJECT_SOURCE_DIR}/.version) # If git is not available (e.g. when building from source package) # we can extract the package version from .version file. file (STRINGS .version NN_PACKAGE_VERSION) else () set (NN_PACKAGE_VERSION "Unknown") endif() # User-defined options. option (NN_STATIC_LIB "Build static library instead of shared library." OFF) option (NN_ENABLE_DOC "Enable building documentation." ON) option (NN_ENABLE_COVERAGE "Enable coverage reporting." OFF) option (NN_ENABLE_GETADDRINFO_A "Enable/disable use of getaddrinfo_a in place of getaddrinfo." ON) option (NN_TESTS "Build and run nanomsg tests" ON) option (NN_TOOLS "Build nanomsg tools" ON) option (NN_ENABLE_NANOCAT "Enable building nanocat utility." ${NN_TOOLS}) set (NN_MAX_SOCKETS 512 CACHE STRING "max number of nanomsg sockets that can be created") # Platform checks. if (CMAKE_C_COMPILER_ID STREQUAL "GNU") set(NN_WARN_FLAGS "-Wall -Wextra") elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") set(NN_WARN_FLAGS "-Wall -Wextra") elseif (CMAKE_C_COMPILER_ID STREQUAL "AppleClang") set(NN_WARN_FLAGS "-Wall -Wextra") endif() if (NN_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(NN_COVERAGE_FLAGS "-g -O0 --coverage") elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") set(NN_COVERAGE_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") elseif (CMAKE_C_COMPILER_ID STREQUAL "AppleClang") set(NN_COVERAGE_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") else() message(FATAL_ERROR "Unable to enable coverage for your compiler.") endif() endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${NN_WARN_FLAGS} ${NN_COVERAGE_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${NN_WARN_FLAGS} ${NN_COVERAGE_FLAGS}") find_package (Threads REQUIRED) message(STATUS "OS System is ${CMAKE_SYSTEM_NAME}") message(STATUS "OS Version is ${CMAKE_SYSTEM_VERSION}") if (CMAKE_SYSTEM_NAME MATCHES "Linux") add_definitions (-DNN_HAVE_LINUX) if (CMAKE_SYSTEM_VERSION MATCHES "Microsoft") add_definitions (-DNN_HAVE_WSL) endif() elseif (CMAKE_SYSTEM_NAME MATCHES "Android") add_definitions (-DNN_HAVE_ANDROID) add_definitions (-DNN_HAVE_LINUX) elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin") add_definitions (-DNN_HAVE_OSX) elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") set (NN_HAVE_WINSOCK 1) add_definitions (-DNN_HAVE_WINDOWS) add_definitions (-D_CRT_SECURE_NO_WARNINGS) # 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 "FreeBSD") add_definitions (-DNN_HAVE_FREEBSD) elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") add_definitions (-DNN_HAVE_NETBSD) elseif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") add_definitions (-DNN_HAVE_OPENBSD) elseif (CMAKE_SYSTEM_NAME MATCHES "Solaris|SunOS") add_definitions (-DNN_HAVE_SOLARIS) elseif (CMAKE_SYSTEM_NAME MATCHES "HP-UX") add_definitions (-DNN_HAVE_HPUX) elseif (CMAKE_SYSTEM_NAME MATCHES "QNX") add_definitions (-DNN_HAVE_QNX) else () message (AUTHOR_WARNING "WARNING: This platform may or may not be supported: ${CMAKE_SYSTEM_NAME}") message (AUTHOR_WARNING "${ISSUE_REPORT_MSG}") endif () if (NN_STATIC_LIB) add_definitions (-DNN_STATIC_LIB) endif () macro (nn_check_func SYM DEF) check_function_exists (${SYM} ${DEF}) if (${DEF}) add_definitions (-D${DEF}=1) endif () endmacro (nn_check_func) macro (nn_check_sym SYM HDR DEF) check_symbol_exists (${SYM} ${HDR} ${DEF}) if (${DEF}) add_definitions (-D${DEF}=1) endif () endmacro (nn_check_sym) macro (nn_check_lib LIB SYM DEF) check_library_exists (${LIB} ${SYM} "" ${DEF}) if (${DEF}) add_definitions (-D${DEF}=1) set(NN_REQUIRED_LIBRARIES ${NN_REQUIRED_LIBRARIES} ${LIB}) endif () endmacro (nn_check_lib) macro (nn_check_struct_member STR MEM HDR DEF) check_struct_has_member ("struct ${STR}" ${MEM} ${HDR} ${DEF}) if (${DEF}) add_definitions (-D${DEF}=1) endif () endmacro (nn_check_struct_member) if (WIN32) # Windows is a special snowflake. set(NN_REQUIRED_LIBRARIES ${NN_REQUIRED_LIBRARIES} ws2_32) set(NN_REQUIRED_LIBRARIES ${NN_REQUIRED_LIBRARIES} mswsock) set(NN_REQUIRED_LIBRARIES ${NN_REQUIRED_LIBRARIES} advapi32) nn_check_sym (InitializeConditionVariable windows.h NN_HAVE_CONDVAR) if (NOT NN_HAVE_CONDVAR) message (FATAL_ERROR "Modern Windows API support is missing. " "Versions of Windows prior to Vista are not supported. " "Further, the 32-bit MinGW environment is not supported. " "Ensure you have at least Windows Vista or newer, and are " "using either Visual Studio 2010 or newer or MinGW-W64.") endif() else () # Unconditionally declare the following feature test macros. These are # needed for some platforms (glibc and SunOS/illumos) and should be harmless # on the others. add_definitions (-D_GNU_SOURCE) add_definitions (-D_REENTRANT) add_definitions (-D_THREAD_SAFE) add_definitions (-D_POSIX_PTHREAD_SEMANTICS) nn_check_func (gethrtime NN_HAVE_GETHRTIME) nn_check_func (socketpair NN_HAVE_SOCKETPAIR) nn_check_func (eventfd NN_HAVE_EVENTFD) nn_check_func (pipe NN_HAVE_PIPE) nn_check_func (pipe2 NN_HAVE_PIPE2) nn_check_func (accept4 NN_HAVE_ACCEPT4) nn_check_func (epoll_create NN_HAVE_EPOLL) nn_check_func (kqueue NN_HAVE_KQUEUE) nn_check_func (poll NN_HAVE_POLL) nn_check_lib (anl getaddrinfo_a NN_HAVE_GETADDRINFO_A) nn_check_lib (rt clock_gettime NN_HAVE_CLOCK_GETTIME) nn_check_lib (rt sem_wait NN_HAVE_SEMAPHORE_RT) nn_check_lib (pthread sem_wait NN_HAVE_SEMAPHORE_PTHREAD) nn_check_lib (nsl gethostbyname NN_HAVE_LIBNSL) nn_check_lib (socket socket NN_HAVE_LIBSOCKET) nn_check_sym (CLOCK_MONOTONIC time.h NN_HAVE_CLOCK_MONOTONIC) nn_check_sym (atomic_cas_32 atomic.h NN_HAVE_ATOMIC_SOLARIS) nn_check_sym (AF_UNIX sys/socket.h NN_HAVE_UNIX_SOCKETS) nn_check_sym (backtrace_symbols_fd execinfo.h NN_HAVE_BACKTRACE) nn_check_struct_member(msghdr msg_control sys/socket.h NN_HAVE_MSG_CONTROL) if (NN_HAVE_SEMAPHORE_RT OR NN_HAVE_SEMAPHORE_PTHREAD) if (NOT CMAKE_SYSTEM_NAME MATCHES "Darwin") # macOS doesn't have unnamed semaphores add_definitions (-DNN_HAVE_SEMAPHORE) endif() endif () endif () if (NOT NN_ENABLE_GETADDRINFO_A) add_definitions (-DNN_DISABLE_GETADDRINFO_A) endif () check_c_source_compiles (" #include int main() { volatile uint32_t n = 0; __sync_fetch_and_add (&n, 1); __sync_fetch_and_sub (&n, 1); return 0; } " NN_HAVE_GCC_ATOMIC_BUILTINS) if (NN_HAVE_GCC_ATOMIC_BUILTINS) add_definitions (-DNN_HAVE_GCC_ATOMIC_BUILTINS) endif () add_definitions(-DNN_MAX_SOCKETS=${NN_MAX_SOCKETS}) add_subdirectory (src) # Build the tools if (NN_ENABLE_NANOCAT) add_executable (nanocat tools/nanocat.c tools/options.c) target_link_libraries (nanocat ${PROJECT_NAME}) endif () if (NN_ENABLE_DOC) find_program (ASCIIDOCTOR_EXE asciidoctor) if (NOT ASCIIDOCTOR_EXE) message (WARNING "Could not find asciidoctor: skipping docs") set (NN_ENABLE_DOC OFF) else () message (STATUS "Using asciidoctor at ${ASCIIDOCTOR_EXE}") endif () endif () # Build the documenation if (NN_ENABLE_DOC) set (NN_DOCDIR ${CMAKE_CURRENT_SOURCE_DIR}/doc) set (NN_STYLESHEET ${NN_DOCDIR}/stylesheet.css) set (NN_TITLE ${PROJECT_NAME} ${NN_PACKAGE_VERSION}) set (NN_A2M ${ASCIIDOCTOR_EXE} -b manpage -amanmanual='${NN_TITLE}') set (NN_A2H ${ASCIIDOCTOR_EXE} -d manpage -b html5 -a stylesheeet=${NN_STYLESHEET} -aversion-label=${PROJECT_NAME} -arevnumber=${NN_PACKAGE_VERSION}) macro (add_libnanomsg_man NAME SECT) add_custom_command ( OUTPUT ${NAME}.${SECT} COMMAND ${NN_A2M} -o ${NAME}.${SECT} ${NN_DOCDIR}/${NAME}.adoc MAIN_DEPENDENCY ${NN_DOCDIR}/${NAME}.adoc ) add_custom_command ( OUTPUT ${NAME}.html COMMAND ${NN_A2H} -o ${NAME}.html ${NN_DOCDIR}/${NAME}.adoc DEPENDS ${NN_STYLESHEET} MAIN_DEPENDENCY ${NN_DOCDIR}/${NAME}.adoc ) set(NN_MANS ${NN_MANS} ${NAME}.${SECT}) set(NN_HTMLS ${NN_HTMLS} ${NAME}.html) install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.html DESTINATION ${CMAKE_INSTALL_DOCDIR} ) install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.${SECT} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${SECT} ) endmacro (add_libnanomsg_man) if (NN_ENABLE_NANOCAT) add_libnanomsg_man (nanocat 1) endif () add_libnanomsg_man (nn_errno 3) add_libnanomsg_man (nn_strerror 3) add_libnanomsg_man (nn_symbol 3) add_libnanomsg_man (nn_symbol_info 3) add_libnanomsg_man (nn_allocmsg 3) add_libnanomsg_man (nn_reallocmsg 3) add_libnanomsg_man (nn_freemsg 3) add_libnanomsg_man (nn_socket 3) add_libnanomsg_man (nn_close 3) add_libnanomsg_man (nn_get_statistic 3) add_libnanomsg_man (nn_getsockopt 3) add_libnanomsg_man (nn_setsockopt 3) add_libnanomsg_man (nn_bind 3) add_libnanomsg_man (nn_connect 3) add_libnanomsg_man (nn_shutdown 3) add_libnanomsg_man (nn_send 3) add_libnanomsg_man (nn_recv 3) add_libnanomsg_man (nn_sendmsg 3) add_libnanomsg_man (nn_recvmsg 3) add_libnanomsg_man (nn_device 3) add_libnanomsg_man (nn_cmsg 3) add_libnanomsg_man (nn_poll 3) add_libnanomsg_man (nn_term 3) add_libnanomsg_man (nanomsg 7) add_libnanomsg_man (nn_pair 7) add_libnanomsg_man (nn_reqrep 7) add_libnanomsg_man (nn_pubsub 7) add_libnanomsg_man (nn_survey 7) add_libnanomsg_man (nn_pipeline 7) add_libnanomsg_man (nn_bus 7) add_libnanomsg_man (nn_inproc 7) add_libnanomsg_man (nn_ipc 7) add_libnanomsg_man (nn_tcp 7) add_libnanomsg_man (nn_ws 7) add_libnanomsg_man (nn_env 7) add_custom_target (man ALL DEPENDS ${NN_MANS}) add_custom_target (html ALL DEPENDS ${NN_HTMLS}) endif () # Build unit tests. if (NN_TESTS) enable_testing () set (all_tests "") set (TEST_PORT 12100) macro (add_libnanomsg_test NAME TIMEOUT) list (APPEND all_tests ${NAME}) add_executable (${NAME} tests/${NAME}.c) target_link_libraries (${NAME} ${PROJECT_NAME}) add_test (NAME ${NAME} COMMAND ${NAME} ${TEST_PORT}) set_tests_properties (${NAME} PROPERTIES TIMEOUT ${TIMEOUT}) math (EXPR TEST_PORT "${TEST_PORT}+10") endmacro (add_libnanomsg_test) # Transport tests. add_libnanomsg_test (inproc 5) add_libnanomsg_test (inproc_shutdown 5) add_libnanomsg_test (ipc 5) add_libnanomsg_test (ipc_shutdown 30) add_libnanomsg_test (ipc_stress 5) add_libnanomsg_test (tcp 20) add_libnanomsg_test (tcp_shutdown 120) add_libnanomsg_test (ws 20) # Protocol tests. add_libnanomsg_test (pair 5) add_libnanomsg_test (pubsub 5) add_libnanomsg_test (reqrep 5) add_libnanomsg_test (pipeline 5) add_libnanomsg_test (survey 5) add_libnanomsg_test (bus 5) # Feature tests. add_libnanomsg_test (async_shutdown 30) add_libnanomsg_test (block 5) add_libnanomsg_test (term 5) add_libnanomsg_test (timeo 5) add_libnanomsg_test (iovec 5) add_libnanomsg_test (msg 5) add_libnanomsg_test (prio 5) add_libnanomsg_test (poll 5) add_libnanomsg_test (device 5) add_libnanomsg_test (device4 5) add_libnanomsg_test (device5 5) add_libnanomsg_test (device6 5) add_libnanomsg_test (device7 30) add_libnanomsg_test (emfile 5) add_libnanomsg_test (domain 5) add_libnanomsg_test (trie 5) add_libnanomsg_test (list 5) add_libnanomsg_test (hash 5) add_libnanomsg_test (stats 5) add_libnanomsg_test (symbol 5) add_libnanomsg_test (separation 5) add_libnanomsg_test (zerocopy 5) add_libnanomsg_test (shutdown 5) add_libnanomsg_test (cmsg 5) add_libnanomsg_test (bug328 5) add_libnanomsg_test (bug777 5) add_libnanomsg_test (ws_async_shutdown 5) add_libnanomsg_test (reqttl 10) add_libnanomsg_test (surveyttl 10) # Platform-specific tests if (WIN32) add_libnanomsg_test (win_sec_attr 5) endif() # Build the performance tests. macro (add_libnanomsg_perf NAME) add_executable (${NAME} perf/${NAME}.c) target_link_libraries (${NAME} ${PROJECT_NAME}) endmacro (add_libnanomsg_perf) add_libnanomsg_perf (inproc_lat) add_libnanomsg_perf (inproc_thr) add_libnanomsg_perf (local_lat) add_libnanomsg_perf (remote_lat) add_libnanomsg_perf (local_thr) add_libnanomsg_perf (remote_thr) endif () install (TARGETS LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) install (TARGETS ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install (FILES src/nn.h DESTINATION include/nanomsg) install (FILES src/inproc.h DESTINATION include/nanomsg) install (FILES src/ipc.h DESTINATION include/nanomsg) install (FILES src/tcp.h DESTINATION include/nanomsg) install (FILES src/ws.h DESTINATION include/nanomsg) install (FILES src/pair.h DESTINATION include/nanomsg) install (FILES src/pubsub.h DESTINATION include/nanomsg) install (FILES src/reqrep.h DESTINATION include/nanomsg) install (FILES src/pipeline.h DESTINATION include/nanomsg) install (FILES src/survey.h DESTINATION include/nanomsg) install (FILES src/bus.h DESTINATION include/nanomsg) if (NN_ENABLE_NANOCAT) install (TARGETS nanocat RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() set (CPACK_PACKAGE_NAME ${PROJECT_NAME}) set (CPACK_PACKAGE_VERSION ${NN_PACKAGE_VERSION}) 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}-${NN_PACKAGE_VERSION}") add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source) include (CPack) nanomsg-1.1.5/COPYING000066400000000000000000000020551336111550300142130ustar00rootroot00000000000000 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. "nanomsg" is a trademark of Martin Sustrik nanomsg-1.1.5/README.md000066400000000000000000000122321336111550300144350ustar00rootroot00000000000000Welcome to nanomsg ================== [![Release](https://img.shields.io/github/release/nanomsg/nanomsg.svg)](https://github.com/nanomsg/nanomsg/releases/latest) [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/nanomsg/nanomsg/blob/master/COPYING) [![Linux Status](https://img.shields.io/circleci/project/github/nanomsg/nanomsg/master.svg?label=linux)](https://circleci.com/gh/nanomsg/nanomsg) [![Windows Status](https://img.shields.io/appveyor/ci/nanomsg/nanomsg/master.svg?label=windows)](https://ci.appveyor.com/project/nanomsg/nanomsg) [![Coverage](https://codecov.io/gh/nanomsg/nanomsg/branch/master/graph/badge.svg?label=coverage)](https://codecov.io/gh/nanomsg/nanomsg) [![Gitter](https://img.shields.io/badge/gitter-join-brightgreen.svg)](https://gitter.im/nanomsg/nanomsg) The nanomsg library is a simple high-performance implementation of several "scalability protocols". These scalability protocols are light-weight messaging protocols which can be used to solve a number of very common messaging patterns, such as request/reply, publish/subscribe, surveyor/respondent, and so forth. These protocols can run over a variety of transports such as TCP, UNIX sockets, and even WebSocket. For more information check the [website](http://nanomsg.org). Prerequisites ------------- 1. Windows. * Windows Vista or newer (Windows XP and 2003 are *NOT* supported) * Microsoft Visual Studio 2010 (including C++) or newer, or mingw-w64. (Specifically mingw and older Microsoft compilers are *NOT supported, and we do not test mingw-w64 at all, so YMMV.) * CMake 2.8.7 or newer, available in $PATH as `cmake` 2. POSIX (Linux, MacOS X, UNIX) * ANSI C compiler supporting C89 * POSIX pthreads (should be present on all modern POSIX systems) * BSD sockets support for both TCP and UNIX domain sockets * CMake (http://cmake.org) 2.8.7 or newer, available in $PATH as `cmake` 3. Documentation (optional) * asciidoctor (http://asciidoctor.org/) available as `asciidoctor` * If not present, docs are not formatted, but left in readable ASCII * Also available on-line at http://nanomsg.org/documentation Quick Build Instructions ------------------------ These steps here are the minimum steps to get a default Debug build. Using CMake you can do many other things, including setting additional variables, setting up for static builds, or generation project or solution files for different development environments. Please check the CMake website for all the various options that CMake supports. ## POSIX This assumes you have a shell in the project directory, and have the cmake and suitable compilers (and any required supporting tools like linkers or archivers) on your path. 1. `% mkdir build` 2. `% cd build` 3. `% cmake ..` 4. `% cmake --build .` 5. `% ctest .` 6. `% sudo cmake --build . --target install` 7. `% sudo ldconfig` (if on Linux) ## Windows This assumes you are in a command or powershell window and have the appropriate variables setup to support Visual Studio, typically by running `vcvarsall.bat` or similar with the appropriate argument(s). It also assumes you are in the project directory. 1. `md build` 2. `cd build` 3. `cmake ..` 4. `cmake --build . --config Debug` 5. `ctest -C Debug .` 6. `cmake --build . --config Debug --target install` *NB:* This may have to be done using an Administrator account. Static Library -------------- We normally build a dynamic library (.so or .DLL) by default. If you want a static library (.a or .LIB), configure by passing `-DNN_STATIC_LIB=ON` to the first `cmake` command. ### POSIX POSIX systems will need to link with the libraries normally used when building network applications. For some systems this might mean -lnsl or -lsocket. ### Windows You will also need to define `NN_STATIC_LIB` in your compilation environment when building programs that use this library. This is required because of the way Windows changes symbol names depending on whether the symbols should be exported in a DLL or not. When using the .LIB on Windows, you will also need to link with the ws2_32, mswsock, and advapi32 libraries, as nanomsg depends on them. Support ------- This library is considered to be in "sustaining" mode, which means that new feature development has ended, and bug fixes are made only when strictly necessary for severe issues. New development is now occuring in the [NNG](https://github.com/nanomsg/nng) project, which offers both protocol and API compatibility with this project. Please consider using NNG for new projects. Please see the file SUPPORT for more details. Resources --------- Website: [http://nanomsg.org](http://nanomsg.org) Source code: [https://github.com/nanomsg/nanomsg](http://github.com/nanomsg/nanomsg) Documentation: [http://nanomsg.org/documentation.html](http://nanomsg.org/documentation.html) Bug tracker: [https://github.com/nanomsg/nanomsg/issues](http://github.com/nanomsg/nanomsg/issues) Mailing list: [nanomsg@freelists.org](http://www.freelists.org/list/nanomsg) Gitter Chat: [https://gitter.im/nanomsg/nanomsg](https://gitter.im/nanomsg/nanomsg) IRC chatroom: [#nanomsg at irc.freenode.net/8001](http://webchat.freenode.net?channels=%23nanomsg) nanomsg-1.1.5/RELEASING000066400000000000000000000030441336111550300144130ustar00rootroot00000000000000Release process =============== 1. Check CI * CircleCI: https://circleci.com/gh/nanomsg/nanomsg/tree/master * AppVeyor: https://ci.appveyor.com/project/nanomsg/nanomsg 2. Bump ABI version as appropriate (see the docs on versioning). This happens in src/nn.h, check links there on which numbers to update. 3. Bump the version in the .version file, such as 0.10-beta or 1.0 or whatever. This should match the tag you are going to use. 4. Commit and push both of the above changes back to the public repo. 5. Tag the new version, e.g. git tag -a 0.3-beta. (Make sure to use -a to create an annotated tag.) 6. Push the tag to the repo, e.g. git push origin 0.3-beta. 7. Wait a little bit for CI to build. 8. Check the AppVeyor CI again just to be sure. 9. Check the github releases page - a release for the tag should have already been created with artifacts ready to download. 10. Update the _config.yml page on the website (see gh-pages branch of the repo). The only thing that needs to be updated is the "latest" and "latest_date". 11. In the online docs (gh-pages branch), copy the man pages (adoc format) into a subdirectory of _adoc named after the version (e.g. "_adoc/v1.1.3"), then run the _adoc/build.sh script. Add the resulting "v1.1.3" directory, commit, and push. 12. Send the announcement about the release. These commands might be useful: git log --oneline 0.2-alpha..0.3-beta | wc -l git diff -U0 0.2-alpha..0.3-beta AUTHORS 13. Update the topic in the Gitter chatroom accordingly. nanomsg-1.1.5/SUPPORT000066400000000000000000000020541336111550300142560ustar00rootroot00000000000000SUPPORT ======= This project ("nanomsg") or more properly "nanomsg 1.0" is now in "sustaining" mode. This means that generally the project maintainers will only integrate fixes or release new versions when severe defects are found. The reason for this is that new development effort has transitioned to the "NNG" project (see https://github.com/nanomsg/nng for more information). The possible exception to this would be for features with a specific commercial sponsorship, for commercial users unable to use NNG. The NNG project as of this writing has *nearly* complete compatibility with nanomsg (99% of apps will work with no source code changes, and the NNG library is also wire compatible with nanomsg, so that projects built with the two separate libraries can interoperate seamlessly). In addition it offers higher scalability, reliability, and usability. It also offers a number of more advanced features. Commercial support for both NNG and this project ("nanomsg") is offered by Staysail Systems, Inc. Contact info@staysail.tech for more information. nanomsg-1.1.5/cmake/000077500000000000000000000000001336111550300142365ustar00rootroot00000000000000nanomsg-1.1.5/cmake/nanomsg-config.cmake.in000066400000000000000000000033021336111550300205500ustar00rootroot00000000000000# # Copyright (c) 2018 Dennis Klein # # 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. # @PACKAGE_INIT@ ### General variables for project discovery/inspection set_and_check(@PROJECT_NAME@_INSTALL_PREFIX @PACKAGE_CMAKE_INSTALL_PREFIX@) set_and_check(@PROJECT_NAME@_BINDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@) set_and_check(@PROJECT_NAME@_INCDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@) set_and_check(@PROJECT_NAME@_LIBDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@) ### Import targets include(@PACKAGE_CMAKE_INSTALL_PREFIX@/@PACKAGE_INSTALL_DESTINATION@/@PROJECT_NAME@-target.cmake) check_required_components(@PROJECT_NAME@) nanomsg-1.1.5/configure000077500000000000000000000051561336111550300150740ustar00rootroot00000000000000#!/bin/sh # # Copyright 2016 Garrett D'Amore # # 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. # # # This configure script provides the usual autoconf style interface for # installation, but simply uses cmake. # SRCDIR=`dirname $0` CURDIR=`pwd` strip_arg() { x=`echo "$1" | sed "s/[^=]*=//"` eval $2=\"$x\" } warn() { echo "$*" 1>&2 } find_prog() { SIFS="${IFS= }" IFS=: for p in $PATH; do if [ -x ${p}/$1 ] then IFS="${SIFS}" echo "${p}/${1}" return 0 fi done IFS="${SIFS}" return 1 } need_cmake() { warn "This program requires CMake 2.6 or newer to build." warn "Obtain CMake from www.cmake.org" exit 1 } help() { echo "This configure script is a convenience wrapper around" echo "CMake. Only a limited subset of configuration options" echo "are supported. For a fully featured build, use CMake". echo echo "Execute as $0 [options]" echo echo "Options supported are:" echo echo " --prefix={path} Set installation directory prefix." echo " --with-cmake={path} Location of CMake executable." echo exit 1 } # Argument parsing PREFIX=/usr/local while [ -n "$1" ]; do case "$1" in --with-cmake) CMAKE="$2" shift 2 ;; --with-cmake=*) strip_arg "$1" CMAKE shift ;; --prefix) if [ -z "$2" ]; then help fi PREFIX="$2" shift 2 ;; --prefix=*) strip_arg "$1" PREFIX shift ;; *) help ;; esac done if [ -z "${CMAKE}" ]; then CMAKE=`find_prog cmake` || need_cmake fi if [ -f src/nn.h ] then warn "NOTE: Building in the source directory is not recommended." fi GENERATOR="Unix Makefiles" "$CMAKE" -G "$GENERATOR" "-DCMAKE_INSTALL_PREFIX=$PREFIX" $SRCDIR nanomsg-1.1.5/demo/000077500000000000000000000000001336111550300141025ustar00rootroot00000000000000nanomsg-1.1.5/demo/CMakeLists.txt000066400000000000000000000013731336111550300166460ustar00rootroot00000000000000# # Demonstration CMakeLists.txt for nanomsg demos. # # This file shows how one might use nanomsg from a another project # that is also CMake-driven. # # Thanks for the idea goes to @maddouri. # cmake_minimum_required (VERSION 2.8.7) project(nanomsg-demo) # Call this from your own project's makefile. find_package(nanomsg CONFIG REQUIRED) add_executable(async_demo async_demo.c) target_link_libraries(async_demo nanomsg) add_executable(device_demo device_demo.c) target_link_libraries(device_demo nanomsg) add_executable(pthread_demo pthread_demo.c) target_link_libraries(pthread_demo nanomsg) add_executable(pubsub_demo pubsub_demo.c) target_link_libraries(pubsub_demo nanomsg) add_executable(rpc_demo rpc_demo.c) target_link_libraries(rpc_demo nanomsg) nanomsg-1.1.5/demo/README000066400000000000000000000004751336111550300147700ustar00rootroot00000000000000The programs here are intended to demonstrate how to use the nanomsg API. The intention is that you can use these programs (or parts thereof) in your own code. We welcome further contributions here. These have their own CMake driven configuration if you want to build them all. They are not built automatically. nanomsg-1.1.5/demo/async_demo.c000066400000000000000000000210301336111550300163630ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. "nanomsg" is a trademark of Martin Sustrik */ /* 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 -s Then connect to it with the client as async_client . For example: % ./async_demo tcp://127.0.0.1:5555 -s & % ./async_demo tcp://127.0.0.1:5555 323 Request took 324 milliseconds. */ #include #include #include #include #include #include #include /* MAXJOBS is a limit on the on the number of outstanding requests we can queue. We will not accept new inbound jobs if we have more than this queued. The reason for this limit is to prevent a bad client from consuming all server resources with new job requests. */ #define MAXJOBS 100 /* 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 { struct work *next; struct nn_msghdr request; uint64_t expire; void *control; }; /* Return the UNIX time in milliseconds. You'll need a working gettimeofday(), so this won't work on Windows. */ uint64_t milliseconds (void) { struct timeval tv; gettimeofday (&tv, NULL); return (((uint64_t)tv.tv_sec * 1000) + ((uint64_t)tv.tv_usec / 1000)); } /* The server runs forever. */ int server(const char *url) { int fd; struct work *worklist = NULL; int npending = 0; /* Create the socket. */ fd = nn_socket(AF_SP_RAW, NN_REP); if (fd < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); return (-1); } /* Bind to the URL. This will bind to the address and listen synchronously; new clients will be accepted asynchronously without further action from the calling program. */ if (nn_bind (fd, url) < 0) { fprintf (stderr, "nn_bind: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } /* Main processing loop. */ for (;;) { uint32_t timer; int rc; int timeout; uint64_t now; struct work *work, **srch; uint8_t *body; void *control; struct nn_iovec iov; struct nn_msghdr hdr; struct nn_pollfd pfd[1]; /* Figure out if any work requests are finished, and can be responded to. */ timeout = -1; while ((work = worklist) != NULL) { now = milliseconds (); if (work->expire > now) { timeout = (work->expire - now); break; } worklist = work->next; npending--; rc = nn_sendmsg (fd, &work->request, NN_DONTWAIT); if (rc < 0) { fprintf (stderr, "nn_sendmsg: %s\n", nn_strerror (nn_errno ())); nn_freemsg (work->request.msg_control); } free (work); } /* This check ensures that we don't allow more than a set limit of concurrent jobs to be queued. This protects us from resource exhaustion by malicious or defective clients. */ if (npending >= MAXJOBS) { nn_poll (pfd, 0, timeout); continue; } pfd[0].fd = fd; pfd[0].events = NN_POLLIN; pfd[0].revents = 0; nn_poll (pfd, 1, timeout); if ((pfd[0].revents & NN_POLLIN) == 0) { continue; } /* So there should be a message waiting for us to receive. We handle it by parsing it, creating a work request for it, and adding the work request to the worklist. */ memset (&hdr, 0, sizeof (hdr)); control = NULL; iov.iov_base = &body; iov.iov_len = NN_MSG; hdr.msg_iov = &iov; hdr.msg_iovlen = 1; hdr.msg_control = &control; hdr.msg_controllen = NN_MSG; rc = nn_recvmsg (fd, &hdr, 0); if (rc < 0) { /* Any error here is unexpected. */ fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ())); break; } if (rc != sizeof (uint32_t)) { fprintf (stderr, "nn_recv: wanted %d, but got %d\n", (int) sizeof (uint32_t), rc); nn_freemsg (body); nn_freemsg (control); continue; } memcpy (&timer, body, sizeof (timer)); nn_freemsg (body); work = malloc (sizeof (*work)); if (work == NULL) { fprintf (stderr, "malloc: %s\n", strerror (errno)); /* Fatal error -- other programs can try to handle it better. */ break; } memset (work, 0, sizeof (*work)); work->expire = milliseconds () + ntohl (timer); work->control = control; work->request.msg_iovlen = 0; /* No payload data to send. */ work->request.msg_iov = NULL; work->request.msg_control = &work->control; work->request.msg_controllen = NN_MSG; /* Insert the work request into the list in order. */ srch = &worklist; for (;;) { if ((*srch == NULL) || ((*srch)->expire > work->expire)) { work->next = *srch; *srch = work; npending++; break; } srch = &((*srch)->next); } } /* This may wind up orphaning requests in the queue. We are going to exit with an error anyway, so don't worry about it. */ nn_close (fd); return (-1); } /* The client runs just once, and then returns. */ int client (const char *url, const char *msecstr) { int fd; int rc; char *greeting; uint8_t msg[sizeof (uint32_t)]; uint64_t start; uint64_t end; unsigned msec; msec = atoi(msecstr); fd = nn_socket (AF_SP, NN_REQ); if (fd < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); return (-1); } if (nn_connect (fd, url) < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } msec = htonl(msec); memcpy (msg, &msec, sizeof (msec)); start = milliseconds (); if (nn_send (fd, msg, sizeof (msg), 0) < 0) { fprintf (stderr, "nn_send: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } rc = nn_recv (fd, &msg, sizeof (msg), 0); if (rc < 0) { fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } nn_close (fd); end = milliseconds (); 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 [-s|name]\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); } nanomsg-1.1.5/demo/device_demo.c000066400000000000000000000172371336111550300165230ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. "nanomsg" is a trademark of Martin Sustrik */ /* This program serves as an example for how to write a simple device service, using a rendezvous. This works by having the program support three modes. The protocol is is REQ/REP, where the REQ is a name, and the REP is a greeting based on the name, and an instance number (we use the process ID) and time of day. We provide a rendezvous server running the device code, where servers and clients can connect. Both sides of the device are in bind mode, and both servers and clients run in connect mode. This lets us support many servers and clients simultaneously. For example, if I want to have servers rendezvous at port 5554 and clients at port 5555: % ./device_demo -d tcp://127.0.0.1:5554 tcp://127.0.0.1:5555 & % ./device_demo -s tcp://127.0.0.1:5554 & % ./device_demo -c tcp://127.0.0.1:5555 Garrett Good morning, Garrett. */ #include #include #include #include #include #include #include /* The server runs forever. */ int server(const char *url) { int fd; /* Create the socket. */ fd = nn_socket (AF_SP, NN_REP); if (fd < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); return (-1); } /* Connect to the URL. This will connect to the address and listen synchronously; new clients will be accepted asynchronously without further action from the calling program. */ if (nn_connect (fd, url) < 0) { fprintf (stderr, "nn_connect: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } /* Now we can just process results. Note that there is no explicit accept required. We just receive a request, and reply to it. Its important to note that we must not issue two receives in a row without replying first, or the following receive(s) will cancel any unreplied requests. */ for (;;) { char username[128]; char greeting[128]; time_t secs; struct tm *now; char *daytime; int rc; char *fmt; rc = nn_recv (fd, username, sizeof (username), 0); if (rc < 0) { /* Any error here is unexpected. */ fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ())); break; } secs = time (NULL); now = localtime (&secs); if (now->tm_hour < 12) { daytime = "morning"; } else if (now->tm_hour < 17) { daytime = "afternoon"; } else if (now->tm_hour < 20) { daytime = "evening"; } else { daytime = "night"; } /* Ensure ASCIIZ terminated string. */ if (rc < sizeof (username)) { username[rc] = '\0'; } else { username[sizeof (username) - 1] = '\0'; } fmt = "Good %s, %s (from %d)."; /* Technically this might be overly pessimistic about size. */ if ((strlen (username) + strlen (daytime) + strlen (fmt)) >= sizeof (greeting)) { fmt = "I'm sorry, your name is too long. But good %s anyway."; } /* snprintf would be safer, but the above check protects us. */ sprintf (greeting, fmt, daytime, username, (int)getpid()); rc = nn_send (fd, greeting, strlen (greeting), 0); if (rc < 0) { /* There are several legitimate reasons this can fail. We note them for debugging purposes, but then ignore otherwise. If the socket is closed or failing, we will notice in recv above, and exit then. */ fprintf (stderr, "nn_send: %s (ignoring)\n", nn_strerror (nn_errno ())); } } nn_close (fd); return (-1); } /* The client runs just once, and then returns. */ int client (const char *url, const char *username) { int fd; int rc; char *greeting; char *msg; fd = nn_socket (AF_SP, NN_REQ); if (fd < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); return (-1); } if (nn_connect (fd, url) < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } usleep(1000); if (nn_send (fd, username, strlen (username), 0) < 0) { fprintf (stderr, "nn_send: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } /* Here we ask the library to allocate response buffer for us (NN_MSG). */ rc = nn_recv (fd, &msg, NN_MSG, 0); if (rc < 0) { fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } nn_close (fd); /* Response is not ASCIIZ terminated. */ greeting = calloc (rc + 1, 1); if (greeting == NULL) { fprintf (stderr, "calloc: %s\n", strerror (errno)); return (-1); } memcpy(greeting, msg, rc); nn_freemsg (msg); printf ("%s\n", greeting); free (greeting); return (0); } int device (const char *url1, const char *url2) { int s1, s2, rv; s1 = nn_socket (AF_SP_RAW, NN_REQ); if (s1 < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); return (-1); } if (nn_bind (s1, url1) < 0) { fprintf (stderr, "nn_bind1(%s): %s\n", url1, nn_strerror (nn_errno ())); return (-1); } s2 = nn_socket (AF_SP_RAW, NN_REP); if (s2 < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror(nn_errno ())); return (-1); } if (nn_bind (s2, url2) < 0) { fprintf (stderr, "nn_bind2(%s): %s\n", url2, nn_strerror (nn_errno ())); return (-1); } if (nn_device (s1, s2) != 0) { fprintf (stderr, "nn_device: %s\n", nn_strerror (nn_errno ())); return (-1); } return (0); } int main (int argc, char **argv) { int rc; if ((argc == 3) && (strcmp (argv[1], "-s") == 0)) { rc = server (argv[2]); } else if ((argc == 4) && (strcmp (argv[1], "-d") == 0)) { rc = device (argv[2], argv[3]); } else if ((argc == 4) && (strcmp (argv[1], "-c") == 0)) { rc = client (argv[2], argv[3]); } else { fprintf (stderr, "Usage: %s -s \n", argv[0]); fprintf (stderr, "Usage: %s -d \n", argv[0]); fprintf (stderr, "Usage: %s -c \n", argv[0]); exit (EXIT_FAILURE); } exit (rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } nanomsg-1.1.5/demo/pthread_demo.c000066400000000000000000000156451336111550300167140ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. "nanomsg" is a trademark of Martin Sustrik */ /* This program serves as an example for how to write a threaded RPC service, using the RAW request/reply pattern and pthreads. Multiple worker threads are spawned on a single socket, and each worker processes jobs in order. 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 pthread_demo -s Then connect to it with the client as pthread_client . For example: % ./pthread_demo tcp://127.0.0.1:5555 -s & % ./pthread_demo tcp://127.0.0.1:5555 323 Request took 324 milliseconds. */ #include #include #include #include #include #include #include #include #include /* MAXWORKERS is a limit on the on the number of workers we will fire off. Since each worker processes jobs sequentially, this is a limit on the concurrency of the server. New inbound messages will queue up waiting for a worker to receive them. */ #define MAXWORKERS 100 /* Return the UNIX time in milliseconds. You'll need a working gettimeofday(), so this won't work on Windows. */ uint64_t milliseconds (void) { struct timeval tv; gettimeofday (&tv, NULL); return (((uint64_t)tv.tv_sec * 1000) + ((uint64_t)tv.tv_usec / 1000)); } void *worker (void *arg) { int fd = (intptr_t)arg; /* Main processing loop. */ for (;;) { uint32_t timer; int rc; int timeout; uint8_t *body; void *control; struct nn_iovec iov; struct nn_msghdr hdr; memset (&hdr, 0, sizeof (hdr)); control = NULL; iov.iov_base = &body; iov.iov_len = NN_MSG; hdr.msg_iov = &iov; hdr.msg_iovlen = 1; hdr.msg_control = &control; hdr.msg_controllen = NN_MSG; rc = nn_recvmsg (fd, &hdr, 0); if (rc < 0) { if (nn_errno () == EBADF) { return (NULL); /* Socket closed by another thread. */ } /* Any error here is unexpected. */ fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ())); break; } if (rc != sizeof (uint32_t)) { fprintf (stderr, "nn_recv: wanted %d, but got %d\n", (int) sizeof (uint32_t), rc); nn_freemsg (body); nn_freemsg (control); continue; } memcpy (&timer, body, sizeof (timer)); nn_freemsg (body); /* Poor mans usleep but in msec. */ poll (NULL, 0, ntohl (timer)); hdr.msg_iov = NULL; hdr.msg_iovlen = 0; rc = nn_sendmsg (fd, &hdr, 0); if (rc < 0) { fprintf (stderr, "nn_send: %s\n", nn_strerror (nn_errno ())); nn_freemsg (control); } } /* We got here, so close the file. That will cause the other threads to shut down too. */ nn_close (fd); return (NULL); } /* The server runs forever. */ int server(const char *url) { int fd; int i; pthread_t tids [MAXWORKERS]; int rc; /* Create the socket. */ fd = nn_socket(AF_SP_RAW, NN_REP); if (fd < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); return (-1); } /* Bind to the URL. This will bind to the address and listen synchronously; new clients will be accepted asynchronously without further action from the calling program. */ if (nn_bind (fd, url) < 0) { fprintf (stderr, "nn_bind: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } memset (tids, 0, sizeof (tids)); /* Start up the threads. */ for (i = 0; i < MAXWORKERS; i++) { rc = pthread_create (&tids[i], NULL, worker, (void *)(intptr_t)fd); if (rc < 0) { fprintf (stderr, "pthread_create: %s\n", strerror (rc)); nn_close (fd); break; } } /* Now wait on them to finish. */ for (i = 0; i < MAXWORKERS; i++) { if (tids[i] != NULL) { pthread_join (tids[i], NULL); } } return (-1); } /* The client runs just once, and then returns. */ int client (const char *url, const char *msecstr) { int fd; int rc; char *greeting; uint8_t msg[sizeof (uint32_t)]; uint64_t start; uint64_t end; unsigned msec; msec = atoi(msecstr); fd = nn_socket (AF_SP, NN_REQ); if (fd < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); return (-1); } if (nn_connect (fd, url) < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } msec = htonl(msec); memcpy (msg, &msec, sizeof (msec)); start = milliseconds (); if (nn_send (fd, msg, sizeof (msg), 0) < 0) { fprintf (stderr, "nn_send: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } rc = nn_recv (fd, &msg, sizeof (msg), 0); if (rc < 0) { fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } nn_close (fd); end = milliseconds (); 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 [-s|name]\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); } nanomsg-1.1.5/demo/pubsub_demo.c000066400000000000000000000132511336111550300165540ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. "nanomsg" is a trademark of Martin Sustrik */ /* This program serves as an example for how to write a simple PUB SUB service, The server is just a single threaded for loop which broadcasts messages to clients, every so often. The message is a binary format message, containing two 32-bit unsigned integers. The first is UNIX time, and the second is the number of directly connected subscribers. The clients stay connected and print a message with this information along with their process ID to standard output. To run this program, start the server as pubsub_demo -s Then connect to it with the client as pubsub_demo For example: % ./pubsub_demo tcp://127.0.0.1:5555 -s & % ./pubsub_demo tcp://127.0.0.1:5555 & % ./pubsub_demo tcp://127.0.0.1:5555 & 11:23:54 There are 2 clients connected. 11:24:04 There are 2 clients connected. .. */ #include #include #include #include #include /* For htonl and ntohl */ #include #include #include /* The server runs forever. */ int server(const char *url) { int fd; /* Create the socket. */ fd = nn_socket (AF_SP, NN_PUB); if (fd < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); return (-1); } /* Bind to the URL. This will bind to the address and listen synchronously; new clients will be accepted asynchronously without further action from the calling program. */ if (nn_bind (fd, url) < 0) { fprintf (stderr, "nn_bind: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } /* Now we can just publish results. Note that there is no explicit accept required. We just start writing the information. */ for (;;) { uint8_t msg[2 * sizeof (uint32_t)]; uint32_t secs, subs; int rc; secs = (uint32_t) time (NULL); subs = (uint32_t) nn_get_statistic (fd, NN_STAT_CURRENT_CONNECTIONS); secs = htonl (secs); subs = htonl (subs); memcpy (msg, &secs, sizeof (secs)); memcpy (msg + sizeof (secs), &subs, sizeof (subs)); rc = nn_send (fd, msg, sizeof (msg), 0); if (rc < 0) { /* There are several legitimate reasons this can fail. We note them for debugging purposes, but then ignore otherwise. */ fprintf (stderr, "nn_send: %s (ignoring)\n", nn_strerror (nn_errno ())); } sleep(10); } /* NOTREACHED */ nn_close (fd); return (-1); } /* The client runs in a loop, displaying the content. */ int client (const char *url) { int fd; int rc; fd = nn_socket (AF_SP, NN_SUB); if (fd < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); return (-1); } if (nn_connect (fd, url) < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } /* We want all messages, so just subscribe to the empty value. */ if (nn_setsockopt (fd, NN_SUB, NN_SUB_SUBSCRIBE, "", 0) < 0) { fprintf (stderr, "nn_setsockopt: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } for (;;) { uint8_t msg[2 * sizeof (uint32_t)]; char hhmmss[9]; /* HH:MM:SS\0 */ uint32_t subs, secs; time_t t; rc = nn_recv (fd, msg, sizeof (msg), 0); if (rc < 0) { fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ())); break; } if (rc != sizeof (msg)) { fprintf (stderr, "nn_recv: got %d bytes, wanted %d\n", rc, (int)sizeof (msg)); break; } memcpy (&secs, msg, sizeof (secs)); memcpy (&subs, msg + sizeof (secs), sizeof (subs)); t = (time_t) ntohl(secs); strftime (hhmmss, sizeof (hhmmss), "%T", localtime (&t)); printf ("%s There are %u clients connected.\n", hhmmss, (unsigned) getpid(), (unsigned) ntohl(subs)); } nn_close (fd); return (-1); } int main (int argc, char **argv) { int rc; if ((argc == 3) && (strcmp (argv[2], "-s") == 0)) { rc = server (argv[1]); } else if (argc == 2) { rc = client (argv[1]); } else { fprintf (stderr, "Usage: %s [-s]\n", argv[0]); exit (EXIT_FAILURE); } exit (rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } nanomsg-1.1.5/demo/rpc_demo.c000066400000000000000000000147361336111550300160510ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. "nanomsg" is a trademark of Martin Sustrik */ /* This program serves as an example for how to write a simple RPC service, using the request/reply pattern. The server is just a single threaded for loop, which processes each request. The requests run quickly enough that there is no need for parallelism. Our demonstration application layer protocol is simple. The client sends a name, and the server replies with a greeting based on the time of day. The messages are sent in ASCII, and are not zero terminated. To run this program, start the server as rpc_demo -s Then connect to it with the client as rpc_client . The client will print a timezone appropriate greeting, based on the time at the server. For example: % ./rpc_demo tcp://127.0.0.1:5555 -s & % ./rpc_demo tcp://127.0.0.1:5555 Garrett Good morning, Garrett. */ #include #include #include #include #include #include /* The server runs forever. */ int server(const char *url) { int fd; /* Create the socket. */ fd = nn_socket (AF_SP, NN_REP); if (fd < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); return (-1); } /* Bind to the URL. This will bind to the address and listen synchronously; new clients will be accepted asynchronously without further action from the calling program. */ if (nn_bind (fd, url) < 0) { fprintf (stderr, "nn_bind: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } /* Now we can just process results. Note that there is no explicit accept required. We just receive a request, and reply to it. Its important to note that we must not issue two receives in a row without replying first, or the following receive(s) will cancel any unreplied requests. */ for (;;) { char username[128]; char greeting[128]; time_t secs; struct tm *now; char *daytime; int rc; char *fmt; rc = nn_recv (fd, username, sizeof (username), 0); if (rc < 0) { /* Any error here is unexpected. */ fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ())); break; } secs = time (NULL); now = localtime (&secs); if (now->tm_hour < 12) { daytime = "morning"; } else if (now->tm_hour < 17) { daytime = "afternoon"; } else if (now->tm_hour < 20) { daytime = "evening"; } else { daytime = "night"; } /* Ensure ASCIIZ terminated string. */ if (rc < sizeof (username)) { username[rc] = '\0'; } else { username[sizeof (username) - 1] = '\0'; } fmt = "Good %s, %s."; /* Technically this might be overly pessimistic about size. */ if ((strlen (username) + strlen (daytime) + strlen (fmt)) >= sizeof (greeting)) { fmt = "I'm sorry, your name is too long. But good %s anyway."; } /* snprintf would be safer, but the above check protects us. */ sprintf (greeting, fmt, daytime, username); rc = nn_send (fd, greeting, strlen (greeting), 0); if (rc < 0) { /* There are several legitimate reasons this can fail. We note them for debugging purposes, but then ignore otherwise. If the socket is closed or failing, we will notice in recv above, and exit then. */ fprintf (stderr, "nn_send: %s (ignoring)\n", nn_strerror (nn_errno ())); } } nn_close (fd); return (-1); } /* The client runs just once, and then returns. */ int client (const char *url, const char *username) { int fd; int rc; char *greeting; char *msg; fd = nn_socket (AF_SP, NN_REQ); if (fd < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); return (-1); } if (nn_connect (fd, url) < 0) { fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } if (nn_send (fd, username, strlen (username), 0) < 0) { fprintf (stderr, "nn_send: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } /* Here we ask the library to allocate response buffer for us (NN_MSG). */ rc = nn_recv (fd, &msg, NN_MSG, 0); if (rc < 0) { fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ())); nn_close (fd); return (-1); } nn_close (fd); /* Response is not ASCIIZ terminated. */ greeting = malloc (rc + 1); if (greeting == NULL) { fprintf (stderr, "malloc: %s\n", strerror (errno)); return (-1); } memcpy(greeting, msg, rc); greeting[rc] = '\0'; nn_freemsg (msg); printf ("%s\n", greeting); free(greeting); return (0); } int main (int argc, char **argv) { int rc; if (argc < 3) { fprintf (stderr, "Usage: %s [-s|name]\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); } nanomsg-1.1.5/doc/000077500000000000000000000000001336111550300137235ustar00rootroot00000000000000nanomsg-1.1.5/doc/README000066400000000000000000000005601336111550300146040ustar00rootroot00000000000000This directory contains the documentation for nanomsg library. To build the documentation (both man pages and web pages) do "./configure --enable-doc" and "make" in the build directory; man pages will be installed with "make install". You must have asciidoctor installed. The stylesheet.css file is taken from asciidoctor-stylesheet-factory, and is the colony theme. nanomsg-1.1.5/doc/nanocat.adoc000066400000000000000000000122421336111550300161770ustar00rootroot00000000000000nanocat(1) ========== NAME ---- nanocat - a command-line interface to nanomsg SYNOPSIS -------- nanocat --req {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ] nanocat --rep {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-AQ] nanocat --push {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] nanocat --pull {--connect ADDR|--bind ADDR} [-AQ] nanocat --pub {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] nanocat --sub {--connect ADDR|--bind ADDR} [--subscribe PREFIX ...] [-AQ] nanocat --surveyor {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ] nanocat --respondent {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-AQ] nanocat --bus {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ] nanocat --pair {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ] In the case symlinks are installed: nn_req {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ] nn_rep {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-AQ] nn_push {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] nn_pull {--connect ADDR|--bind ADDR} [-AQ] nn_pub {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] nn_sub {--connect ADDR|--bind ADDR} [--subscribe PREFIX ...] [-AQ] nn_surveyor {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ] nn_respondent {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-AQ] nn_bus {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ] nn_pair {--connect ADDR|--bind ADDR} {--data DATA|--file PATH} [-i SEC] [-AQ] DESCRIPTION ----------- The nanocat is a command-line tool to send and receive data via nanomsg sockets. It can be used for debugging purposes, sending files through the network, health checking the system or whatever else you can think of. OPTIONS ------- Generic: *--verbose,-v*:: Increase verbosity of the nanocat *--silent,-q*:: Decrease verbosity of the nanocat *--help,-h*:: This help text Socket Types: *--push*:: Use NN_PUSH socket type *--pull*:: Use NN_PULL socket type *--pub*:: Use NN_PUB socket type *--sub*:: Use NN_SUB socket type *--req*:: Use NN_REQ socket type *--rep*:: Use NN_REP socket type *--surveyor*:: Use NN_SURVEYOR socket type *--respondent*:: Use NN_RESPONDENT socket type *--bus*:: Use NN_BUS socket type *--pair*:: Use NN_PAIR socket type Socket Options: *--bind* 'ADDR':: Bind socket to the address ADDR *--connect* 'ADDR':: Connect socket to the address ADDR *--bind-ipc,-X* 'PATH':: Bind socket to the ipc address "ipc://PATH". *--connect-ipc,-x* 'PATH':: Connect socket to the ipc address "ipc://PATH". *--bind-local,-L* 'PORT':: Bind socket to the tcp address "tcp://127.0.0.1:PORT". *--connect-local,-l* 'PORT':: Connect socket to the tcp address "tcp://127.0.0.1:PORT". *--recv-timeout* 'SEC':: Set timeout for receiving a message *--send-timeout* 'SEC':: Set timeout for sending a message SUB Socket Options: *--subscribe* 'PREFIX':: Subscribe to the prefix PREFIX. Note: socket will be subscribed to everything (empty prefix) if no prefixes are specified on the command-line. Input Options: *--format* 'FORMAT':: Use echo format FORMAT (same as the options below) *--raw*:: Dump message as is (Note: no delimiters are printed) *--ascii,-A*:: Print ASCII part of message delimited by newline. All non-ascii characters replaced by dot. *--quoted,-Q*:: Print each message on separate line in double quotes with C-like character escaping *--msgpack*:: Print each message as msgpacked string (raw type). This is useful for programmatic parsing. Output Options: *--interval,-i* 'SEC':: Send message (or request) every SEC seconds *--delay,-d* 'SEC':: Wait for SEC seconds before sending message (useful for one-shot PUB sockets) *--data,-D* 'DATA':: Send DATA to the socket and quit for PUB, PUSH, PAIR, BUS socket. Use DATA to reply for REP or RESPONDENT socket. Send DATA as request for REQ or SURVEYOR socket. *--file,-F* 'PATH':: Same as --data but get data from file PATH EXAMPLES -------- The ping-pong with nn_req/nn_rep sockets (must be run simultaneously): nanocat --rep --bind tcp://127.0.0.1:1234 --data pong --format ascii nanocat --req --connect tcp://127.0.0.1:1234 --data ping --format ascii Or in shorter to write form: nn_rep -L1234 -Dpong -A nn_req -l1234 -Dping -A Do periodic requests once a second: nn_req -l1234 -Dping -A -i 1 The rep socket that never reply (no -D option), may be used to check if resending the requests is actually work: nanocat --rep --connect ipc:///var/run/app/req.socket Send an output of the ls to whatever would connect to 127.0.0.1:1234 then exit: ls | nanocat --push -L1234 -F- Send heartbeats to imaginary monitoring service: nanocat --pub --connect tpc://monitoring.example.org -D"I am alive!" --interval 10 SEE ALSO -------- <> AUTHORS ------- link:mailto:paul@colomiets.name[Paul Colomiets] nanomsg-1.1.5/doc/nanomsg.adoc000066400000000000000000000050541336111550300162210ustar00rootroot00000000000000nanomsg(7) ========== NAME ---- nanomsg - scalability protocols library SYNOPSIS -------- *cc* ['flags'] 'files' *-lnanomsg* ['libraries'] DESCRIPTION ----------- Following functions are exported by nanomsg library: Create an SP socket:: <> Close an SP socket:: <> Set a socket option:: <> Retrieve a socket option:: <> Add a local endpoint to the socket:: <> Add a remote endpoint to the socket:: <> Remove an endpoint from the socket:: <> Send a message:: <> Receive a message:: <> Fine-grained alternative to nn_send:: <> Fine-grained alternative to nn_recv:: <> Allocation of messages:: <> <> <> Manipulation of message control data:: <> Multiplexing:: <> Retrieve the current errno:: <> Convert an error number into human-readable string:: <> Query the names and values of nanomsg symbols:: <> Query properties of nanomsg symbols:: <> Query statistics on a socket:: <> Start a device:: <> Notify all sockets about process termination:: <> Environment variables that influence nanomsg work:: <> Following scalability protocols are provided by nanomsg: One-to-one protocol:: <> Request/reply protocol:: <> Publish/subscribe protocol:: <> Survey protocol:: <> Pipeline protocol:: <> Message bus protocol:: <> Following transport mechanisms are provided by nanomsg: In-process transport:: <> Inter-process transport:: <> TCP transport:: <> WebSocket transport:: <> The following tool is installed with the library: nanocat:: <> AUTHORS ------- link:mailto:garrett@damore.org[Garrett D'Amore] link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_allocmsg.adoc000066400000000000000000000032011336111550300170430ustar00rootroot00000000000000nn_allocmsg(3) ============== NAME ---- nn_allocmsg - allocate a message SYNOPSIS -------- *#include * *void *nn_allocmsg (size_t 'size', int 'type');* DESCRIPTION ----------- Allocate a message of the specified 'size' to be sent in zero-copy fashion. The content of the message is undefined after allocation and it should be filled in by the user. While <> and <> allow to send arbitrary buffers, buffers allocated using _nn_allocmsg()_ can be more efficient for large messages as they allow for using zero-copy techniques. 'type' parameter specifies type of allocation mechanism to use. Zero is the default one, however, individual transport mechanisms may define their own allocation mechanisms, such as allocating in shared memory or allocating a memory block pinned down to a physical memory address. Such allocation, when used with the transport that defines them, should be more efficient than the default allocation mechanism. RETURN VALUE ------------ If the function succeeds pointer to newly allocated buffer is returned. Otherwise, NULL is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EINVAL*:: Supplied allocation 'type' is invalid. *ENOMEM*:: Not enough memory to allocate the message. EXAMPLE ------- ---- void *buf = nn_allocmsg (12, 0); memcpy (buf, "Hello world!", 12); nn_send (s, &buf, NN_MSG, 0); ---- SEE ALSO -------- <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_bind.adoc000066400000000000000000000047041336111550300161670ustar00rootroot00000000000000nn_bind(3) ========== NAME ---- nn_bind - add a local endpoint to the socket SYNOPSIS -------- *#include * *int nn_bind (int 's', const char '*addr');* DESCRIPTION ----------- Adds a local endpoint to the socket 's'. The endpoint can be then used by other applications to connect to. The 'addr' argument consists of two parts as follows: 'transport'`://`'address'. The 'transport' specifies the underlying transport protocol to use. The meaning of the 'address' part is specific to the underlying transport protocol. For the list of available transport protocols check the list on <> manual page. Maximum length of the 'addr' parameter is specified by _NN_SOCKADDR_MAX_ defined in '' header file. Note that nn_bind and <> may be called multiple times on the same socket thus allowing the socket to communicate with multiple heterogeneous endpoints. NOTE ---- Unlike with traditional BSD sockets, this function operates asynchronously, and returns to the caller before the operation is complete. As a result, attempts to send data or receive data on the socket may not succeed until the underlying transport actually establishes a connection. RETURN VALUE ------------ If the function succeeds positive endpoint ID is returned. Endpoint ID can be later used to remove the endpoint from the socket via <> function. If the function fails, then -1 is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EBADF*:: The provided socket is invalid. *EMFILE*:: Maximum number of active endpoints was reached. *EINVAL*:: The syntax of the supplied address is invalid. *ENAMETOOLONG*:: The supplied address is too long. *EPROTONOSUPPORT*:: The requested transport protocol is not supported. *EADDRNOTAVAIL*:: The requested endpoint is not local. *ENODEV*:: Address specifies a nonexistent interface. *EADDRINUSE*:: The requested local endpoint is already in use. *ETERM*:: The library is terminating. EXAMPLE ------- ---- s = nn_socket (AF_SP, NN_PUB); eid1 = nn_bind (s, "inproc://test"); eid2 = nn_bind (s, "tcp://127.0.0.1:5560"); ---- SEE ALSO -------- <> <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] link:mailto:garrett@damore.org[Garrett D'Amore] nanomsg-1.1.5/doc/nn_bus.adoc000066400000000000000000000023311336111550300160360ustar00rootroot00000000000000nn_bus(7) ========= NAME ---- nn_bus - message bus scalability protocol SYNOPSIS -------- *#include * *#include * DESCRIPTION ----------- Broadcasts messages from any node to all other nodes in the topology. The socket should never receive messages that it sent itself. This pattern scales only to local level (within a single machine or within a single LAN). Trying to scale it further can result in overloading individual nodes with messages. WARNING: For bus topology to function correctly, user is responsible for ensuring that path from each node to any other node exists within the topology. Raw (AF_SP_RAW) BUS socket never sends the message to the peer it was received from. Socket Types ~~~~~~~~~~~~ NN_BUS:: Sent messages are distributed to all nodes in the topology. Incoming messages from all other nodes in the topology are fair-queued in the socket. Socket Options ~~~~~~~~~~~~~~ There are no options defined at the moment. SEE ALSO -------- <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_close.adoc000066400000000000000000000021021336111550300163460ustar00rootroot00000000000000nn_close(3) =========== NAME ---- nn_close - close an SP socket SYNOPSIS -------- *#include * *int nn_close (int 's');* DESCRIPTION ----------- Closes the socket 's'. Any buffered inbound messages that were not yet received by the application will be discarded. The library will try to deliver any outstanding outbound messages for the time specified by _NN_LINGER_ socket option. The call will block in the meantime. RETURN VALUE ------------ If the function succeeds zero is returned. Otherwise, -1 is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EBADF*:: The provided socket is invalid. *EINTR*:: Operation was interrupted by a signal. The socket is not fully closed yet. Operation can be re-started by calling _nn_close()_ again. EXAMPLE ------- ---- int s = nn_socket (AF_SP, NN_PUB); assert (s >= 0); int rc = nn_close (s); assert (rc == 0); ---- SEE ALSO -------- <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_cmsg.adoc000066400000000000000000000044431336111550300162040ustar00rootroot00000000000000nn_cmsg(3) ========== NAME ---- nn_cmsg - access control information SYNOPSIS -------- *#include * *struct nn_cmsghdr *NN_CMSG_FIRSTHDR(struct nn_msghdr '*hdr');* *struct nn_cmsghdr *NN_CMSG_NXTHDR(struct nn_msghdr '*hdr', struct nn_cmsghdr '*cmsg');* *unsigned char *NN_CMSG_DATA(struct nn_cmsghdr '*cmsg');* *size_t NN_CMSG_SPACE(size_t 'len');* *size_t NN_CMSG_LEN(size_t 'len');* DESCRIPTION ----------- These functions can be used to iterate over ancillary data attached to a message. Structure 'nn_cmsghdr' represents a single ancillary property and contains following members: size_t cmsg_len; int cmsg_level; int cmsg_type; 'cmsg_len' is the size of the property data, including the preceding nn_cmsghdr structure. 'cmsg_level' is the level of the property; same values can be used as with <> and <>. 'cmsg_type' is the name of the property. These names are specific for each level. _NN_CMSG_FIRSTHDR_ returns a pointer to the first nn_cmsghdr in the control buffer in the supplied nn_msghdr structure. _NN_CMSG_NXTHDR_ returns the next nn_cmsghdr after the supplied nn_cmsghdr. Returns NULL if there isn't enough space in the buffer. _NN_CMSG_DATA_ returns a pointer to the data associated with supplied nn_cmsghdr. _NN_CMSG_SPACE_ returns the number of bytes occupied by nn_cmsghdr with payload of the specified length. _NN_CMSG_LEN_ returns the value to store in the cmsg_len member of the cmsghdr structure, taking into account any necessary alignment. EXAMPLE ------- Iterating over ancillary properties: ---- struct nn_cmsghdr *hdr = NN_CMSG_FIRSTHDR (&msg); while (hdr != NULL) { size_t len = hdr->cmsg_len - sizeof (nn_cmsghdr); printf ("level: %d property: %d length: %dB data: ", (int) hdr->cmsg_level, (int) hdr->cmsg_type, (int) len); unsigned char *data = NN_CMSG_DATA(hdr); while (len) { printf ("%02X", *data); ++data; --len; } printf ("\n"); hdr = NN_CMSG_NXTHDR (&msg, hdr); } ---- SEE ALSO -------- <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_connect.adoc000066400000000000000000000047771336111550300167160ustar00rootroot00000000000000nn_connect(3) ============= NAME ---- nn_connect - add a remote endpoint to the socket SYNOPSIS -------- *#include * *int nn_connect (int 's', const char '*addr');* DESCRIPTION ----------- Adds a remote endpoint to the socket 's'. The library would then try to connect to the specified remote endpoint. The 'addr' argument consists of two parts as follows: 'transport'`://`'address'. The 'transport' specifies the underlying transport protocol to use. The meaning of the 'address' part is specific to the underlying transport protocol. For the list of available transport protocols check the list on <> manual page. Maximum length of the 'addr' parameter is specified by _NN_SOCKADDR_MAX_ defined in '' header file. Note that nn_connect and <> may be called multiple times on the same socket thus allowing the socket to communicate with multiple heterogeneous endpoints. NOTE ---- Unlike with traditional BSD sockets, this function operates asynchronously, and returns to the caller before the operation is complete. As a result, attempts to send data or receive data on the socket may not succeed until the underlying transport actually establishes the connection. Further, the connection may be lost, without any notification to the caller. The library will attempt to reconnect automatically in such an event. RETURN VALUE ------------ If the function succeeds positive endpoint ID is returned. Endpoint ID can be later used to remove the endpoint from the socket via <> function. If the function fails negative value is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EBADF*:: The provided socket is invalid. *EMFILE*:: Maximum number of active endpoints was reached. *EINVAL*:: The syntax of the supplied address is invalid. *ENAMETOOLONG*:: The supplied address is too long. *EPROTONOSUPPORT*:: The requested transport protocol is not supported. *ENODEV*:: Address specifies a nonexistent interface. *ETERM*:: The library is terminating. EXAMPLE ------- ---- s = nn_socket (AF_SP, NN_PUB); eid1 = nn_connect (s, "ipc:///tmp/test.ipc"); eid2 = nn_connect (s, "tcp://server001:5560"); ---- SEE ALSO -------- <> <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] link:mailto:garrett@damore.org[Garrett D'Amore] nanomsg-1.1.5/doc/nn_device.adoc000066400000000000000000000027711336111550300165140ustar00rootroot00000000000000nn_device(3) ============ NAME ---- nn_device - start a device SYNOPSIS -------- *#include * *int nn_device (int 's1', int 's2');* DESCRIPTION ----------- Starts a device to forward messages between two sockets. If both sockets are valid, _nn_device_ function loops and sends any messages received from 's1' to 's2' and vice versa. If only one socket is valid and the other is negative, _nn_device_ works in a "loopback" mode -- it loops and sends any messages received from the socket back to itself. To break the loop and make _nn_device_ function exit use the <> function. RETURN VALUE ------------ The function loops until it hits an error. In such a case it returns -1 and sets 'errno' to one of the values defined below. ERRORS ------ *EBADF*:: One of the provided sockets is invalid. *EINVAL*:: Either one of the socket is not an AF_SP_RAW socket; or the two sockets don't belong to the same protocol; or the directionality of the sockets doesn't fit (e.g. attempt to join two SINK sockets to form a device). *EINTR*:: The operation was interrupted by delivery of a signal. *ETERM*:: The library is terminating. EXAMPLE ------- ---- int s1 = nn_socket (AF_SP_RAW, NN_REQ); nn_bind (s1, "tcp://127.0.0.1:5555"); int s2 = nn_socket (AF_SP_RAW, NN_REP); nn_bind (s2, "tcp://127.0.0.1:5556"); nn_device (s1, s2); ---- SEE ALSO -------- <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_env.adoc000066400000000000000000000022371336111550300160420ustar00rootroot00000000000000nn_env(7) ========== NAME ---- nn_env - nanomsg environment variables SYNOPSIS -------- Environment variables that influence the way nanomsg works DESCRIPTION ----------- *This functionality is experimental and a subject to change at any time* Following environment variables are used to turn on some debugging for any nanomsg application. Please, do not try to parse output and do not build business logic based on it. NN_PRINT_ERRORS:: If set to a non-empty string nanomsg will print errors to stderr. Some errors will be resolved by nanomsg itself (e.g. if nanomsg can't establish connection it will retry again in a moment). Some depend on the environment (e.g. port that is bound by another process need to be released). In any case nanomsg will not repeat the error message until error is clear and appear again (e.g. connection established then broken again). NOTES ----- The output of the debugging facility (NN_PRINT_ERRORS) is intended for reading by a human and a subject for change at any time (even after 1.0 release). SEE ALSO -------- <> AUTHORS ------- link:mailto:paul@colomiets.name[Paul Colomiets] nanomsg-1.1.5/doc/nn_errno.adoc000066400000000000000000000022741336111550300164000ustar00rootroot00000000000000nn_errno(3) =========== NAME ---- nn_errno - retrieve the current errno SYNOPSIS -------- *#include * *int nn_errno (void);* DESCRIPTION ----------- Returns value of 'errno' for the current thread. On most systems, 'errno' can be accessed directly and this function is not needed. However, on Windows, there are multiple implementations of the CRT library (single-threaded, multi-threaded, release, debug) and each of them has its own instance of 'errno'. Thus, if nanomsg library and the application that uses it link with different versions of the CRT library, they don't share the same instance of 'errno'. Consequently, error codes set by nanomsg cannot be accessed by the application. To overcome this problem, application can use _nn_errno()_ function to retrieve nanomsg's value of 'errno'. RETURN VALUE ------------ Returns value of 'errno' for the current thread. ERRORS ------ No errors are defined. EXAMPLE ------- ---- rc = nn_send (s, "ABC", 3, 0); if (rc < 0) printf ("nn_send failed with error code %d\n", nn_errno ()); ---- SEE ALSO -------- <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_freemsg.adoc000066400000000000000000000021151336111550300166750ustar00rootroot00000000000000nn_freemsg(3) ============= NAME ---- nn_freemsg - deallocate a message SYNOPSIS -------- *#include * *int nn_freemsg (void '*msg');* DESCRIPTION ----------- Deallocates a message allocated using <> function or received via <> or <> function. While <> and <> allow to receive data into arbitrary buffers, using library-allocated buffers can be more efficient for large messages as it allows for using zero-copy techniques. RETURN VALUE ------------ If the function succeeds zero is returned. Otherwise, -1 is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EFAULT*:: The message pointer is invalid. EXAMPLE ------- ---- void *buf; nn_recv (s, &buf, NN_MSG, 0); nn_freemsg (buf); ---- SEE ALSO -------- <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_get_statistic.adoc000066400000000000000000000053561336111550300201250ustar00rootroot00000000000000nn_get_statistic(3) =================== NAME ---- nn_get_statistic - retrieve statistics from nanomsg socket SYNOPSIS -------- *#include * *uint64_t nn_get_statistic (int 's', int 'statistic');* DESCRIPTION ----------- Retrieves the value of a statistic from the socket. CAUTION: While this API is stable, these statistics are intended for human consumption, to facilitate observability and debugging. The actual statistics themselves as well as their meanings are unstable, and subject to change without notice. Programs should not depend on the presence or values of any particular statistic. The following statistics are maintained by the nanomsg core framework; others may be present. As those are undocumented, no interpretration should be made from them. Not all statistics are relevant to all transports. For example, the <> transport does not maintain any of the connection related statistics. *NN_STAT_ESTABLISHED_CONNECTIONS*:: The number of connections successfully established that were initiated from this socket. *NN_STAT_ACCEPTED_CONNECTIONS*:: The number of connections successfully established that were accepted by this socket. *NN_STAT_DROPPED_CONNECTIONS*:: The number of established connections that were dropped by this socket. *NN_STAT_BROKEN_CONNECTIONS*:: The number of established connections that were closed by this socket, typically due to protocol errors. *NN_STAT_CONNECT_ERRORS*:: The number of errors encountered by this socket trying to connect to a remote peer. *NN_STAT_BIND_ERRORS*:: The number of errors encountered by this socket trying to bind to a local address. *NN_STAT_ACCEPT_ERRORS*:: The number of errors encountered by this socket trying to accept a a connection from a remote peer. *NN_STAT_CURRENT_CONNECTIONS*:: The number of connections currently estabalished to this socket. *NN_STAT_MESSAGES_SENT*:: The number messages sent by this socket. *NN_STAT_MESSAGES_RECEIVED*:: The number messages received by this socket. *NN_STAT_BYTES_SENT*:: The number of bytes sent by this socket. *NN_STAT_BYTES_RECEIVED*:: The number of bytes received by this socket. RETURN VALUE ------------ On success, the value of the statistic is returned, otherwise (uint64_t)-1 is returned. ERRORS ------ *EINVAL*:: The statistic is invalid or unsupported. *EBADF*:: The provided socket is invalid. *ETERM*:: The library is terminating. EXAMPLE ------- ---- val = nn_get_statistic (s, NN_STAT_MESSAGES_SENT); if (val == 0) printf ("No messages have been sent yet.\n"); ---- SEE ALSO -------- <> <> <> AUTHORS ------- link:mailto:garrett@damore.org[Garrett D'Amore] nanomsg-1.1.5/doc/nn_getsockopt.adoc000066400000000000000000000154061336111550300174360ustar00rootroot00000000000000nn_getsockopt(3) ================ NAME ---- nn_getsockopt - retrieve a socket option SYNOPSIS -------- *#include * *int nn_getsockopt (int 's', int 'level', int 'option', void '*optval', size_t '*optvallen');* DESCRIPTION ----------- Retrieves the value for the 'option'. The 'level' argument specifies the protocol level at which the option resides. For generic socket-level options use _NN_SOL_SOCKET_ level. For socket-type-specific options use socket type for 'level' argument (e.g. _NN_SUB_). For transport-specific options use ID of the transport as the 'level' argument (e.g. _NN_TCP_). The value is stored in the buffer pointed to by 'optval' argument. Size of the buffer is specified by the 'optvallen' argument. If the size of the option is greater than size of the buffer, the value will be silently truncated. Otherwise, the 'optvallen' will be modified to indicate the actual length of the option. __ header defines generic socket-level options (_NN_SOL_SOCKET_ level). The options are as follows: *NN_DOMAIN*:: Returns the domain constant as it was passed to _nn_socket()_. *NN_PROTOCOL*:: Returns the protocol constant as it was passed to _nn_socket()_. *NN_LINGER*:: Specifies how long the socket should try to send pending outbound messages after _nn_close()_ have been called, in milliseconds. Negative value means infinite linger. The type of the option is int. Default value is 1000 (1 second). *NN_SNDBUF*:: Size of the send buffer, in bytes. To prevent blocking for messages larger than the buffer, exactly one message may be buffered in addition to the data in the send buffer. The type of this option is int. Default value is 128kB. *NN_RCVBUF*:: Size of the receive buffer, in bytes. To prevent blocking for messages larger than the buffer, exactly one message may be buffered in addition to the data in the receive buffer. The type of this option is int. Default value is 128kB. *NN_RCVMAXSIZE*:: Maximum message size that can be received, in bytes. Negative value means that the received size is limited only by available addressable memory. The type of this option is int. Default is 1024kB. *NN_SNDTIMEO*:: The timeout for send operation on the socket, in milliseconds. If message cannot be sent within the specified timeout, ETIMEDOUT error is returned. Negative value means infinite timeout. The type of the option is int. Default value is -1. *NN_RCVTIMEO*:: The timeout for recv operation on the socket, in milliseconds. If message cannot be received within the specified timeout, ETIMEDOUT error is returned. Negative value means infinite timeout. The type of the option is int. Default value is -1. *NN_RECONNECT_IVL*:: For connection-based transports such as TCP, this option specifies how long to wait, in milliseconds, when connection is broken before trying to re-establish it. Note that actual reconnect interval may be randomised to some extent to prevent severe reconnection storms. The type of the option is int. Default value is 100 (0.1 second). *NN_RECONNECT_IVL_MAX*:: This option is to be used only in addition to _NN_RECONNECT_IVL_ option. It specifies maximum reconnection interval. On each reconnect attempt, the previous interval is doubled until _NN_RECONNECT_IVL_MAX_ is reached. Value of zero means that no exponential backoff is performed and reconnect interval is based only on _NN_RECONNECT_IVL_. If _NN_RECONNECT_IVL_MAX_ is less than _NN_RECONNECT_IVL_, it is ignored. The type of the option is int. Default value is 0. *NN_SNDPRIO*:: Retrieves outbound priority currently set on the socket. This option has no effect on socket types that send messages to all the peers. However, if the socket type sends each message to a single peer (or a limited set of peers), peers with high priority take precedence over peers with low priority. The type of the option is int. Highest priority is 1, lowest priority is 16. Default value is 8. *NN_RCVPRIO*:: Sets inbound priority for endpoints subsequently added to the socket. This option has no effect on socket types that are not able to receive messages. When receiving a message, messages from peer with higher priority are received before messages from peer with lower priority. The type of the option is int. Highest priority is 1, lowest priority is 16. Default value is 8. *NN_IPV4ONLY*:: If set to 1, only IPv4 addresses are used. If set to 0, both IPv4 and IPv6 addresses are used. The type of the option is int. Default value is 1. *NN_SNDFD*:: Retrieves a file descriptor that is readable when a message can be sent to the socket. The descriptor should be used only for polling and never read from or written to. The type of the option is same as the type of file descriptor on the platform. That is, int on POSIX-complaint platforms and SOCKET on Windows. The descriptor becomes invalid and should not be used any more once the socket is closed. This socket option is not available for unidirectional recv-only socket types. *NN_RCVFD*:: Retrieves a file descriptor that is readable when a message can be received from the socket. The descriptor should be used only for polling and never read from or written to. The type of the option is same as the type of file descriptor on the platform. That is, int on POSIX-complaint platforms and SOCKET on Windows. The descriptor becomes invalid and should not be used any more once the socket is closed. This socket option is not available for unidirectional send-only socket types. *NN_SOCKET_NAME*:: Socket name for error reporting and statistics. The type of the option is string. Default value is "N" where N is socket integer. *This option is experimental, see <> for details* *NN_MAXTTL*:: Retrieves the maximum number of "hops" a message can go through before it is dropped. Each time the message is received (for example via the <> function) counts as a single hop. This provides a form of protection against inadvertent loops. RETURN VALUE ------------ If the function succeeds zero is returned. Otherwise, -1 is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EBADF*:: The provided socket is invalid. *ENOPROTOOPT*:: The option is unknown at the level indicated. *ETERM*:: The library is terminating. EXAMPLE ------- ---- int linger; size_t sz = sizeof (linger); nn_getsockopt (s, NN_SOL_SOCKET, NN_LINGER, &linger, &sz); ---- SEE ALSO -------- <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] link:mailto:garrett@damore.org[Garrett D'Amore] nanomsg-1.1.5/doc/nn_inproc.adoc000066400000000000000000000031651336111550300165450ustar00rootroot00000000000000nn_inproc(7) ============ NAME ---- nn_inproc - in-process transport mechanism SYNOPSIS -------- *#include * *#include * DESCRIPTION ----------- In-process transport allows to send messages between threads or modules inside a process. In-process address is an arbitrary case-sensitive string preceded by 'inproc://' protocol specifier. All in-process addresses are visible from any module within the process. They are not visible from outside of the process. The nature of in-process transport makes it easy to pass pointers between threads instead of actual data. This is, however, considered a bad application design and violates the scalable share-nothing architecture. If you do pass pointers among threads, synchronising thread access to shared data becomes your responsibility. Such design also prevents moving the thread into different process or machine once the need arises. As a rule of the thumb, don't pass pointers among threads unless you know what you are doing. The overall buffer size for an inproc connection is determined by NN_RCVBUF socket option on the receiving end of the connection. NN_SNDBUF socket option is ignored. In addition to the buffer, one message of arbitrary size will fit into the buffer. That way, even messages larger than the buffer can be transfered via inproc connection. EXAMPLE ------- ---- nn_bind (s1, "inproc://test"); nn_connect (s2, "inproc://test); ---- SEE ALSO -------- <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_ipc.adoc000066400000000000000000000023461336111550300160260ustar00rootroot00000000000000nn_ipc(7) ========= NAME ---- nn_ipc - inter-process transport mechanism SYNOPSIS -------- *#include * *#include * DESCRIPTION ----------- Inter-process transport allows for sending messages between processes within a single box. The implementation uses native IPC mechanism provided by the local operating system and the IPC addresses are thus OS-specific. On POSIX-compliant systems, UNIX domain sockets are used and IPC addresses are file references. Note that both relative (ipc://test.ipc) and absolute (ipc:///tmp/test.ipc) paths may be used. Also note that access rights on the IPC files must be set in such a way that the appropriate applications can actually use them. On Windows, named pipes are used for IPC. IPC address is an arbitrary case-insensitive string containing any character except for backslash. Internally, address ipc://test means that named pipe \\.\pipe\test will be used. EXAMPLE ------- ---- nn_bind (s1, "ipc:///tmp/test.ipc"); nn_connect (s2, "ipc:///tmp/test.ipc"); ---- SEE ALSO -------- <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_pair.adoc000066400000000000000000000030731336111550300162040ustar00rootroot00000000000000nn_pair(7) ========== NAME ---- nn_pair - one-to-one scalability protocol SYNOPSIS -------- *#include * *#include * DESCRIPTION ----------- Pair protocol is the simplest and least scalable scalability protocol. It allows scaling by breaking the application in exactly two pieces. For example, if a monolithic application handles both accounting and agenda of HR department, it can be split into two applications (accounting vs. HR) that are run on two separate servers. These applications can then communicate via PAIR sockets. The downside of this protocol is that its scaling properties are very limited. Splitting the application into two pieces allows to scale the two servers. To add the third server to the cluster, the application has to be split once more, say by separating HR functionality into hiring module and salary computation module. Whenever possible, try to use one of the more scalable protocols instead. Socket Types ~~~~~~~~~~~~ NN_PAIR:: Socket for communication with exactly one peer. Each party can send messages at any time. If the peer is not available or send buffer is full subsequent calls to <> will block until it's possible to send the message. Socket Options ~~~~~~~~~~~~~~ No protocol-specific socket options are defined at the moment. SEE ALSO -------- <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_pipeline.adoc000066400000000000000000000017621336111550300170610ustar00rootroot00000000000000nn_pipeline(7) ============== NAME ---- nn_pipeline - scalability protocol for passing tasks through a series of processing steps SYNOPSIS -------- *#include * *#include * DESCRIPTION ----------- Fair queues messages from the previous processing step and load balances them among instances of the next processing step. Socket Types ~~~~~~~~~~~~ NN_PUSH:: This socket is used to send messages to a cluster of load-balanced nodes. Receive operation is not implemented on this socket type. NN_PULL:: This socket is used to receive a message from a cluster of nodes. Send operation is not implemented on this socket type. Socket Options ~~~~~~~~~~~~~~ No protocol-specific socket options are defined at the moment. SEE ALSO -------- <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_poll.adoc000066400000000000000000000050131336111550300162130ustar00rootroot00000000000000nn_poll(3) ========== NAME ---- nn_poll - poll a set of SP sockets for readability and/or writability SYNOPSIS -------- *#include * *int nn_poll (struct nn_pollfd *fds, int nfds, int timeout);* DESCRIPTION ----------- The function checks a set of SP socket and reports whether it's possible to send a message to the socket and/or receive a message from each socket. 'fds' argument is an array of nn_pollfd structures with 'nfds' argument specifying the size of the array: ---- struct nn_pollfd { int fd; short events; short revents; }; ---- Each entry in the array represents an SP socket to check. 'events' field specifies which events to check for. The value is a bitwise combination of the following values: *NN_POLLIN*:: Check whether at least one message can be received from the 'fd' socket without blocking. *NN_POLLOUT*:: Check whether at least one message can be sent to the 'fd' socket without blocking. After the function returns, 'revents' field contains bitwise combination of NN_POLLIN and NN_POLLOUT according to whether the socket is readable or writable. 'timeout' parameter specifies how long (in milliseconds) should the function block if there are no events to report. RETURN VALUE ------------ Upon successful completion, the number of nn_pollfds structures with events signaled is returned. In case of timeout, return value is 0. In case of error, -1 is returned and 'errno' is set the one of the values below. ERRORS ------ *EBADF*:: Some of the provided sockets are invalid. *EINTR*:: The operation was interrupted by delivery of a signal before the message was sent. *ETERM*:: The library is terminating. NOTE ---- nn_poll is a convenience function. You can achieve same behaviour by using NN_RCVFD and NN_SNDFD socket options. However, using the socket options allows for usage that's not possible with nn_poll, such as simultaneous polling for both SP and OS-level sockets, integration of SP sockets with external event loops etc. EXAMPLE ------- ---- struct nn_pollfd pfd [2]; pfd [0].fd = s1; pfd [0].events = NN_POLLIN | NN_POLLOUT; pfd [1].fd = s2; pfd [1].events = NN_POLLIN; rc = nn_poll (pfd, 2, 2000); if (rc == 0) { printf ("Timeout!"); exit (1); } if (rc == -1) { printf ("Error!"); exit (1); } if (pfd [0].revents & NN_POLLIN) { printf ("Message can be received from s1!"); exit (1); } ---- SEE ALSO -------- <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_pubsub.adoc000066400000000000000000000054151336111550300165530ustar00rootroot00000000000000nn_pubsub(7) ============ NAME ---- nn_pubsub - publish/subscribe scalability protocol SYNOPSIS -------- *#include * *#include * DESCRIPTION ----------- Broadcasts messages to multiple destinations. Messages are sent from NN_PUB sockets and will only be received by NN_SUB sockets that have subscribed to the matching 'topic'. Topic is an arbitrary sequence of bytes at the beginning of the message body. The NN_SUB socket will determine whether a message should be delivered to the user by comparing the subscribed topics (using NN_SUB_SUBSCRIBE on a full SUB socket) to the bytes initial bytes in the incoming message, up to the size of the topic. ---- nn_setsockopt (s, NN_SUB, NN_SUB_SUBSCRIBE, "Hello", 5); ---- Will match any message with intial 5 bytes being "Hello", for example, message "Hello, World!" will match. Topic with zero length matches any message. If the socket is subscribed to multiple topics, message matching any of them will be delivered to the user. Since the filtering is performed on the Subscriber side, all the messages from Publisher will be sent over the transport layer. The entire message, including the topic, is delivered to the user. Socket Types ~~~~~~~~~~~~ NN_PUB:: This socket is used to distribute messages to multiple destinations. Receive operation is not defined. NN_SUB:: Receives messages from the publisher. Only messages that the socket is subscribed to are received. When the socket is created there are no subscriptions and thus no messages will be received. Send operation is not defined on this socket. Socket Options ~~~~~~~~~~~~~~ NN_SUB_SUBSCRIBE:: Defined on full SUB socket. Subscribes for a particular topic. Type of the option is string. A single NN_SUB socket can handle multiple subscriptions. NN_SUB_UNSUBSCRIBE:: Defined on full SUB socket. Unsubscribes from a particular topic. Type of the option is string. EXAMPLE ~~~~~~~ ---- int pub = nn_socket (AF_SP, NN_PUB); int sub = nn_socket (AF_SP, NN_SUB); int nbytes; void *buf = NULL; char *addr = "inproc://example"; nn_setsockopt (sub, NN_SUB, NN_SUB_SUBSCRIBE, "foo", 3); nn_setsockopt (sub, NN_SUB, NN_SUB_SUBSCRIBE, "bar", 3); nn_bind(pub, addr); nn_connect(sub, addr); nbytes = nn_send (pub, "foo|Hello!", 10); assert(nbytes == 10); nbytes = nn_recv (sub, &buf, NN_MSG, 0); assert (nbytes == 10); nn_freemsg (buf); nbytes = nn_send (pub, "baz|World!", 10); /* Message is not delivered because if matches no subscription. */ nbytes = nn_recv(sub, &buf, NN_MSG, 0); ---- SEE ALSO -------- <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_reallocmsg.adoc000066400000000000000000000017261336111550300174040ustar00rootroot00000000000000nn_reallocmsg(3) ================ NAME ---- nn_reallocmsg - reallocate a message SYNOPSIS -------- *#include * *void *nn_reallocmsg (void *'msg', size_t 'size');* DESCRIPTION ----------- Reallocate a message previously allocated by <> or received from a peer using NN_MSG mechanism. Note that as with the standard _realloc_, the operation may involve copying the data in the buffer. RETURN VALUE ------------ If the function succeeds pointer to newly allocated buffer is returned. Otherwise, NULL is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *ENOMEM*:: Not enough memory to allocate the message. EXAMPLE ------- ---- void *buf = nn_allocmsg (12, 0); void *newbuf = nn_reallocmsg (buf, 20); nn_freemsg (newbuf); ---- SEE ALSO -------- <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_recv.adoc000066400000000000000000000056711336111550300162160ustar00rootroot00000000000000nn_recv(3) ========== NAME ---- nn_recv - receive a message SYNOPSIS -------- *#include * *int nn_recv (int 's', void '*buf', size_t 'len', int 'flags');* DESCRIPTION ----------- Receive a message from the socket 's' and store it in the buffer referenced by the 'buf' argument. Any bytes exceeding the length specified by the 'len' argument will be truncated. Alternatively, _nanomsg_ can allocate the buffer for you. To do so, let the 'buf' parameter be a pointer to a void* variable (pointer to pointer) to the receive buffer and set the 'len' parameter to _NN_MSG_. If the call is successful the user is responsible for deallocating the message using the <> function. The 'flags' argument is a combination of the flags defined below: *NN_DONTWAIT*:: Specifies that the operation should be performed in non-blocking mode. If the message cannot be received straight away, the function will fail with 'errno' set to EAGAIN. RETURN VALUE ------------ If the function succeeds number of bytes in the message is returned. Otherwise, -1 is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EBADF*:: The provided socket is invalid. *ENOTSUP*:: The operation is not supported by this socket type. *EFSM*:: The operation cannot be performed on this socket at the moment because socket is not in the appropriate state. This error may occur with socket types that switch between several states. *EAGAIN*:: Non-blocking mode was requested and there's no message to receive at the moment. *EINTR*:: The operation was interrupted by delivery of a signal before the message was received. *ETIMEDOUT*:: Individual socket types may define their own specific timeouts. If such timeout is hit this error will be returned. *ETERM*:: The library is terminating. EXAMPLES -------- Receiving a message into a buffer allocated by the user:: This example code will retrieve a message of either 100 bytes or less. If a larger message was sent it will be truncated to 100 bytes. ---- char buf [100]; nbytes = nn_recv (s, buf, sizeof (buf), 0); ---- Receiving a message into a buffer allocated by _nanomsg_:: The following will get a message from the pipe with a buffer allocated by the system. It is large enough to accommodate the entire message. This is a good way to get the entire message without truncating if the size of the message is unknown. It is the user's responsibility to call <> after processing the message. ---- void *buf = NULL; nbytes = nn_recv (s, &buf, NN_MSG, 0); if (nbytes < 0) { /* handle error */ ... } else { /* process message */ ... nn_freemsg (buf); } ---- Note that this can be more efficient than manually allocating a buffer since it is a zero-copy operation. SEE ALSO -------- <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_recvmsg.adoc000066400000000000000000000063021336111550300167150ustar00rootroot00000000000000nn_recvmsg(3) ============= NAME ---- nn_recvmsg - fine-grained alternative to nn_recv SYNOPSIS -------- *#include * *NN_EXPORT int nn_recvmsg (int 's', struct nn_msghdr '*msghdr', int 'flags');* DESCRIPTION ----------- Receives a message from socket 's' into buffers specified by 'msghdr' parameter along with any additional control data. 'msghdr' parameter should be nullified before being used. Structure 'nn_msghdr' contains at least following members: struct nn_iovec *msg_iov; int msg_iovlen; void *msg_control; size_t msg_controllen; 'msg_iov' points to a gather array of buffers to fill in. 'msg_iovlen' specifies the size of the array. 'msg_control' points to the buffer to hold control information associated with the received message. 'msg_controllen' specifies the length of the buffer. If the control information should not be retrieved, set 'msg_control' parameter to NULL. For detailed discussion of how to parse the control information check <> man page. Structure 'nn_iovec' defines one element in the gather array (a buffer to be filled in by message data) and contains following members: void *iov_base; size_t iov_len; Alternatively, _nanomsg_ library can allocate the buffer for you. To do so, let the 'iov_base' point to void* variable to receive the buffer and set 'iov_len' to _NN_MSG_. After successful completion user is responsible for deallocating the message using <> function. Gather array in _nn_msghdr_ structure can contain only one element in this case. The 'flags' argument is a combination of the flags defined below: *NN_DONTWAIT*:: Specifies that the operation should be performed in non-blocking mode. If the message cannot be received straight away, the function will fail with 'errno' set to EAGAIN. RETURN VALUE ------------ If the function succeeds number of bytes in the message is returned. Otherwise, -1 is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EBADF*:: The provided socket is invalid. *ENOTSUP*:: The operation is not supported by this socket type. *EFSM*:: The operation cannot be performed on this socket at the moment because socket is not in the appropriate state. This error may occur with socket types that switch between several states. *EAGAIN*:: Non-blocking mode was requested and there's no message to receive at the moment. *EINTR*:: The operation was interrupted by delivery of a signal before the message was received. *ETIMEDOUT*:: Individual socket types may define their own specific timeouts. If such timeout is hit this error will be returned. *ETERM*:: The library is terminating. EXAMPLE ------- ---- struct nn_msghdr hdr; struct nn_iovec iov [2]; char buf0 [4]; char buf1 [2]; iov [0].iov_base = buf0; iov [0].iov_len = sizeof (buf0); iov [1].iov_base = buf1; iov [1].iov_len = sizeof (buf1); memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = iov; hdr.msg_iovlen = 2; nn_recvmsg (s, &hdr, 0); ---- SEE ALSO -------- <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_reqrep.adoc000066400000000000000000000035651336111550300165550ustar00rootroot00000000000000nn_reqrep(7) ============ NAME ---- nn_reqrep - request/reply scalability protocol SYNOPSIS -------- *#include * *#include * DESCRIPTION ----------- This protocol is used to distribute the workload among multiple stateless workers. Please note that request/reply applications should be stateless. It's important to include all the information necessary to process the request in the request itself, including information about the sender or the originator of the request if this is necessary to respond to the request. Sender information cannot be retrieved from the underlying socket connection since, firstly, transports like IPC may not have a firm notion of a message origin. Secondly, transports that have some notion may not have a reliable one -- a TCP disconnect may mean a new sender, or it may mean a temporary loss in network connectivity. For this reason, sender information must be included by the application if required. Allocating 6 randomly-generated bytes in the message for the lifetime of the connection is sufficient for most purposes. For longer-lived applications, an UUID is more suitable. Socket Types ~~~~~~~~~~~~ NN_REQ:: Used to implement the client application that sends requests and receives replies. NN_REP:: Used to implement the stateless worker that receives requests and sends replies. Socket Options ~~~~~~~~~~~~~~ NN_REQ_RESEND_IVL:: This option is defined on the full REQ socket. If reply is not received in specified amount of milliseconds, the request will be automatically resent. The type of this option is int. Default value is 60000 (1 minute). SEE ALSO -------- <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_send.adoc000066400000000000000000000046231336111550300162040ustar00rootroot00000000000000nn_send(3) ========== NAME ---- nn_send - send a message SYNOPSIS -------- *#include * *int nn_send (int 's', const void '*buf', size_t 'len', int 'flags');* DESCRIPTION ----------- The function will send a message containing the data from buffer pointed to by 'buf' parameter to the socket 's'. The message will be 'len' bytes long. Alternatively, to send a buffer allocated by <> function set the buf parameter to point to the pointer to the buffer and 'len' parameter to _NN_MSG_ constant. In this case a successful call to _nn_send_ will deallocate the buffer. Trying to deallocate it afterwards will result in undefined behaviour. Which of the peers the message will be sent to is determined by the particular socket type. The 'flags' argument is a combination of the flags defined below: *NN_DONTWAIT*:: Specifies that the operation should be performed in non-blocking mode. If the message cannot be sent straight away, the function will fail with 'errno' set to EAGAIN. RETURN VALUE ------------ If the function succeeds, the number of bytes in the message is returned. Otherwise, -1 is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EFAULT*:: 'buf' is NULL or 'len' is NN_MSG and the message pointer (pointed to by 'buf') is NULL. *EBADF*:: The provided socket is invalid. *ENOTSUP*:: The operation is not supported by this socket type. *EFSM*:: The operation cannot be performed on this socket at the moment because the socket is not in the appropriate state. This error may occur with socket types that switch between several states. *EAGAIN*:: Non-blocking mode was requested and the message cannot be sent at the moment. *EINTR*:: The operation was interrupted by delivery of a signal before the message was sent. *ETIMEDOUT*:: Individual socket types may define their own specific timeouts. If such timeout is hit, this error will be returned. *ETERM*:: The library is terminating. EXAMPLE ------- Using data directly: ---- nbytes = nn_send (s, "ABC", 3, 0); assert (nbytes == 3); ---- Using a pre-allocated message buffer: ---- void *msg = nn_allocmsg(3, 0); strncpy(msg, "ABC", 3); nbytes = nn_send (s, &msg, NN_MSG, 0); assert (nbytes == 3); ---- SEE ALSO -------- <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_sendmsg.adoc000066400000000000000000000100641336111550300167070ustar00rootroot00000000000000nn_sendmsg(3) ============= NAME ---- nn_sendmsg - fine-grained alternative to nn_send SYNOPSIS -------- *#include * *int nn_sendmsg (int 's', const struct nn_msghdr '*msghdr', int 'flags');* DESCRIPTION ----------- Sends data specified by 'msghdr' parameter to socket 's' along with any additional control data. 'msghdr' structure should be nullified before being used. Structure 'nn_msghdr' contains at least following members: struct nn_iovec *msg_iov; int msg_iovlen; void *msg_control; size_t msg_controllen; 'msg_iov' points to a scatter array of buffers to send. 'msg_iovlen' specifies the size of the array. 'msg_control' points to the buffer containing control information to be associated with the message being sent. 'msg_controllen' specifies the length of the buffer. If there's no control information to send, 'msg_control' should be set to NULL. For detailed discussion of how to set control data check <> man page. Structure 'nn_iovec' defines one element in the scatter array (i.e. a buffer to send to the socket) and contains following members: void *iov_base; size_t iov_len; Alternatively, to send a buffer allocated by <> function set 'iov_base' to point to the pointer to the buffer and 'iov_len' to _NN_MSG_ constant. In this case a successful call to _nn_sendmsg_ will deallocate the buffer. Trying to deallocate it afterwards will result in undefined behaviour. Also, scatter array in _nn_msghdr_ structure can contain only one element in this case. To which of the peers will the message be sent to is determined by the particular socket type. The 'flags' argument is a combination of the flags defined below: *NN_DONTWAIT*:: Specifies that the operation should be performed in non-blocking mode. If the message cannot be sent straight away, the function will fail with 'errno' set to EAGAIN. RETURN VALUE ------------ If the function succeeds number of bytes in the message is returned. Otherwise, -1 is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EINVAL*:: Either 'msghdr' is NULL, there are multiple scatter buffers but length is set to 'NN_MSG' for one of them, or the sum of 'iov_len' values for the scatter buffers overflows 'size_t'. These are early checks and no pre-allocated message is freed in this case. *EMSGSIZE*:: msghdr->msg_iovlen is negative. This is an early check and no pre-allocated message is freed in this case. *EFAULT*:: The supplied pointer for the pre-allocated message buffer or the scatter buffer is NULL, or the length for the scatter buffer is 0. *EBADF*:: The provided socket is invalid. *ENOTSUP*:: The operation is not supported by this socket type. *EFSM*:: The operation cannot be performed on this socket at the moment because socket is not in the appropriate state. This error may occur with socket types that switch between several states. *EAGAIN*:: Non-blocking mode was requested and the message cannot be sent at the moment. *EINTR*:: The operation was interrupted by delivery of a signal before the message was sent. *ETIMEDOUT*:: Individual socket types may define their own specific timeouts. If such timeout is hit this error will be returned. *ETERM*:: The library is terminating. EXAMPLE ------- Usage of multiple scatter buffers: ---- struct nn_msghdr hdr; struct nn_iovec iov [2]; iov [0].iov_base = "Hello"; iov [0].iov_len = 5; iov [1].iov_base = "World"; iov [1].iov_len = 5; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = iov; hdr.msg_iovlen = 2; nn_sendmsg (s, &hdr, 0); ---- Usage of a single message: ---- void *msg; struct nn_msghdr hdr; struct nn_iovec iov; msg = nn_allocmsg(12, 0); strcpy(msg, "Hello World"); iov.iov_base = &msg; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; nn_sendmsg (s, &hdr, 0); ---- SEE ALSO -------- <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_setsockopt.adoc000066400000000000000000000131451336111550300174500ustar00rootroot00000000000000nn_setsockopt(3) ================ NAME ---- nn_setsockopt - set a socket option SYNOPSIS -------- *#include * *int nn_setsockopt (int 's', int 'level', int 'option', const void '*optval', size_t 'optvallen');* DESCRIPTION ----------- Sets the value of the 'option'. The 'level' argument specifies the protocol level at which the option resides. For generic socket-level options use _NN_SOL_SOCKET_ level. For socket-type-specific options use socket type for 'level' argument (e.g. _NN_SUB_). For transport-specific options use ID of the transport as the 'level' argument (e.g. _NN_TCP_). The new value is pointed to by 'optval' argument. Size of the option is specified by the 'optvallen' argument. __ header defines generic socket-level options (_NN_SOL_SOCKET_ level). The options are as follows: *NN_SNDBUF*:: Size of the send buffer, in bytes. To prevent blocking for messages larger than the buffer, exactly one message may be buffered in addition to the data in the send buffer. The type of this option is int. Default value is 128kB. *NN_RCVBUF*:: Size of the receive buffer, in bytes. To prevent blocking for messages larger than the buffer, exactly one message may be buffered in addition to the data in the receive buffer. The type of this option is int. Default value is 128kB. *NN_RCVMAXSIZE*:: Maximum message size that can be received, in bytes. Negative value means that the received size is limited only by available addressable memory. The type of this option is int. Default is 1024kB. *NN_SNDTIMEO*:: The timeout for send operation on the socket, in milliseconds. If message cannot be sent within the specified timeout, ETIMEDOUT error is returned. Negative value means infinite timeout. The type of the option is int. Default value is -1. *NN_RCVTIMEO*:: The timeout for recv operation on the socket, in milliseconds. If message cannot be received within the specified timeout, ETIMEDOUT error is returned. Negative value means infinite timeout. The type of the option is int. Default value is -1. *NN_RECONNECT_IVL*:: For connection-based transports such as TCP, this option specifies how long to wait, in milliseconds, when connection is broken before trying to re-establish it. Note that actual reconnect interval may be randomised to some extent to prevent severe reconnection storms. The type of the option is int. Default value is 100 (0.1 second). *NN_RECONNECT_IVL_MAX*:: This option is to be used only in addition to _NN_RECONNECT_IVL_ option. It specifies maximum reconnection interval. On each reconnect attempt, the previous interval is doubled until _NN_RECONNECT_IVL_MAX_ is reached. Value of zero means that no exponential backoff is performed and reconnect interval is based only on _NN_RECONNECT_IVL_. If _NN_RECONNECT_IVL_MAX_ is less than _NN_RECONNECT_IVL_, it is ignored. The type of the option is int. Default value is 0. *NN_SNDPRIO*:: Sets outbound priority for endpoints subsequently added to the socket. This option has no effect on socket types that send messages to all the peers. However, if the socket type sends each message to a single peer (or a limited set of peers), peers with high priority take precedence over peers with low priority. The type of the option is int. Highest priority is 1, lowest priority is 16. Default value is 8. *NN_RCVPRIO*:: Sets inbound priority for endpoints subsequently added to the socket. This option has no effect on socket types that are not able to receive messages. When receiving a message, messages from peer with higher priority are received before messages from peer with lower priority. The type of the option is int. Highest priority is 1, lowest priority is 16. Default value is 8. *NN_IPV4ONLY*:: If set to 1, only IPv4 addresses are used. If set to 0, both IPv4 and IPv6 addresses are used. The type of the option is int. Default value is 1. *NN_SOCKET_NAME*:: Socket name for error reporting and statistics. The type of the option is string. Default value is "socket.N" where N is socket integer. *This option is experimental, see <> for details* *NN_MAXTTL*:: Sets the maximum number of "hops" a message can go through before it is dropped. Each time the message is received (for example via the <> function) counts as a single hop. This provides a form of protection against inadvertent loops. *NN_LINGER*:: This option is not implemented, and should not be used in new code. Applications which need to be sure that their messages are delivered to a remote peer should either use an acknowledgement (implied when receiving a reply on <> sockets), or insert a suitable delay before calling <> or exiting the application. RETURN VALUE ------------ If the function succeeds zero is returned. Otherwise, -1 is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EBADF*:: The provided socket is invalid. *ENOPROTOOPT*:: The option is unknown at the level indicated. *EINVAL*:: The specified option value is invalid. *ETERM*:: The library is terminating. EXAMPLE ------- ---- int linger = 1000; nn_setsockopt (s, NN_SOL_SOCKET, NN_LINGER, &linger, sizeof (linger)); nn_setsockopt (s, NN_SUB, NN_SUB_SUBSCRIBE, "ABC", 3); ---- SEE ALSO -------- <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] link:mailto:garrett@damore.org[Garrett D'Amore] nanomsg-1.1.5/doc/nn_shutdown.adoc000066400000000000000000000025141336111550300171230ustar00rootroot00000000000000nn_shutdown(3) ============== NAME ---- nn_shutdown - remove an endpoint from a socket SYNOPSIS -------- *#include * *int nn_shutdown (int 's', int 'how');* DESCRIPTION ----------- Removes an endpoint from socket 's'. 'how' parameter specifies the ID of the endpoint to remove as returned by prior call to <> or <>. _nn_shutdown()_ call will return immediately, however, the library will try to deliver any outstanding outbound messages to the endpoint for the time specified by _NN_LINGER_ socket option. RETURN VALUE ------------ If the function succeeds zero is returned. Otherwise, -1 is returned and 'errno' is set to to one of the values defined below. ERRORS ------ *EBADF*:: The provided socket is invalid. *EINVAL*:: The 'how' parameter doesn't correspond to an active endpoint. *EINTR*:: Operation was interrupted by a signal. The endpoint is not fully closed yet. Operation can be re-started by calling _nn_shutdown()_ again. *ETERM*:: The library is terminating. EXAMPLE ------- ---- s = nn_socket (AF_SP, NN_PUB); eid = nn_bind (s, "inproc://test"); nn_shutdown (s, eid); ---- SEE ALSO -------- <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_socket.adoc000066400000000000000000000044201336111550300165360ustar00rootroot00000000000000nn_socket(3) ============ NAME ---- nn_socket - create an SP socket SYNOPSIS -------- *#include * *int nn_socket (int 'domain', int 'protocol');* DESCRIPTION ----------- Creates an SP socket with specified 'domain' and 'protocol'. Returns a file descriptor for the newly created socket. Following domains are defined at the moment: *AF_SP*:: Standard full-blown SP socket. *AF_SP_RAW*:: Raw SP socket. Raw sockets omit the end-to-end functionality found in AF_SP sockets and thus can be used to implement intermediary devices in SP topologies. 'protocol' parameter defines the type of the socket, which in turn determines the exact semantics of the socket. Check manual pages for individual SP protocols to get the list of available socket types. The newly created socket is initially not associated with any endpoints. In order to establish a message flow at least one endpoint has to be added to the socket using <> or <> function. Also note that 'type' argument as found in standard _socket(2)_ function is omitted from _nn_socket_. All the SP sockets are message-based and thus of _SOCK_SEQPACKET_ type. RETURN VALUE ------------ If the function succeeds file descriptor of the new socket is returned. Otherwise, -1 is returned and 'errno' is set to to one of the values defined below. Note that file descriptors returned by _nn_socket_ function are not standard file descriptors and will exhibit undefined behaviour when used with system functions. Moreover, it may happen that a system file descriptor and file descriptor of an SP socket will incidentally collide (be equal). ERRORS ------ *EAFNOSUPPORT*:: Specified address family is not supported. *EINVAL*:: Unknown protocol. *EMFILE*:: The limit on the total number of open SP sockets or OS limit for file descriptors has been reached. *ETERM*:: The library is terminating. EXAMPLE ------- ---- int s = nn_socket (AF_SP, NN_PUB); assert (s >= 0); ---- SEE ALSO -------- <> <> <> <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_strerror.adoc000066400000000000000000000014171336111550300171330ustar00rootroot00000000000000nn_strerror(3) ============== NAME ---- nn_strerror - convert an error number into human-readable string SYNOPSIS -------- *#include * *const char *nn_strerror (int 'errnum');* DESCRIPTION ----------- Converts error number (errno) into a human-readable string. As opposed to 'strerror(3)' this function handles nanomsg-specific errors in addition to standard system errors. RETURN VALUE ------------ Return error message string. ERRORS ------ No errors are defined. EXAMPLE ------- ---- rc = nn_send (s, "ABC", 3, 0); if (rc < 0) printf ("nn_send failed: %s\n", nn_strerror (errno)); ---- SEE ALSO -------- <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_survey.adoc000066400000000000000000000024741336111550300166120ustar00rootroot00000000000000nn_survey(7) ============ NAME ---- nn_survey - survey scalability protocol SYNOPSIS -------- *#include * *#include * DESCRIPTION ----------- Allows to broadcast a survey to multiple locations and gather the responses. Socket Types ~~~~~~~~~~~~ NN_SURVEYOR:: Used to send the survey. The survey is delivered to all the connected respondents. Once the query is sent, the socket can be used to receive the responses. When the survey deadline expires, receive will return ETIMEDOUT error. NN_RESPONDENT:: Use to respond to the survey. Survey is received using receive function, response is sent using send function. This socket can be connected to at most one peer. Socket Options ~~~~~~~~~~~~~~ NN_SURVEYOR_DEADLINE:: Specifies how long to wait for responses to the survey. Once the deadline expires, receive function will return ETIMEDOUT error and all subsequent responses to the survey will be silently dropped. The deadline is measured in milliseconds. Option type is int. Default value is 1000 (1 second). SEE ALSO -------- <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_symbol.adoc000066400000000000000000000035721336111550300165620ustar00rootroot00000000000000nn_symbol(3) ============ NAME ---- nn_symbol - query the names and values of nanomsg symbols SYNOPSIS -------- *#include * *const char *nn_symbol (int 'i', int '*value');* DESCRIPTION ----------- Retrieves the symbol name and value at index 'i'. Indices start at 0. An index has no significance to its associated symbol; the mappings may change between library versions. Typically a client will iterate through the symbols until nn_symbol returns NULL in order to collect all the symbols. All symbols exposed by 'nn_symbol' are available directly in the C API, generally as preprocessor macros. Thus, this function is useful mostly for language bindings that can't parse the header file and rely on retrieving the symbols in the runtime. Note that the NN_MSG symbol is not exported by the _nn_symbol_ function. First, it is a pointer rather than an integer; second, the symbol is not supposed to be exported from language bindings to the user. Instead, language bindings should provide the zero-copy functionality in a language-specific way, if at all (zero-copy functionality may not make sense for some languages/bindings). RETURN VALUE ------------ If 'i' is valid, returns the name of the symbol at that index. If the pointer 'value' is not NULL, the symbol's value is stored there. If 'i' is out-of-range, nn_symbol returns NULL and sets 'errno' to EINVAL. ERRORS ------ *EINVAL*:: The passed index 'i' was out-of-range; it was less than zero or greater-than-or- equal-to the number of symbols. EXAMPLE ------- ---- int value, i; for (i = 0; ; ++i) { const char* name = nn_symbol (i, &value); if (name == NULL) break; printf ("'%s' = %d\n", name, value); } ---- SEE ALSO -------- <> <> <> <> AUTHORS ------- link:mailto:evan@neomantra.net[Evan Wies] nanomsg-1.1.5/doc/nn_symbol_info.adoc000066400000000000000000000104371336111550300175730ustar00rootroot00000000000000nn_symbol_info(3) ================= NAME ---- nn_symbol_info - query the names and properties of nanomsg symbols SYNOPSIS -------- *#include * *int nn_symbol_info (int 'i', struct nn_symbol_properties '*buf', int 'buflen');* DESCRIPTION ----------- Retrieves the symbol name and value at index 'i'. Indices start at 0. An index has no significance to its associated symbol; the mappings may change between library versions. The nn_symbol_properties has the following definition: ---- struct nn_symbol_properties { /* The constant value */ int value; /* The constant name */ const char* name; /* The constant namespace, or zero for namespaces themselves */ int ns; /* The option type for socket option constants */ int type; /* The unit for the option value for socket option constants */ int unit; }; ---- More structure members may be added in future, but the input pointer will be written only up to 'buflen' so the ABI is forward-compatible. Typically a client will iterate through the symbols until nn_symbol_info returns NULL in order to collect all the symbols. All symbols exposed by 'nn_symbol_info' are available directly in the C API, generally as preprocessor macros. Thus, this function is useful mostly for language bindings that can't parse the header file and rely on retrieving the symbols at runtime. Note that the NN_MSG symbol is not exported by the 'nn_symbol_info' function. First, it is a pointer rather than an integer; second, the symbol is not supposed to be exported from language bindings to the user. Instead, language bindings should provide the zero-copy functionality in a language-specific way, if at all (zero-copy functionality may not make sense for some languages/bindings). AVAILABLE NAMESPACES -------------------- *NN_NS_NAMESPACE*:: Equals to zero and denotes the NN_NS_* constants themselves *NN_NS_VERSION*:: Nanomsg version constants *NN_NS_DOMAIN*:: Socket domain (or address family) constants AF_SP, AF_SP_RAW *NN_NS_TRANSPORT*:: Transport name constants (used for socket options mainly) *NN_NS_PROTOCOL*:: Socket protocol constants *NN_NS_OPTION_LEVEL*:: Socket option level constants (NN_SOL_SOCKET) *NN_NS_SOCKET_OPTION*:: Socket options for NN_SOL_SOCKET level *NN_NS_TRANSPORT_OPTION*:: Socket options for transport level (used with transport constants) *NN_NS_OPTION_TYPE*:: The option types (described below) *NN_NS_FLAG*:: The nn_send/nn_recv flags (only NN_DONTWAIT for now) *NN_NS_ERROR*:: The errno values *NN_NS_LIMIT*:: Various nanomsg limits (only NN_SOCKADDR_MAX for now) *NN_NS_EVENT*:: Event flags (bit mask) for use with nn_poll (NN_POLLIN, NN_POLLOUT) AVAILABLE OPTION TYPES ---------------------- *NN_TYPE_NONE*:: No type, is returned for constants that are not socket options *NN_TYPE_INT*:: The integer type *NN_TYPE_STR*:: String (char *) type More types may be added in the future to nanomsg. You may enumerate all of them using the 'nn_symbol_info' itself by checking 'NN_NS_OPTION_TYPE' namespace. AVAILABLE OPTION UNITS ---------------------- *NN_UNIT_NONE*:: No unit, is returned for constants that are not socket options, or do not have any meaningful unit (strings, integer values) *NN_UNIT_BYTES*:: The option value is expressed in bytes *NN_UNIT_MILLISECONDS*:: The option value is expressed in milliseconds *NN_UNIT_PRIORITY*:: The option value is a priority, an integer from 1 to 16 *NN_UNIT_BOOLEAN*:: The option value is boolean, an integer 0 or 1 More types may be added in the future to nanomsg. You may enumerate all of them using the 'nn_symbol_info' itself by checking 'NN_NS_OPTION_TYPE' namespace. RETURN VALUE ------------ If 'i' is valid, returns the number of bytes stored at the structure. The maximum value that can be returned is 'buflen'. If 'i' is out-of-range, nn_symbol_info returns zero. EXAMPLE ------- ---- int i; for (i = 0; ; ++i) { struct nn_symbol_properties sym; int rc = nn_symbol_info (i, &sym, sizeof (sym)); if(rc == 0) break; assert (rc == sizeof (sym)); printf ("'%s' = %d\n", sym.name, sym.value); } ---- SEE ALSO -------- <> <> <> <> AUTHORS ------- link:mailto:paul@colomiets.name[Paul Colomiets] link:mailto:garrett@damore.org[Garrett D'Amore] nanomsg-1.1.5/doc/nn_tcp.adoc000066400000000000000000000043021336111550300160330ustar00rootroot00000000000000nn_tcp(7) ========= NAME ---- nn_tcp - TCP transport mechanism SYNOPSIS -------- *#include * *#include * DESCRIPTION ----------- TCP transport allows for passing messages over the network using simple reliable one-to-one connections. TCP is the most widely used transport protocol, it is virtually ubiquitous and thus the transport of choice for communication over the network. When binding a TCP socket address of the form tcp://interface:port should be used. Port is the TCP port number to use. Interface is one of the following (optionally placed within square brackets): * Asterisk character (*) meaning all local network interfaces. * IPv4 address of a local network interface in numeric form (192.168.0.111). * IPv6 address of a local network interface in numeric form (::1). When connecting a TCP socket address of the form tcp://interface;address:port should be used. Port is the TCP port number to use. Interface is optional and specifies which local network interface to use. If not specified, OS will select an appropriate interface itself. If specified it can be one of the following (optionally placed within square brackets): * IPv4 address of a local network interface in numeric form (192.168.0.111). * IPv6 address of a local network interface in numeric form (::1). Finally, address specifies the remote address to connect to. It can be one of the following (optionally placed within square brackets): * IPv4 address of a remote network interface in numeric form (192.168.0.111). * IPv6 address of a remote network interface in numeric form (::1). * The DNS name of the remote box. Socket Options ~~~~~~~~~~~~~~ NN_TCP_NODELAY:: This option, when set to 1, disables Nagle's algorithm. It also disables delaying of TCP acknowledgments. Using this option improves latency at the expense of throughput. Type of this option is int. Default value is 0. EXAMPLE ------- ---- nn_bind (s1, "tcp://*:5555"); nn_connect (s2, "tcp://myserver:5555"); ---- SEE ALSO -------- <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] nanomsg-1.1.5/doc/nn_term.adoc000066400000000000000000000023021336111550300162120ustar00rootroot00000000000000nn_term(3) ========== NAME ---- nn_term - notify all sockets about process termination SYNOPSIS -------- *#include * *void nn_term (void);* DESCRIPTION ----------- To help with shutdown of multi-threaded programs nanomsg provides the _nn_term()_ function which closes all open sockets, and releases all related resources. If a socket is blocked inside a blocking function, such as <>, it will be unblocked and EBADF error will be returned to the user. Subsequent calls on such sockets will also return EBADF. Attempting to open a new socket with <> will result in an ETERM error. If waiting for _NN_SNDFD_ or _NN_RCVFD_ using a polling function, such as _poll()_ or _select()_, the call will unblock with both _NN_SNDFD_ and _NN_RCVFD_ signaled. EXAMPLE ------- ---- s = nn_socket (AF_SP, NN_PAIR); nn_term (); rc = nn_send (s, "ABC", 3, 0); assert (rc == -1 && errno == EBADF); ---- SEE ALSO -------- <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] link:mailto:garrett@damore.org[Garrett D'Amore] nanomsg-1.1.5/doc/nn_ws.adoc000066400000000000000000000063511336111550300157040ustar00rootroot00000000000000nn_ws(7) ======== NAME ---- nn_ws - WebSocket transport mechanism SYNOPSIS -------- *#include * *#include * DESCRIPTION ----------- The WebSocket transport uses the framing protocol specified in RFC 6455 to transport messages. The initial handshake is done using HTTP headers, with the `Sec-Websocket-Protocol` header set to the SP protocol used by the server. For example, a REQ client will send `rep.sp.nanomsg.org`. Each SP message is transported in a single WebSocket frame, with no additional data or headers applied. By default this library sends and expects to receive binary frames. When calling either `nn_bind()` or `nn_connect()`, omitting the port defaults to the RFC 6455 default port 80 for HTTP. For example, `ws://127.0.0.1` is equivalent to `ws://127.0.0.1:80` WebSocket over TLS is not supported by this library, at this time. URI limitations ~~~~~~~~~~~~~~~ When calling `nn_connect()`, the URI may also optionally include the path to a resource and/or query parameters. .Path and query parameters ========================== s1 = nn_socket (AF_SP, NN_PAIR); nn_connect (s1, "ws://example.com/path?query=value"); ========================== This implementation includes the full path and any query parameters in the HTTP handshake when establishing connections with `nn_connect()`. This information is not available via the nanomsg API afterwards, however. Likewise, this implementation does not examine or use either any path or query parameters that may be supplied to `nn_bind()`, as it only binds to the TCP port. This implementation acts as a limited HTTP server that offers SP over WebSocket at all URIs for the given TCP address. Applications, however, should not depend on this behavior; intervening infrastructure may proxy, filter or route based on URI, and other implementations of the SP over WebSocket protocol may offer other HTTP services at the same TCP port, utilizing the path, query parameters, or both to determine the service to be used. Socket Options ~~~~~~~~~~~~~~ NN_WS_MSG_TYPE:: This option may be set to NN_WS_MSG_TYPE_TEXT or NN_WS_MSG_TYPE_BINARY. The value of this determines whether data messages are sent as WebSocket text frames, or binary frames, per RFC 6455. Text frames should contain only valid UTF-8 text in their payload, or they will be rejected. Binary frames may contain any data. Not all WebSocket implementations support binary frames. The default is to send binary frames. + This option may also be specified as control data when when sending a message with `nn_sendmsg()`. TODO: NN_TCP_NODELAY:: This option, when set to 1, disables Nagle's algorithm. It also disables delaying of TCP acknowledgments. Using this option improves latency at the expense of throughput. Type of this option is int. Default value is 0. EXAMPLE ------- ---- nn_bind (s1, "ws://*:5555"); nn_connect (s2, "ws://myserver:5555"); ---- SEE ALSO -------- <> <> <> <> <> <> AUTHORS ------- link:mailto:sustrik@250bpm.com[Martin Sustrik] link:mailto:jack@wirebirdlabs.com[Jack R. Dunaway] link:mailto:garrett@damore.org[Garrett D'Amore] nanomsg-1.1.5/doc/stylesheet.css000066400000000000000000001075151336111550300166370ustar00rootroot00000000000000/*! normalize.css v2.1.2 | MIT License | git.io/normalize */ /* ========================================================================== HTML5 display definitions ========================================================================== */ /** Correct `block` display not defined in IE 8/9. */ article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; } /** Correct `inline-block` display not defined in IE 8/9. */ audio, canvas, video { display: inline-block; } /** Prevent modern browsers from displaying `audio` without controls. Remove excess height in iOS 5 devices. */ audio:not([controls]) { display: none; height: 0; } /** Address `[hidden]` styling not present in IE 8/9. Hide the `template` element in IE, Safari, and Firefox < 22. */ [hidden], template { display: none; } script { display: none !important; } /* ========================================================================== Base ========================================================================== */ /** 1. Set default font family to sans-serif. 2. Prevent iOS text size adjust after orientation change, without disabling user zoom. */ html { font-family: sans-serif; /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ } /** Remove default margin. */ body { margin: 0; } /* ========================================================================== Links ========================================================================== */ /** Remove the gray background color from active links in IE 10. */ a { background: transparent; } /** Address `outline` inconsistency between Chrome and other browsers. */ a:focus { outline: thin dotted; } /** Improve readability when focused and also mouse hovered in all browsers. */ a:active, a:hover { outline: 0; } /* ========================================================================== Typography ========================================================================== */ /** Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari 5, and Chrome. */ h1 { font-size: 2em; margin: 0.67em 0; } /** Address styling not present in IE 8/9, Safari 5, and Chrome. */ abbr[title] { border-bottom: 1px dotted; } /** Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. */ b, strong { font-weight: bold; } /** Address styling not present in Safari 5 and Chrome. */ dfn { font-style: italic; } /** Address differences between Firefox and other browsers. */ hr { -moz-box-sizing: content-box; box-sizing: content-box; height: 0; } /** Address styling not present in IE 8/9. */ mark { background: #ff0; color: #000; } /** Correct font family set oddly in Safari 5 and Chrome. */ code, kbd, pre, samp { font-family: monospace, serif; font-size: 1em; } /** Improve readability of pre-formatted text in all browsers. */ pre { white-space: pre-wrap; } /** Set consistent quote types. */ q { quotes: "\201C" "\201D" "\2018" "\2019"; } /** Address inconsistent and variable font size in all browsers. */ small { font-size: 80%; } /** Prevent `sub` and `sup` affecting `line-height` in all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } /* ========================================================================== Embedded content ========================================================================== */ /** Remove border when inside `a` element in IE 8/9. */ img { border: 0; } /** Correct overflow displayed oddly in IE 9. */ svg:not(:root) { overflow: hidden; } /* ========================================================================== Figures ========================================================================== */ /** Address margin not present in IE 8/9 and Safari 5. */ figure { margin: 0; } /* ========================================================================== Forms ========================================================================== */ /** Define consistent border, margin, and padding. */ fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; } /** 1. Correct `color` not being inherited in IE 8/9. 2. Remove padding so people aren't caught out if they zero out fieldsets. */ legend { border: 0; /* 1 */ padding: 0; /* 2 */ } /** 1. Correct font family not being inherited in all browsers. 2. Correct font size not being inherited in all browsers. 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. */ button, input, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 2 */ margin: 0; /* 3 */ } /** Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet. */ button, input { line-height: normal; } /** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. Correct `select` style inheritance in Firefox 4+ and Opera. */ button, select { text-transform: none; } /** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. */ button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ } /** Re-set default cursor for disabled elements. */ button[disabled], html input[disabled] { cursor: default; } /** 1. Address box sizing set to `content-box` in IE 8/9. 2. Remove excess padding in IE 8/9. */ input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof). */ input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; } /** Remove inner padding and search cancel button in Safari 5 and Chrome on OS X. */ input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** Remove inner padding and border in Firefox 4+. */ button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; } /** 1. Remove default vertical scrollbar in IE 8/9. 2. Improve readability and alignment in all browsers. */ textarea { overflow: auto; /* 1 */ vertical-align: top; /* 2 */ } /* ========================================================================== Tables ========================================================================== */ /** Remove most spacing between table cells. */ table { border-collapse: collapse; border-spacing: 0; } meta.foundation-mq-small { font-family: "only screen and (min-width: 768px)"; width: 768px; } meta.foundation-mq-medium { font-family: "only screen and (min-width:1280px)"; width: 1280px; } meta.foundation-mq-large { font-family: "only screen and (min-width:1440px)"; width: 1440px; } *, *:before, *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; } html, body { font-size: 100%; } body { background: #fff; color: #222; padding: 0; margin: 0; font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; font-weight: normal; font-style: normal; line-height: 1; position: relative; cursor: auto; } a:hover { cursor: pointer; } img, object, embed { max-width: 100%; height: auto; } object, embed { height: 100%; } img { -ms-interpolation-mode: bicubic; } #map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object { max-width: none !important; } .left { float: left !important; } .right { float: right !important; } .text-left { text-align: left !important; } .text-right { text-align: right !important; } .text-center { text-align: center !important; } .text-justify { text-align: justify !important; } .hide { display: none; } .antialiased, body { -webkit-font-smoothing: antialiased; } img { display: inline-block; vertical-align: middle; } textarea { height: auto; min-height: 50px; } select { width: 100%; } object, svg { display: inline-block; vertical-align: middle; } .center { margin-left: auto; margin-right: auto; } .spread { width: 100%; } p.lead, .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { font-size: 1.21875em; line-height: 1.6; } .subheader, .admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { line-height: 1.4; color: #003b6b; font-weight: 300; margin-top: 0.2em; margin-bottom: 0.5em; } /* Typography resets */ div, dl, dt, dd, ul, ol, li, h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6, pre, form, p, blockquote, th, td { margin: 0; padding: 0; direction: ltr; } /* Default Link Styles */ a { color: #00579e; text-decoration: none; line-height: inherit; } a:hover, a:focus { color: #333; } a img { border: none; } /* Default paragraph styles */ p { font-family: Arial, sans-serif; font-weight: normal; font-size: 1em; line-height: 1.6; margin-bottom: 0.75em; text-rendering: optimizeLegibility; } p aside { font-size: 0.875em; line-height: 1.35; font-style: italic; } /* Default header styles */ h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { font-family: Arial, sans-serif; font-weight: normal; font-style: normal; color: #7B2D00; text-rendering: optimizeLegibility; margin-top: 0.5em; margin-bottom: 0.5em; line-height: 1.2125em; } h1 small, h2 small, h3 small, #toctitle small, .sidebarblock > .content > .title small, h4 small, h5 small, h6 small { font-size: 60%; color: #ff6b15; line-height: 0; } h1 { font-size: 2.125em; } h2 { font-size: 1.6875em; } h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.375em; } h4 { font-size: 1.125em; } h5 { font-size: 1.125em; } h6 { font-size: 1em; } hr { border: solid #ddd; border-width: 1px 0 0; clear: both; margin: 1.25em 0 1.1875em; height: 0; } /* Helpful Typography Defaults */ em, i { font-style: italic; line-height: inherit; } strong, b { font-weight: bold; line-height: inherit; } small { font-size: 60%; line-height: inherit; } code { font-family: Consolas, "Liberation Mono", Courier, monospace; font-weight: bold; color: #003426; } /* Lists */ ul, ol, dl { font-size: 1em; line-height: 1.6; margin-bottom: 0.75em; list-style-position: outside; font-family: Arial, sans-serif; } ul, ol { margin-left: 1.5em; } ul.no-bullet, ol.no-bullet { margin-left: 1.5em; } /* Unordered Lists */ ul li ul, ul li ol { margin-left: 1.25em; margin-bottom: 0; font-size: 1em; /* Override nested font-size change */ } ul.square li ul, ul.circle li ul, ul.disc li ul { list-style: inherit; } ul.square { list-style-type: square; } ul.circle { list-style-type: circle; } ul.disc { list-style-type: disc; } ul.no-bullet { list-style: none; } /* Ordered Lists */ ol li ul, ol li ol { margin-left: 1.25em; margin-bottom: 0; } /* Definition Lists */ dl dt { margin-bottom: 0.3em; font-weight: bold; } dl dd { margin-bottom: 0.75em; } /* Abbreviations */ abbr, acronym { text-transform: uppercase; font-size: 90%; color: black; border-bottom: 1px dotted #ddd; cursor: help; } abbr { text-transform: none; } /* Blockquotes */ blockquote { margin: 0 0 0.75em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #ddd; } blockquote cite { display: block; font-size: 0.8125em; color: #e15200; } blockquote cite:before { content: "\2014 \0020"; } blockquote cite a, blockquote cite a:visited { color: #e15200; } blockquote, blockquote p { line-height: 1.6; color: #333; } /* Microformats */ .vcard { display: inline-block; margin: 0 0 1.25em 0; border: 1px solid #ddd; padding: 0.625em 0.75em; } .vcard li { margin: 0; display: block; } .vcard .fn { font-weight: bold; font-size: 0.9375em; } .vevent .summary { font-weight: bold; } .vevent abbr { cursor: auto; text-decoration: none; font-weight: bold; border: none; padding: 0 0.0625em; } @media only screen and (min-width: 768px) { h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.4; } h1 { font-size: 2.75em; } h2 { font-size: 2.3125em; } h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.6875em; } h4 { font-size: 1.4375em; } } /* Tables */ table { background: #fff; margin-bottom: 1.25em; border: solid 1px #d8d8ce; } table thead, table tfoot { background: -webkit-linear-gradient(top, #add386, #90b66a); font-weight: bold; } table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td { padding: 0.5em 0.625em 0.625em; font-size: inherit; color: #fff; text-align: left; } table tr th, table tr td { padding: 0.5625em 0.625em; font-size: inherit; color: #6d6e71; } table tr.even, table tr.alt, table tr:nth-of-type(even) { background: #edf2f2; } table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td { display: table-cell; line-height: 1.4; } body { tab-size: 4; } h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.4; } a:hover, a:focus { text-decoration: underline; } .clearfix:before, .clearfix:after, .float-group:before, .float-group:after { content: " "; display: table; } .clearfix:after, .float-group:after { clear: both; } *:not(pre) > code { font-size: inherit; font-style: normal !important; letter-spacing: 0; padding: 3px 2px 1px 2px; background-color: #eee; border: 1px solid #ddd; -webkit-border-radius: 0; border-radius: 0; line-height: inherit; } pre, pre > code { line-height: 1.6; color: black; font-family: Consolas, "Liberation Mono", Courier, monospace; font-weight: normal; } .keyseq { color: #333333; } kbd { font-family: Consolas, "Liberation Mono", Courier, monospace; display: inline-block; color: black; font-size: 0.65em; line-height: 1.45; background-color: #f7f7f7; border: 1px solid #ccc; -webkit-border-radius: 3px; border-radius: 3px; -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; margin: 0 0.15em; padding: 0.2em 0.5em; vertical-align: middle; position: relative; top: -0.1em; white-space: nowrap; } .keyseq kbd:first-child { margin-left: 0; } .keyseq kbd:last-child { margin-right: 0; } .menuseq, .menu { color: black; } b.button:before, b.button:after { position: relative; top: -1px; font-weight: normal; } b.button:before { content: "["; padding: 0 3px 0 2px; } b.button:after { content: "]"; padding: 0 2px 0 3px; } #header, #content, #footnotes, #footer { width: 100%; margin-left: auto; margin-right: auto; margin-top: 0; margin-bottom: 0; max-width: 62.5em; *zoom: 1; position: relative; padding-left: 1.5em; padding-right: 1.5em; } #header:before, #header:after, #content:before, #content:after, #footnotes:before, #footnotes:after, #footer:before, #footer:after { content: " "; display: table; } #header:after, #content:after, #footnotes:after, #footer:after { clear: both; } #content { margin-top: 1.25em; } #content:before { content: none; } #header > h1:first-child { color: #7B2D00; margin-top: 2.25rem; margin-bottom: 0; } #header > h1:first-child + #toc { margin-top: 8px; border-top: 1px solid #ddd; } #header > h1:only-child, body.toc2 #header > h1:nth-last-child(2) { border-bottom: 1px solid #ddd; padding-bottom: 8px; } #header .details { border-bottom: 1px solid #ddd; line-height: 1.45; padding-top: 0.25em; padding-bottom: 0.25em; padding-left: 0.25em; color: #e15200; display: -ms-flexbox; display: -webkit-flex; display: flex; -ms-flex-flow: row wrap; -webkit-flex-flow: row wrap; flex-flow: row wrap; } #header .details span:first-child { margin-left: -0.125em; } #header .details span.email a { color: #333; } #header .details br { display: none; } #header .details br + span:before { content: "\00a0\2013\00a0"; } #header .details br + span.author:before { content: "\00a0\22c5\00a0"; color: #333; } #header .details br + span#revremark:before { content: "\00a0|\00a0"; } #header #revnumber { text-transform: capitalize; } #header #revnumber:after { content: "\00a0"; } #content > h1:first-child:not([class]) { color: #7B2D00; border-bottom: 1px solid #ddd; padding-bottom: 8px; margin-top: 0; padding-top: 1rem; margin-bottom: 1.25rem; } #toc { border-bottom: 0 solid #ddd; padding-bottom: 0.5em; } #toc > ul { margin-left: 0.125em; } #toc ul.sectlevel0 > li > a { font-style: italic; } #toc ul.sectlevel0 ul.sectlevel1 { margin: 0.5em 0; } #toc ul { font-family: Arial, sans-serif; list-style-type: none; } #toc li { line-height: 1.3334; margin-top: 0.3334em; } #toc a { text-decoration: none; } #toc a:active { text-decoration: underline; } #toctitle { color: #003b6b; font-size: 1.2em; } @media only screen and (min-width: 768px) { #toctitle { font-size: 1.375em; } body.toc2 { padding-left: 15em; padding-right: 0; } #toc.toc2 { margin-top: 0 !important; background-color: #fff; position: fixed; width: 15em; left: 0; top: 0; border-right: 1px solid #ddd; border-top-width: 0 !important; border-bottom-width: 0 !important; z-index: 1000; padding: 1.25em 1em; height: 100%; overflow: auto; } #toc.toc2 #toctitle { margin-top: 0; margin-bottom: 0.8rem; font-size: 1.2em; } #toc.toc2 > ul { font-size: 0.9em; margin-bottom: 0; } #toc.toc2 ul ul { margin-left: 0; padding-left: 1em; } #toc.toc2 ul.sectlevel0 ul.sectlevel1 { padding-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; } body.toc2.toc-right { padding-left: 0; padding-right: 15em; } body.toc2.toc-right #toc.toc2 { border-right-width: 0; border-left: 1px solid #ddd; left: auto; right: 0; } } @media only screen and (min-width: 1280px) { body.toc2 { padding-left: 20em; padding-right: 0; } #toc.toc2 { width: 20em; } #toc.toc2 #toctitle { font-size: 1.375em; } #toc.toc2 > ul { font-size: 0.95em; } #toc.toc2 ul ul { padding-left: 1.25em; } body.toc2.toc-right { padding-left: 0; padding-right: 20em; } } #content #toc { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: #fff; -webkit-border-radius: 0; border-radius: 0; } #content #toc > :first-child { margin-top: 0; } #content #toc > :last-child { margin-bottom: 0; } #footer { max-width: 100%; background-color: none; padding: 1.25em; } #footer-text { color: black; line-height: 1.44; } .sect1 { padding-bottom: 0.625em; } @media only screen and (min-width: 768px) { .sect1 { padding-bottom: 1.25em; } } .sect1 + .sect1 { border-top: 0 solid #ddd; } #content h1 > a.anchor, h2 > a.anchor, h3 > a.anchor, #toctitle > a.anchor, .sidebarblock > .content > .title > a.anchor, h4 > a.anchor, h5 > a.anchor, h6 > a.anchor { position: absolute; z-index: 1001; width: 1.5ex; margin-left: -1.5ex; display: block; text-decoration: none !important; visibility: hidden; text-align: center; font-weight: normal; } #content h1 > a.anchor:before, h2 > a.anchor:before, h3 > a.anchor:before, #toctitle > a.anchor:before, .sidebarblock > .content > .title > a.anchor:before, h4 > a.anchor:before, h5 > a.anchor:before, h6 > a.anchor:before { content: "\00A7"; font-size: 0.85em; display: block; padding-top: 0.1em; } #content h1:hover > a.anchor, #content h1 > a.anchor:hover, h2:hover > a.anchor, h2 > a.anchor:hover, h3:hover > a.anchor, #toctitle:hover > a.anchor, .sidebarblock > .content > .title:hover > a.anchor, h3 > a.anchor:hover, #toctitle > a.anchor:hover, .sidebarblock > .content > .title > a.anchor:hover, h4:hover > a.anchor, h4 > a.anchor:hover, h5:hover > a.anchor, h5 > a.anchor:hover, h6:hover > a.anchor, h6 > a.anchor:hover { visibility: visible; } #content h1 > a.link, h2 > a.link, h3 > a.link, #toctitle > a.link, .sidebarblock > .content > .title > a.link, h4 > a.link, h5 > a.link, h6 > a.link { color: #7B2D00; text-decoration: none; } #content h1 > a.link:hover, h2 > a.link:hover, h3 > a.link:hover, #toctitle > a.link:hover, .sidebarblock > .content > .title > a.link:hover, h4 > a.link:hover, h5 > a.link:hover, h6 > a.link:hover { color: #622400; } .audioblock, .imageblock, .literalblock, .listingblock, .stemblock, .videoblock { margin-bottom: 1.25em; } .admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { text-rendering: optimizeLegibility; text-align: left; } table.tableblock > caption.title { white-space: nowrap; overflow: visible; max-width: 0; } .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { color: #7B2D00; } table.tableblock #preamble > .sectionbody > .paragraph:first-of-type p { font-size: inherit; } .admonitionblock > table { border-collapse: separate; border: 0; background: none; width: 100%; } .admonitionblock > table td.icon { text-align: center; width: 80px; } .admonitionblock > table td.icon img { max-width: none; } .admonitionblock > table td.icon .title { font-weight: bold; font-family: Arial, sans-serif; text-transform: uppercase; } .admonitionblock > table td.content { padding-left: 1.125em; padding-right: 1.25em; border-left: 1px solid #ddd; color: #e15200; } .admonitionblock > table td.content > :last-child > :last-child { margin-bottom: 0; } .exampleblock > .content { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: #fff; -webkit-border-radius: 0; border-radius: 0; } .exampleblock > .content > :first-child { margin-top: 0; } .exampleblock > .content > :last-child { margin-bottom: 0; } .sidebarblock { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background: #fff; -webkit-border-radius: 0; border-radius: 0; } .sidebarblock > :first-child { margin-top: 0; } .sidebarblock > :last-child { margin-bottom: 0; } .sidebarblock > .content > .title { color: #003b6b; margin-top: 0; } .exampleblock > .content > :last-child > :last-child, .exampleblock > .content .olist > ol > li:last-child > :last-child, .exampleblock > .content .ulist > ul > li:last-child > :last-child, .exampleblock > .content .qlist > ol > li:last-child > :last-child, .sidebarblock > .content > :last-child > :last-child, .sidebarblock > .content .olist > ol > li:last-child > :last-child, .sidebarblock > .content .ulist > ul > li:last-child > :last-child, .sidebarblock > .content .qlist > ol > li:last-child > :last-child { margin-bottom: 0; } .literalblock pre, .listingblock pre:not(.highlight), .listingblock pre[class="highlight"], .listingblock pre[class^="highlight "], .listingblock pre.CodeRay, .listingblock pre.prettyprint { background: #eee; } .sidebarblock .literalblock pre, .sidebarblock .listingblock pre:not(.highlight), .sidebarblock .listingblock pre[class="highlight"], .sidebarblock .listingblock pre[class^="highlight "], .sidebarblock .listingblock pre.CodeRay, .sidebarblock .listingblock pre.prettyprint { background: #f2f1f1; } .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { border: 1px dashed #666; -webkit-border-radius: 0; border-radius: 0; word-wrap: break-word; padding: 1.25em 1.5625em 1.125em 1.5625em; font-size: 0.8125em; } .literalblock pre.nowrap, .literalblock pre[class].nowrap, .listingblock pre.nowrap, .listingblock pre[class].nowrap { overflow-x: auto; white-space: pre; word-wrap: normal; } @media only screen and (min-width: 768px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 0.90625em; } } @media only screen and (min-width: 1280px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 1em; } } .literalblock.output pre { color: #eee; background-color: black; } .listingblock pre.highlightjs { padding: 0; } .listingblock pre.highlightjs > code { padding: 1.25em 1.5625em 1.125em 1.5625em; -webkit-border-radius: 0; border-radius: 0; } .listingblock > .content { position: relative; } .listingblock code[data-lang]:before { display: none; content: attr(data-lang); position: absolute; font-size: 0.75em; top: 0.425rem; right: 0.5rem; line-height: 1; text-transform: uppercase; color: #999; } .listingblock:hover code[data-lang]:before { display: block; } .listingblock.terminal pre .command:before { content: attr(data-prompt); padding-right: 0.5em; color: #999; } .listingblock.terminal pre .command:not([data-prompt]):before { content: "$"; } table.pyhltable { border-collapse: separate; border: 0; margin-bottom: 0; background: none; } table.pyhltable td { vertical-align: top; padding-top: 0; padding-bottom: 0; line-height: 1.6; } table.pyhltable td.code { padding-left: .75em; padding-right: 0; } pre.pygments .lineno, table.pyhltable td:not(.code) { color: #999; padding-left: 0; padding-right: .5em; border-right: 1px solid #ddd; } pre.pygments .lineno { display: inline-block; margin-right: .25em; } table.pyhltable .linenodiv { background: none !important; padding-right: 0 !important; } .quoteblock { margin: 0 1em 0.75em 1.5em; display: table; } .quoteblock > .title { margin-left: -1.5em; margin-bottom: 0.75em; } .quoteblock blockquote, .quoteblock blockquote p { color: #333; font-size: 1.15rem; line-height: 1.75; word-spacing: 0.1em; letter-spacing: 0; font-style: italic; text-align: justify; } .quoteblock blockquote { margin: 0; padding: 0; border: 0; } .quoteblock blockquote:before { content: "\201c"; float: left; font-size: 2.75em; font-weight: bold; line-height: 0.6em; margin-left: -0.6em; color: #003b6b; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .quoteblock blockquote > .paragraph:last-child p { margin-bottom: 0; } .quoteblock .attribution { margin-top: 0.5em; margin-right: 0.5ex; text-align: right; } .quoteblock .quoteblock { margin-left: 0; margin-right: 0; padding: 0.5em 0; border-left: 3px solid #e15200; } .quoteblock .quoteblock blockquote { padding: 0 0 0 0.75em; } .quoteblock .quoteblock blockquote:before { display: none; } .verseblock { margin: 0 1em 0.75em 1em; } .verseblock pre { font-family: "Open Sans", "DejaVu Sans", sans; font-size: 1.15rem; color: #333; font-weight: 300; text-rendering: optimizeLegibility; } .verseblock pre strong { font-weight: 400; } .verseblock .attribution { margin-top: 1.25rem; margin-left: 0.5ex; } .quoteblock .attribution, .verseblock .attribution { font-size: 0.8125em; line-height: 1.45; font-style: italic; } .quoteblock .attribution br, .verseblock .attribution br { display: none; } .quoteblock .attribution cite, .verseblock .attribution cite { display: block; letter-spacing: -0.025em; color: #e15200; } .quoteblock.abstract { margin: 0 0 0.75em 0; display: block; } .quoteblock.abstract blockquote, .quoteblock.abstract blockquote p { text-align: left; word-spacing: 0; } .quoteblock.abstract blockquote:before, .quoteblock.abstract blockquote p:first-of-type:before { display: none; } table.tableblock { max-width: 100%; border-collapse: separate; } table.tableblock td > .paragraph:last-child p > p:last-child, table.tableblock th > p:last-child, table.tableblock td > p:last-child { margin-bottom: 0; } table.tableblock, th.tableblock, td.tableblock { border: 0 solid #d8d8ce; } table.grid-all th.tableblock, table.grid-all td.tableblock { border-width: 0 1px 1px 0; } table.grid-all tfoot > tr > th.tableblock, table.grid-all tfoot > tr > td.tableblock { border-width: 1px 1px 0 0; } table.grid-cols th.tableblock, table.grid-cols td.tableblock { border-width: 0 1px 0 0; } table.grid-all * > tr > .tableblock:last-child, table.grid-cols * > tr > .tableblock:last-child { border-right-width: 0; } table.grid-rows th.tableblock, table.grid-rows td.tableblock { border-width: 0 0 1px 0; } table.grid-all tbody > tr:last-child > th.tableblock, table.grid-all tbody > tr:last-child > td.tableblock, table.grid-all thead:last-child > tr > th.tableblock, table.grid-rows tbody > tr:last-child > th.tableblock, table.grid-rows tbody > tr:last-child > td.tableblock, table.grid-rows thead:last-child > tr > th.tableblock { border-bottom-width: 0; } table.grid-rows tfoot > tr > th.tableblock, table.grid-rows tfoot > tr > td.tableblock { border-width: 1px 0 0 0; } table.frame-all { border-width: 1px; } table.frame-sides { border-width: 0 1px; } table.frame-topbot { border-width: 1px 0; } th.halign-left, td.halign-left { text-align: left; } th.halign-right, td.halign-right { text-align: right; } th.halign-center, td.halign-center { text-align: center; } th.valign-top, td.valign-top { vertical-align: top; } th.valign-bottom, td.valign-bottom { vertical-align: bottom; } th.valign-middle, td.valign-middle { vertical-align: middle; } table thead th, table tfoot th { font-weight: bold; } tbody tr th { display: table-cell; line-height: 1.4; background: -webkit-linear-gradient(top, #add386, #90b66a); } tbody tr th, tbody tr th p, tfoot tr th, tfoot tr th p { color: #fff; font-weight: bold; } p.tableblock > code:only-child { background: none; padding: 0; } p.tableblock { font-size: 1em; } td > div.verse { white-space: pre; } ol { margin-left: 1.75em; } ul li ol { margin-left: 1.5em; } dl dd { margin-left: 1.125em; } dl dd:last-child, dl dd:last-child > :last-child { margin-bottom: 0; } ol > li p, ul > li p, ul dd, ol dd, .olist .olist, .ulist .ulist, .ulist .olist, .olist .ulist { margin-bottom: 0.375em; } ul.unstyled, ol.unnumbered, ul.checklist, ul.none { list-style-type: none; } ul.unstyled, ol.unnumbered, ul.checklist { margin-left: 0.625em; } ul.checklist li > p:first-child > .fa-square-o:first-child, ul.checklist li > p:first-child > .fa-check-square-o:first-child { width: 1em; font-size: 0.85em; } ul.checklist li > p:first-child > input[type="checkbox"]:first-child { width: 1em; position: relative; top: 1px; } ul.inline { margin: 0 auto 0.375em auto; margin-left: -1.375em; margin-right: 0; padding: 0; list-style: none; overflow: hidden; } ul.inline > li { list-style: none; float: left; margin-left: 1.375em; display: block; } ul.inline > li > * { display: block; } .unstyled dl dt { font-weight: normal; font-style: normal; } ol.arabic { list-style-type: decimal; } ol.decimal { list-style-type: decimal-leading-zero; } ol.loweralpha { list-style-type: lower-alpha; } ol.upperalpha { list-style-type: upper-alpha; } ol.lowerroman { list-style-type: lower-roman; } ol.upperroman { list-style-type: upper-roman; } ol.lowergreek { list-style-type: lower-greek; } .hdlist > table, .colist > table { border: 0; background: none; } .hdlist > table > tbody > tr, .colist > table > tbody > tr { background: none; } td.hdlist1, td.hdlist2 { vertical-align: top; padding: 0 0.625em; } td.hdlist1 { font-weight: bold; padding-bottom: 0.75em; } .literalblock + .colist, .listingblock + .colist { margin-top: -0.5em; } .colist > table tr > td:first-of-type { padding: 0 0.75em; line-height: 1; } .colist > table tr > td:last-of-type { padding: 0.25em 0; } .thumb, .th { line-height: 0; display: inline-block; border: solid 4px #fff; -webkit-box-shadow: 0 0 0 1px #ddd; box-shadow: 0 0 0 1px #ddd; } .imageblock.left, .imageblock[style*="float: left"] { margin: 0.25em 0.625em 1.25em 0; } .imageblock.right, .imageblock[style*="float: right"] { margin: 0.25em 0 1.25em 0.625em; } .imageblock > .title { margin-bottom: 0; } .imageblock.thumb, .imageblock.th { border-width: 6px; } .imageblock.thumb > .title, .imageblock.th > .title { padding: 0 0.125em; } .image.left, .image.right { margin-top: 0.25em; margin-bottom: 0.25em; display: inline-block; line-height: 0; } .image.left { margin-right: 0.625em; } .image.right { margin-left: 0.625em; } a.image { text-decoration: none; display: inline-block; } a.image object { pointer-events: none; } sup.footnote, sup.footnoteref { font-size: 0.875em; position: static; vertical-align: super; } sup.footnote a, sup.footnoteref a { text-decoration: none; } sup.footnote a:active, sup.footnoteref a:active { text-decoration: underline; } #footnotes { padding-top: 0.75em; padding-bottom: 0.75em; margin-bottom: 0.625em; } #footnotes hr { width: 20%; min-width: 6.25em; margin: -0.25em 0 0.75em 0; border-width: 1px 0 0 0; } #footnotes .footnote { padding: 0 0.375em 0 0.225em; line-height: 1.3334; font-size: 0.875em; margin-left: 1.2em; text-indent: -1.05em; margin-bottom: 0.2em; } #footnotes .footnote a:first-of-type { font-weight: bold; text-decoration: none; } #footnotes .footnote:last-of-type { margin-bottom: 0; } #content #footnotes { margin-top: -0.625em; margin-bottom: 0; padding: 0.75em 0; } .gist .file-data > table { border: 0; background: #fff; width: 100%; margin-bottom: 0; } .gist .file-data > table td.line-data { width: 99%; } div.unbreakable { page-break-inside: avoid; } .big { font-size: larger; } .small { font-size: smaller; } .underline { text-decoration: underline; } .overline { text-decoration: overline; } .line-through { text-decoration: line-through; } .aqua { color: #00bfbf; } .aqua-background { background-color: #00fafa; } .black { color: black; } .black-background { background-color: black; } .blue { color: #0000bf; } .blue-background { background-color: #0000fa; } .fuchsia { color: #bf00bf; } .fuchsia-background { background-color: #fa00fa; } .gray { color: #606060; } .gray-background { background-color: #7d7d7d; } .green { color: #006000; } .green-background { background-color: #007d00; } .lime { color: #00bf00; } .lime-background { background-color: #00fa00; } .maroon { color: #600000; } .maroon-background { background-color: #7d0000; } .navy { color: #000060; } .navy-background { background-color: #00007d; } .olive { color: #606000; } .olive-background { background-color: #7d7d00; } .purple { color: #600060; } .purple-background { background-color: #7d007d; } .red { color: #bf0000; } .red-background { background-color: #fa0000; } .silver { color: #909090; } .silver-background { background-color: #bcbcbc; } .teal { color: #006060; } .teal-background { background-color: #007d7d; } .white { color: #bfbfbf; } .white-background { background-color: #fafafa; } .yellow { color: #bfbf00; } .yellow-background { background-color: #fafa00; } span.icon > .fa { cursor: default; } .admonitionblock td.icon [class^="fa icon-"] { font-size: 2.5em; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); cursor: default; } .admonitionblock td.icon .icon-note:before { content: "\f05a"; color: #004177; } .admonitionblock td.icon .icon-tip:before { content: "\f0eb"; text-shadow: 1px 1px 2px rgba(155, 155, 0, 0.8); color: #111; } .admonitionblock td.icon .icon-warning:before { content: "\f071"; color: #bf6900; } .admonitionblock td.icon .icon-caution:before { content: "\f06d"; color: #bf3400; } .admonitionblock td.icon .icon-important:before { content: "\f06a"; color: #bf0000; } .conum[data-value] { display: inline-block; color: #fff !important; background-color: black; -webkit-border-radius: 100px; border-radius: 100px; text-align: center; font-size: 0.75em; width: 1.67em; height: 1.67em; line-height: 1.67em; font-family: "Open Sans", "DejaVu Sans", sans-serif; font-style: normal; font-weight: bold; } .conum[data-value] * { color: #fff !important; } .conum[data-value] + b { display: none; } .conum[data-value]:after { content: attr(data-value); } pre .conum[data-value] { position: relative; top: -0.125em; } b.conum * { color: inherit !important; } .conum:not([data-value]):empty { display: none; } h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { border-bottom: 1px solid #ddd; } .sect1 { padding-bottom: 0; } #toctitle { color: #00406F; font-weight: normal; margin-top: 1.5em; } .sidebarblock { border-color: #aaa; } code { -webkit-border-radius: 4px; border-radius: 4px; } p.tableblock.header { color: #6d6e71; } .literalblock pre, .listingblock pre { background: #eee; } nanomsg-1.1.5/perf/000077500000000000000000000000001336111550300141125ustar00rootroot00000000000000nanomsg-1.1.5/perf/README000066400000000000000000000004751336111550300150000ustar00rootroot00000000000000This directory contains simple performance measurement utilities: - inproc_lat measures the latency of the inproc transport - inproc_thr measures the throughput of the inproc transport - local_lat and remote_lat measure the latency other transports - local_thr and remote_thr measure the throughput other transports nanomsg-1.1.5/perf/inproc_lat.c000066400000000000000000000067251336111550300164220ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/utils/attr.h" #include "../src/utils/err.c" #include "../src/utils/thread.c" #include "../src/utils/sleep.c" #include "../src/utils/stopwatch.c" #include #include #include #include static size_t message_size; static int roundtrip_count; void worker (void *arg) { int rc; int s; int i; char *buf; s = *(int *)arg; buf = malloc (message_size); assert (buf); for (i = 0; i != roundtrip_count; i++) { rc = nn_recv (s, buf, message_size, 0); assert (rc == (int)message_size); rc = nn_send (s, buf, message_size, 0); assert (rc == (int)message_size); } free (buf); } int main (int argc, char *argv []) { int rc; int s; int w; int i; char *buf; struct nn_thread thread; struct nn_stopwatch stopwatch; uint64_t elapsed; double latency; if (argc != 3) { printf ("usage: inproc_lat \n"); return 1; } message_size = atoi (argv [1]); roundtrip_count = atoi (argv [2]); s = nn_socket (AF_SP, NN_PAIR); assert (s != -1); rc = nn_bind (s, "inproc://inproc_lat"); assert (rc >= 0); w = nn_socket (AF_SP, NN_PAIR); assert (w != -1); rc = nn_connect (w, "inproc://inproc_lat"); assert (rc >= 0); buf = malloc (message_size); assert (buf); memset (buf, 111, message_size); /* Wait a bit till the worker thread blocks in nn_recv(). */ nn_thread_init (&thread, worker, &w); nn_sleep (100); nn_stopwatch_init (&stopwatch); for (i = 0; i != roundtrip_count; i++) { rc = nn_send (s, buf, message_size, 0); assert (rc == (int)message_size); rc = nn_recv (s, buf, message_size, 0); assert (rc == (int)message_size); } elapsed = nn_stopwatch_term (&stopwatch); latency = (double) elapsed / (roundtrip_count * 2); printf ("message size: %d [B]\n", (int) message_size); printf ("roundtrip count: %d\n", (int) roundtrip_count); printf ("average latency: %.3f [us]\n", (double) latency); nn_thread_term (&thread); free (buf); rc = nn_close (s); assert (rc == 0); rc = nn_close (w); assert (rc == 0); return 0; } nanomsg-1.1.5/perf/inproc_thr.c000066400000000000000000000071131336111550300164270ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/utils/attr.h" #include "../src/utils/err.c" #include "../src/utils/thread.c" #include "../src/utils/stopwatch.c" #include #include #include #include static size_t message_size; static int message_count; void worker (void *arg) { int rc; int s; int i; char *buf; s = *(int *)arg; buf = malloc (message_size); assert (buf); memset (buf, 111, message_size); rc = nn_send (s, NULL, 0, 0); assert (rc == 0); for (i = 0; i != message_count; i++) { rc = nn_send (s, buf, message_size, 0); assert (rc == (int)message_size); } free (buf); } int main (int argc, char *argv []) { int rc; int s; int w; int i; char *buf; struct nn_thread thread; struct nn_stopwatch stopwatch; uint64_t elapsed; unsigned long throughput; double megabits; if (argc != 3) { printf ("usage: thread_thr \n"); return 1; } message_size = atoi (argv [1]); message_count = atoi (argv [2]); s = nn_socket (AF_SP, NN_PAIR); assert (s != -1); rc = nn_bind (s, "inproc://inproc_thr"); assert (rc >= 0); w = nn_socket (AF_SP, NN_PAIR); assert (w != -1); rc = nn_connect (w, "inproc://inproc_thr"); assert (rc >= 0); buf = malloc (message_size); assert (buf); nn_thread_init (&thread, worker, &w); /* First message is used to start the stopwatch. */ rc = nn_recv (s, buf, message_size, 0); assert (rc == 0); nn_stopwatch_init (&stopwatch); for (i = 0; i != message_count; i++) { rc = nn_recv (s, buf, message_size, 0); assert (rc == (int)message_size); } elapsed = nn_stopwatch_term (&stopwatch); nn_thread_term (&thread); free (buf); rc = nn_close (s); assert (rc == 0); rc = nn_close (w); assert (rc == 0); if (elapsed == 0) elapsed = 1; throughput = (unsigned long) ((double) message_count / (double) elapsed * 1000000); megabits = (double) (throughput * message_size * 8) / 1000000; printf ("message size: %d [B]\n", (int) message_size); printf ("message count: %d\n", (int) message_count); printf ("mean throughput: %d [msg/s]\n", (int) throughput); printf ("mean throughput: %.3f [Mb/s]\n", (double) megabits); return 0; } nanomsg-1.1.5/perf/local_lat.c000066400000000000000000000051641336111550300162160ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/tcp.h" #include "../src/pair.h" #include #include #include #include "../src/utils/err.c" #include "../src/utils/sleep.c" int main (int argc, char *argv []) { const char *bind_to; size_t sz; int rts; char *buf; int nbytes; int s; int rc; int i; int opt; if (argc != 4) { printf ("usage: local_lat \n"); return 1; } bind_to = argv [1]; sz = atoi (argv [2]); rts = atoi (argv [3]); s = nn_socket (AF_SP, NN_PAIR); nn_assert (s != -1); opt = 1; rc = nn_setsockopt (s, NN_TCP, NN_TCP_NODELAY, &opt, sizeof (opt)); nn_assert (rc == 0); opt = -1; rc = nn_setsockopt (s, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); nn_assert (rc == 0); opt = 1000; rc = nn_setsockopt (s, NN_SOL_SOCKET, NN_LINGER, &opt, sizeof (opt)); nn_assert (rc == 0); rc = nn_bind (s, bind_to); nn_assert (rc >= 0); buf = malloc (sz); nn_assert (buf); memset (buf, 111, sz); for (i = 0; i != rts; i++) { nbytes = nn_recv (s, buf, sz, 0); nn_assert (nbytes == (int)sz); nbytes = nn_send (s, buf, sz, 0); nn_assert (nbytes == (int)sz); } free (buf); /* Linger doesn't always work, so stick around another second. */ nn_sleep (1000); rc = nn_close (s); nn_assert (rc == 0); return 0; } nanomsg-1.1.5/perf/local_thr.c000066400000000000000000000055331336111550300162330ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include #include #include "../src/utils/stopwatch.c" #include "../src/utils/err.c" int main (int argc, char *argv []) { const char *bind_to; size_t sz; int count; char *buf; int nbytes; int s; int rc; int i; int opt; struct nn_stopwatch sw; uint64_t total; uint64_t thr; double mbs; if (argc != 4) { printf ("usage: local_thr \n"); return 1; } bind_to = argv [1]; sz = atoi (argv [2]); count = atoi (argv [3]); s = nn_socket (AF_SP, NN_PAIR); nn_assert (s != -1); rc = nn_bind (s, bind_to); nn_assert (rc >= 0); opt = -1; rc = nn_setsockopt (s, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); nn_assert (rc == 0); opt = 1000; rc = nn_setsockopt (s, NN_SOL_SOCKET, NN_LINGER, &opt, sizeof (opt)); nn_assert (rc == 0); buf = malloc (sz); nn_assert (buf); nbytes = nn_recv (s, buf, sz, 0); nn_assert (nbytes == 0); nn_stopwatch_init (&sw); for (i = 0; i != count; i++) { nbytes = nn_recv (s, buf, sz, 0); nn_assert (nbytes == (int)sz); } total = nn_stopwatch_term (&sw); if (total == 0) total = 1; thr = (uint64_t) ((double) count / (double) total * 1000000); mbs = (double) (thr * sz * 8) / 1000000; printf ("message size: %d [B]\n", (int) sz); printf ("message count: %d\n", (int) count); printf ("throughput: %d [msg/s]\n", (int) thr); printf ("throughput: %.3f [Mb/s]\n", (double) mbs); free (buf); rc = nn_close (s); nn_assert (rc == 0); return 0; } nanomsg-1.1.5/perf/remote_lat.c000066400000000000000000000054001336111550300164100ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/tcp.h" #include "../src/pair.h" #include #include #include #include "../src/utils/stopwatch.c" #include "../src/utils/err.c" int main (int argc, char *argv []) { const char *connect_to; size_t sz; int rts; char *buf; int nbytes; int s; int rc; int i; int opt; struct nn_stopwatch sw; uint64_t total; double lat; if (argc != 4) { printf ("usage: remote_lat \n"); return 1; } connect_to = argv [1]; sz = atoi (argv [2]); rts = atoi (argv [3]); s = nn_socket (AF_SP, NN_PAIR); nn_assert (s != -1); opt = 1; rc = nn_setsockopt (s, NN_TCP, NN_TCP_NODELAY, &opt, sizeof (opt)); nn_assert (rc == 0); opt = -1; rc = nn_setsockopt (s, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); nn_assert (rc == 0); rc = nn_connect (s, connect_to); nn_assert (rc >= 0); buf = malloc (sz); nn_assert (buf); memset (buf, 111, sz); nn_stopwatch_init (&sw); for (i = 0; i != rts; i++) { nbytes = nn_send (s, buf, sz, 0); nn_assert (nbytes == (int)sz); nbytes = nn_recv (s, buf, sz, 0); nn_assert (nbytes == (int)sz); } total = nn_stopwatch_term (&sw); lat = (double) total / (rts * 2); printf ("message size: %d [B]\n", (int) sz); printf ("roundtrip count: %d\n", (int) rts); printf ("average latency: %.3f [us]\n", (double) lat); free (buf); rc = nn_close (s); nn_assert (rc == 0); return 0; } nanomsg-1.1.5/perf/remote_thr.c000066400000000000000000000047731336111550300164410ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include #include #include #include "../src/utils/err.c" #include "../src/utils/sleep.c" int main (int argc, char *argv []) { const char *connect_to; size_t sz; int count; char *buf; int nbytes; int s; int rc; int i; int opt; if (argc != 4) { printf ("usage: remote_thr \n"); return 1; } connect_to = argv [1]; sz = atoi (argv [2]); count = atoi (argv [3]); s = nn_socket (AF_SP, NN_PAIR); nn_assert (s != -1); rc = nn_connect (s, connect_to); nn_assert (rc >= 0); opt = -1; rc = nn_setsockopt (s, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); nn_assert (rc == 0); opt = 1000; rc = nn_setsockopt (s, NN_SOL_SOCKET, NN_LINGER, &opt, sizeof (opt)); nn_assert (rc == 0); buf = malloc (sz); nn_assert (buf); memset (buf, 111, sz); nbytes = nn_send (s, buf, 0, 0); nn_assert (nbytes == 0); for (i = 0; i != count; i++) { nbytes = nn_send (s, buf, sz, 0); nn_assert (nbytes == (int)sz); } free (buf); /* Linger doesn't always do the trick, so sleep a bit to be sure. */ nn_sleep (1000); rc = nn_close (s); nn_assert (rc == 0); return 0; } nanomsg-1.1.5/src/000077500000000000000000000000001336111550300137455ustar00rootroot00000000000000nanomsg-1.1.5/src/CMakeLists.txt000066400000000000000000000254631336111550300165170ustar00rootroot00000000000000# # Copyright (c) 2012-2013 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 Garrett D'Amore # Copyright (c) 2018 Dennis Klein # # 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. # set (NN_SOURCES nn.h inproc.h ipc.h tcp.h ws.h pair.h pubsub.h reqrep.h pipeline.h survey.h bus.h core/ep.h core/ep.c core/global.h core/global.c core/pipe.c core/poll.c core/sock.h core/sock.c core/sockbase.c core/symbol.c aio/ctx.h aio/ctx.c aio/fsm.h aio/fsm.c aio/pool.h aio/pool.c aio/timer.h aio/timer.c aio/timerset.h aio/timerset.c aio/usock.h aio/usock.c aio/worker.h aio/worker.c utils/alloc.h utils/alloc.c utils/atomic.h utils/atomic.c utils/attr.h utils/chunk.h utils/chunk.c utils/chunkref.h utils/chunkref.c utils/clock.h utils/clock.c utils/closefd.h utils/closefd.c utils/cont.h utils/efd.h utils/efd.c utils/err.h utils/err.c utils/fast.h utils/fd.h utils/hash.h utils/hash.c utils/list.h utils/list.c utils/msg.h utils/msg.c utils/condvar.h utils/condvar.c utils/mutex.h utils/mutex.c utils/once.h utils/once.c utils/queue.h utils/queue.c utils/random.h utils/random.c utils/sem.h utils/sem.c utils/sleep.h utils/sleep.c utils/strcasecmp.c utils/strcasecmp.h utils/strcasestr.c utils/strcasestr.h utils/strncasecmp.c utils/strncasecmp.h utils/thread.h utils/thread.c utils/wire.h utils/wire.c devices/device.h devices/device.c protocols/utils/dist.h protocols/utils/dist.c protocols/utils/excl.h protocols/utils/excl.c protocols/utils/fq.h protocols/utils/fq.c protocols/utils/lb.h protocols/utils/lb.c protocols/utils/priolist.h protocols/utils/priolist.c protocols/bus/bus.c protocols/bus/xbus.h protocols/bus/xbus.c protocols/pipeline/push.c protocols/pipeline/pull.c protocols/pipeline/xpull.h protocols/pipeline/xpull.c protocols/pipeline/xpush.h protocols/pipeline/xpush.c protocols/pair/pair.c protocols/pair/xpair.h protocols/pair/xpair.c protocols/pubsub/pub.c protocols/pubsub/sub.c protocols/pubsub/trie.h protocols/pubsub/trie.c protocols/pubsub/xpub.h protocols/pubsub/xpub.c protocols/pubsub/xsub.h protocols/pubsub/xsub.c protocols/reqrep/req.h protocols/reqrep/req.c protocols/reqrep/rep.h protocols/reqrep/rep.c protocols/reqrep/task.h protocols/reqrep/task.c protocols/reqrep/xrep.h protocols/reqrep/xrep.c protocols/reqrep/xreq.h protocols/reqrep/xreq.c protocols/survey/respondent.c protocols/survey/surveyor.c protocols/survey/xrespondent.h protocols/survey/xrespondent.c protocols/survey/xsurveyor.h protocols/survey/xsurveyor.c transports/utils/backoff.h transports/utils/backoff.c transports/utils/dns.h transports/utils/dns.c transports/utils/dns_getaddrinfo.h transports/utils/dns_getaddrinfo.inc transports/utils/dns_getaddrinfo_a.h transports/utils/dns_getaddrinfo_a.inc transports/utils/iface.h transports/utils/iface.c transports/utils/literal.h transports/utils/literal.c transports/utils/port.h transports/utils/port.c transports/utils/streamhdr.h transports/utils/streamhdr.c transports/utils/base64.h transports/utils/base64.c transports/inproc/binproc.h transports/inproc/binproc.c transports/inproc/cinproc.h transports/inproc/cinproc.c transports/inproc/inproc.c transports/inproc/ins.h transports/inproc/ins.c transports/inproc/msgqueue.h transports/inproc/msgqueue.c transports/inproc/sinproc.h transports/inproc/sinproc.c transports/ipc/aipc.h transports/ipc/aipc.c transports/ipc/bipc.h transports/ipc/bipc.c transports/ipc/cipc.h transports/ipc/cipc.c transports/ipc/ipc.c transports/ipc/sipc.h transports/ipc/sipc.c transports/tcp/atcp.h transports/tcp/atcp.c transports/tcp/btcp.h transports/tcp/btcp.c transports/tcp/ctcp.h transports/tcp/ctcp.c transports/tcp/stcp.h transports/tcp/stcp.c transports/tcp/tcp.c transports/ws/aws.h transports/ws/aws.c transports/ws/bws.h transports/ws/bws.c transports/ws/cws.h transports/ws/cws.c transports/ws/sws.h transports/ws/sws.c transports/ws/ws.c transports/ws/ws_handshake.h transports/ws/ws_handshake.c transports/ws/sha1.h transports/ws/sha1.c ) if (WIN32) list (APPEND NN_SOURCES aio/usock_win.h aio/usock_win.inc aio/worker_win.h aio/worker_win.inc utils/thread_win.h utils/thread_win.inc utils/win.h ) elseif (UNIX) list (APPEND NN_SOURCES aio/usock_posix.h aio/usock_posix.inc aio/worker_posix.h aio/worker_posix.inc utils/thread_posix.h utils/thread_posix.inc ) else () message (FATAL_ERROR "Assertion failed; this path is unreachable.") endif () if (NN_HAVE_EPOLL) add_definitions (-DNN_USE_EPOLL) list (APPEND NN_SOURCES aio/poller.h aio/poller.c aio/poller_epoll.h aio/poller_epoll.inc ) elseif (NN_HAVE_KQUEUE) add_definitions (-DNN_USE_KQUEUE) list (APPEND NN_SOURCES aio/poller.h aio/poller.c aio/poller_kqueue.h aio/poller_kqueue.inc ) elseif (NN_HAVE_POLL) add_definitions (-DNN_USE_POLL) list (APPEND NN_SOURCES aio/poller.h aio/poller.c aio/poller_poll.h aio/poller_poll.inc ) elseif (NN_HAVE_WINSOCK) # No operation else () message (SEND_ERROR "ERROR: could not determine socket polling method.") message (SEND_ERROR "${ISSUE_REPORT_MSG}" ) endif () if (NN_HAVE_EVENTFD) add_definitions (-DNN_USE_EVENTFD) list (APPEND NN_SOURCES utils/efd_eventfd.h utils/efd_eventfd.inc ) elseif (NN_HAVE_PIPE) add_definitions (-DNN_USE_PIPE) list (APPEND NN_SOURCES utils/efd_pipe.h utils/efd_pipe.inc ) elseif (NN_HAVE_SOCKETPAIR) add_definitions (-DNN_USE_SOCKETPAIR) list (APPEND NN_SOURCES utils/efd_socketpair.h utils/efd_socketpair.inc ) elseif (NN_HAVE_WINSOCK) add_definitions (-DNN_USE_WINSOCK) list (APPEND NN_SOURCES utils/efd_win.h utils/efd_win.inc ) else () message (SEND_ERROR "ERROR: could not determine socket signaling method.") message (SEND_ERROR "${ISSUE_REPORT_MSG}" ) endif () # Provide same folder structure in IDE as on disk foreach (f ${NN_SOURCES}) # Get the path of the file relative to source directory if (IS_ABSOLUTE "${f}") file (RELATIVE_PATH f ${CMAKE_CURRENT_SOURCE_DIR} ${f}) endif () set (SRC_GROUP "${f}") set (f "${CMAKE_CURRENT_SOURCE_DIR}/${f}") # Remove the filename part string (REGEX REPLACE "(.*)(/[^/]*)$" "\\1" SRC_GROUP ${SRC_GROUP}) # CMake source_group expects \\, not / string (REPLACE / \\ SRC_GROUP ${SRC_GROUP}) source_group ("${SRC_GROUP}" FILES ${f}) endforeach () if (NN_STATIC_LIB) add_library (${PROJECT_NAME} STATIC ${NN_SOURCES}) target_compile_definitions (${PROJECT_NAME} PUBLIC NN_STATIC_LIB) else () add_library (${PROJECT_NAME} SHARED ${NN_SOURCES}) add_definitions (-DNN_SHARED_LIB) set_target_properties (${PROJECT_NAME} PROPERTIES SOVERSION "${NN_ABI_VERSION}" VERSION "${NN_LIB_VERSION}" ) endif () # Set library outputs same as top-level project binary outputs set_target_properties (${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) set_target_properties (${PROJECT_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) set_target_properties (${PROJECT_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) target_link_libraries (${PROJECT_NAME} ${NN_REQUIRED_LIBRARIES}) if(THREADS_HAVE_PTHREAD_ARG) add_definitions (-pthread) endif() if(CMAKE_THREAD_LIBS_INIT) target_link_libraries (${PROJECT_NAME} "${CMAKE_THREAD_LIBS_INIT}") endif() # pkg-config file if(NN_REQUIRED_LIBRARIES) foreach (lib ${NN_REQUIRED_LIBRARIES}) set (NN_REQUIRED_LFLAGS "${NN_REQUIRED_LFLAGS} -l${lib}") endforeach() endif() configure_file (pkgconfig.in ${PROJECT_NAME}.pc @ONLY) target_include_directories(${PROJECT_NAME} PUBLIC $) install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install (TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-target ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) # Generate and install CMake package include(CMakePackageConfigHelpers) set(PACKAGE_INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${NN_PACKAGE_VERSION} ) install(EXPORT ${PROJECT_NAME}-target DESTINATION ${PACKAGE_INSTALL_DESTINATION} ) write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake VERSION ${NN_PACKAGE_VERSION} COMPATIBILITY SameMajorVersion ) configure_package_config_file( ${CMAKE_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake INSTALL_DESTINATION ${PACKAGE_INSTALL_DESTINATION} PATH_VARS CMAKE_INSTALL_PREFIX ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake DESTINATION ${PACKAGE_INSTALL_DESTINATION} ) nanomsg-1.1.5/src/README000066400000000000000000000002231336111550300146220ustar00rootroot00000000000000This directory contains all headers that interconnect various parts of the system. The public API, the interface for protocols and transports etc. nanomsg-1.1.5/src/aio/000077500000000000000000000000001336111550300145155ustar00rootroot00000000000000nanomsg-1.1.5/src/aio/ctx.c000066400000000000000000000066041336111550300154650ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "ctx.h" #include "../utils/err.h" #include "../utils/cont.h" #include "../utils/fast.h" void nn_ctx_init (struct nn_ctx *self, struct nn_pool *pool, nn_ctx_onleave onleave) { nn_mutex_init (&self->sync); self->pool = pool; nn_queue_init (&self->events); nn_queue_init (&self->eventsto); self->onleave = onleave; } void nn_ctx_term (struct nn_ctx *self) { nn_queue_term (&self->eventsto); nn_queue_term (&self->events); nn_mutex_term (&self->sync); } void nn_ctx_enter (struct nn_ctx *self) { nn_mutex_lock (&self->sync); } void nn_ctx_leave (struct nn_ctx *self) { struct nn_queue_item *item; struct nn_fsm_event *event; struct nn_queue eventsto; /* Process any queued events before leaving the context. */ while (1) { item = nn_queue_pop (&self->events); event = nn_cont (item, struct nn_fsm_event, item); if (!event) break; nn_fsm_event_process (event); } /* Notify the owner that we are leaving the context. */ if (nn_fast (self->onleave != NULL)) self->onleave (self); /* Shortcut in the case there are no external events. */ if (nn_queue_empty (&self->eventsto)) { nn_mutex_unlock (&self->sync); return; } /* Make a copy of the queue of the external events so that it does not get corrupted once we unlock the context. */ eventsto = self->eventsto; nn_queue_init (&self->eventsto); nn_mutex_unlock (&self->sync); /* Process any queued external events. Before processing each event lock the context it belongs to. */ while (1) { item = nn_queue_pop (&eventsto); event = nn_cont (item, struct nn_fsm_event, item); if (!event) break; nn_ctx_enter (event->fsm->ctx); nn_fsm_event_process (event); nn_ctx_leave (event->fsm->ctx); } nn_queue_term (&eventsto); } struct nn_worker *nn_ctx_choose_worker (struct nn_ctx *self) { return nn_pool_choose_worker (self->pool); } void nn_ctx_raise (struct nn_ctx *self, struct nn_fsm_event *event) { nn_queue_push (&self->events, &event->item); } void nn_ctx_raiseto (struct nn_ctx *self, struct nn_fsm_event *event) { nn_queue_push (&self->eventsto, &event->item); } nanomsg-1.1.5/src/aio/ctx.h000066400000000000000000000037251336111550300154730ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_CTX_INCLUDED #define NN_CTX_INCLUDED #include "../utils/mutex.h" #include "../utils/queue.h" #include "worker.h" #include "pool.h" #include "fsm.h" /* AIO context for objects using AIO subsystem. */ typedef void (*nn_ctx_onleave) (struct nn_ctx *self); struct nn_ctx { struct nn_mutex sync; struct nn_pool *pool; struct nn_queue events; struct nn_queue eventsto; nn_ctx_onleave onleave; }; void nn_ctx_init (struct nn_ctx *self, struct nn_pool *pool, nn_ctx_onleave onleave); void nn_ctx_term (struct nn_ctx *self); void nn_ctx_enter (struct nn_ctx *self); void nn_ctx_leave (struct nn_ctx *self); struct nn_worker *nn_ctx_choose_worker (struct nn_ctx *self); void nn_ctx_raise (struct nn_ctx *self, struct nn_fsm_event *event); void nn_ctx_raiseto (struct nn_ctx *self, struct nn_fsm_event *event); #endif nanomsg-1.1.5/src/aio/fsm.c000066400000000000000000000135711336111550300154550ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "fsm.h" #include "ctx.h" #include "../utils/err.h" #include "../utils/attr.h" #include #define NN_FSM_STATE_IDLE 1 #define NN_FSM_STATE_ACTIVE 2 #define NN_FSM_STATE_STOPPING 3 void nn_fsm_event_init (struct nn_fsm_event *self) { self->fsm = NULL; self->src = -1; self->srcptr = NULL; self->type = -1; nn_queue_item_init (&self->item); } void nn_fsm_event_term (NN_UNUSED struct nn_fsm_event *self) { /* We don't term the queue item, although one might think we ought to. It turns out that there are some hairy recursions which can cause events to get submitted to queues even after the FSM is stopped. We could spend more effort fixing this, and perhaps we ought to. But given that the assertion itself is harmless, if an FSM event is orphaned it should be pretty harmless -- the event won't be processed but the FSM is shutting down anyway. So skip it for now. Later, if we don't rewrite/gut the entire FSM machinery, we can revisit this. */ /* nn_queue_item_term (&self->item); */ } int nn_fsm_event_active (struct nn_fsm_event *self) { return nn_queue_item_isinqueue (&self->item); } void nn_fsm_event_process (struct nn_fsm_event *self) { int src; int type; void *srcptr; src = self->src; type = self->type; srcptr = self->srcptr; self->src = -1; self->type = -1; self->srcptr = NULL; nn_fsm_feed (self->fsm, src, type, srcptr); } void nn_fsm_feed (struct nn_fsm *self, int src, int type, void *srcptr) { if (nn_slow (self->state != NN_FSM_STATE_STOPPING)) { self->fn (self, src, type, srcptr); } else { self->shutdown_fn (self, src, type, srcptr); } } void nn_fsm_init_root (struct nn_fsm *self, nn_fsm_fn fn, nn_fsm_fn shutdown_fn, struct nn_ctx *ctx) { self->fn = fn; self->shutdown_fn = shutdown_fn; self->state = NN_FSM_STATE_IDLE; self->src = -1; self->srcptr = NULL; self->owner = NULL; self->ctx = ctx; nn_fsm_event_init (&self->stopped); } void nn_fsm_init (struct nn_fsm *self, nn_fsm_fn fn, nn_fsm_fn shutdown_fn, int src, void *srcptr, struct nn_fsm *owner) { self->fn = fn; self->shutdown_fn = shutdown_fn; self->state = NN_FSM_STATE_IDLE; self->src = src; self->srcptr = srcptr; self->owner = owner; self->ctx = owner->ctx; nn_fsm_event_init (&self->stopped); } void nn_fsm_term (struct nn_fsm *self) { nn_assert (nn_fsm_isidle (self)); nn_fsm_event_term (&self->stopped); } void nn_fsm_start (struct nn_fsm *self) { nn_assert (nn_fsm_isidle (self)); self->fn (self, NN_FSM_ACTION, NN_FSM_START, NULL); self->state = NN_FSM_STATE_ACTIVE; } int nn_fsm_isidle (struct nn_fsm *self) { return self->state == NN_FSM_STATE_IDLE && !nn_fsm_event_active (&self->stopped) ? 1 : 0; } void nn_fsm_stop (struct nn_fsm *self) { /* If stopping of the state machine was already requested, do nothing. */ if (self->state != NN_FSM_STATE_ACTIVE) return; self->state = NN_FSM_STATE_STOPPING; self->shutdown_fn (self, NN_FSM_ACTION, NN_FSM_STOP, NULL); } void nn_fsm_stopped (struct nn_fsm *self, int type) { nn_assert_state (self, NN_FSM_STATE_STOPPING); nn_fsm_raise (self, &self->stopped, type); self->state = NN_FSM_STATE_IDLE; } void nn_fsm_stopped_noevent (struct nn_fsm *self) { nn_assert_state (self, NN_FSM_STATE_STOPPING); self->state = NN_FSM_STATE_IDLE; } void nn_fsm_swap_owner (struct nn_fsm *self, struct nn_fsm_owner *owner) { int oldsrc; struct nn_fsm *oldowner; oldsrc = self->src; oldowner = self->owner; self->src = owner->src; self->owner = owner->fsm; owner->src = oldsrc; owner->fsm = oldowner; } struct nn_worker *nn_fsm_choose_worker (struct nn_fsm *self) { return nn_ctx_choose_worker (self->ctx); } void nn_fsm_action (struct nn_fsm *self, int type) { nn_assert (type > 0); nn_fsm_feed (self, NN_FSM_ACTION, type, NULL); } void nn_fsm_raise_from_src (struct nn_fsm *self, struct nn_fsm_event *event, int src, int type) { event->fsm = self; event->src = src; event->srcptr = self->srcptr; event->type = type; nn_ctx_raise (self->ctx, event); } void nn_fsm_raise (struct nn_fsm *self, struct nn_fsm_event *event, int type) { event->fsm = self->owner; event->src = self->src; event->srcptr = self->srcptr; event->type = type; nn_ctx_raise (self->ctx, event); } void nn_fsm_raiseto (struct nn_fsm *self, struct nn_fsm *dst, struct nn_fsm_event *event, int src, int type, void *srcptr) { event->fsm = dst; event->src = src; event->srcptr = srcptr; event->type = type; nn_ctx_raiseto (self->ctx, event); } nanomsg-1.1.5/src/aio/fsm.h000066400000000000000000000103011336111550300154460ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_FSM_INCLUDED #define NN_FSM_INCLUDED #include "../utils/queue.h" /* Base class for state machines. */ struct nn_ctx; struct nn_fsm; struct nn_worker; struct nn_fsm_event { struct nn_fsm *fsm; int src; void *srcptr; int type; struct nn_queue_item item; }; void nn_fsm_event_init (struct nn_fsm_event *self); void nn_fsm_event_term (struct nn_fsm_event *self); int nn_fsm_event_active (struct nn_fsm_event *self); void nn_fsm_event_process (struct nn_fsm_event *self); /* Special source for actions. It's negative not to clash with user-defined sources. */ #define NN_FSM_ACTION -2 /* Actions generated by fsm object. The values are negative not to clash with user-defined actions. */ #define NN_FSM_START -2 #define NN_FSM_STOP -3 /* Virtual function to be implemented by the derived class to handle the incoming events. */ typedef void (*nn_fsm_fn) (struct nn_fsm *self, int src, int type, void *srcptr); struct nn_fsm_owner { int src; struct nn_fsm *fsm; }; struct nn_fsm { nn_fsm_fn fn; nn_fsm_fn shutdown_fn; int state; int src; void *srcptr; struct nn_fsm *owner; struct nn_ctx *ctx; struct nn_fsm_event stopped; }; void nn_fsm_init_root (struct nn_fsm *self, nn_fsm_fn fn, nn_fsm_fn shutdown_fn, struct nn_ctx *ctx); void nn_fsm_init (struct nn_fsm *self, nn_fsm_fn fn, nn_fsm_fn shutdown_fn, int src, void *srcptr, struct nn_fsm *owner); void nn_fsm_term (struct nn_fsm *self); int nn_fsm_isidle (struct nn_fsm *self); void nn_fsm_start (struct nn_fsm *self); void nn_fsm_stop (struct nn_fsm *self); void nn_fsm_stopped (struct nn_fsm *self, int type); void nn_fsm_stopped_noevent (struct nn_fsm *self); /* Replaces current owner of the fsm by the owner speicified by 'owner' parameter. The parameter will hold the old owner afrer the call. */ void nn_fsm_swap_owner (struct nn_fsm *self, struct nn_fsm_owner *owner); struct nn_worker *nn_fsm_choose_worker (struct nn_fsm *self); /* Using this function state machine can trigger an action on itself. */ void nn_fsm_action (struct nn_fsm *self, int type); /* Send event from the state machine to its owner. */ void nn_fsm_raise_from_src (struct nn_fsm *self, struct nn_fsm_event *event, int src, int type); /* Send event from the state machine to its owner. */ void nn_fsm_raise (struct nn_fsm *self, struct nn_fsm_event *event, int type); /* Send event to the specified state machine. It's caller's responsibility to ensure that the destination state machine will still exist when the event is delivered. NOTE: This function is a hack to make inproc transport work in the most efficient manner. Do not use it outside of inproc transport! */ void nn_fsm_raiseto (struct nn_fsm *self, struct nn_fsm *dst, struct nn_fsm_event *event, int src, int type, void *srcptr); /* This function is very lowlevel action feeding Used in worker threads and timers, shouldn't be used by others use nn_fsm_action/nn_fsm_raise/nn_fsm_raiseto instread*/ void nn_fsm_feed (struct nn_fsm *self, int src, int type, void *srcptr); #endif nanomsg-1.1.5/src/aio/poller.c000066400000000000000000000026361336111550300161650ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved. 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. */ #include "poller.h" #if defined NN_USE_EPOLL #include "poller_epoll.inc" #elif defined NN_USE_KQUEUE #include "poller_kqueue.inc" #elif defined NN_USE_POLL #include "poller_poll.inc" #else #error #endif nanomsg-1.1.5/src/aio/poller.h000066400000000000000000000043321336111550300161650ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved. 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. */ #ifndef NN_POLLER_INCLUDED #define NN_POLLER_INCLUDED #define NN_POLLER_IN 1 #define NN_POLLER_OUT 2 #define NN_POLLER_ERR 3 #if defined NN_USE_EPOLL #include "poller_epoll.h" #elif defined NN_USE_KQUEUE #include "poller_kqueue.h" #elif defined NN_USE_POLL #include "poller_poll.h" #else #error #endif int nn_poller_init (struct nn_poller *self); void nn_poller_term (struct nn_poller *self); void nn_poller_add (struct nn_poller *self, int fd, struct nn_poller_hndl *hndl); void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl); void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl); void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl); void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl); void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl); int nn_poller_wait (struct nn_poller *self, int timeout); int nn_poller_event (struct nn_poller *self, int *event, struct nn_poller_hndl **hndl); #endif nanomsg-1.1.5/src/aio/poller_epoll.h000066400000000000000000000032131336111550300173550ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include #include #include #define NN_POLLER_HAVE_ASYNC_ADD 1 #define NN_POLLER_MAX_EVENTS 32 struct nn_poller_hndl { int fd; uint32_t events; }; struct nn_poller { /* Current pollset. */ int ep; /* Number of events being processed at the moment. */ int nevents; /* Index of the event being processed at the moment. */ int index; /* Events being processed at the moment. */ struct epoll_event events [NN_POLLER_MAX_EVENTS]; }; nanomsg-1.1.5/src/aio/poller_epoll.inc000066400000000000000000000144111336111550300177010ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "../utils/fast.h" #include "../utils/err.h" #include "../utils/closefd.h" #include #include #include int nn_poller_init (struct nn_poller *self) { #ifndef EPOLL_CLOEXEC int rc; #endif #ifdef EPOLL_CLOEXEC self->ep = epoll_create1 (EPOLL_CLOEXEC); #else /* Size parameter is unused, we can safely set it to 1. */ self->ep = epoll_create (1); rc = fcntl (self->ep, F_SETFD, FD_CLOEXEC); errno_assert (rc != -1); #endif if (self->ep == -1) { if (errno == ENFILE || errno == EMFILE) return -EMFILE; errno_assert (0); } self->nevents = 0; self->index = 0; return 0; } void nn_poller_term (struct nn_poller *self) { nn_closefd (self->ep); } void nn_poller_add (struct nn_poller *self, int fd, struct nn_poller_hndl *hndl) { struct epoll_event ev; /* Initialise the handle and add the file descriptor to the pollset. */ hndl->fd = fd; hndl->events = 0; memset (&ev, 0, sizeof (ev)); ev.events = 0; ev.data.ptr = (void*) hndl; epoll_ctl (self->ep, EPOLL_CTL_ADD, fd, &ev); } void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl) { int i; /* Remove the file descriptor from the pollset. */ epoll_ctl (self->ep, EPOLL_CTL_DEL, hndl->fd, NULL); /* Invalidate any subsequent events on this file descriptor. */ for (i = self->index; i != self->nevents; ++i) if (self->events [i].data.ptr == hndl) self->events [i].events = 0; } void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl) { struct epoll_event ev; /* If already polling for IN, do nothing. */ if (nn_slow (hndl->events & EPOLLIN)) return; /* Start polling for IN. */ hndl->events |= EPOLLIN; memset (&ev, 0, sizeof (ev)); ev.events = hndl->events; ev.data.ptr = (void*) hndl; epoll_ctl (self->ep, EPOLL_CTL_MOD, hndl->fd, &ev); } void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl) { int i; struct epoll_event ev; /* If not polling for IN, do nothing. */ if (nn_slow (!(hndl->events & EPOLLIN))) return; /* Stop polling for IN. */ hndl->events &= ~EPOLLIN; memset (&ev, 0, sizeof (ev)); ev.events = hndl->events; ev.data.ptr = (void*) hndl; epoll_ctl (self->ep, EPOLL_CTL_MOD, hndl->fd, &ev); /* Invalidate any subsequent IN events on this file descriptor. */ for (i = self->index; i != self->nevents; ++i) if (self->events [i].data.ptr == hndl) self->events [i].events &= ~EPOLLIN; } void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl) { struct epoll_event ev; int fd = hndl->fd; /* If already polling for OUT, do nothing. */ if (nn_slow (hndl->events & EPOLLOUT)) return; /* Start polling for OUT. */ hndl->events |= EPOLLOUT; memset (&ev, 0, sizeof (ev)); ev.events = hndl->events; ev.data.ptr = (void*) hndl; epoll_ctl (self->ep, EPOLL_CTL_MOD, fd, &ev); } void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl) { int i; struct epoll_event ev; /* If not polling for OUT, do nothing. */ if (nn_slow (!(hndl->events & EPOLLOUT))) return; /* Stop polling for OUT. */ hndl->events &= ~EPOLLOUT; memset (&ev, 0, sizeof (ev)); ev.events = hndl->events; ev.data.ptr = (void*) hndl; epoll_ctl (self->ep, EPOLL_CTL_MOD, hndl->fd, &ev); /* Invalidate any subsequent OUT events on this file descriptor. */ for (i = self->index; i != self->nevents; ++i) if (self->events [i].data.ptr == hndl) self->events [i].events &= ~EPOLLOUT; } int nn_poller_wait (struct nn_poller *self, int timeout) { int nevents; /* Clear all existing events. */ self->nevents = 0; self->index = 0; /* Wait for new events. */ while (1) { nevents = epoll_wait (self->ep, self->events, NN_POLLER_MAX_EVENTS, timeout); if (nn_slow (nevents == -1 && errno == EINTR)) continue; break; } errno_assert (self->nevents != -1); self->nevents = nevents; return 0; } int nn_poller_event (struct nn_poller *self, int *event, struct nn_poller_hndl **hndl) { /* Skip over empty events. */ while (self->index < self->nevents) { if (self->events [self->index].events != 0) break; ++self->index; } /* If there is no stored event, let the caller know. */ if (nn_slow (self->index >= self->nevents)) return -EAGAIN; /* Return next event to the caller. Remove the event from the set. */ *hndl = (struct nn_poller_hndl*) self->events [self->index].data.ptr; if (nn_fast (self->events [self->index].events & EPOLLIN)) { *event = NN_POLLER_IN; self->events [self->index].events &= ~EPOLLIN; return 0; } else if (nn_fast (self->events [self->index].events & EPOLLOUT)) { *event = NN_POLLER_OUT; self->events [self->index].events &= ~EPOLLOUT; return 0; } else { *event = NN_POLLER_ERR; ++self->index; return 0; } } nanomsg-1.1.5/src/aio/poller_kqueue.h000066400000000000000000000032041336111550300175410ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include #include #include #define NN_POLLER_MAX_EVENTS 32 #define NN_POLLER_EVENT_IN 1 #define NN_POLLER_EVENT_OUT 2 struct nn_poller_hndl { int fd; int events; }; struct nn_poller { /* Current pollset. */ int kq; /* Number of events being processed at the moment. */ int nevents; /* Index of the event being processed at the moment. */ int index; /* Cached events. */ struct kevent events [NN_POLLER_MAX_EVENTS]; }; nanomsg-1.1.5/src/aio/poller_kqueue.inc000066400000000000000000000142751336111550300200750ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "../utils/attr.h" #include "../utils/fast.h" #include "../utils/err.h" #include "../utils/closefd.h" #include /* NetBSD has different definition of udata. */ #if defined NN_HAVE_NETBSD #define nn_poller_udata intptr_t #else #define nn_poller_udata void* #endif int nn_poller_init (struct nn_poller *self) { self->kq = kqueue (); if (self->kq == -1) { if (errno == ENFILE || errno == EMFILE) return -EMFILE; errno_assert (0); } self->nevents = 0; self->index = 0; return 0; } void nn_poller_term (struct nn_poller *self) { nn_closefd (self->kq); } void nn_poller_add (NN_UNUSED struct nn_poller *self, int fd, struct nn_poller_hndl *hndl) { /* Initialise the handle. */ hndl->fd = fd; hndl->events = 0; } void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl) { struct kevent ev; int i; if (hndl->events & NN_POLLER_EVENT_IN) { EV_SET (&ev, hndl->fd, EVFILT_READ, EV_DELETE, 0, 0, 0); kevent (self->kq, &ev, 1, NULL, 0, NULL); } if (hndl->events & NN_POLLER_EVENT_OUT) { EV_SET (&ev, hndl->fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); kevent (self->kq, &ev, 1, NULL, 0, NULL); } /* Invalidate any subsequent events on this file descriptor. */ for (i = self->index; i != self->nevents; ++i) if (self->events [i].ident == (unsigned) hndl->fd) self->events [i].udata = (nn_poller_udata) NULL; } void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl) { int rc; struct kevent ev; if (!(hndl->events & NN_POLLER_EVENT_IN)) { EV_SET (&ev, hndl->fd, EVFILT_READ, EV_ADD, 0, 0, (nn_poller_udata) hndl); rc = kevent (self->kq, &ev, 1, NULL, 0, NULL); if (rc != -1) hndl->events |= NN_POLLER_EVENT_IN; } } void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl) { int rc; struct kevent ev; int i; if (hndl->events & NN_POLLER_EVENT_IN) { EV_SET (&ev, hndl->fd, EVFILT_READ, EV_DELETE, 0, 0, 0); rc = kevent (self->kq, &ev, 1, NULL, 0, NULL); hndl->events &= ~NN_POLLER_EVENT_IN; } /* Invalidate any subsequent IN events on this file descriptor. */ for (i = self->index; i != self->nevents; ++i) if (self->events [i].ident == (unsigned) hndl->fd && self->events [i].filter == EVFILT_READ) self->events [i].udata = (nn_poller_udata) NULL; } void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl) { int rc; struct kevent ev; int fd = hndl->fd; if (!(hndl->events & NN_POLLER_EVENT_OUT)) { EV_SET (&ev, fd, EVFILT_WRITE, EV_ADD, 0, 0, (nn_poller_udata) hndl); rc = kevent (self->kq, &ev, 1, NULL, 0, NULL); if (rc != -1) hndl->events |= NN_POLLER_EVENT_OUT; } } void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl) { int rc; struct kevent ev; int i; int fd = hndl->fd; if (hndl->events & NN_POLLER_EVENT_OUT) { EV_SET (&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0); rc = kevent (self->kq, &ev, 1, NULL, 0, NULL); if (rc != -1) { hndl->events &= ~NN_POLLER_EVENT_OUT; } } /* Invalidate any subsequent OUT events on this file descriptor. */ for (i = self->index; i != self->nevents; ++i) if (self->events [i].ident == (unsigned) hndl->fd && self->events [i].filter == EVFILT_WRITE) self->events [i].udata = (nn_poller_udata) NULL; } int nn_poller_wait (struct nn_poller *self, int timeout) { struct timespec ts; int nevents; /* Clear all existing events. */ self->nevents = 0; self->index = 0; /* Wait for new events. */ #if defined NN_IGNORE_EINTR again: #endif ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000000; nevents = kevent (self->kq, NULL, 0, &self->events [0], NN_POLLER_MAX_EVENTS, timeout >= 0 ? &ts : NULL); if (nevents == -1 && errno == EINTR) #if defined NN_IGNORE_EINTR goto again; #else return -EINTR; #endif errno_assert (nevents != -1); self->nevents = nevents; return 0; } int nn_poller_event (struct nn_poller *self, int *event, struct nn_poller_hndl **hndl) { /* Skip over empty events. */ while (self->index < self->nevents) { if (self->events [self->index].udata) break; ++self->index; } /* If there is no stored event, let the caller know. */ if (nn_slow (self->index >= self->nevents)) return -EAGAIN; /* Return next event to the caller. Remove the event from the set. */ *hndl = (struct nn_poller_hndl*) self->events [self->index].udata; if (self->events [self->index].flags & EV_EOF) *event = NN_POLLER_ERR; else if (self->events [self->index].filter == EVFILT_WRITE) *event = NN_POLLER_OUT; else if (self->events [self->index].filter == EVFILT_READ) *event = NN_POLLER_IN; else nn_assert (0); ++self->index; return 0; } nanomsg-1.1.5/src/aio/poller_poll.h000066400000000000000000000036631336111550300172210ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include #define NN_POLLER_HAVE_ASYNC_ADD 0 struct nn_poller_hndl { int index; }; struct nn_poller { /* Actual number of elements in the pollset. */ int size; /* Index of the event being processed at the moment. */ int index; /* Number of allocated elements in the pollset. */ int capacity; /* The pollset. */ struct pollfd *pollset; /* List of handles associated with elements in the pollset. Either points to the handle associated with the file descriptor (hndl) or is part of the list of removed pollitems (removed). */ struct nn_hndls_item { struct nn_poller_hndl *hndl; int prev; int next; } *hndls; /* List of removed pollitems, linked by indices. -1 means empty list. */ int removed; }; nanomsg-1.1.5/src/aio/poller_poll.inc000066400000000000000000000143411336111550300175360ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "../utils/alloc.h" #include "../utils/err.h" #define NN_POLLER_GRANULARITY 16 int nn_poller_init (struct nn_poller *self) { self->size = 0; self->index = 0; self->capacity = NN_POLLER_GRANULARITY; self->pollset = nn_alloc (sizeof (struct pollfd) * NN_POLLER_GRANULARITY, "pollset"); alloc_assert (self->pollset); self->hndls = nn_alloc (sizeof (struct nn_hndls_item) * NN_POLLER_GRANULARITY, "hndlset"); alloc_assert (self->hndls); self->removed = -1; return 0; } void nn_poller_term (struct nn_poller *self) { nn_free (self->pollset); nn_free (self->hndls); } void nn_poller_add (struct nn_poller *self, int fd, struct nn_poller_hndl *hndl) { int rc; /* If the capacity is too low to accommodate the next item, resize it. */ if (nn_slow (self->size >= self->capacity)) { self->capacity *= 2; self->pollset = nn_realloc (self->pollset, sizeof (struct pollfd) * self->capacity); alloc_assert (self->pollset); self->hndls = nn_realloc (self->hndls, sizeof (struct nn_hndls_item) * self->capacity); alloc_assert (self->hndls); } /* Add the fd to the pollset. */ self->pollset [self->size].fd = fd; self->pollset [self->size].events = 0; self->pollset [self->size].revents = 0; hndl->index = self->size; self->hndls [self->size].hndl = hndl; ++self->size; } void nn_poller_rm (struct nn_poller *self, struct nn_poller_hndl *hndl) { /* No more events will be reported on this fd. */ self->pollset [hndl->index].revents = 0; /* Add the fd into the list of removed fds. */ if (self->removed != -1) self->hndls [self->removed].prev = hndl->index; self->hndls [hndl->index].hndl = NULL; self->hndls [hndl->index].prev = -1; self->hndls [hndl->index].next = self->removed; self->removed = hndl->index; } void nn_poller_set_in (struct nn_poller *self, struct nn_poller_hndl *hndl) { self->pollset [hndl->index].events |= POLLIN; } void nn_poller_reset_in (struct nn_poller *self, struct nn_poller_hndl *hndl) { self->pollset [hndl->index].events &= ~POLLIN; self->pollset [hndl->index].revents &= ~POLLIN; } void nn_poller_set_out (struct nn_poller *self, struct nn_poller_hndl *hndl) { self->pollset [hndl->index].events |= POLLOUT; } void nn_poller_reset_out (struct nn_poller *self, struct nn_poller_hndl *hndl) { self->pollset [hndl->index].events &= ~POLLOUT; self->pollset [hndl->index].revents &= ~POLLOUT; } int nn_poller_wait (struct nn_poller *self, int timeout) { int rc; int i; /* First, get rid of removed fds. */ while (self->removed != -1) { /* Remove the fd from the list of removed fds. */ i = self->removed; self->removed = self->hndls [i].next; /* Replace the removed fd by the one at the end of the pollset. */ --self->size; if (i != self->size) { self->pollset [i] = self->pollset [self->size]; if (self->hndls [i].next != -1) self->hndls [self->hndls [i].next].prev = -1; self->hndls [i] = self->hndls [self->size]; if (self->hndls [i].hndl) self->hndls [i].hndl->index = i; } /* The fd from the end of the pollset may have been on removed fds list itself. If so, adjust the removed list. */ if (nn_slow (!self->hndls [i].hndl)) { if (self->hndls [i].prev != -1) self->hndls [self->hndls [i].prev].next = i; if (self->hndls [i].next != -1) self->hndls [self->hndls [i].next].prev = i; if (self->removed == self->size) self->removed = i; } } self->index = 0; /* Wait for new events. */ #if defined NN_IGNORE_EINTR again: #endif rc = poll (self->pollset, self->size, timeout); if (nn_slow (rc < 0 && errno == EINTR)) #if defined NN_IGNORE_EINTR goto again; #else return -EINTR; #endif errno_assert (rc >= 0); return 0; } int nn_poller_event (struct nn_poller *self, int *event, struct nn_poller_hndl **hndl) { int rc; /* Skip over empty events. This will also skip over removed fds as they have their revents nullified. */ while (self->index < self->size) { if (self->pollset [self->index].revents != 0) break; ++self->index; } /* If there is no available event, let the caller know. */ if (nn_slow (self->index >= self->size)) return -EAGAIN; /* Return next event to the caller. Remove the event from revents. */ *hndl = self->hndls [self->index].hndl; if (nn_fast (self->pollset [self->index].revents & POLLIN)) { *event = NN_POLLER_IN; self->pollset [self->index].revents &= ~POLLIN; return 0; } else if (nn_fast (self->pollset [self->index].revents & POLLOUT)) { *event = NN_POLLER_OUT; self->pollset [self->index].revents &= ~POLLOUT; return 0; } else { *event = NN_POLLER_ERR; ++self->index; return 0; } } nanomsg-1.1.5/src/aio/pool.c000066400000000000000000000030111336111550300156250ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "pool.h" /* TODO: The dummy implementation of a thread pool. As for now there's only one worker thread created. */ int nn_pool_init (struct nn_pool *self) { return nn_worker_init (&self->worker); } void nn_pool_term (struct nn_pool *self) { nn_worker_term (&self->worker); } struct nn_worker *nn_pool_choose_worker (struct nn_pool *self) { return &self->worker; } nanomsg-1.1.5/src/aio/pool.h000066400000000000000000000026611336111550300156440ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_POOL_INCLUDED #define NN_POOL_INCLUDED #include "worker.h" /* Worker thread pool. */ struct nn_pool { struct nn_worker worker; }; int nn_pool_init (struct nn_pool *self); void nn_pool_term (struct nn_pool *self); struct nn_worker *nn_pool_choose_worker (struct nn_pool *self); #endif nanomsg-1.1.5/src/aio/timer.c000066400000000000000000000140641336111550300160060ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. 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. */ #include "timer.h" #include "../utils/cont.h" #include "../utils/fast.h" #include "../utils/err.h" #include "../utils/attr.h" /* Timer state reflects the state as seen by the user thread. It says nothing about the state of affairs in the worker thread. */ #define NN_TIMER_STATE_IDLE 1 #define NN_TIMER_STATE_ACTIVE 2 #define NN_TIMER_STATE_STOPPING 3 #define NN_TIMER_SRC_START_TASK 1 #define NN_TIMER_SRC_STOP_TASK 2 /* Private functions. */ static void nn_timer_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_timer_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); void nn_timer_init (struct nn_timer *self, int src, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_timer_handler, nn_timer_shutdown, src, self, owner); self->state = NN_TIMER_STATE_IDLE; nn_worker_task_init (&self->start_task, NN_TIMER_SRC_START_TASK, &self->fsm); nn_worker_task_init (&self->stop_task, NN_TIMER_SRC_STOP_TASK, &self->fsm); nn_worker_timer_init (&self->wtimer, &self->fsm); nn_fsm_event_init (&self->done); self->worker = nn_fsm_choose_worker (&self->fsm); self->timeout = -1; } void nn_timer_term (struct nn_timer *self) { nn_assert_state (self, NN_TIMER_STATE_IDLE); nn_fsm_event_term (&self->done); nn_worker_timer_term (&self->wtimer); nn_worker_task_term (&self->stop_task); nn_worker_task_term (&self->start_task); nn_fsm_term (&self->fsm); } int nn_timer_isidle (struct nn_timer *self) { return nn_fsm_isidle (&self->fsm); } void nn_timer_start (struct nn_timer *self, int timeout) { /* Negative timeout make no sense. */ nn_assert (timeout >= 0); self->timeout = timeout; nn_fsm_start (&self->fsm); } void nn_timer_stop (struct nn_timer *self) { nn_fsm_stop (&self->fsm); } static void nn_timer_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_timer *timer; timer = nn_cont (self, struct nn_timer, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { timer->state = NN_TIMER_STATE_STOPPING; nn_worker_execute (timer->worker, &timer->stop_task); return; } if (nn_slow (timer->state == NN_TIMER_STATE_STOPPING)) { if (src != NN_TIMER_SRC_STOP_TASK) return; nn_assert (type == NN_WORKER_TASK_EXECUTE); nn_worker_rm_timer (timer->worker, &timer->wtimer); timer->state = NN_TIMER_STATE_IDLE; nn_fsm_stopped (&timer->fsm, NN_TIMER_STOPPED); return; } nn_fsm_bad_state(timer->state, src, type); } static void nn_timer_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_timer *timer; timer = nn_cont (self, struct nn_timer, fsm); switch (timer->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_TIMER_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: /* Send start event to the worker thread. */ timer->state = NN_TIMER_STATE_ACTIVE; nn_worker_execute (timer->worker, &timer->start_task); return; default: nn_fsm_bad_action (timer->state, src, type); } default: nn_fsm_bad_source (timer->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_TIMER_STATE_ACTIVE: if (src == NN_TIMER_SRC_START_TASK) { nn_assert (type == NN_WORKER_TASK_EXECUTE); nn_assert (timer->timeout >= 0); nn_worker_add_timer (timer->worker, timer->timeout, &timer->wtimer); timer->timeout = -1; return; } if (srcptr == &timer->wtimer) { switch (type) { case NN_WORKER_TIMER_TIMEOUT: /* Notify the user about the timeout. */ nn_assert (timer->timeout == -1); nn_fsm_raise (&timer->fsm, &timer->done, NN_TIMER_TIMEOUT); return; default: nn_fsm_bad_action (timer->state, src, type); } } nn_fsm_bad_source (timer->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (timer->state, src, type); } } nanomsg-1.1.5/src/aio/timer.h000066400000000000000000000034331336111550300160110ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_TIMER_INCLUDED #define NN_TIMER_INCLUDED #include "fsm.h" #include "worker.h" #define NN_TIMER_TIMEOUT 1 #define NN_TIMER_STOPPED 2 struct nn_timer { struct nn_fsm fsm; int state; struct nn_worker_task start_task; struct nn_worker_task stop_task; struct nn_worker_timer wtimer; struct nn_fsm_event done; struct nn_worker *worker; int timeout; }; void nn_timer_init (struct nn_timer *self, int src, struct nn_fsm *owner); void nn_timer_term (struct nn_timer *self); int nn_timer_isidle (struct nn_timer *self); void nn_timer_start (struct nn_timer *self, int timeout); void nn_timer_stop (struct nn_timer *self); #endif nanomsg-1.1.5/src/aio/timerset.c000066400000000000000000000101061336111550300165130ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "timerset.h" #include "../utils/fast.h" #include "../utils/cont.h" #include "../utils/clock.h" #include "../utils/err.h" void nn_timerset_init (struct nn_timerset *self) { nn_list_init (&self->timeouts); } void nn_timerset_term (struct nn_timerset *self) { nn_list_term (&self->timeouts); } int nn_timerset_add (struct nn_timerset *self, int timeout, struct nn_timerset_hndl *hndl) { struct nn_list_item *it; struct nn_timerset_hndl *ith; int first; /* Compute the instant when the timeout will be due. */ hndl->timeout = nn_clock_ms() + timeout; /* Insert it into the ordered list of timeouts. */ for (it = nn_list_begin (&self->timeouts); it != nn_list_end (&self->timeouts); it = nn_list_next (&self->timeouts, it)) { ith = nn_cont (it, struct nn_timerset_hndl, list); if (hndl->timeout < ith->timeout) break; } /* If the new timeout happens to be the first one to expire, let the user know that the current waiting interval has to be changed. */ first = nn_list_begin (&self->timeouts) == it ? 1 : 0; nn_list_insert (&self->timeouts, &hndl->list, it); return first; } int nn_timerset_rm (struct nn_timerset *self, struct nn_timerset_hndl *hndl) { int first; /* Ignore if handle is not in the timeouts list. */ if (!nn_list_item_isinlist (&hndl->list)) return 0; /* If it was the first timeout that was removed, the actual waiting time may have changed. We'll thus return 1 to let the user know. */ first = nn_list_begin (&self->timeouts) == &hndl->list ? 1 : 0; nn_list_erase (&self->timeouts, &hndl->list); return first; } int nn_timerset_timeout (struct nn_timerset *self) { int timeout; if (nn_fast (nn_list_empty (&self->timeouts))) return -1; timeout = (int) (nn_cont (nn_list_begin (&self->timeouts), struct nn_timerset_hndl, list)->timeout - nn_clock_ms()); return timeout < 0 ? 0 : timeout; } int nn_timerset_event (struct nn_timerset *self, struct nn_timerset_hndl **hndl) { struct nn_timerset_hndl *first; /* If there's no timeout, there's no event to report. */ if (nn_fast (nn_list_empty (&self->timeouts))) return -EAGAIN; /* If no timeout have expired yet, there's no event to return. */ first = nn_cont (nn_list_begin (&self->timeouts), struct nn_timerset_hndl, list); if (first->timeout > nn_clock_ms()) return -EAGAIN; /* Return the first timeout and remove it from the list of active timeouts. */ nn_list_erase (&self->timeouts, &first->list); *hndl = first; return 0; } void nn_timerset_hndl_init (struct nn_timerset_hndl *self) { nn_list_item_init (&self->list); } void nn_timerset_hndl_term (struct nn_timerset_hndl *self) { nn_list_item_term (&self->list); } int nn_timerset_hndl_isactive (struct nn_timerset_hndl *self) { return nn_list_item_isinlist (&self->list); } nanomsg-1.1.5/src/aio/timerset.h000066400000000000000000000041121336111550300165200ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_TIMERSET_INCLUDED #define NN_TIMERSET_INCLUDED #include #include "../utils/list.h" /* This class stores a list of timeouts and reports the next one to expire along with the time till it happens. */ struct nn_timerset_hndl { struct nn_list_item list; uint64_t timeout; }; struct nn_timerset { struct nn_list timeouts; }; void nn_timerset_init (struct nn_timerset *self); void nn_timerset_term (struct nn_timerset *self); int nn_timerset_add (struct nn_timerset *self, int timeout, struct nn_timerset_hndl *hndl); int nn_timerset_rm (struct nn_timerset *self, struct nn_timerset_hndl *hndl); int nn_timerset_timeout (struct nn_timerset *self); int nn_timerset_event (struct nn_timerset *self, struct nn_timerset_hndl **hndl); void nn_timerset_hndl_init (struct nn_timerset_hndl *self); void nn_timerset_hndl_term (struct nn_timerset_hndl *self); int nn_timerset_hndl_isactive (struct nn_timerset_hndl *self); #endif nanomsg-1.1.5/src/aio/usock.c000066400000000000000000000024741336111550300160140ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "usock.h" #if defined NN_HAVE_WINDOWS #include "usock_win.inc" #else #include "usock_posix.inc" #endif int nn_usock_geterrno (struct nn_usock *self) { return self->errnum; } nanomsg-1.1.5/src/aio/usock.h000066400000000000000000000071611336111550300160170ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_USOCK_INCLUDED #define NN_USOCK_INCLUDED /* Import the definition of nn_iovec. */ #include "../nn.h" /* OS-level sockets. */ /* Event types generated by nn_usock. */ #define NN_USOCK_CONNECTED 1 #define NN_USOCK_ACCEPTED 2 #define NN_USOCK_SENT 3 #define NN_USOCK_RECEIVED 4 #define NN_USOCK_ERROR 5 #define NN_USOCK_ACCEPT_ERROR 6 #define NN_USOCK_STOPPED 7 #define NN_USOCK_SHUTDOWN 8 /* Maximum number of iovecs that can be passed to nn_usock_send function. */ #define NN_USOCK_MAX_IOVCNT 3 /* Size of the buffer used for batch-reads of inbound data. To keep the performance optimal make sure that this value is larger than network MTU. */ #define NN_USOCK_BATCH_SIZE 2048 #if defined NN_HAVE_WINDOWS #include "usock_win.h" #else #include "usock_posix.h" #endif void nn_usock_init (struct nn_usock *self, int src, struct nn_fsm *owner); void nn_usock_term (struct nn_usock *self); int nn_usock_isidle (struct nn_usock *self); int nn_usock_start (struct nn_usock *self, int domain, int type, int protocol); void nn_usock_start_fd (struct nn_usock *self, int fd); void nn_usock_stop (struct nn_usock *self); void nn_usock_swap_owner (struct nn_usock *self, struct nn_fsm_owner *owner); int nn_usock_setsockopt (struct nn_usock *self, int level, int optname, const void *optval, size_t optlen); int nn_usock_bind (struct nn_usock *self, const struct sockaddr *addr, size_t addrlen); int nn_usock_listen (struct nn_usock *self, int backlog); /* Accept a new connection from a listener. When done, NN_USOCK_ACCEPTED event will be delivered to the accepted socket. To cancel the operation, stop the socket being accepted. Listening socket should not be stopped while accepting a new socket is underway. */ void nn_usock_accept (struct nn_usock *self, struct nn_usock *listener); /* When all the tuning is done on the accepted socket, call this function to activate standard data transfer phase. */ void nn_usock_activate (struct nn_usock *self); /* Start connecting. Prior to this call the socket has to be bound to a local address. When connecting is done NN_USOCK_CONNECTED event will be reaised. If connecting fails NN_USOCK_ERROR event will be raised. */ void nn_usock_connect (struct nn_usock *self, const struct sockaddr *addr, size_t addrlen); void nn_usock_send (struct nn_usock *self, const struct nn_iovec *iov, int iovcnt); void nn_usock_recv (struct nn_usock *self, void *buf, size_t len, int *fd); int nn_usock_geterrno (struct nn_usock *self); #endif nanomsg-1.1.5/src/aio/usock_posix.h000066400000000000000000000061451336111550300172420ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "fsm.h" #include "worker.h" #include #include #include struct nn_usock { /* State machine base class. */ struct nn_fsm fsm; int state; /* The worker thread the usock is associated with. */ struct nn_worker *worker; /* The underlying OS socket and handle that represents it in the poller. */ int s; struct nn_worker_fd wfd; /* Members related to receiving data. */ struct { /* The buffer being filled in at the moment. */ uint8_t *buf; size_t len; /* Buffer for batch-reading inbound data. */ uint8_t *batch; /* Size of the batch buffer. */ size_t batch_len; /* Current position in the batch buffer. The data preceding this position were already received by the user. The data that follow will be received in the future. */ size_t batch_pos; /* File descriptor received via SCM_RIGHTS, if any. */ int *pfd; } in; /* Members related to sending data. */ struct { /* msghdr being sent at the moment. */ struct msghdr hdr; /* List of buffers being sent at the moment. Referenced from 'hdr'. */ struct iovec iov [NN_USOCK_MAX_IOVCNT]; } out; /* Asynchronous tasks for the worker. */ struct nn_worker_task task_connecting; struct nn_worker_task task_connected; struct nn_worker_task task_accept; struct nn_worker_task task_send; struct nn_worker_task task_recv; struct nn_worker_task task_stop; /* Events raised by the usock. */ struct nn_fsm_event event_established; struct nn_fsm_event event_sent; struct nn_fsm_event event_received; struct nn_fsm_event event_error; /* In ACCEPTING state points to the socket being accepted. In BEING_ACCEPTED state points to the listener socket. */ struct nn_usock *asock; /* Errno remembered in NN_USOCK_ERROR state */ int errnum; }; nanomsg-1.1.5/src/aio/usock_posix.inc000066400000000000000000001233661336111550300175710ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #include "../utils/alloc.h" #include "../utils/closefd.h" #include "../utils/cont.h" #include "../utils/fast.h" #include "../utils/err.h" #include "../utils/attr.h" #include #include #include #include #define NN_USOCK_STATE_IDLE 1 #define NN_USOCK_STATE_STARTING 2 #define NN_USOCK_STATE_BEING_ACCEPTED 3 #define NN_USOCK_STATE_ACCEPTED 4 #define NN_USOCK_STATE_CONNECTING 5 #define NN_USOCK_STATE_ACTIVE 6 #define NN_USOCK_STATE_REMOVING_FD 7 #define NN_USOCK_STATE_DONE 8 #define NN_USOCK_STATE_LISTENING 9 #define NN_USOCK_STATE_ACCEPTING 10 #define NN_USOCK_STATE_CANCELLING 11 #define NN_USOCK_STATE_STOPPING 12 #define NN_USOCK_STATE_STOPPING_ACCEPT 13 #define NN_USOCK_STATE_ACCEPTING_ERROR 14 #define NN_USOCK_ACTION_ACCEPT 1 #define NN_USOCK_ACTION_BEING_ACCEPTED 2 #define NN_USOCK_ACTION_CANCEL 3 #define NN_USOCK_ACTION_LISTEN 4 #define NN_USOCK_ACTION_CONNECT 5 #define NN_USOCK_ACTION_ACTIVATE 6 #define NN_USOCK_ACTION_DONE 7 #define NN_USOCK_ACTION_ERROR 8 #define NN_USOCK_ACTION_STARTED 9 #define NN_USOCK_SRC_FD 1 #define NN_USOCK_SRC_TASK_CONNECTING 2 #define NN_USOCK_SRC_TASK_CONNECTED 3 #define NN_USOCK_SRC_TASK_ACCEPT 4 #define NN_USOCK_SRC_TASK_SEND 5 #define NN_USOCK_SRC_TASK_RECV 6 #define NN_USOCK_SRC_TASK_STOP 7 /* Private functions. */ static void nn_usock_init_from_fd (struct nn_usock *self, int s); static int nn_usock_send_raw (struct nn_usock *self, struct msghdr *hdr); static int nn_usock_recv_raw (struct nn_usock *self, void *buf, size_t *len); static int nn_usock_geterr (struct nn_usock *self); static void nn_usock_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_usock_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); void nn_usock_init (struct nn_usock *self, int src, struct nn_fsm *owner) { /* Initalise the state machine. */ nn_fsm_init (&self->fsm, nn_usock_handler, nn_usock_shutdown, src, self, owner); self->state = NN_USOCK_STATE_IDLE; /* Choose a worker thread to handle this socket. */ self->worker = nn_fsm_choose_worker (&self->fsm); /* Actual file descriptor will be generated during 'start' step. */ self->s = -1; self->errnum = 0; self->in.buf = NULL; self->in.len = 0; self->in.batch = NULL; self->in.batch_len = 0; self->in.batch_pos = 0; self->in.pfd = NULL; memset (&self->out.hdr, 0, sizeof (struct msghdr)); /* Initialise tasks for the worker thread. */ nn_worker_fd_init (&self->wfd, NN_USOCK_SRC_FD, &self->fsm); nn_worker_task_init (&self->task_connecting, NN_USOCK_SRC_TASK_CONNECTING, &self->fsm); nn_worker_task_init (&self->task_connected, NN_USOCK_SRC_TASK_CONNECTED, &self->fsm); nn_worker_task_init (&self->task_accept, NN_USOCK_SRC_TASK_ACCEPT, &self->fsm); nn_worker_task_init (&self->task_send, NN_USOCK_SRC_TASK_SEND, &self->fsm); nn_worker_task_init (&self->task_recv, NN_USOCK_SRC_TASK_RECV, &self->fsm); nn_worker_task_init (&self->task_stop, NN_USOCK_SRC_TASK_STOP, &self->fsm); /* Intialise events raised by usock. */ nn_fsm_event_init (&self->event_established); nn_fsm_event_init (&self->event_sent); nn_fsm_event_init (&self->event_received); nn_fsm_event_init (&self->event_error); /* accepting is not going on at the moment. */ self->asock = NULL; } void nn_usock_term (struct nn_usock *self) { nn_assert_state (self, NN_USOCK_STATE_IDLE); if (self->in.batch) nn_free (self->in.batch); nn_fsm_event_term (&self->event_error); nn_fsm_event_term (&self->event_received); nn_fsm_event_term (&self->event_sent); nn_fsm_event_term (&self->event_established); nn_worker_cancel (self->worker, &self->task_stop); nn_worker_cancel (self->worker, &self->task_recv); nn_worker_cancel (self->worker, &self->task_send); nn_worker_cancel (self->worker, &self->task_accept); nn_worker_cancel (self->worker, &self->task_connected); nn_worker_cancel (self->worker, &self->task_connecting); nn_worker_task_term (&self->task_stop); nn_worker_task_term (&self->task_recv); nn_worker_task_term (&self->task_send); nn_worker_task_term (&self->task_accept); nn_worker_task_term (&self->task_connected); nn_worker_task_term (&self->task_connecting); nn_worker_fd_term (&self->wfd); nn_fsm_term (&self->fsm); } int nn_usock_isidle (struct nn_usock *self) { return nn_fsm_isidle (&self->fsm); } int nn_usock_start (struct nn_usock *self, int domain, int type, int protocol) { int s; /* If the operating system allows to directly open the socket with CLOEXEC flag, do so. That way there are no race conditions. */ #ifdef SOCK_CLOEXEC type |= SOCK_CLOEXEC; #endif /* Open the underlying socket. */ s = socket (domain, type, protocol); if (nn_slow (s < 0)) return -errno; nn_usock_init_from_fd (self, s); /* Start the state machine. */ nn_fsm_start (&self->fsm); return 0; } void nn_usock_start_fd (struct nn_usock *self, int fd) { nn_usock_init_from_fd (self, fd); nn_fsm_start (&self->fsm); nn_fsm_action (&self->fsm, NN_USOCK_ACTION_STARTED); } static void nn_usock_init_from_fd (struct nn_usock *self, int s) { int rc; int opt; nn_assert (self->state == NN_USOCK_STATE_IDLE || self->state == NN_USOCK_STATE_BEING_ACCEPTED); /* Store the file descriptor. */ nn_assert (self->s == -1); self->s = s; /* Setting FD_CLOEXEC option immediately after socket creation is the second best option after using SOCK_CLOEXEC. There is a race condition here (if process is forked between socket creation and setting the option) but the problem is pretty unlikely to happen. */ #if defined FD_CLOEXEC rc = fcntl (self->s, F_SETFD, FD_CLOEXEC); #if defined NN_HAVE_OSX errno_assert (rc != -1 || errno == EINVAL); #else errno_assert (rc != -1); #endif #endif /* If applicable, prevent SIGPIPE signal when writing to the connection already closed by the peer. */ #ifdef SO_NOSIGPIPE opt = 1; rc = setsockopt (self->s, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof (opt)); #if defined NN_HAVE_OSX errno_assert (rc == 0 || errno == EINVAL); #else errno_assert (rc == 0); #endif #endif /* Switch the socket to the non-blocking mode. All underlying sockets are always used in the callbackhronous mode. */ opt = fcntl (self->s, F_GETFL, 0); if (opt == -1) opt = 0; if (!(opt & O_NONBLOCK)) { rc = fcntl (self->s, F_SETFL, opt | O_NONBLOCK); #if defined NN_HAVE_OSX errno_assert (rc != -1 || errno == EINVAL); #else errno_assert (rc != -1); #endif } } void nn_usock_stop (struct nn_usock *self) { nn_fsm_stop (&self->fsm); } void nn_usock_async_stop (struct nn_usock *self) { nn_worker_execute (self->worker, &self->task_stop); nn_fsm_raise (&self->fsm, &self->event_error, NN_USOCK_SHUTDOWN); } void nn_usock_swap_owner (struct nn_usock *self, struct nn_fsm_owner *owner) { nn_fsm_swap_owner (&self->fsm, owner); } int nn_usock_setsockopt (struct nn_usock *self, int level, int optname, const void *optval, size_t optlen) { int rc; /* The socket can be modified only before it's active. */ nn_assert (self->state == NN_USOCK_STATE_STARTING || self->state == NN_USOCK_STATE_ACCEPTED); /* EINVAL errors are ignored on OSX platform. The reason for that is buggy OSX behaviour where setsockopt returns EINVAL if the peer have already disconnected. Thus, nn_usock_setsockopt() can succeed on OSX even though the option value was invalid, but the peer have already closed the connection. This behaviour should be relatively harmless. */ rc = setsockopt (self->s, level, optname, optval, (socklen_t) optlen); #if defined NN_HAVE_OSX if (nn_slow (rc != 0 && errno != EINVAL)) return -errno; #else if (nn_slow (rc != 0)) return -errno; #endif return 0; } int nn_usock_bind (struct nn_usock *self, const struct sockaddr *addr, size_t addrlen) { int rc; int opt; /* The socket can be bound only before it's connected. */ nn_assert_state (self, NN_USOCK_STATE_STARTING); /* Windows Subsystem for Linux - SO_REUSEADDR is different, and the Windows semantics are very wrong for us. */ #ifndef NN_HAVE_WSL /* Allow re-using the address. */ opt = 1; rc = setsockopt (self->s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); errno_assert (rc == 0); #endif rc = bind (self->s, addr, (socklen_t) addrlen); if (nn_slow (rc != 0)) return -errno; return 0; } int nn_usock_listen (struct nn_usock *self, int backlog) { int rc; /* You can start listening only before the socket is connected. */ nn_assert_state (self, NN_USOCK_STATE_STARTING); /* Start listening for incoming connections. */ rc = listen (self->s, backlog); if (nn_slow (rc != 0)) return -errno; /* Notify the state machine. */ nn_fsm_action (&self->fsm, NN_USOCK_ACTION_LISTEN); return 0; } void nn_usock_accept (struct nn_usock *self, struct nn_usock *listener) { int s; /* Start the actual accepting. */ if (nn_fsm_isidle(&self->fsm)) { nn_fsm_start (&self->fsm); nn_fsm_action (&self->fsm, NN_USOCK_ACTION_BEING_ACCEPTED); } nn_fsm_action (&listener->fsm, NN_USOCK_ACTION_ACCEPT); /* Try to accept new connection in synchronous manner. */ #if NN_HAVE_ACCEPT4 s = accept4 (listener->s, NULL, NULL, SOCK_CLOEXEC); if ((s < 0) && (errno == ENOTSUP)) { /* Apparently some old versions of Linux have a stub for this in libc, without any of the underlying kernel support. */ s = accept (listener->s, NULL, NULL); } #else s = accept (listener->s, NULL, NULL); #endif /* Immediate success. */ if (nn_fast (s >= 0)) { /* Disassociate the listener socket from the accepted socket. Is useful if we restart accepting on ACCEPT_ERROR */ listener->asock = NULL; self->asock = NULL; nn_usock_init_from_fd (self, s); nn_fsm_action (&listener->fsm, NN_USOCK_ACTION_DONE); nn_fsm_action (&self->fsm, NN_USOCK_ACTION_DONE); return; } /* Detect a failure. Note that in ECONNABORTED case we simply ignore the error and wait for next connection in asynchronous manner. */ errno_assert (errno == EAGAIN || errno == EWOULDBLOCK || errno == ECONNABORTED || errno == ENFILE || errno == EMFILE || errno == ENOBUFS || errno == ENOMEM); /* Pair the two sockets. They are already paired in case previous attempt failed on ACCEPT_ERROR */ nn_assert (!self->asock || self->asock == listener); self->asock = listener; nn_assert (!listener->asock || listener->asock == self); listener->asock = self; /* Some errors are just ok to ignore for now. We also stop repeating any errors until next IN_FD event so that we are not in a tight loop and allow processing other events in the meantime */ if (nn_slow (errno != EAGAIN && errno != EWOULDBLOCK && errno != ECONNABORTED && errno != listener->errnum)) { listener->errnum = errno; listener->state = NN_USOCK_STATE_ACCEPTING_ERROR; nn_fsm_raise (&listener->fsm, &listener->event_error, NN_USOCK_ACCEPT_ERROR); return; } /* Ask the worker thread to wait for the new connection. */ nn_worker_execute (listener->worker, &listener->task_accept); } void nn_usock_activate (struct nn_usock *self) { nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ACTIVATE); } void nn_usock_connect (struct nn_usock *self, const struct sockaddr *addr, size_t addrlen) { int rc; /* Notify the state machine that we've started connecting. */ nn_fsm_action (&self->fsm, NN_USOCK_ACTION_CONNECT); /* Do the connect itself. */ rc = connect (self->s, addr, (socklen_t) addrlen); /* Immediate success. */ if (nn_fast (rc == 0)) { nn_fsm_action (&self->fsm, NN_USOCK_ACTION_DONE); return; } /* Immediate error. */ if (nn_slow (errno != EINPROGRESS)) { self->errnum = errno; nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR); return; } /* Start asynchronous connect. */ nn_worker_execute (self->worker, &self->task_connecting); } void nn_usock_send (struct nn_usock *self, const struct nn_iovec *iov, int iovcnt) { int rc; int i; int out; /* Make sure that the socket is actually alive. */ if (self->state != NN_USOCK_STATE_ACTIVE) { nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR); return; } /* Copy the iovecs to the socket. */ nn_assert (iovcnt <= NN_USOCK_MAX_IOVCNT); self->out.hdr.msg_iov = self->out.iov; out = 0; for (i = 0; i != iovcnt; ++i) { if (iov [i].iov_len == 0) continue; self->out.iov [out].iov_base = iov [i].iov_base; self->out.iov [out].iov_len = iov [i].iov_len; out++; } self->out.hdr.msg_iovlen = out; /* Try to send the data immediately. */ rc = nn_usock_send_raw (self, &self->out.hdr); /* Success. */ if (nn_fast (rc == 0)) { nn_fsm_raise (&self->fsm, &self->event_sent, NN_USOCK_SENT); return; } /* Errors. */ if (nn_slow (rc != -EAGAIN)) { errnum_assert (rc == -ECONNRESET, -rc); nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR); return; } /* Ask the worker thread to send the remaining data. */ nn_worker_execute (self->worker, &self->task_send); } void nn_usock_recv (struct nn_usock *self, void *buf, size_t len, int *fd) { int rc; size_t nbytes; /* Make sure that the socket is actually alive. */ if (self->state != NN_USOCK_STATE_ACTIVE) { nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR); return; } /* Try to receive the data immediately. */ nbytes = len; self->in.pfd = fd; rc = nn_usock_recv_raw (self, buf, &nbytes); if (nn_slow (rc < 0)) { errnum_assert (rc == -ECONNRESET, -rc); nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR); return; } /* Success. */ if (nn_fast (nbytes == len)) { nn_fsm_raise (&self->fsm, &self->event_received, NN_USOCK_RECEIVED); return; } /* There are still data to receive in the background. */ self->in.buf = ((uint8_t*) buf) + nbytes; self->in.len = len - nbytes; /* Ask the worker thread to receive the remaining data. */ nn_worker_execute (self->worker, &self->task_recv); } static int nn_internal_tasks (struct nn_usock *usock, int src, int type) { /******************************************************************************/ /* Internal tasks sent from the user thread to the worker thread. */ /******************************************************************************/ switch (src) { case NN_USOCK_SRC_TASK_SEND: nn_assert (type == NN_WORKER_TASK_EXECUTE); nn_worker_set_out (usock->worker, &usock->wfd); return 1; case NN_USOCK_SRC_TASK_RECV: nn_assert (type == NN_WORKER_TASK_EXECUTE); nn_worker_set_in (usock->worker, &usock->wfd); return 1; case NN_USOCK_SRC_TASK_CONNECTED: nn_assert (type == NN_WORKER_TASK_EXECUTE); nn_worker_add_fd (usock->worker, usock->s, &usock->wfd); return 1; case NN_USOCK_SRC_TASK_CONNECTING: nn_assert (type == NN_WORKER_TASK_EXECUTE); nn_worker_add_fd (usock->worker, usock->s, &usock->wfd); nn_worker_set_out (usock->worker, &usock->wfd); return 1; case NN_USOCK_SRC_TASK_ACCEPT: nn_assert (type == NN_WORKER_TASK_EXECUTE); nn_worker_add_fd (usock->worker, usock->s, &usock->wfd); nn_worker_set_in (usock->worker, &usock->wfd); return 1; } return 0; } static void nn_usock_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_usock *usock; usock = nn_cont (self, struct nn_usock, fsm); if (nn_internal_tasks (usock, src, type)) return; if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { /* Socket in ACCEPTING or CANCELLING state cannot be closed. Stop the socket being accepted first. */ nn_assert (usock->state != NN_USOCK_STATE_ACCEPTING && usock->state != NN_USOCK_STATE_CANCELLING); usock->errnum = 0; /* Synchronous stop. */ if (usock->state == NN_USOCK_STATE_IDLE) goto finish3; if (usock->state == NN_USOCK_STATE_DONE) goto finish2; if (usock->state == NN_USOCK_STATE_STARTING || usock->state == NN_USOCK_STATE_ACCEPTED || usock->state == NN_USOCK_STATE_ACCEPTING_ERROR || usock->state == NN_USOCK_STATE_LISTENING) goto finish1; /* When socket that's being accepted is asked to stop, we have to ask the listener socket to stop accepting first. */ if (usock->state == NN_USOCK_STATE_BEING_ACCEPTED) { nn_fsm_action (&usock->asock->fsm, NN_USOCK_ACTION_CANCEL); usock->state = NN_USOCK_STATE_STOPPING_ACCEPT; return; } /* Asynchronous stop. */ if (usock->state != NN_USOCK_STATE_REMOVING_FD) nn_usock_async_stop (usock); usock->state = NN_USOCK_STATE_STOPPING; return; } if (nn_slow (usock->state == NN_USOCK_STATE_STOPPING_ACCEPT)) { nn_assert (src == NN_FSM_ACTION && type == NN_USOCK_ACTION_DONE); goto finish2; } if (nn_slow (usock->state == NN_USOCK_STATE_STOPPING)) { if (src != NN_USOCK_SRC_TASK_STOP) return; nn_assert (type == NN_WORKER_TASK_EXECUTE); nn_worker_rm_fd (usock->worker, &usock->wfd); finish1: nn_closefd (usock->s); usock->s = -1; finish2: usock->state = NN_USOCK_STATE_IDLE; nn_fsm_stopped (&usock->fsm, NN_USOCK_STOPPED); finish3: return; } nn_fsm_bad_state(usock->state, src, type); } static void nn_usock_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { int rc; struct nn_usock *usock; int s; size_t sz; int sockerr; usock = nn_cont (self, struct nn_usock, fsm); if(nn_internal_tasks(usock, src, type)) return; switch (usock->state) { /******************************************************************************/ /* IDLE state. */ /* nn_usock object is initialised, but underlying OS socket is not yet */ /* created. */ /******************************************************************************/ case NN_USOCK_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: usock->state = NN_USOCK_STATE_STARTING; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* STARTING state. */ /* Underlying OS socket is created, but it's not yet passed to the worker */ /* thread. In this state we can set socket options, local and remote */ /* address etc. */ /******************************************************************************/ case NN_USOCK_STATE_STARTING: /* Events from the owner of the usock. */ switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_LISTEN: usock->state = NN_USOCK_STATE_LISTENING; return; case NN_USOCK_ACTION_CONNECT: usock->state = NN_USOCK_STATE_CONNECTING; return; case NN_USOCK_ACTION_BEING_ACCEPTED: usock->state = NN_USOCK_STATE_BEING_ACCEPTED; return; case NN_USOCK_ACTION_STARTED: nn_worker_add_fd (usock->worker, usock->s, &usock->wfd); usock->state = NN_USOCK_STATE_ACTIVE; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* BEING_ACCEPTED state. */ /* accept() was called on the usock. Now the socket is waiting for a new */ /* connection to arrive. */ /******************************************************************************/ case NN_USOCK_STATE_BEING_ACCEPTED: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_DONE: usock->state = NN_USOCK_STATE_ACCEPTED; nn_fsm_raise (&usock->fsm, &usock->event_established, NN_USOCK_ACCEPTED); return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* ACCEPTED state. */ /* Connection was accepted, now it can be tuned. Afterwards, it'll move to */ /* the active state. */ /******************************************************************************/ case NN_USOCK_STATE_ACCEPTED: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ACTIVATE: nn_worker_add_fd (usock->worker, usock->s, &usock->wfd); usock->state = NN_USOCK_STATE_ACTIVE; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* CONNECTING state. */ /* Asynchronous connecting is going on. */ /******************************************************************************/ case NN_USOCK_STATE_CONNECTING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_DONE: usock->state = NN_USOCK_STATE_ACTIVE; nn_worker_execute (usock->worker, &usock->task_connected); nn_fsm_raise (&usock->fsm, &usock->event_established, NN_USOCK_CONNECTED); return; case NN_USOCK_ACTION_ERROR: nn_closefd (usock->s); usock->s = -1; usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_USOCK_SRC_FD: switch (type) { case NN_WORKER_FD_OUT: nn_worker_reset_out (usock->worker, &usock->wfd); usock->state = NN_USOCK_STATE_ACTIVE; sockerr = nn_usock_geterr(usock); if (sockerr == 0) { nn_fsm_raise (&usock->fsm, &usock->event_established, NN_USOCK_CONNECTED); } else { usock->errnum = sockerr; nn_worker_rm_fd (usock->worker, &usock->wfd); rc = close (usock->s); errno_assert (rc == 0); usock->s = -1; usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); } return; case NN_WORKER_FD_ERR: nn_worker_rm_fd (usock->worker, &usock->wfd); nn_closefd (usock->s); usock->s = -1; usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Socket is connected. It can be used for sending and receiving data. */ /******************************************************************************/ case NN_USOCK_STATE_ACTIVE: switch (src) { case NN_USOCK_SRC_FD: switch (type) { case NN_WORKER_FD_IN: sz = usock->in.len; rc = nn_usock_recv_raw (usock, usock->in.buf, &sz); if (nn_fast (rc == 0)) { usock->in.len -= sz; usock->in.buf += sz; if (!usock->in.len) { nn_worker_reset_in (usock->worker, &usock->wfd); nn_fsm_raise (&usock->fsm, &usock->event_received, NN_USOCK_RECEIVED); } return; } errnum_assert (rc == -ECONNRESET, -rc); goto error; case NN_WORKER_FD_OUT: rc = nn_usock_send_raw (usock, &usock->out.hdr); if (nn_fast (rc == 0)) { nn_worker_reset_out (usock->worker, &usock->wfd); nn_fsm_raise (&usock->fsm, &usock->event_sent, NN_USOCK_SENT); return; } if (nn_fast (rc == -EAGAIN)) return; errnum_assert (rc == -ECONNRESET, -rc); goto error; case NN_WORKER_FD_ERR: error: nn_worker_rm_fd (usock->worker, &usock->wfd); nn_closefd (usock->s); usock->s = -1; usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ERROR: usock->state = NN_USOCK_STATE_REMOVING_FD; nn_usock_async_stop (usock); return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source(usock->state, src, type); } /******************************************************************************/ /* REMOVING_FD state. */ /******************************************************************************/ case NN_USOCK_STATE_REMOVING_FD: switch (src) { case NN_USOCK_SRC_TASK_STOP: switch (type) { case NN_WORKER_TASK_EXECUTE: nn_worker_rm_fd (usock->worker, &usock->wfd); nn_closefd (usock->s); usock->s = -1; usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); return; default: nn_fsm_bad_action (usock->state, src, type); } /* Events from the file descriptor are ignored while it is being removed. */ case NN_USOCK_SRC_FD: return; case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ERROR: return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* DONE state. */ /* Socket is closed. The only thing that can be done in this state is */ /* stopping the usock. */ /******************************************************************************/ case NN_USOCK_STATE_DONE: return; /******************************************************************************/ /* LISTENING state. */ /* Socket is listening for new incoming connections, however, user is not */ /* accepting a new connection. */ /******************************************************************************/ case NN_USOCK_STATE_LISTENING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ACCEPT: usock->state = NN_USOCK_STATE_ACCEPTING; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* ACCEPTING state. */ /* User is waiting asynchronouslyfor a new inbound connection */ /* to be accepted. */ /******************************************************************************/ case NN_USOCK_STATE_ACCEPTING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_DONE: usock->state = NN_USOCK_STATE_LISTENING; return; case NN_USOCK_ACTION_CANCEL: usock->state = NN_USOCK_STATE_CANCELLING; nn_worker_execute (usock->worker, &usock->task_stop); return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_USOCK_SRC_FD: switch (type) { case NN_WORKER_FD_IN: /* New connection arrived in asynchronous manner. */ #if NN_HAVE_ACCEPT4 s = accept4 (usock->s, NULL, NULL, SOCK_CLOEXEC); #else s = accept (usock->s, NULL, NULL); #endif /* ECONNABORTED is an valid error. New connection was closed by the peer before we were able to accept it. If it happens do nothing and wait for next incoming connection. */ if (nn_slow (s < 0 && errno == ECONNABORTED)) return; /* Resource allocation errors. It's not clear from POSIX specification whether the new connection is closed in this case or whether it remains in the backlog. In the latter case it would be wise to wait here for a while to prevent busy looping. */ if (nn_slow (s < 0 && (errno == ENFILE || errno == EMFILE || errno == ENOBUFS || errno == ENOMEM))) { usock->errnum = errno; usock->state = NN_USOCK_STATE_ACCEPTING_ERROR; /* Wait till the user starts accepting once again. */ nn_worker_rm_fd (usock->worker, &usock->wfd); nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ACCEPT_ERROR); return; } /* Any other error is unexpected. */ errno_assert (s >= 0); /* Initialise the new usock object. */ nn_usock_init_from_fd (usock->asock, s); usock->asock->state = NN_USOCK_STATE_ACCEPTED; /* Notify the user that connection was accepted. */ nn_fsm_raise (&usock->asock->fsm, &usock->asock->event_established, NN_USOCK_ACCEPTED); /* Disassociate the listener socket from the accepted socket. */ usock->asock->asock = NULL; usock->asock = NULL; /* Wait till the user starts accepting once again. */ nn_worker_rm_fd (usock->worker, &usock->wfd); usock->state = NN_USOCK_STATE_LISTENING; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* ACCEPTING_ERROR state. */ /* Waiting the socket to accept the error and restart */ /******************************************************************************/ case NN_USOCK_STATE_ACCEPTING_ERROR: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ACCEPT: usock->state = NN_USOCK_STATE_ACCEPTING; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* CANCELLING state. */ /******************************************************************************/ case NN_USOCK_STATE_CANCELLING: switch (src) { case NN_USOCK_SRC_TASK_STOP: switch (type) { case NN_WORKER_TASK_EXECUTE: nn_worker_rm_fd (usock->worker, &usock->wfd); usock->state = NN_USOCK_STATE_LISTENING; /* Notify the accepted socket that it was stopped. */ nn_fsm_action (&usock->asock->fsm, NN_USOCK_ACTION_DONE); return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_USOCK_SRC_FD: switch (type) { case NN_WORKER_FD_IN: return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* Invalid state */ /******************************************************************************/ default: nn_fsm_bad_state (usock->state, src, type); } } static int nn_usock_send_raw (struct nn_usock *self, struct msghdr *hdr) { ssize_t nbytes; /* Try to send the data. */ #if defined MSG_NOSIGNAL nbytes = sendmsg (self->s, hdr, MSG_NOSIGNAL); #else nbytes = sendmsg (self->s, hdr, 0); #endif /* Handle errors. */ if (nn_slow (nbytes < 0)) { if (nn_fast (errno == EAGAIN || errno == EWOULDBLOCK)) nbytes = 0; else { /* If the connection fails, return ECONNRESET. */ return -ECONNRESET; } } /* Some bytes were sent. Adjust the iovecs accordingly. */ while (nbytes) { if (nbytes >= (ssize_t)hdr->msg_iov->iov_len) { --hdr->msg_iovlen; if (!hdr->msg_iovlen) { nn_assert (nbytes == (ssize_t)hdr->msg_iov->iov_len); return 0; } nbytes -= hdr->msg_iov->iov_len; ++hdr->msg_iov; } else { *((uint8_t**) &(hdr->msg_iov->iov_base)) += nbytes; hdr->msg_iov->iov_len -= nbytes; return -EAGAIN; } } if (hdr->msg_iovlen > 0) return -EAGAIN; return 0; } static int nn_usock_recv_raw (struct nn_usock *self, void *buf, size_t *len) { size_t sz; size_t length; ssize_t nbytes; struct iovec iov; struct msghdr hdr; unsigned char ctrl [256]; #if defined NN_HAVE_MSG_CONTROL struct cmsghdr *cmsg; #endif int fd; /* If batch buffer doesn't exist, allocate it. The point of delayed deallocation to allow non-receiving sockets, such as TCP listening sockets, to do without the batch buffer. */ if (nn_slow (!self->in.batch)) { self->in.batch = nn_alloc (NN_USOCK_BATCH_SIZE, "AIO batch buffer"); alloc_assert (self->in.batch); } /* Try to satisfy the recv request by data from the batch buffer. */ length = *len; sz = self->in.batch_len - self->in.batch_pos; if (sz) { if (sz > length) sz = length; memcpy (buf, self->in.batch + self->in.batch_pos, sz); self->in.batch_pos += sz; buf = ((char*) buf) + sz; length -= sz; if (!length) return 0; } /* If recv request is greater than the batch buffer, get the data directly into the place. Otherwise, read data to the batch buffer. */ if (length > NN_USOCK_BATCH_SIZE) { iov.iov_base = buf; iov.iov_len = length; } else { iov.iov_base = self->in.batch; iov.iov_len = NN_USOCK_BATCH_SIZE; } memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; #if defined NN_HAVE_MSG_CONTROL hdr.msg_control = ctrl; hdr.msg_controllen = sizeof (ctrl); #else *((int*) ctrl) = -1; hdr.msg_accrights = ctrl; hdr.msg_accrightslen = sizeof (int); #endif nbytes = recvmsg (self->s, &hdr, 0); /* Handle any possible errors. */ if (nn_slow (nbytes <= 0)) { if (nn_slow (nbytes == 0)) return -ECONNRESET; /* Zero bytes received. */ if (nn_fast (errno == EAGAIN || errno == EWOULDBLOCK)) nbytes = 0; else { /* If the peer closes the connection, return ECONNRESET. */ return -ECONNRESET; } } /* Extract the associated file descriptor, if any. */ if (nbytes > 0) { #if defined NN_HAVE_MSG_CONTROL cmsg = CMSG_FIRSTHDR (&hdr); while (cmsg) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { if (self->in.pfd) { memcpy (self->in.pfd, CMSG_DATA (cmsg), sizeof (*self->in.pfd)); self->in.pfd = NULL; } else { memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd)); nn_closefd (fd); } break; } cmsg = CMSG_NXTHDR (&hdr, cmsg); } #else if (hdr.msg_accrightslen > 0) { nn_assert (hdr.msg_accrightslen == sizeof (int)); if (self->in.pfd) { memcpy (self->in.pfd, hdr.msg_accrights, sizeof (*self->in.pfd)); self->in.pfd = NULL; } else { memcpy (&fd, hdr.msg_accrights, sizeof (fd)); nn_closefd (fd); } } #endif } /* If the data were received directly into the place we can return straight away. */ if (length > NN_USOCK_BATCH_SIZE) { length -= nbytes; *len -= length; return 0; } /* New data were read to the batch buffer. Copy the requested amount of it to the user-supplied buffer. */ self->in.batch_len = nbytes; self->in.batch_pos = 0; if (nbytes) { sz = nbytes > (ssize_t)length ? length : (size_t)nbytes; memcpy (buf, self->in.batch, sz); length -= sz; self->in.batch_pos += sz; } *len -= length; return 0; } static int nn_usock_geterr (struct nn_usock *self) { int rc; int opt; #if defined NN_HAVE_HPUX int optsz; #else socklen_t optsz; #endif opt = 0; optsz = sizeof (opt); rc = getsockopt (self->s, SOL_SOCKET, SO_ERROR, &opt, &optsz); /* The following should handle both Solaris and UNIXes derived from BSD. */ if (rc == -1) return errno; errno_assert (rc == 0); nn_assert (optsz == sizeof (opt)); return opt; } nanomsg-1.1.5/src/aio/usock_win.h000066400000000000000000000056411336111550300166750ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "fsm.h" #include "worker.h" #include "../utils/win.h" struct nn_usock { /* The state machine. */ struct nn_fsm fsm; int state; union { /* The actual underlying socket. Can be used as a HANDLE too. */ SOCKET s; /* Named pipe handle. Cannot be used as a SOCKET. */ HANDLE p; }; /* For NamedPipes, closing an accepted pipe differs from other pipes. If the NamedPipe was accepted, this member is set to 1. 0 otherwise. */ int isaccepted; /* Asynchronous operations being executed on the socket. */ struct nn_worker_op in; struct nn_worker_op out; /* When accepting new socket, they have to be created with same type as the listening socket. Thus, in listening socket we have to store its exact type. */ int domain; int type; int protocol; /* Events raised by the usock. */ struct nn_fsm_event event_established; struct nn_fsm_event event_sent; struct nn_fsm_event event_received; struct nn_fsm_event event_error; /* In ACCEPTING state points to the socket being accepted. In BEING_ACCEPTED state points to the listener socket. */ struct nn_usock *asock; /* Buffer allocated for output of AcceptEx function. If accepting is not done on this socket, the field is set to NULL. */ void *ainfo; /* For NamedPipes, we store the address inside the socket. */ struct sockaddr_un pipename; /* For now we allocate a new buffer for each write to a named pipe. */ void *pipesendbuf; /* Pointer to the security attribute structure */ SECURITY_ATTRIBUTES *sec_attr; /* Out Buffer and In Buffer size */ int outbuffersz; int inbuffersz; /* Errno remembered in NN_USOCK_ERROR state */ int errnum; }; nanomsg-1.1.5/src/aio/usock_win.inc000066400000000000000000001072641336111550300172230ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2018 Staysail Systems, Inc. Copyright 2018 Capitar IT Group BV 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. */ #include "worker.h" #include "../utils/err.h" #include "../utils/cont.h" #include "../utils/alloc.h" #include #include #include #define NN_USOCK_STATE_IDLE 1 #define NN_USOCK_STATE_STARTING 2 #define NN_USOCK_STATE_BEING_ACCEPTED 3 #define NN_USOCK_STATE_ACCEPTED 4 #define NN_USOCK_STATE_CONNECTING 5 #define NN_USOCK_STATE_ACTIVE 6 #define NN_USOCK_STATE_CANCELLING_IO 7 #define NN_USOCK_STATE_DONE 8 #define NN_USOCK_STATE_LISTENING 9 #define NN_USOCK_STATE_ACCEPTING 10 #define NN_USOCK_STATE_CANCELLING 11 #define NN_USOCK_STATE_STOPPING 12 #define NN_USOCK_STATE_STOPPING_ACCEPT 13 #define NN_USOCK_ACTION_ACCEPT 1 #define NN_USOCK_ACTION_BEING_ACCEPTED 2 #define NN_USOCK_ACTION_CANCEL 3 #define NN_USOCK_ACTION_LISTEN 4 #define NN_USOCK_ACTION_CONNECT 5 #define NN_USOCK_ACTION_ACTIVATE 6 #define NN_USOCK_ACTION_DONE 7 #define NN_USOCK_ACTION_ERROR 8 #define NN_USOCK_SRC_IN 1 #define NN_USOCK_SRC_OUT 2 /* Private functions. */ static void nn_usock_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_usock_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static int nn_usock_cancel_io (struct nn_usock *self); static void nn_usock_create_io_completion (struct nn_usock *self); DWORD nn_usock_open_pipe (struct nn_usock *self, const char *name); void nn_usock_accept_pipe (struct nn_usock *self, struct nn_usock *listener); void nn_usock_init (struct nn_usock *self, int src, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_usock_handler, nn_usock_shutdown, src, self, owner); self->state = NN_USOCK_STATE_IDLE; self->s = INVALID_SOCKET; self->isaccepted = 0; nn_worker_op_init (&self->in, NN_USOCK_SRC_IN, &self->fsm); nn_worker_op_init (&self->out, NN_USOCK_SRC_OUT, &self->fsm); self->domain = -1; self->type = -1; self->protocol = -1; /* Intialise events raised by usock. */ nn_fsm_event_init (&self->event_established); nn_fsm_event_init (&self->event_sent); nn_fsm_event_init (&self->event_received); nn_fsm_event_init (&self->event_error); /* No accepting is going on at the moment. */ self->asock = NULL; self->ainfo = NULL; /* NamedPipe-related stuff. */ memset (&self->pipename, 0, sizeof (self->pipename)); self->pipesendbuf = NULL; self->sec_attr = NULL; /* default size for both in and out buffers is 4096 */ self->outbuffersz = 4096; self->inbuffersz = 4096; } void nn_usock_term (struct nn_usock *self) { nn_assert_state (self, NN_USOCK_STATE_IDLE); if (self->ainfo) nn_free (self->ainfo); if (self->pipesendbuf) nn_free (self->pipesendbuf); nn_fsm_event_term (&self->event_error); nn_fsm_event_term (&self->event_received); nn_fsm_event_term (&self->event_sent); nn_fsm_event_term (&self->event_established); nn_worker_op_term (&self->out); nn_worker_op_term (&self->in); nn_fsm_term (&self->fsm); } int nn_usock_isidle (struct nn_usock *self) { return nn_fsm_isidle (&self->fsm); } int nn_usock_start (struct nn_usock *self, int domain, int type, int protocol) { int rc; #if defined IPV6_V6ONLY DWORD only; #endif #if defined HANDLE_FLAG_INHERIT BOOL brc; #endif /* NamedPipes aren't sockets. They don't need all the socket initialisation stuff. */ if (domain != AF_UNIX) { /* Open the underlying socket. */ self->s = socket (domain, type, protocol); if (self->s == INVALID_SOCKET) return -nn_err_wsa_to_posix (WSAGetLastError ()); /* Disable inheriting the socket to the child processes. */ #if defined HANDLE_FLAG_INHERIT brc = SetHandleInformation (self->p, HANDLE_FLAG_INHERIT, 0); win_assert (brc); #endif /* IPv4 mapping for IPv6 sockets is disabled by default. Switch it on. */ #if defined IPV6_V6ONLY if (domain == AF_INET6) { only = 0; rc = setsockopt (self->s, IPPROTO_IPV6, IPV6_V6ONLY, (const char*) &only, sizeof (only)); wsa_assert (rc != SOCKET_ERROR); } #endif /* Associate the socket with a worker thread/completion port. */ nn_usock_create_io_completion (self); } /* Remember the type of the socket. */ self->domain = domain; self->type = type; self->protocol = protocol; /* Start the state machine. */ nn_fsm_start (&self->fsm); return 0; } void nn_usock_start_fd (struct nn_usock *self, int fd) { nn_assert (0); } void nn_usock_stop (struct nn_usock *self) { nn_fsm_stop (&self->fsm); } void nn_usock_swap_owner (struct nn_usock *self, struct nn_fsm_owner *owner) { nn_fsm_swap_owner (&self->fsm, owner); } int nn_usock_setsockopt (struct nn_usock *self, int level, int optname, const void *optval, size_t optlen) { int rc; /* NamedPipes aren't sockets. We can't set socket options on them. For now we'll ignore the options. */ if (self->domain == AF_UNIX) return 0; /* The socket can be modified only before it's active. */ nn_assert (self->state == NN_USOCK_STATE_STARTING || self->state == NN_USOCK_STATE_ACCEPTED); nn_assert (optlen < INT_MAX); rc = setsockopt (self->s, level, optname, (char*) optval, (int) optlen); if (nn_slow (rc == SOCKET_ERROR)) return -nn_err_wsa_to_posix (WSAGetLastError ()); return 0; } int nn_usock_bind (struct nn_usock *self, const struct sockaddr *addr, size_t addrlen) { int rc; ULONG opt; /* In the case of named pipes, let's save the address for the later use. */ if (self->domain == AF_UNIX) { if (addrlen > sizeof (struct sockaddr_un)) return -EINVAL; memcpy (&self->pipename, addr, addrlen); return 0; } /* You can set socket options only before the socket is connected. */ nn_assert_state (self, NN_USOCK_STATE_STARTING); /* On Windows, the bound port can be hijacked if SO_EXCLUSIVEADDRUSE is not set. */ opt = 1; rc = setsockopt (self->s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*) &opt, sizeof (opt)); wsa_assert (rc != SOCKET_ERROR); nn_assert (addrlen < INT_MAX); rc = bind (self->s, addr, (int) addrlen); if (nn_slow (rc == SOCKET_ERROR)) return -nn_err_wsa_to_posix (WSAGetLastError ()); return 0; } int nn_usock_listen (struct nn_usock *self, int backlog) { int rc; /* You can start listening only before the socket is connected. */ nn_assert_state (self, NN_USOCK_STATE_STARTING); /* Start listening for incoming connections. NamedPipes are already created in the listening state, so no need to do anything here. */ if (self->domain != AF_UNIX) { rc = listen (self->s, backlog); if (nn_slow (rc == SOCKET_ERROR)) return -nn_err_wsa_to_posix (WSAGetLastError ()); } /* Notify the state machine. */ nn_fsm_action (&self->fsm, NN_USOCK_ACTION_LISTEN); return 0; } void nn_usock_accept (struct nn_usock *self, struct nn_usock *listener) { int rc; BOOL brc; DWORD nbytes; /* NamedPipes have their own accepting mechanism. */ if (listener->domain == AF_UNIX) { nn_usock_accept_pipe (self, listener); return; } rc = nn_usock_start (self, listener->domain, listener->type, listener->protocol); /* TODO: EMFILE can be returned here. */ errnum_assert (rc == 0, -rc); nn_fsm_action (&listener->fsm, NN_USOCK_ACTION_ACCEPT); nn_fsm_action (&self->fsm, NN_USOCK_ACTION_BEING_ACCEPTED); /* If the memory for accept information is not yet allocated, do so. */ if (!listener->ainfo) { listener->ainfo = nn_alloc (512, "accept info"); alloc_assert (listener->ainfo); } /* Wait for the incoming connection. */ memset (&listener->in.olpd, 0, sizeof (listener->in.olpd)); brc = AcceptEx (listener->s, self->s, listener->ainfo, 0, 256, 256, &nbytes, &listener->in.olpd); /* Immediate success. */ if (nn_fast (brc == TRUE)) { nn_fsm_action (&listener->fsm, NN_USOCK_ACTION_DONE); nn_fsm_action (&self->fsm, NN_USOCK_ACTION_DONE); return; } /* We don't expect a synchronous failure at this point. */ wsa_assert (nn_slow (WSAGetLastError () == WSA_IO_PENDING)); /* Pair the two sockets. */ nn_assert (!self->asock); self->asock = listener; nn_assert (!listener->asock); listener->asock = self; /* Asynchronous accept. */ nn_worker_op_start (&listener->in); } void nn_usock_activate (struct nn_usock *self) { nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ACTIVATE); } void nn_usock_connect (struct nn_usock *self, const struct sockaddr *addr, size_t addrlen) { BOOL brc; GUID fid = WSAID_CONNECTEX; LPFN_CONNECTEX pconnectex; DWORD nbytes; DWORD winerror; /* Fail if the socket is already connected, closed or such. */ nn_assert_state (self, NN_USOCK_STATE_STARTING); /* Notify the state machine that we've started connecting. */ nn_fsm_action (&self->fsm, NN_USOCK_ACTION_CONNECT); memset (&self->out.olpd, 0, sizeof (self->out.olpd)); if (self->domain == AF_UNIX) { winerror = nn_usock_open_pipe (self, ((struct sockaddr_un*) addr)->sun_path); } else { /* Get the pointer to connect function. */ brc = WSAIoctl (self->s, SIO_GET_EXTENSION_FUNCTION_POINTER, &fid, sizeof (fid), &pconnectex, sizeof (pconnectex), &nbytes, NULL, NULL) == 0; wsa_assert (brc == TRUE); nn_assert (nbytes == sizeof (pconnectex)); /* Ensure it is safe to cast this value to what might be a smaller integer type to conform to the pconnectex function signature. */ nn_assert (addrlen < INT_MAX); /* Connect itself. */ brc = pconnectex (self->s, addr, (int) addrlen, NULL, 0, NULL, &self->out.olpd); winerror = brc ? ERROR_SUCCESS : WSAGetLastError (); } /* Immediate success. */ if (nn_fast (winerror == ERROR_SUCCESS)) { nn_fsm_action (&self->fsm, NN_USOCK_ACTION_DONE); return; } /* Immediate error. */ if (nn_slow (winerror != WSA_IO_PENDING)) { nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR); return; } /* Asynchronous connect. */ nn_worker_op_start (&self->out); } void nn_usock_send (struct nn_usock *self, const struct nn_iovec *iov, int iovcnt) { int rc; BOOL brc; WSABUF wbuf [NN_USOCK_MAX_IOVCNT]; int i; size_t len; size_t idx; DWORD error; /* Make sure that the socket is actually alive. */ nn_assert_state (self, NN_USOCK_STATE_ACTIVE); /* Create a WinAPI-style iovec. */ len = 0; nn_assert (iovcnt <= NN_USOCK_MAX_IOVCNT); for (i = 0; i != iovcnt; ++i) { wbuf [i].buf = (char FAR*) iov [i].iov_base; wbuf [i].len = (ULONG) iov [i].iov_len; len += iov [i].iov_len; } /* Start the send operation. */ memset (&self->out.olpd, 0, sizeof (self->out.olpd)); if (self->domain == AF_UNIX) { /* TODO: Do not copy the buffer, find an efficent way to Write multiple buffers that doesn't affect the state machine. */ /* Ensure the total buffer size does not exceed size limitation of WriteFile. */ nn_assert (len <= MAXDWORD); nn_assert (!self->pipesendbuf); self->pipesendbuf = nn_alloc (len, "named pipe sendbuf"); idx = 0; for (i = 0; i != iovcnt; ++i) { memcpy ((char*)(self->pipesendbuf) + idx, iov [i].iov_base, iov [i].iov_len); idx += iov [i].iov_len; } brc = WriteFile (self->p, self->pipesendbuf, (DWORD) len, NULL, &self->out.olpd); if (nn_fast (brc || GetLastError() == ERROR_IO_PENDING)) { nn_worker_op_start (&self->out); return; } error = GetLastError(); win_assert (error == ERROR_NO_DATA); self->errnum = EINVAL; nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR); return; } rc = WSASend (self->s, wbuf, iovcnt, NULL, 0, &self->out.olpd, NULL); if (nn_fast (rc == 0)) { nn_worker_op_start (&self->out); return; } error = WSAGetLastError(); if (nn_fast (error == WSA_IO_PENDING)) { nn_worker_op_start (&self->out); return; } wsa_assert (error == WSAECONNABORTED || error == WSAECONNRESET || error == WSAENETDOWN || error == WSAENETRESET || error == WSAENOBUFS || error == WSAEWOULDBLOCK); self->errnum = nn_err_wsa_to_posix (error); nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR); } void nn_usock_recv_start_wsock (void *arg) { struct nn_usock *self = arg; WSABUF wbuf; DWORD flags; DWORD error; /* Start the receive operation. */ wbuf.len = (ULONG) self->in.resid; wbuf.buf = (char FAR*) self->in.buf; flags = MSG_WAITALL; memset (&self->in.olpd, 0, sizeof (self->in.olpd)); if (WSARecv (self->s, &wbuf, 1, NULL, &flags, &self->in.olpd, NULL) == 0) { error = ERROR_SUCCESS; } else { error = WSAGetLastError (); } switch (error) { case ERROR_SUCCESS: case WSA_IO_PENDING: nn_worker_op_start (&self->in); return; default: nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR); return; } } void nn_usock_recv_start_pipe (void *arg) { struct nn_usock *self = arg; void *buf = self->in.buf; DWORD len = (DWORD) self->in.resid; DWORD error; /* Start the receive operation. */ memset (&self->in.olpd, 0, sizeof (self->in.olpd)); if (ReadFile (self->p, buf, len, NULL, &self->in.olpd)) { error = ERROR_SUCCESS; } else { error = GetLastError (); } switch (error) { case ERROR_SUCCESS: case ERROR_IO_PENDING: nn_worker_op_start (&self->in); return; default: nn_fsm_action (&self->fsm, NN_USOCK_ACTION_ERROR); return; } } void nn_usock_recv (struct nn_usock *self, void *buf, size_t len, int *fd) { /* Passing file descriptors is not implemented on Windows platform. */ if (fd) *fd = -1; /* Make sure that the socket is actually alive. */ nn_assert_state (self, NN_USOCK_STATE_ACTIVE); self->in.resid = len; self->in.buf = buf; self->in.arg = self; self->in.zero_is_error = 1; if (self->domain == AF_UNIX) { self->in.start = nn_usock_recv_start_pipe; } else { self->in.start = nn_usock_recv_start_wsock; } self->in.start (self->in.arg); } static void nn_usock_create_io_completion (struct nn_usock *self) { struct nn_worker *worker; HANDLE cp; /* Associate the socket with a worker thread/completion port. */ worker = nn_fsm_choose_worker (&self->fsm); cp = CreateIoCompletionPort ( self->p, nn_worker_getcp(worker), (ULONG_PTR) NULL, 0); nn_assert(cp); } static void nn_usock_create_pipe (struct nn_usock *self, const char *name) { char fullname [256]; /* First, create a fully qualified name for the named pipe. */ _snprintf(fullname, sizeof (fullname), "\\\\.\\pipe\\%s", name); self->p = CreateNamedPipeA ( (char*) fullname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, PIPE_UNLIMITED_INSTANCES, self->outbuffersz, self->inbuffersz, 0, self->sec_attr); /* TODO: How to properly handle self->p == INVALID_HANDLE_VALUE? */ win_assert (self->p != INVALID_HANDLE_VALUE); self->isaccepted = 1; nn_usock_create_io_completion (self); } DWORD nn_usock_open_pipe (struct nn_usock *self, const char *name) { char fullname [256]; DWORD winerror; DWORD mode; BOOL brc; /* First, create a fully qualified name for the named pipe. */ _snprintf(fullname, sizeof (fullname), "\\\\.\\pipe\\%s", name); self->p = CreateFileA ( fullname, GENERIC_READ | GENERIC_WRITE, 0, self->sec_attr, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL); if (self->p == INVALID_HANDLE_VALUE) return GetLastError (); mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT; brc = SetNamedPipeHandleState ( self->p, &mode, NULL, NULL); if (!brc) { CloseHandle (self->p); self->p = INVALID_HANDLE_VALUE; return GetLastError (); } self->isaccepted = 0; nn_usock_create_io_completion (self); winerror = GetLastError (); if (winerror != ERROR_SUCCESS && winerror != ERROR_ALREADY_EXISTS) return winerror; return ERROR_SUCCESS; } void nn_usock_accept_pipe (struct nn_usock *self, struct nn_usock *listener) { int rc; BOOL brc; DWORD winerror; /* TODO: EMFILE can be returned here. */ rc = nn_usock_start (self, listener->domain, listener->type, listener->protocol); errnum_assert(rc == 0, -rc); nn_fsm_action(&listener->fsm, NN_USOCK_ACTION_ACCEPT); nn_fsm_action(&self->fsm, NN_USOCK_ACTION_BEING_ACCEPTED); /* If the memory for accept information is not yet allocated, do so now. */ if (!listener->ainfo) { listener->ainfo = nn_alloc (512, "accept info"); alloc_assert (listener->ainfo); } /* Wait for the incoming connection. */ memset (&listener->in.olpd, 0, sizeof(listener->in.olpd)); nn_usock_create_pipe (self, listener->pipename.sun_path); brc = ConnectNamedPipe (self->p, (LPOVERLAPPED) &listener->in.olpd); /* TODO: Can this function possibly succeed? */ nn_assert (brc == 0); winerror = GetLastError(); /* Immediate success. */ if (nn_fast (winerror == ERROR_PIPE_CONNECTED)) { nn_fsm_action (&listener->fsm, NN_USOCK_ACTION_DONE); nn_fsm_action (&self->fsm, NN_USOCK_ACTION_DONE); return; } /* We don't expect a synchronous failure at this point. */ wsa_assert (nn_slow (winerror == WSA_IO_PENDING)); /* Pair the two sockets. */ nn_assert (!self->asock); self->asock = listener; nn_assert (!listener->asock); listener->asock = self; /* Asynchronous accept. */ nn_worker_op_start (&listener->in); } static void nn_usock_close (struct nn_usock *self) { int rc; BOOL brc; if (self->domain == AF_UNIX) { if (self->p == INVALID_HANDLE_VALUE) return; if (self->isaccepted) DisconnectNamedPipe(self->p); brc = CloseHandle (self->p); self->p = INVALID_HANDLE_VALUE; win_assert (brc); } else { rc = closesocket (self->s); self->s = INVALID_SOCKET; wsa_assert (rc == 0); } } static void nn_usock_shutdown (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_usock *usock; usock = nn_cont (self, struct nn_usock, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { /* Socket in ACCEPTING state cannot be closed. Stop the socket being accepted first. */ nn_assert (usock->state != NN_USOCK_STATE_ACCEPTING); /* Synchronous stop. */ if (usock->state == NN_USOCK_STATE_IDLE) goto finish3; if (usock->state == NN_USOCK_STATE_DONE) goto finish2; if (usock->state == NN_USOCK_STATE_STARTING || usock->state == NN_USOCK_STATE_ACCEPTED || usock->state == NN_USOCK_STATE_LISTENING) goto finish1; /* When socket that's being accepted is asked to stop, we have to ask the listener socket to stop accepting first. */ if (usock->state == NN_USOCK_STATE_BEING_ACCEPTED) { nn_fsm_action (&usock->asock->fsm, NN_USOCK_ACTION_CANCEL); usock->state = NN_USOCK_STATE_STOPPING_ACCEPT; return; } /* If we were already in the process of cancelling overlapped operations, we don't have to do anything. Continue waiting till cancelling is finished. */ if (usock->state == NN_USOCK_STATE_CANCELLING_IO) { usock->state = NN_USOCK_STATE_STOPPING; return; } /* Notify our parent that pipe socket is shutting down */ nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_SHUTDOWN); /* In all remaining states we'll simply cancel all overlapped operations. */ if (nn_usock_cancel_io (usock) == 0) goto finish1; usock->state = NN_USOCK_STATE_STOPPING; return; } if (nn_slow (usock->state == NN_USOCK_STATE_STOPPING_ACCEPT)) { nn_assert (src == NN_FSM_ACTION && type == NN_USOCK_ACTION_DONE); goto finish1; } if (nn_slow (usock->state == NN_USOCK_STATE_STOPPING)) { if (!nn_worker_op_isidle (&usock->in) || !nn_worker_op_isidle (&usock->out)) return; finish1: nn_usock_close(usock); finish2: usock->state = NN_USOCK_STATE_IDLE; nn_fsm_stopped (&usock->fsm, NN_USOCK_STOPPED); finish3: return; } nn_fsm_bad_state(usock->state, src, type); } static void nn_usock_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_usock *usock; usock = nn_cont (self, struct nn_usock, fsm); switch (usock->state) { /*****************************************************************************/ /* IDLE state. */ /*****************************************************************************/ case NN_USOCK_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: usock->state = NN_USOCK_STATE_STARTING; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /*****************************************************************************/ /* STARTING state. */ /*****************************************************************************/ case NN_USOCK_STATE_STARTING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_LISTEN: usock->state = NN_USOCK_STATE_LISTENING; return; case NN_USOCK_ACTION_CONNECT: usock->state = NN_USOCK_STATE_CONNECTING; return; case NN_USOCK_ACTION_BEING_ACCEPTED: usock->state = NN_USOCK_STATE_BEING_ACCEPTED; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /*****************************************************************************/ /* BEING_ACCEPTED state. */ /*****************************************************************************/ case NN_USOCK_STATE_BEING_ACCEPTED: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_DONE: usock->state = NN_USOCK_STATE_ACCEPTED; nn_fsm_raise (&usock->fsm, &usock->event_established, NN_USOCK_ACCEPTED); return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /*****************************************************************************/ /* ACCEPTED state. */ /*****************************************************************************/ case NN_USOCK_STATE_ACCEPTED: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ACTIVATE: usock->state = NN_USOCK_STATE_ACTIVE; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /*****************************************************************************/ /* CONNECTING state. */ /*****************************************************************************/ case NN_USOCK_STATE_CONNECTING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_DONE: usock->state = NN_USOCK_STATE_ACTIVE; nn_fsm_raise (&usock->fsm, &usock->event_established, NN_USOCK_CONNECTED); return; case NN_USOCK_ACTION_ERROR: nn_usock_close(usock); usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_USOCK_SRC_OUT: switch (type) { case NN_WORKER_OP_DONE: usock->state = NN_USOCK_STATE_ACTIVE; nn_fsm_raise (&usock->fsm, &usock->event_established, NN_USOCK_CONNECTED); return; case NN_WORKER_OP_ERROR: nn_usock_close(usock); usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /*****************************************************************************/ /* ACTIVE state. */ /*****************************************************************************/ case NN_USOCK_STATE_ACTIVE: switch (src) { case NN_USOCK_SRC_IN: switch (type) { case NN_WORKER_OP_DONE: nn_fsm_raise (&usock->fsm, &usock->event_received, NN_USOCK_RECEIVED); return; case NN_WORKER_OP_ERROR: if (nn_usock_cancel_io (usock) == 0) { nn_fsm_raise(&usock->fsm, &usock->event_error, NN_USOCK_ERROR); nn_usock_close (usock); usock->state = NN_USOCK_STATE_DONE; return; } usock->state = NN_USOCK_STATE_CANCELLING_IO; return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_USOCK_SRC_OUT: switch (type) { case NN_WORKER_OP_DONE: if (usock->pipesendbuf) { nn_free(usock->pipesendbuf); usock->pipesendbuf = NULL; } nn_fsm_raise (&usock->fsm, &usock->event_sent, NN_USOCK_SENT); return; case NN_WORKER_OP_ERROR: if (nn_usock_cancel_io (usock) == 0) { nn_fsm_raise(&usock->fsm, &usock->event_error, NN_USOCK_ERROR); nn_usock_close(usock); usock->state = NN_USOCK_STATE_DONE; return; } usock->state = NN_USOCK_STATE_CANCELLING_IO; return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ERROR: if (nn_usock_cancel_io (usock) == 0) { nn_fsm_raise(&usock->fsm, &usock->event_error, NN_USOCK_SHUTDOWN); nn_usock_close(usock); usock->state = NN_USOCK_STATE_DONE; return; } usock->state = NN_USOCK_STATE_CANCELLING_IO; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /*****************************************************************************/ /* CANCELLING_IO state. */ /*****************************************************************************/ case NN_USOCK_STATE_CANCELLING_IO: switch (src) { case NN_USOCK_SRC_IN: case NN_USOCK_SRC_OUT: if (!nn_worker_op_isidle (&usock->in) || !nn_worker_op_isidle (&usock->out)) return; nn_fsm_raise(&usock->fsm, &usock->event_error, NN_USOCK_SHUTDOWN); nn_usock_close(usock); usock->state = NN_USOCK_STATE_DONE; return; default: nn_fsm_bad_source (usock->state, src, type); } /*****************************************************************************/ /* DONE state. */ /*****************************************************************************/ case NN_USOCK_STATE_DONE: nn_fsm_bad_source (usock->state, src, type); /*****************************************************************************/ /* LISTENING state. */ /*****************************************************************************/ case NN_USOCK_STATE_LISTENING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ACCEPT: usock->state = NN_USOCK_STATE_ACCEPTING; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /*****************************************************************************/ /* ACCEPTING state. */ /*****************************************************************************/ case NN_USOCK_STATE_ACCEPTING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_DONE: usock->state = NN_USOCK_STATE_LISTENING; return; case NN_USOCK_ACTION_CANCEL: if (usock->p == INVALID_HANDLE_VALUE && usock->asock != NULL && usock->domain == AF_UNIX) { usock->p = usock->asock->p; nn_usock_cancel_io (usock); usock->p = INVALID_HANDLE_VALUE; } else { nn_usock_cancel_io(usock); } usock->state = NN_USOCK_STATE_CANCELLING; return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_USOCK_SRC_IN: switch (type) { case NN_WORKER_OP_DONE: /* Adjust the new usock object. */ usock->asock->state = NN_USOCK_STATE_ACCEPTED; /* Notify the user that connection was accepted. */ nn_fsm_raise (&usock->asock->fsm, &usock->asock->event_established, NN_USOCK_ACCEPTED); /* Disassociate the listener socket from the accepted socket. */ usock->asock->asock = NULL; usock->asock = NULL; /* Wait till the user starts accepting once again. */ usock->state = NN_USOCK_STATE_LISTENING; return; case NN_WORKER_OP_ERROR: nn_usock_close(usock->asock); usock->asock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->asock->fsm, &usock->asock->event_error, NN_USOCK_ERROR); usock->asock->asock = NULL; usock->asock = NULL; /* Wait till the user starts accepting once again. */ usock->state = NN_USOCK_STATE_LISTENING; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /*****************************************************************************/ /* CANCELLING state. */ /*****************************************************************************/ case NN_USOCK_STATE_CANCELLING: switch (src) { case NN_USOCK_SRC_IN: switch (type) { case NN_WORKER_OP_DONE: case NN_WORKER_OP_ERROR: /* TODO: The socket being accepted should be closed here. */ usock->state = NN_USOCK_STATE_LISTENING; /* Notify the accepted socket that it was stopped. */ nn_fsm_action (&usock->asock->fsm, NN_USOCK_ACTION_DONE); return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /*****************************************************************************/ /* Invalid state. */ /*****************************************************************************/ default: nn_fsm_bad_state (usock->state, src, type); } } /*****************************************************************************/ /* State machine actions. */ /*****************************************************************************/ /* Returns 0 if there's nothing to cancel or 1 otherwise. */ static int nn_usock_cancel_io (struct nn_usock *self) { int rc; BOOL brc; /* For some reason simple CancelIo doesn't seem to work here. We have to use CancelIoEx instead. */ rc = 0; if (!nn_worker_op_isidle (&self->in)) { brc = CancelIoEx (self->p, &self->in.olpd); win_assert (brc || GetLastError () == ERROR_NOT_FOUND); rc = 1; } if (!nn_worker_op_isidle (&self->out)) { brc = CancelIoEx (self->p, &self->out.olpd); win_assert (brc || GetLastError () == ERROR_NOT_FOUND); rc = 1; } return rc; } nanomsg-1.1.5/src/aio/worker.c000066400000000000000000000031451336111550300161750ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "worker.h" #if defined NN_HAVE_WINDOWS #include "worker_win.inc" #else #include "worker_posix.inc" #endif void nn_worker_timer_init (struct nn_worker_timer *self, struct nn_fsm *owner) { self->owner = owner; nn_timerset_hndl_init (&self->hndl); } void nn_worker_timer_term (struct nn_worker_timer *self) { nn_timerset_hndl_term (&self->hndl); } int nn_worker_timer_isactive (struct nn_worker_timer *self) { return nn_timerset_hndl_isactive (&self->hndl); } nanomsg-1.1.5/src/aio/worker.h000066400000000000000000000045301336111550300162010ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. 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. */ #ifndef NN_WORKER_INCLUDED #define NN_WORKER_INCLUDED #include "fsm.h" #include "timerset.h" #if defined NN_HAVE_WINDOWS #include "worker_win.h" #else #include "worker_posix.h" #endif #define NN_WORKER_TIMER_TIMEOUT 1 struct nn_worker_timer { struct nn_fsm *owner; struct nn_timerset_hndl hndl; }; void nn_worker_timer_init (struct nn_worker_timer *self, struct nn_fsm *owner); void nn_worker_timer_term (struct nn_worker_timer *self); int nn_worker_timer_isactive (struct nn_worker_timer *self); #define NN_WORKER_TASK_EXECUTE 1 struct nn_worker_task; void nn_worker_task_init (struct nn_worker_task *self, int src, struct nn_fsm *owner); void nn_worker_task_term (struct nn_worker_task *self); struct nn_worker; int nn_worker_init (struct nn_worker *self); void nn_worker_term (struct nn_worker *self); void nn_worker_execute (struct nn_worker *self, struct nn_worker_task *task); void nn_worker_cancel (struct nn_worker *self, struct nn_worker_task *task); void nn_worker_add_timer (struct nn_worker *self, int timeout, struct nn_worker_timer *timer); void nn_worker_rm_timer (struct nn_worker *self, struct nn_worker_timer *timer); #endif nanomsg-1.1.5/src/aio/worker_posix.h000066400000000000000000000047061336111550300174300ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. 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. */ #include "../utils/queue.h" #include "../utils/mutex.h" #include "../utils/thread.h" #include "../utils/efd.h" #include "poller.h" #define NN_WORKER_FD_IN NN_POLLER_IN #define NN_WORKER_FD_OUT NN_POLLER_OUT #define NN_WORKER_FD_ERR NN_POLLER_ERR struct nn_worker_fd { int src; struct nn_fsm *owner; struct nn_poller_hndl hndl; }; void nn_worker_fd_init (struct nn_worker_fd *self, int src, struct nn_fsm *owner); void nn_worker_fd_term (struct nn_worker_fd *self); struct nn_worker_task { int src; struct nn_fsm *owner; struct nn_queue_item item; }; struct nn_worker { struct nn_mutex sync; struct nn_queue tasks; struct nn_queue_item stop; struct nn_efd efd; struct nn_poller poller; struct nn_poller_hndl efd_hndl; struct nn_timerset timerset; struct nn_thread thread; }; void nn_worker_add_fd (struct nn_worker *self, int s, struct nn_worker_fd *fd); void nn_worker_rm_fd(struct nn_worker *self, struct nn_worker_fd *fd); void nn_worker_set_in (struct nn_worker *self, struct nn_worker_fd *fd); void nn_worker_reset_in (struct nn_worker *self, struct nn_worker_fd *fd); void nn_worker_set_out (struct nn_worker *self, struct nn_worker_fd *fd); void nn_worker_reset_out (struct nn_worker *self, struct nn_worker_fd *fd); nanomsg-1.1.5/src/aio/worker_posix.inc000066400000000000000000000200371336111550300177450ustar00rootroot00000000000000/* Copyright (c) 2013-2014 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "ctx.h" #include "../utils/err.h" #include "../utils/fast.h" #include "../utils/cont.h" #include "../utils/attr.h" #include "../utils/queue.h" /* Private functions. */ static void nn_worker_routine (void *arg); void nn_worker_fd_init (struct nn_worker_fd *self, int src, struct nn_fsm *owner) { self->src = src; self->owner = owner; } void nn_worker_fd_term (NN_UNUSED struct nn_worker_fd *self) { } void nn_worker_add_fd (struct nn_worker *self, int s, struct nn_worker_fd *fd) { nn_poller_add (&self->poller, s, &fd->hndl); } void nn_worker_rm_fd (struct nn_worker *self, struct nn_worker_fd *fd) { nn_poller_rm (&self->poller, &fd->hndl); } void nn_worker_set_in (struct nn_worker *self, struct nn_worker_fd *fd) { nn_poller_set_in (&self->poller, &fd->hndl); } void nn_worker_reset_in (struct nn_worker *self, struct nn_worker_fd *fd) { nn_poller_reset_in (&self->poller, &fd->hndl); } void nn_worker_set_out (struct nn_worker *self, struct nn_worker_fd *fd) { nn_poller_set_out (&self->poller, &fd->hndl); } void nn_worker_reset_out (struct nn_worker *self, struct nn_worker_fd *fd) { nn_poller_reset_out (&self->poller, &fd->hndl); } void nn_worker_add_timer (struct nn_worker *self, int timeout, struct nn_worker_timer *timer) { nn_timerset_add (&self->timerset, timeout, &timer->hndl); } void nn_worker_rm_timer (struct nn_worker *self, struct nn_worker_timer *timer) { nn_timerset_rm (&self->timerset, &timer->hndl); } void nn_worker_task_init (struct nn_worker_task *self, int src, struct nn_fsm *owner) { self->src = src; self->owner = owner; nn_queue_item_init (&self->item); } void nn_worker_task_term (struct nn_worker_task *self) { nn_queue_item_term (&self->item); } int nn_worker_init (struct nn_worker *self) { int rc; rc = nn_efd_init (&self->efd); if (rc < 0) return rc; nn_mutex_init (&self->sync); nn_queue_init (&self->tasks); nn_queue_item_init (&self->stop); nn_poller_init (&self->poller); nn_poller_add (&self->poller, nn_efd_getfd (&self->efd), &self->efd_hndl); nn_poller_set_in (&self->poller, &self->efd_hndl); nn_timerset_init (&self->timerset); nn_thread_init (&self->thread, nn_worker_routine, self); return 0; } void nn_worker_term (struct nn_worker *self) { /* Ask worker thread to terminate. */ nn_mutex_lock (&self->sync); nn_queue_push (&self->tasks, &self->stop); nn_efd_signal (&self->efd); nn_mutex_unlock (&self->sync); /* Wait till worker thread terminates. */ nn_thread_term (&self->thread); /* Clean up. */ nn_timerset_term (&self->timerset); nn_poller_term (&self->poller); nn_efd_term (&self->efd); nn_queue_item_term (&self->stop); nn_queue_term (&self->tasks); nn_mutex_term (&self->sync); } void nn_worker_execute (struct nn_worker *self, struct nn_worker_task *task) { nn_mutex_lock (&self->sync); nn_queue_push (&self->tasks, &task->item); nn_efd_signal (&self->efd); nn_mutex_unlock (&self->sync); } void nn_worker_cancel (struct nn_worker *self, struct nn_worker_task *task) { nn_mutex_lock (&self->sync); nn_queue_remove (&self->tasks, &task->item); nn_mutex_unlock (&self->sync); } static void nn_worker_routine (void *arg) { int rc; struct nn_worker *self; int pevent; struct nn_poller_hndl *phndl; struct nn_timerset_hndl *thndl; struct nn_queue tasks; struct nn_queue_item *item; struct nn_worker_task *task; struct nn_worker_fd *fd; struct nn_worker_timer *timer; self = (struct nn_worker*) arg; /* Infinite loop. It will be interrupted only when the object is shut down. */ while (1) { /* Wait for new events and/or timeouts. */ rc = nn_poller_wait (&self->poller, nn_timerset_timeout (&self->timerset)); errnum_assert (rc == 0, -rc); /* Process all expired timers. */ while (1) { rc = nn_timerset_event (&self->timerset, &thndl); if (rc == -EAGAIN) break; errnum_assert (rc == 0, -rc); timer = nn_cont (thndl, struct nn_worker_timer, hndl); nn_ctx_enter (timer->owner->ctx); nn_fsm_feed (timer->owner, -1, NN_WORKER_TIMER_TIMEOUT, timer); nn_ctx_leave (timer->owner->ctx); } /* Process all events from the poller. */ while (1) { /* Get next poller event, such as IN or OUT. */ rc = nn_poller_event (&self->poller, &pevent, &phndl); if (nn_slow (rc == -EAGAIN)) break; /* If there are any new incoming worker tasks, process them. */ if (phndl == &self->efd_hndl) { nn_assert (pevent == NN_POLLER_IN); /* Make a local copy of the task queue. This way the application threads are not blocked and can post new tasks while the existing tasks are being processed. Also, new tasks can be posted from within task handlers. */ nn_mutex_lock (&self->sync); nn_efd_unsignal (&self->efd); memcpy (&tasks, &self->tasks, sizeof (tasks)); nn_queue_init (&self->tasks); nn_mutex_unlock (&self->sync); while (1) { /* Next worker task. */ item = nn_queue_pop (&tasks); if (nn_slow (!item)) break; /* If the worker thread is asked to stop, do so. */ if (nn_slow (item == &self->stop)) { /* Make sure we remove all the other workers from the queue, because we're not doing anything with them. */ while (nn_queue_pop (&tasks) != NULL) { continue; } nn_queue_term (&tasks); return; } /* It's a user-defined task. Notify the user that it has arrived in the worker thread. */ task = nn_cont (item, struct nn_worker_task, item); nn_ctx_enter (task->owner->ctx); nn_fsm_feed (task->owner, task->src, NN_WORKER_TASK_EXECUTE, task); nn_ctx_leave (task->owner->ctx); } nn_queue_term (&tasks); continue; } /* It's a true I/O event. Invoke the handler. */ fd = nn_cont (phndl, struct nn_worker_fd, hndl); nn_ctx_enter (fd->owner->ctx); nn_fsm_feed (fd->owner, fd->src, pevent, fd); nn_ctx_leave (fd->owner->ctx); } } } nanomsg-1.1.5/src/aio/worker_win.h000066400000000000000000000045371336111550300170650ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2018 Staysail Systems, Inc. Copyright 2018 Capitar IT Group BV 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. */ #include "fsm.h" #include "timerset.h" #include "../utils/win.h" #include "../utils/thread.h" struct nn_worker_task { int src; struct nn_fsm *owner; }; #define NN_WORKER_OP_DONE 1 #define NN_WORKER_OP_ERROR 2 struct nn_worker_op { int src; struct nn_fsm *owner; int state; /* This structure is to be used by the user, not nn_worker_op itself. Actual usage is specific to the asynchronous operation in question. */ OVERLAPPED olpd; /* We might have transferred less than requested. This keeps track. */ size_t resid; char *buf; void *arg; void (*start)(struct nn_usock *); int zero_is_error; }; void nn_worker_op_init (struct nn_worker_op *self, int src, struct nn_fsm *owner); void nn_worker_op_term (struct nn_worker_op *self); /* Call this function when asynchronous operation is started. */ void nn_worker_op_start (struct nn_worker_op *self); int nn_worker_op_isidle (struct nn_worker_op *self); struct nn_worker { HANDLE cp; struct nn_timerset timerset; struct nn_thread thread; }; HANDLE nn_worker_getcp (struct nn_worker *self); nanomsg-1.1.5/src/aio/worker_win.inc000066400000000000000000000171041336111550300174010ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2018 Staysail Systems, Inc. Copyright 2018 Capitar IT Group BV 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. */ #include "ctx.h" #include "usock.h" #include "../utils/err.h" #include "../utils/cont.h" #include "../utils/fast.h" #define NN_WORKER_MAX_EVENTS 32 #define NN_WORKER_OP_STATE_IDLE 1 #define NN_WORKER_OP_STATE_ACTIVE 2 /* The value of this variable is irrelevant. It's used only as a placeholder for the address that is used as the 'stop' event ID. */ const int nn_worker_stop = 0; /* Private functions. */ static void nn_worker_routine (void *arg); void nn_worker_task_init (struct nn_worker_task *self, int src, struct nn_fsm *owner) { self->src = src; self->owner = owner; } void nn_worker_task_term (struct nn_worker_task *self) { } void nn_worker_op_init (struct nn_worker_op *self, int src, struct nn_fsm *owner) { self->src = src; self->owner = owner; self->state = NN_WORKER_OP_STATE_IDLE; self->start = NULL; self->buf = NULL; self->resid = 0; self->zero_is_error = 0; } void nn_worker_op_term (struct nn_worker_op *self) { nn_assert_state (self, NN_WORKER_OP_STATE_IDLE); } void nn_worker_op_start (struct nn_worker_op *self) { self->state = NN_WORKER_OP_STATE_ACTIVE; } int nn_worker_op_isidle (struct nn_worker_op *self) { return self->state == NN_WORKER_OP_STATE_IDLE ? 1 : 0; } int nn_worker_init (struct nn_worker *self) { self->cp = CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, 0, 0); win_assert (self->cp); nn_timerset_init (&self->timerset); nn_thread_init (&self->thread, nn_worker_routine, self); return 0; } void nn_worker_term (struct nn_worker *self) { BOOL brc; /* Ask worker thread to terminate. */ brc = PostQueuedCompletionStatus (self->cp, 0, (ULONG_PTR) &nn_worker_stop, NULL); win_assert (brc); /* Wait till worker thread terminates. */ nn_thread_term (&self->thread); nn_timerset_term (&self->timerset); brc = CloseHandle (self->cp); win_assert (brc); } void nn_worker_execute (struct nn_worker *self, struct nn_worker_task *task) { BOOL brc; brc = PostQueuedCompletionStatus (self->cp, 0, (ULONG_PTR) task, NULL); win_assert (brc); } void nn_worker_add_timer (struct nn_worker *self, int timeout, struct nn_worker_timer *timer) { nn_timerset_add (&((struct nn_worker*) self)->timerset, timeout, &timer->hndl); } void nn_worker_rm_timer (struct nn_worker *self, struct nn_worker_timer *timer) { nn_timerset_rm (&((struct nn_worker*) self)->timerset, &timer->hndl); } HANDLE nn_worker_getcp (struct nn_worker *self) { return self->cp; } static void nn_worker_routine (void *arg) { int rc; BOOL brc; struct nn_worker *self; int timeout; ULONG count; ULONG i; struct nn_timerset_hndl *thndl; struct nn_worker_timer *timer; struct nn_worker_task *task; struct nn_worker_op *op; OVERLAPPED_ENTRY entries [NN_WORKER_MAX_EVENTS]; self = (struct nn_worker*) arg; while (1) { /* Process all expired timers. */ while (1) { rc = nn_timerset_event (&self->timerset, &thndl); if (nn_fast (rc == -EAGAIN)) break; errnum_assert (rc == 0, -rc); timer = nn_cont (thndl, struct nn_worker_timer, hndl); nn_ctx_enter (timer->owner->ctx); nn_fsm_feed (timer->owner, -1, NN_WORKER_TIMER_TIMEOUT, timer); nn_ctx_leave (timer->owner->ctx); } /* Compute the time interval till next timer expiration. */ timeout = nn_timerset_timeout (&self->timerset); /* Wait for new events and/or timeouts. */ brc = GetQueuedCompletionStatusEx (self->cp, entries, NN_WORKER_MAX_EVENTS, &count, timeout < 0 ? INFINITE : timeout, FALSE); if (nn_slow (!brc && GetLastError () == WAIT_TIMEOUT)) continue; win_assert (brc); for (i = 0; i != count; ++i) { /* Process I/O completion events. */ if (nn_fast (entries [i].lpOverlapped != NULL)) { DWORD nxfer; op = nn_cont (entries [i].lpOverlapped, struct nn_worker_op, olpd); /* The 'Internal' field is actually an NTSTATUS. Report success and error. Ignore warnings and informational messages.*/ rc = entries [i].Internal & 0xc0000000; switch (rc) { case 0x00000000: nxfer = entries[i].dwNumberOfBytesTransferred; if ((nxfer == 0) && (op->zero_is_error != 0)) { rc = NN_WORKER_OP_ERROR; break; } if (op->start != NULL) { if (nxfer > op->resid) { rc = NN_WORKER_OP_ERROR; break; } op->resid -= nxfer; op->buf += nxfer; /* If we still have more to transfer, keep going. */ if (op->resid != 0) { op->start (op->arg); continue; } } rc = NN_WORKER_OP_DONE; break; case 0xc0000000: nxfer = 0; rc = NN_WORKER_OP_ERROR; break; default: continue; } /* Raise the completion event. */ nn_ctx_enter (op->owner->ctx); nn_assert (op->state != NN_WORKER_OP_STATE_IDLE); op->state = NN_WORKER_OP_STATE_IDLE; nn_fsm_feed (op->owner, op->src, rc, op); nn_ctx_leave (op->owner->ctx); continue; } /* Worker thread shutdown is requested. */ if (nn_slow (entries [i].lpCompletionKey == (ULONG_PTR) &nn_worker_stop)) return; /* Process tasks. */ task = (struct nn_worker_task*) entries [i].lpCompletionKey; nn_ctx_enter (task->owner->ctx); nn_fsm_feed (task->owner, task->src, NN_WORKER_TASK_EXECUTE, task); nn_ctx_leave (task->owner->ctx); } } } nanomsg-1.1.5/src/bus.h000066400000000000000000000024731336111550300147150ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef BUS_H_INCLUDED #define BUS_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #define NN_PROTO_BUS 7 #define NN_BUS (NN_PROTO_BUS * 16 + 0) #ifdef __cplusplus } #endif #endif nanomsg-1.1.5/src/core/000077500000000000000000000000001336111550300146755ustar00rootroot00000000000000nanomsg-1.1.5/src/core/README000066400000000000000000000002571336111550300155610ustar00rootroot00000000000000In this directory all the generic code of the library resides. I.e. the code that is not a transport, not a protocol, not a generic utility, rather a glue between the pieces. nanomsg-1.1.5/src/core/ep.c000066400000000000000000000163241336111550300154530ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "../transport.h" #include "ep.h" #include "sock.h" #include "../utils/err.h" #include "../utils/cont.h" #include "../utils/fast.h" #include "../utils/attr.h" #include #define NN_EP_STATE_IDLE 1 #define NN_EP_STATE_ACTIVE 2 #define NN_EP_STATE_STOPPING 3 #define NN_EP_ACTION_STOPPED 1 /* Private functions. */ static void nn_ep_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_ep_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); int nn_ep_init (struct nn_ep *self, int src, struct nn_sock *sock, int eid, const struct nn_transport *transport, int bind, const char *addr) { int rc; nn_fsm_init (&self->fsm, nn_ep_handler, nn_ep_shutdown, src, self, &sock->fsm); self->state = NN_EP_STATE_IDLE; self->sock = sock; self->eid = eid; self->last_errno = 0; nn_list_item_init (&self->item); memcpy (&self->options, &sock->ep_template, sizeof(struct nn_ep_options)); /* Store the textual form of the address. */ nn_assert (strlen (addr) <= NN_SOCKADDR_MAX); strcpy (self->addr, addr); /* Create transport-specific part of the endpoint. */ if (bind) rc = transport->bind (self); else rc = transport->connect (self); /* Endpoint creation failed. */ if (rc < 0) { nn_list_item_term (&self->item); nn_fsm_term (&self->fsm); return rc; } return 0; } void nn_ep_term (struct nn_ep *self) { nn_assert_state (self, NN_EP_STATE_IDLE); self->ops.destroy (self->tran); nn_list_item_term (&self->item); nn_fsm_term (&self->fsm); } void nn_ep_start (struct nn_ep *self) { nn_fsm_start (&self->fsm); } void nn_ep_stop (struct nn_ep *self) { nn_fsm_stop (&self->fsm); } void nn_ep_stopped (struct nn_ep *self) { /* TODO: Do the following in a more sane way. */ self->fsm.stopped.fsm = &self->fsm; self->fsm.stopped.src = NN_FSM_ACTION; self->fsm.stopped.srcptr = NULL; self->fsm.stopped.type = NN_EP_ACTION_STOPPED; nn_ctx_raise (self->fsm.ctx, &self->fsm.stopped); } struct nn_ctx *nn_ep_getctx (struct nn_ep *self) { return nn_sock_getctx (self->sock); } const char *nn_ep_getaddr (struct nn_ep *self) { return self->addr; } void nn_ep_getopt (struct nn_ep *self, int level, int option, void *optval, size_t *optvallen) { int rc; rc = nn_sock_getopt_inner (self->sock, level, option, optval, optvallen); errnum_assert (rc == 0, -rc); } int nn_ep_ispeer (struct nn_ep *self, int socktype) { return nn_sock_ispeer (self->sock, socktype); } static void nn_ep_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_ep *ep; ep = nn_cont (self, struct nn_ep, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { ep->ops.stop (ep->tran); ep->state = NN_EP_STATE_STOPPING; return; } if (nn_slow (ep->state == NN_EP_STATE_STOPPING)) { if (src != NN_FSM_ACTION || type != NN_EP_ACTION_STOPPED) return; ep->state = NN_EP_STATE_IDLE; nn_fsm_stopped (&ep->fsm, NN_EP_STOPPED); return; } nn_fsm_bad_state (ep->state, src, type); } static void nn_ep_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_ep *ep; ep = nn_cont (self, struct nn_ep, fsm); switch (ep->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_EP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: ep->state = NN_EP_STATE_ACTIVE; return; default: nn_fsm_bad_action (ep->state, src, type); } default: nn_fsm_bad_source (ep->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* We don't expect any events in this state. The only thing that can be done */ /* is closing the endpoint. */ /******************************************************************************/ case NN_EP_STATE_ACTIVE: nn_fsm_bad_source (ep->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (ep->state, src, type); } } void nn_ep_set_error(struct nn_ep *self, int errnum) { if (self->last_errno == errnum) /* Error is still there, no need to report it again */ return; if (self->last_errno == 0) nn_sock_stat_increment (self->sock, NN_STAT_CURRENT_EP_ERRORS, 1); self->last_errno = errnum; nn_sock_report_error (self->sock, self, errnum); } void nn_ep_clear_error (struct nn_ep *self) { if (self->last_errno == 0) /* Error is already clear, no need to report it */ return; nn_sock_stat_increment (self->sock, NN_STAT_CURRENT_EP_ERRORS, -1); self->last_errno = 0; nn_sock_report_error (self->sock, self, 0); } void nn_ep_stat_increment (struct nn_ep *self, int name, int increment) { nn_sock_stat_increment (self->sock, name, increment); } int nn_ep_ispeer_ep (struct nn_ep *self, struct nn_ep *other) { return nn_ep_ispeer (self, other->sock->socktype->protocol); } /* Set up an ep for use by a transport. Note that the core will already have done most of the initialization steps. The tran is passed as the argument to the ops. */ void nn_ep_tran_setup (struct nn_ep *ep, const struct nn_ep_ops *ops, void *tran) { ep->ops = *ops; ep->tran = tran; } nanomsg-1.1.5/src/core/ep.h000066400000000000000000000047551336111550300154650ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_EP_INCLUDED #define NN_EP_INCLUDED #include "../transport.h" #include "../aio/fsm.h" #include "../utils/list.h" /* Events generated by the nn_ep object. */ #define NN_EP_STOPPED 1 struct nn_ep { struct nn_fsm fsm; int state; struct nn_sock *sock; struct nn_ep_options options; int eid; struct nn_list_item item; char addr [NN_SOCKADDR_MAX + 1]; int protocol; /* Error state for endpoint */ int last_errno; /* Transport private state structure */ void *tran; /* Transport specific operations */ struct nn_ep_ops ops; }; int nn_ep_init (struct nn_ep *self, int src, struct nn_sock *sock, int eid, const struct nn_transport *transport, int bind, const char *addr); void nn_ep_term (struct nn_ep *self); void nn_ep_start (struct nn_ep *self); void nn_ep_stop (struct nn_ep *self); void nn_ep_stopped (struct nn_ep *self); struct nn_ctx *nn_ep_getctx (struct nn_ep *self); const char *nn_ep_getaddr (struct nn_ep *self); void nn_ep_getopt (struct nn_ep *self, int level, int option, void *optval, size_t *optvallen); int nn_ep_ispeer (struct nn_ep *self, int socktype); void nn_ep_set_error(struct nn_ep *self, int errnum); void nn_ep_clear_error(struct nn_ep *self); void nn_ep_stat_increment(struct nn_ep *self, int name, int increment); #endif nanomsg-1.1.5/src/core/global.c000066400000000000000000000732031336111550300163060ustar00rootroot00000000000000/* Copyright (c) 2012-2014 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "../nn.h" #include "../transport.h" #include "../protocol.h" #include "global.h" #include "sock.h" #include "ep.h" #include "../aio/pool.h" #include "../aio/timer.h" #include "../utils/err.h" #include "../utils/alloc.h" #include "../utils/mutex.h" #include "../utils/condvar.h" #include "../utils/once.h" #include "../utils/list.h" #include "../utils/cont.h" #include "../utils/random.h" #include "../utils/chunk.h" #include "../utils/msg.h" #include "../utils/attr.h" #include "../pubsub.h" #include "../pipeline.h" #include #include #include #include #if defined NN_HAVE_WINDOWS #include "../utils/win.h" #else #include #endif /* Max number of concurrent SP sockets. Configureable at build time */ #ifndef NN_MAX_SOCKETS #define NN_MAX_SOCKETS 512 #endif /* To save some space, list of unused socket slots uses uint16_t integers to refer to individual sockets. If there's a need to more that 0x10000 sockets, the type should be changed to uint32_t or int. */ CT_ASSERT (NN_MAX_SOCKETS <= 0x10000); #define NN_CTX_FLAG_TERMED 1 #define NN_CTX_FLAG_TERMING 2 #define NN_CTX_FLAG_TERM (NN_CTX_FLAG_TERMED | NN_CTX_FLAG_TERMING) #define NN_GLOBAL_SRC_STAT_TIMER 1 #define NN_GLOBAL_STATE_IDLE 1 #define NN_GLOBAL_STATE_ACTIVE 2 #define NN_GLOBAL_STATE_STOPPING_TIMER 3 /* We could put these in an external header file, but there really is need to. We are the only thing that needs them. */ extern struct nn_socktype nn_pair_socktype; extern struct nn_socktype nn_xpair_socktype; extern struct nn_socktype nn_pub_socktype; extern struct nn_socktype nn_sub_socktype; extern struct nn_socktype nn_xpub_socktype; extern struct nn_socktype nn_xsub_socktype; extern struct nn_socktype nn_rep_socktype; extern struct nn_socktype nn_req_socktype; extern struct nn_socktype nn_xrep_socktype; extern struct nn_socktype nn_xreq_socktype; extern struct nn_socktype nn_push_socktype; extern struct nn_socktype nn_xpush_socktype; extern struct nn_socktype nn_pull_socktype; extern struct nn_socktype nn_xpull_socktype; extern struct nn_socktype nn_respondent_socktype; extern struct nn_socktype nn_surveyor_socktype; extern struct nn_socktype nn_xrespondent_socktype; extern struct nn_socktype nn_xsurveyor_socktype; extern struct nn_socktype nn_bus_socktype; extern struct nn_socktype nn_xbus_socktype; /* Array of known socket types. */ const struct nn_socktype *nn_socktypes[] = { &nn_pair_socktype, &nn_xpair_socktype, &nn_pub_socktype, &nn_sub_socktype, &nn_xpub_socktype, &nn_xsub_socktype, &nn_rep_socktype, &nn_req_socktype, &nn_xrep_socktype, &nn_xreq_socktype, &nn_push_socktype, &nn_xpush_socktype, &nn_pull_socktype, &nn_xpull_socktype, &nn_respondent_socktype, &nn_surveyor_socktype, &nn_xrespondent_socktype, &nn_xsurveyor_socktype, &nn_bus_socktype, &nn_xbus_socktype, NULL, }; /* As with protocols, we could have these in a header file, but we are the only consumer, so just declare them inline. */ extern struct nn_transport nn_inproc; extern struct nn_transport nn_ipc; extern struct nn_transport nn_tcp; extern struct nn_transport nn_ws; const struct nn_transport *nn_transports[] = { &nn_inproc, &nn_ipc, &nn_tcp, &nn_ws, NULL, }; struct nn_global { /* The global table of existing sockets. The descriptor representing the socket is the index to this table. This pointer is also used to find out whether context is initialised. If it is NULL, context is uninitialised. */ struct nn_sock **socks; /* Stack of unused file descriptors. */ uint16_t *unused; /* Number of actual open sockets in the socket table. */ size_t nsocks; /* Combination of the flags listed above. */ int flags; /* Pool of worker threads. */ struct nn_pool pool; /* Timer and other machinery for submitting statistics */ int state; int print_errors; int inited; nn_mutex_t lock; nn_condvar_t cond; }; /* Singleton object containing the global state of the library. */ static struct nn_global self; static nn_once_t once = NN_ONCE_INITIALIZER; /* Context creation- and termination-related private functions. */ static void nn_global_init (void); static void nn_global_term (void); /* Private function that unifies nn_bind and nn_connect functionality. It returns the ID of the newly created endpoint. */ static int nn_global_create_ep (struct nn_sock *, const char *addr, int bind); /* Private socket creator which doesn't initialize global state and does no locking by itself */ static int nn_global_create_socket (int domain, int protocol); /* Socket holds. */ static int nn_global_hold_socket (struct nn_sock **sockp, int s); static int nn_global_hold_socket_locked (struct nn_sock **sockp, int s); static void nn_global_rele_socket(struct nn_sock *); int nn_errno (void) { return nn_err_errno (); } const char *nn_strerror (int errnum) { return nn_err_strerror (errnum); } static void nn_global_init (void) { int i; char *envvar; #if defined NN_HAVE_WINDOWS int rc; WSADATA data; #endif const struct nn_transport *tp; /* Check whether the library was already initialised. If so, do nothing. */ if (self.socks) return; /* On Windows, initialise the socket library. */ #if defined NN_HAVE_WINDOWS rc = WSAStartup (MAKEWORD (2, 2), &data); nn_assert (rc == 0); nn_assert (LOBYTE (data.wVersion) == 2 && HIBYTE (data.wVersion) == 2); #endif /* Initialise the memory allocation subsystem. */ nn_alloc_init (); /* Seed the pseudo-random number generator. */ nn_random_seed (); /* Allocate the global table of SP sockets. */ self.socks = nn_alloc ((sizeof (struct nn_sock*) * NN_MAX_SOCKETS) + (sizeof (uint16_t) * NN_MAX_SOCKETS), "socket table"); alloc_assert (self.socks); for (i = 0; i != NN_MAX_SOCKETS; ++i) self.socks [i] = NULL; self.nsocks = 0; self.flags = 0; /* Print connection and accepting errors to the stderr */ envvar = getenv("NN_PRINT_ERRORS"); /* any non-empty string is true */ self.print_errors = envvar && *envvar; /* Allocate the stack of unused file descriptors. */ self.unused = (uint16_t*) (self.socks + NN_MAX_SOCKETS); alloc_assert (self.unused); for (i = 0; i != NN_MAX_SOCKETS; ++i) self.unused [i] = NN_MAX_SOCKETS - i - 1; /* Initialize transports if needed. */ for (i = 0; (tp = nn_transports[i]) != NULL; i++) { if (tp->init != NULL) { tp->init (); } } /* Start the worker threads. */ nn_pool_init (&self.pool); } static void nn_global_term (void) { #if defined NN_HAVE_WINDOWS int rc; #endif const struct nn_transport *tp; int i; /* If there are no sockets remaining, uninitialise the global context. */ nn_assert (self.socks); if (self.nsocks > 0) return; /* Shut down the worker threads. */ nn_pool_term (&self.pool); /* Ask all the transport to deallocate their global resources. */ for (i = 0; (tp = nn_transports[i]) != NULL; i++) { if (tp->term) tp->term (); } /* Final deallocation of the nn_global object itself. */ nn_free (self.socks); /* This marks the global state as uninitialised. */ self.socks = NULL; /* Shut down the memory allocation subsystem. */ nn_alloc_term (); /* On Windows, uninitialise the socket library. */ #if defined NN_HAVE_WINDOWS rc = WSACleanup (); nn_assert (rc == 0); #endif } void nn_term (void) { int i; if (!self.inited) { return; } nn_mutex_lock (&self.lock); self.flags |= NN_CTX_FLAG_TERMING; nn_mutex_unlock (&self.lock); /* Make sure we really close resources, this will cause global resources to be freed too when the last socket is closed. */ for (i = 0; i < NN_MAX_SOCKETS; i++) { (void) nn_close (i); } nn_mutex_lock (&self.lock); self.flags |= NN_CTX_FLAG_TERMED; self.flags &= ~NN_CTX_FLAG_TERMING; nn_condvar_broadcast(&self.cond); nn_mutex_unlock (&self.lock); } static void nn_lib_init(void) { /* This function is executed once to initialize global locks. */ nn_mutex_init (&self.lock); nn_condvar_init (&self.cond); self.inited = 1; } void nn_init (void) { nn_do_once (&once, nn_lib_init); nn_mutex_lock (&self.lock); /* Wait for any in progress term to complete. */ while (self.flags & NN_CTX_FLAG_TERMING) { nn_condvar_wait (&self.cond, &self.lock, -1); } self.flags &= ~NN_CTX_FLAG_TERMED; nn_mutex_unlock (&self.lock); } void *nn_allocmsg (size_t size, int type) { int rc; void *result; rc = nn_chunk_alloc (size, type, &result); if (rc == 0) return result; errno = -rc; return NULL; } void *nn_reallocmsg (void *msg, size_t size) { int rc; rc = nn_chunk_realloc (size, &msg); if (rc == 0) return msg; errno = -rc; return NULL; } int nn_freemsg (void *msg) { nn_chunk_free (msg); return 0; } struct nn_cmsghdr *nn_cmsg_nxthdr_ (const struct nn_msghdr *mhdr, const struct nn_cmsghdr *cmsg) { char *data; size_t sz; struct nn_cmsghdr *next; size_t headsz; /* Early return if no message is provided. */ if (nn_slow (mhdr == NULL)) return NULL; /* Get the actual data. */ if (mhdr->msg_controllen == NN_MSG) { data = *((void**) mhdr->msg_control); sz = nn_chunk_size (data); } else { data = (char*) mhdr->msg_control; sz = mhdr->msg_controllen; } /* Ancillary data allocation was not even large enough for one element. */ if (nn_slow (sz < NN_CMSG_SPACE (0))) return NULL; /* If cmsg is set to NULL we are going to return first property. Otherwise move to the next property. */ if (!cmsg) next = (struct nn_cmsghdr*) data; else next = (struct nn_cmsghdr*) (((char*) cmsg) + NN_CMSG_ALIGN_ (cmsg->cmsg_len)); /* If there's no space for next property, treat it as the end of the property list. */ headsz = ((char*) next) - data; if (headsz + NN_CMSG_SPACE (0) > sz || headsz + NN_CMSG_ALIGN_ (next->cmsg_len) > sz) return NULL; /* Success. */ return next; } int nn_global_create_socket (int domain, int protocol) { int rc; int s; int i; const struct nn_socktype *socktype; struct nn_sock *sock; /* The function is called with lock held */ /* Only AF_SP and AF_SP_RAW domains are supported. */ if (domain != AF_SP && domain != AF_SP_RAW) { return -EAFNOSUPPORT; } /* If socket limit was reached, report error. */ if (self.nsocks >= NN_MAX_SOCKETS) { return -EMFILE; } /* Find an empty socket slot. */ s = self.unused [NN_MAX_SOCKETS - self.nsocks - 1]; /* Find the appropriate socket type. */ for (i = 0; (socktype = nn_socktypes[i]) != NULL; i++) { if (socktype->domain == domain && socktype->protocol == protocol) { /* Instantiate the socket. */ if ((sock = nn_alloc (sizeof (struct nn_sock), "sock")) == NULL) return -ENOMEM; rc = nn_sock_init (sock, socktype, s); if (rc < 0) { nn_free (sock); return rc; } /* Adjust the global socket table. */ self.socks [s] = sock; ++self.nsocks; return s; } } /* Specified socket type wasn't found. */ return -EINVAL; } int nn_socket (int domain, int protocol) { int rc; nn_do_once (&once, nn_lib_init); nn_mutex_lock (&self.lock); /* If nn_term() was already called, return ETERM. */ if (nn_slow (self.flags & NN_CTX_FLAG_TERM)) { nn_mutex_unlock (&self.lock); errno = ETERM; return -1; } /* Make sure that global state is initialised. */ nn_global_init (); rc = nn_global_create_socket (domain, protocol); if (rc < 0) { nn_global_term (); nn_mutex_unlock (&self.lock); errno = -rc; return -1; } nn_mutex_unlock (&self.lock); return rc; } int nn_close (int s) { int rc; struct nn_sock *sock; nn_mutex_lock (&self.lock); rc = nn_global_hold_socket_locked (&sock, s); if (nn_slow (rc < 0)) { nn_mutex_unlock (&self.lock); errno = -rc; return -1; } /* Start the shutdown process on the socket. This will cause all other socket users, as well as endpoints, to begin cleaning up. This is done with the lock held to ensure that two instances of nn_close can't access the same socket. */ nn_sock_stop (sock); /* We have to drop both the hold we just acquired, as well as the original hold, in order for nn_sock_term to complete. */ nn_sock_rele (sock); nn_sock_rele (sock); nn_mutex_unlock (&self.lock); /* Now clean up. The termination routine below will block until all other consumers of the socket have dropped their holds, and all endpoints have cleanly exited. */ rc = nn_sock_term (sock); if (nn_slow (rc == -EINTR)) { nn_global_rele_socket (sock); errno = EINTR; return -1; } /* Remove the socket from the socket table, add it to unused socket table. */ nn_mutex_lock (&self.lock); self.socks [s] = NULL; self.unused [NN_MAX_SOCKETS - self.nsocks] = s; --self.nsocks; nn_free (sock); /* Destroy the global context if there's no socket remaining. */ nn_global_term (); nn_mutex_unlock (&self.lock); return 0; } int nn_setsockopt (int s, int level, int option, const void *optval, size_t optvallen) { int rc; struct nn_sock *sock; rc = nn_global_hold_socket (&sock, s); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (nn_slow (!optval && optvallen)) { rc = -EFAULT; goto fail; } rc = nn_sock_setopt (sock, level, option, optval, optvallen); if (nn_slow (rc < 0)) goto fail; errnum_assert (rc == 0, -rc); nn_global_rele_socket (sock); return 0; fail: nn_global_rele_socket (sock); errno = -rc; return -1; } int nn_getsockopt (int s, int level, int option, void *optval, size_t *optvallen) { int rc; struct nn_sock *sock; rc = nn_global_hold_socket (&sock, s); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (nn_slow (!optval && optvallen)) { rc = -EFAULT; goto fail; } rc = nn_sock_getopt (sock, level, option, optval, optvallen); if (nn_slow (rc < 0)) goto fail; errnum_assert (rc == 0, -rc); nn_global_rele_socket (sock); return 0; fail: nn_global_rele_socket (sock); errno = -rc; return -1; } int nn_bind (int s, const char *addr) { int rc; struct nn_sock *sock; rc = nn_global_hold_socket (&sock, s); if (rc < 0) { errno = -rc; return -1; } rc = nn_global_create_ep (sock, addr, 1); if (nn_slow (rc < 0)) { nn_global_rele_socket (sock); errno = -rc; return -1; } nn_global_rele_socket (sock); return rc; } int nn_connect (int s, const char *addr) { int rc; struct nn_sock *sock; rc = nn_global_hold_socket (&sock, s); if (nn_slow (rc < 0)) { errno = -rc; return -1; } rc = nn_global_create_ep (sock, addr, 0); if (rc < 0) { nn_global_rele_socket (sock); errno = -rc; return -1; } nn_global_rele_socket (sock); return rc; } int nn_shutdown (int s, int how) { int rc; struct nn_sock *sock; rc = nn_global_hold_socket (&sock, s); if (nn_slow (rc < 0)) { errno = -rc; return -1; } rc = nn_sock_rm_ep (sock, how); if (nn_slow (rc < 0)) { nn_global_rele_socket (sock); errno = -rc; return -1; } nn_assert (rc == 0); nn_global_rele_socket (sock); return 0; } int nn_send (int s, const void *buf, size_t len, int flags) { struct nn_iovec iov; struct nn_msghdr hdr; iov.iov_base = (void*) buf; iov.iov_len = len; hdr.msg_iov = &iov; hdr.msg_iovlen = 1; hdr.msg_control = NULL; hdr.msg_controllen = 0; return nn_sendmsg (s, &hdr, flags); } int nn_recv (int s, void *buf, size_t len, int flags) { struct nn_iovec iov; struct nn_msghdr hdr; iov.iov_base = buf; iov.iov_len = len; hdr.msg_iov = &iov; hdr.msg_iovlen = 1; hdr.msg_control = NULL; hdr.msg_controllen = 0; return nn_recvmsg (s, &hdr, flags); } int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags) { int rc; size_t sz; size_t spsz; int i; struct nn_iovec *iov; struct nn_msg msg; void *chunk; int nnmsg; struct nn_cmsghdr *cmsg; struct nn_sock *sock; rc = nn_global_hold_socket (&sock, s); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (nn_slow (!msghdr)) { rc = -EINVAL; goto fail; } if (nn_slow (msghdr->msg_iovlen < 0)) { rc = -EMSGSIZE; goto fail; } if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) { chunk = *(void**) msghdr->msg_iov [0].iov_base; if (nn_slow (chunk == NULL)) { rc = -EFAULT; goto fail; } sz = nn_chunk_size (chunk); nn_msg_init_chunk (&msg, chunk); nnmsg = 1; } else { /* Compute the total size of the message. */ sz = 0; for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; if (nn_slow (iov->iov_len == NN_MSG)) { rc = -EINVAL; goto fail; } if (nn_slow (!iov->iov_base && iov->iov_len)) { rc = -EFAULT; goto fail; } if (nn_slow (sz + iov->iov_len < sz)) { rc = -EINVAL; goto fail; } sz += iov->iov_len; } /* Create a message object from the supplied scatter array. */ nn_msg_init (&msg, sz); sz = 0; for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; memcpy (((uint8_t*) nn_chunkref_data (&msg.body)) + sz, iov->iov_base, iov->iov_len); sz += iov->iov_len; } nnmsg = 0; } /* Add ancillary data to the message. */ if (msghdr->msg_control) { /* Copy all headers. */ /* TODO: SP_HDR should not be copied here! */ if (msghdr->msg_controllen == NN_MSG) { chunk = *((void**) msghdr->msg_control); nn_chunkref_term (&msg.hdrs); nn_chunkref_init_chunk (&msg.hdrs, chunk); } else { nn_chunkref_term (&msg.hdrs); nn_chunkref_init (&msg.hdrs, msghdr->msg_controllen); memcpy (nn_chunkref_data (&msg.hdrs), msghdr->msg_control, msghdr->msg_controllen); } /* Search for SP_HDR property. */ cmsg = NN_CMSG_FIRSTHDR (msghdr); while (cmsg) { if (cmsg->cmsg_level == PROTO_SP && cmsg->cmsg_type == SP_HDR) { unsigned char *ptr = NN_CMSG_DATA (cmsg); size_t clen = cmsg->cmsg_len - NN_CMSG_SPACE (0); if (clen > sizeof (size_t)) { spsz = *(size_t *)(void *)ptr; if (spsz <= (clen - sizeof (size_t))) { /* Copy body of SP_HDR property into 'sphdr'. */ nn_chunkref_term (&msg.sphdr); nn_chunkref_init (&msg.sphdr, spsz); memcpy (nn_chunkref_data (&msg.sphdr), ptr + sizeof (size_t), spsz); } } break; } cmsg = NN_CMSG_NXTHDR (msghdr, cmsg); } } /* Send it further down the stack. */ rc = nn_sock_send (sock, &msg, flags); if (nn_slow (rc < 0)) { /* If we are dealing with user-supplied buffer, detach it from the message object. */ if (nnmsg) nn_chunkref_init (&msg.body, 0); nn_msg_term (&msg); goto fail; } /* Adjust the statistics. */ nn_sock_stat_increment (sock, NN_STAT_MESSAGES_SENT, 1); nn_sock_stat_increment (sock, NN_STAT_BYTES_SENT, sz); nn_global_rele_socket (sock); return (int) sz; fail: nn_global_rele_socket (sock); errno = -rc; return -1; } int nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags) { int rc; struct nn_msg msg; uint8_t *data; size_t sz; int i; struct nn_iovec *iov; void *chunk; size_t hdrssz; void *ctrl; size_t ctrlsz; size_t spsz; size_t sptotalsz; struct nn_cmsghdr *chdr; struct nn_sock *sock; rc = nn_global_hold_socket (&sock, s); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (nn_slow (!msghdr)) { rc = -EINVAL; goto fail; } if (nn_slow (msghdr->msg_iovlen < 0)) { rc = -EMSGSIZE; goto fail; } /* Get a message. */ rc = nn_sock_recv (sock, &msg, flags); if (nn_slow (rc < 0)) { goto fail; } if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) { chunk = nn_chunkref_getchunk (&msg.body); *(void**) (msghdr->msg_iov [0].iov_base) = chunk; sz = nn_chunk_size (chunk); } else { /* Copy the message content into the supplied gather array. */ data = nn_chunkref_data (&msg.body); sz = nn_chunkref_size (&msg.body); for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; if (nn_slow (iov->iov_len == NN_MSG)) { nn_msg_term (&msg); rc = -EINVAL; goto fail; } if (iov->iov_len > sz) { memcpy (iov->iov_base, data, sz); break; } memcpy (iov->iov_base, data, iov->iov_len); data += iov->iov_len; sz -= iov->iov_len; } sz = nn_chunkref_size (&msg.body); } /* Retrieve the ancillary data from the message. */ if (msghdr->msg_control) { spsz = nn_chunkref_size (&msg.sphdr); sptotalsz = NN_CMSG_SPACE (spsz+sizeof (size_t)); ctrlsz = sptotalsz + nn_chunkref_size (&msg.hdrs); if (msghdr->msg_controllen == NN_MSG) { /* Allocate the buffer. */ rc = nn_chunk_alloc (ctrlsz, 0, &ctrl); errnum_assert (rc == 0, -rc); /* Set output parameters. */ *((void**) msghdr->msg_control) = ctrl; } else { /* Just use the buffer supplied by the user. */ ctrl = msghdr->msg_control; ctrlsz = msghdr->msg_controllen; } /* If SP header alone won't fit into the buffer, return no ancillary properties. */ if (ctrlsz >= sptotalsz) { char *ptr; /* Fill in SP_HDR ancillary property. */ chdr = (struct nn_cmsghdr*) ctrl; chdr->cmsg_len = sptotalsz; chdr->cmsg_level = PROTO_SP; chdr->cmsg_type = SP_HDR; ptr = (void *)chdr; ptr += sizeof (*chdr); *(size_t *)(void *)ptr = spsz; ptr += sizeof (size_t); memcpy (ptr, nn_chunkref_data (&msg.sphdr), spsz); /* Fill in as many remaining properties as possible. Truncate the trailing properties if necessary. */ hdrssz = nn_chunkref_size (&msg.hdrs); if (hdrssz > ctrlsz - sptotalsz) hdrssz = ctrlsz - sptotalsz; memcpy (((char*) ctrl) + sptotalsz, nn_chunkref_data (&msg.hdrs), hdrssz); } } nn_msg_term (&msg); /* Adjust the statistics. */ nn_sock_stat_increment (sock, NN_STAT_MESSAGES_RECEIVED, 1); nn_sock_stat_increment (sock, NN_STAT_BYTES_RECEIVED, sz); nn_global_rele_socket (sock); return (int) sz; fail: nn_global_rele_socket (sock); errno = -rc; return -1; } uint64_t nn_get_statistic (int s, int statistic) { int rc; struct nn_sock *sock; uint64_t val; rc = nn_global_hold_socket (&sock, s); if (nn_slow (rc < 0)) { errno = -rc; return (uint64_t)-1; } switch (statistic) { case NN_STAT_ESTABLISHED_CONNECTIONS: val = sock->statistics.established_connections; break; case NN_STAT_ACCEPTED_CONNECTIONS: val = sock->statistics.accepted_connections; break; case NN_STAT_DROPPED_CONNECTIONS: val = sock->statistics.dropped_connections; break; case NN_STAT_BROKEN_CONNECTIONS: val = sock->statistics.broken_connections; break; case NN_STAT_CONNECT_ERRORS: val = sock->statistics.connect_errors; break; case NN_STAT_BIND_ERRORS: val = sock->statistics.bind_errors; break; case NN_STAT_ACCEPT_ERRORS: val = sock->statistics.bind_errors; break; case NN_STAT_MESSAGES_SENT: val = sock->statistics.messages_sent; break; case NN_STAT_MESSAGES_RECEIVED: val = sock->statistics.messages_received; break; case NN_STAT_BYTES_SENT: val = sock->statistics.bytes_sent; break; case NN_STAT_BYTES_RECEIVED: val = sock->statistics.bytes_received; break; case NN_STAT_CURRENT_CONNECTIONS: val = sock->statistics.current_connections; break; case NN_STAT_INPROGRESS_CONNECTIONS: val = sock->statistics.inprogress_connections; break; case NN_STAT_CURRENT_SND_PRIORITY: val = sock->statistics.current_snd_priority; break; case NN_STAT_CURRENT_EP_ERRORS: val = sock->statistics.current_ep_errors; break; default: val = (uint64_t)-1; errno = EINVAL; break; } nn_global_rele_socket (sock); return val; } static int nn_global_create_ep (struct nn_sock *sock, const char *addr, int bind) { int rc; const char *proto; const char *delim; size_t protosz; const struct nn_transport *tp; int i; /* Check whether address is valid. */ if (!addr) return -EINVAL; if (strlen (addr) >= NN_SOCKADDR_MAX) return -ENAMETOOLONG; /* Separate the protocol and the actual address. */ proto = addr; delim = strchr (addr, ':'); if (!delim) return -EINVAL; if (delim [1] != '/' || delim [2] != '/') return -EINVAL; protosz = delim - addr; addr += protosz + 3; /* Find the specified protocol. */ tp = NULL; for (i = 0; ((tp = nn_transports[i]) != NULL); i++) { if (strlen (tp->name) == protosz && memcmp (tp->name, proto, protosz) == 0) break; } /* The protocol specified doesn't match any known protocol. */ if (tp == NULL) { return -EPROTONOSUPPORT; } /* Ask the socket to create the endpoint. */ rc = nn_sock_add_ep (sock, tp, bind, addr); return rc; } const struct nn_transport *nn_global_transport (int id) { const struct nn_transport *tp; int i; for (i = 0; (tp = nn_transports[i]) != NULL; i++) { if (tp->id == id) return tp; } return NULL; } struct nn_pool *nn_global_getpool () { return &self.pool; } int nn_global_print_errors () { return self.print_errors; } /* Get the socket structure for a socket id. This must be called under the global lock (self.lock.) The socket itself will not be freed while the hold is active. */ int nn_global_hold_socket_locked(struct nn_sock **sockp, int s) { struct nn_sock *sock; if (nn_slow (s < 0 || s >= NN_MAX_SOCKETS || self.socks == NULL)) return -EBADF; sock = self.socks[s]; if (nn_slow (sock == NULL)) { return -EBADF; } if (nn_slow (nn_sock_hold (sock) != 0)) { return -EBADF; } *sockp = sock; return 0; } int nn_global_hold_socket(struct nn_sock **sockp, int s) { int rc; nn_mutex_lock(&self.lock); rc = nn_global_hold_socket_locked(sockp, s); nn_mutex_unlock(&self.lock); return rc; } void nn_global_rele_socket(struct nn_sock *sock) { nn_mutex_lock(&self.lock); nn_sock_rele(sock); nn_mutex_unlock(&self.lock); } nanomsg-1.1.5/src/core/global.h000066400000000000000000000027431336111550300163140ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_GLOBAL_INCLUDED #define NN_GLOBAL_INCLUDED /* Provides access to the list of available transports. */ const struct nn_transport *nn_global_transport (int id); /* Returns the global worker thread pool. */ struct nn_pool *nn_global_getpool (); int nn_global_print_errors(); #endif nanomsg-1.1.5/src/core/pipe.c000066400000000000000000000154721336111550300160070ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "../transport.h" #include "../protocol.h" #include "sock.h" #include "ep.h" #include "../utils/err.h" #include "../utils/fast.h" /* Internal pipe states. */ #define NN_PIPEBASE_STATE_IDLE 1 #define NN_PIPEBASE_STATE_ACTIVE 2 #define NN_PIPEBASE_STATE_FAILED 3 #define NN_PIPEBASE_INSTATE_DEACTIVATED 0 #define NN_PIPEBASE_INSTATE_IDLE 1 #define NN_PIPEBASE_INSTATE_RECEIVING 2 #define NN_PIPEBASE_INSTATE_RECEIVED 3 #define NN_PIPEBASE_INSTATE_ASYNC 4 #define NN_PIPEBASE_OUTSTATE_DEACTIVATED 0 #define NN_PIPEBASE_OUTSTATE_IDLE 1 #define NN_PIPEBASE_OUTSTATE_SENDING 2 #define NN_PIPEBASE_OUTSTATE_SENT 3 #define NN_PIPEBASE_OUTSTATE_ASYNC 4 void nn_pipebase_init (struct nn_pipebase *self, const struct nn_pipebase_vfptr *vfptr, struct nn_ep *ep) { nn_assert (ep->sock); nn_fsm_init (&self->fsm, NULL, NULL, 0, self, &ep->sock->fsm); self->vfptr = vfptr; self->state = NN_PIPEBASE_STATE_IDLE; self->instate = NN_PIPEBASE_INSTATE_DEACTIVATED; self->outstate = NN_PIPEBASE_OUTSTATE_DEACTIVATED; self->sock = ep->sock; memcpy (&self->options, &ep->options, sizeof (struct nn_ep_options)); nn_fsm_event_init (&self->in); nn_fsm_event_init (&self->out); } void nn_pipebase_term (struct nn_pipebase *self) { nn_assert_state (self, NN_PIPEBASE_STATE_IDLE); nn_fsm_event_term (&self->out); nn_fsm_event_term (&self->in); nn_fsm_term (&self->fsm); } int nn_pipebase_start (struct nn_pipebase *self) { int rc; nn_assert_state (self, NN_PIPEBASE_STATE_IDLE); self->state = NN_PIPEBASE_STATE_ACTIVE; self->instate = NN_PIPEBASE_INSTATE_ASYNC; self->outstate = NN_PIPEBASE_OUTSTATE_IDLE; rc = nn_sock_add (self->sock, (struct nn_pipe*) self); if (nn_slow (rc < 0)) { self->state = NN_PIPEBASE_STATE_FAILED; return rc; } nn_fsm_raise (&self->fsm, &self->out, NN_PIPE_OUT); return 0; } void nn_pipebase_stop (struct nn_pipebase *self) { if (self->state == NN_PIPEBASE_STATE_ACTIVE) nn_sock_rm (self->sock, (struct nn_pipe*) self); self->state = NN_PIPEBASE_STATE_IDLE; } void nn_pipebase_received (struct nn_pipebase *self) { if (nn_fast (self->instate == NN_PIPEBASE_INSTATE_RECEIVING)) { self->instate = NN_PIPEBASE_INSTATE_RECEIVED; return; } nn_assert (self->instate == NN_PIPEBASE_INSTATE_ASYNC); self->instate = NN_PIPEBASE_INSTATE_IDLE; nn_fsm_raise (&self->fsm, &self->in, NN_PIPE_IN); } void nn_pipebase_sent (struct nn_pipebase *self) { if (nn_fast (self->outstate == NN_PIPEBASE_OUTSTATE_SENDING)) { self->outstate = NN_PIPEBASE_OUTSTATE_SENT; return; } nn_assert (self->outstate == NN_PIPEBASE_OUTSTATE_ASYNC); self->outstate = NN_PIPEBASE_OUTSTATE_IDLE; nn_fsm_raise (&self->fsm, &self->out, NN_PIPE_OUT); } void nn_pipebase_getopt (struct nn_pipebase *self, int level, int option, void *optval, size_t *optvallen) { int rc; int intval; if (level == NN_SOL_SOCKET) { switch (option) { /* Endpoint options */ case NN_SNDPRIO: intval = self->options.sndprio; break; case NN_RCVPRIO: intval = self->options.rcvprio; break; case NN_IPV4ONLY: intval = self->options.ipv4only; break; /* Fallback to socket options */ default: rc = nn_sock_getopt_inner (self->sock, level, option, optval, optvallen); errnum_assert (rc == 0, -rc); return; } memcpy (optval, &intval, *optvallen < sizeof (int) ? *optvallen : sizeof (int)); *optvallen = sizeof (int); return; } rc = nn_sock_getopt_inner (self->sock, level, option, optval, optvallen); errnum_assert (rc == 0, -rc); } int nn_pipebase_ispeer (struct nn_pipebase *self, int socktype) { return nn_sock_ispeer (self->sock, socktype); } void nn_pipe_setdata (struct nn_pipe *self, void *data) { ((struct nn_pipebase*) self)->data = data; } void *nn_pipe_getdata (struct nn_pipe *self) { return ((struct nn_pipebase*) self)->data; } int nn_pipe_send (struct nn_pipe *self, struct nn_msg *msg) { int rc; struct nn_pipebase *pipebase; pipebase = (struct nn_pipebase*) self; nn_assert (pipebase->outstate == NN_PIPEBASE_OUTSTATE_IDLE); pipebase->outstate = NN_PIPEBASE_OUTSTATE_SENDING; rc = pipebase->vfptr->send (pipebase, msg); errnum_assert (rc >= 0, -rc); if (nn_fast (pipebase->outstate == NN_PIPEBASE_OUTSTATE_SENT)) { pipebase->outstate = NN_PIPEBASE_OUTSTATE_IDLE; return rc; } nn_assert (pipebase->outstate == NN_PIPEBASE_OUTSTATE_SENDING); pipebase->outstate = NN_PIPEBASE_OUTSTATE_ASYNC; return rc | NN_PIPEBASE_RELEASE; } int nn_pipe_recv (struct nn_pipe *self, struct nn_msg *msg) { int rc; struct nn_pipebase *pipebase; pipebase = (struct nn_pipebase*) self; nn_assert (pipebase->instate == NN_PIPEBASE_INSTATE_IDLE); pipebase->instate = NN_PIPEBASE_INSTATE_RECEIVING; rc = pipebase->vfptr->recv (pipebase, msg); errnum_assert (rc >= 0, -rc); if (nn_fast (pipebase->instate == NN_PIPEBASE_INSTATE_RECEIVED)) { pipebase->instate = NN_PIPEBASE_INSTATE_IDLE; return rc; } nn_assert (pipebase->instate == NN_PIPEBASE_INSTATE_RECEIVING); pipebase->instate = NN_PIPEBASE_INSTATE_ASYNC; return rc | NN_PIPEBASE_RELEASE; } void nn_pipe_getopt (struct nn_pipe *self, int level, int option, void *optval, size_t *optvallen) { struct nn_pipebase *pipebase; pipebase = (struct nn_pipebase*) self; nn_pipebase_getopt (pipebase, level, option, optval, optvallen); } nanomsg-1.1.5/src/core/poll.c000066400000000000000000000134131336111550300160110ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "../nn.h" #if defined NN_HAVE_WINDOWS #include "../utils/win.h" #include "../utils/fast.h" #include "../utils/sleep.h" #include "../utils/err.h" int nn_poll (struct nn_pollfd *fds, int nfds, int timeout) { int rc; int i; fd_set fdset; SOCKET fd; int res; size_t sz; struct timeval tv; /* Fill in the fdset, as appropriate. */ FD_ZERO (&fdset); for (i = 0; i != nfds; ++i) { if (fds [i].events & NN_POLLIN) { sz = sizeof (fd); rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_RCVFD, &fd, &sz); if (nn_slow (rc < 0)) { return -1; } nn_assert (sz == sizeof (fd)); FD_SET (fd, &fdset); } if (fds [i].events & NN_POLLOUT) { sz = sizeof (fd); rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_SNDFD, &fd, &sz); if (nn_slow (rc < 0)) { return -1; } nn_assert (sz == sizeof (fd)); FD_SET (fd, &fdset); } } /* Do the polling itself. */ tv.tv_sec = timeout / 1000; tv.tv_usec = timeout % 1000 * 1000; if (nn_fast (nfds)) { rc = select (-1, &fdset, NULL, NULL, &tv); if (nn_slow (rc == 0)) return 0; if (nn_slow (rc == SOCKET_ERROR)) { errno = nn_err_wsa_to_posix (WSAGetLastError ()); return -1; } } else { /* POSIX platforms will sleep until timeout is expired, so let's do the same on Windows. */ if (timeout > 0) nn_sleep(timeout); return 0; } /* Move the results from fdset to the nanomsg pollset. */ res = 0; for (i = 0; i != nfds; ++i) { fds [i].revents = 0; if (fds [i].events & NN_POLLIN) { sz = sizeof (fd); rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_RCVFD, &fd, &sz); if (nn_slow (rc < 0)) { errno = -rc; return -1; } nn_assert (sz == sizeof (fd)); if (FD_ISSET (fd, &fdset)) fds [i].revents |= NN_POLLIN; } if (fds [i].events & NN_POLLOUT) { sz = sizeof (fd); rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_SNDFD, &fd, &sz); if (nn_slow (rc < 0)) { errno = -rc; return -1; } nn_assert (sz == sizeof (fd)); if (FD_ISSET (fd, &fdset)) fds [i].revents |= NN_POLLOUT; } if (fds [i].revents) ++res; } return res; } #else #include "../utils/alloc.h" #include "../utils/fast.h" #include "../utils/err.h" #include #include int nn_poll (struct nn_pollfd *fds, int nfds, int timeout) { int rc; int i; int pos; int fd; int res; size_t sz; struct pollfd *pfd; /* Construct a pollset to be used with OS-level 'poll' function. */ pfd = nn_alloc (sizeof (struct pollfd) * nfds * 2, "pollset"); alloc_assert (pfd); pos = 0; for (i = 0; i != nfds; ++i) { if (fds [i].events & NN_POLLIN) { sz = sizeof (fd); rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_RCVFD, &fd, &sz); if (nn_slow (rc < 0)) { nn_free (pfd); return -1; } nn_assert (sz == sizeof (fd)); pfd [pos].fd = fd; pfd [pos].events = POLLIN; ++pos; } if (fds [i].events & NN_POLLOUT) { sz = sizeof (fd); rc = nn_getsockopt (fds [i].fd, NN_SOL_SOCKET, NN_SNDFD, &fd, &sz); if (nn_slow (rc < 0)) { nn_free (pfd); return -1; } nn_assert (sz == sizeof (fd)); pfd [pos].fd = fd; pfd [pos].events = POLLIN; ++pos; } } /* Do the polling itself. */ rc = poll (pfd, pos, timeout); if (nn_slow (rc <= 0)) { res = errno; nn_free (pfd); errno = res; return rc; } /* Move the results from OS-level poll to nn_poll's pollset. */ res = 0; pos = 0; for (i = 0; i != nfds; ++i) { fds [i].revents = 0; if (fds [i].events & NN_POLLIN) { if (pfd [pos].revents & POLLIN) fds [i].revents |= NN_POLLIN; ++pos; } if (fds [i].events & NN_POLLOUT) { if (pfd [pos].revents & POLLIN) fds [i].revents |= NN_POLLOUT; ++pos; } if (fds [i].revents) ++res; } nn_free (pfd); return res; } #endif nanomsg-1.1.5/src/core/sock.c000066400000000000000000001047061336111550300160100ustar00rootroot00000000000000/* Copyright (c) 2012-2014 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2017 Garrett D'Amore Copyright 2017 Capitar IT Group BV 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. */ #include "../protocol.h" #include "../transport.h" #include "sock.h" #include "global.h" #include "ep.h" #include "../utils/err.h" #include "../utils/cont.h" #include "../utils/clock.h" #include "../utils/fast.h" #include "../utils/alloc.h" #include "../utils/msg.h" #include /* These bits specify whether individual efds are signalled or not at the moment. Storing this information allows us to avoid redundant signalling and unsignalling of the efd objects. */ #define NN_SOCK_FLAG_IN 1 #define NN_SOCK_FLAG_OUT 2 /* Possible states of the socket. */ #define NN_SOCK_STATE_INIT 1 #define NN_SOCK_STATE_ACTIVE 2 #define NN_SOCK_STATE_STOPPING_EPS 3 #define NN_SOCK_STATE_STOPPING 4 #define NN_SOCK_STATE_FINI 5 /* Events sent to the state machine. */ #define NN_SOCK_ACTION_STOPPED 1 /* Subordinated source objects. */ #define NN_SOCK_SRC_EP 1 /* Private functions. */ static struct nn_optset *nn_sock_optset (struct nn_sock *self, int id); static int nn_sock_setopt_inner (struct nn_sock *self, int level, int option, const void *optval, size_t optvallen); static void nn_sock_onleave (struct nn_ctx *self); static void nn_sock_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_sock_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); /* Initialize a socket. A hold is placed on the initialized socket for the caller as well. */ int nn_sock_init (struct nn_sock *self, const struct nn_socktype *socktype, int fd) { int rc; int i; /* Make sure that at least one message direction is supported. */ nn_assert (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND) || !(socktype->flags & NN_SOCKTYPE_FLAG_NORECV)); /* Create the AIO context for the SP socket. */ nn_ctx_init (&self->ctx, nn_global_getpool (), nn_sock_onleave); /* Initialise the state machine. */ nn_fsm_init_root (&self->fsm, nn_sock_handler, nn_sock_shutdown, &self->ctx); self->state = NN_SOCK_STATE_INIT; /* Open the NN_SNDFD and NN_RCVFD efds. Do so, only if the socket type supports send/recv, as appropriate. */ if (socktype->flags & NN_SOCKTYPE_FLAG_NOSEND) memset (&self->sndfd, 0xcd, sizeof (self->sndfd)); else { rc = nn_efd_init (&self->sndfd); if (nn_slow (rc < 0)) return rc; } if (socktype->flags & NN_SOCKTYPE_FLAG_NORECV) memset (&self->rcvfd, 0xcd, sizeof (self->rcvfd)); else { rc = nn_efd_init (&self->rcvfd); if (nn_slow (rc < 0)) { if (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) nn_efd_term (&self->sndfd); return rc; } } nn_sem_init (&self->termsem); nn_sem_init (&self->relesem); if (nn_slow (rc < 0)) { if (!(socktype->flags & NN_SOCKTYPE_FLAG_NORECV)) nn_efd_term (&self->rcvfd); if (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) nn_efd_term (&self->sndfd); return rc; } self->holds = 1; /* Callers hold. */ self->flags = 0; nn_list_init (&self->eps); nn_list_init (&self->sdeps); self->eid = 1; /* Default values for NN_SOL_SOCKET options. */ self->sndbuf = 128 * 1024; self->rcvbuf = 128 * 1024; self->rcvmaxsize = 1024 * 1024; self->sndtimeo = -1; self->rcvtimeo = -1; self->reconnect_ivl = 100; self->reconnect_ivl_max = 0; self->maxttl = 8; self->ep_template.sndprio = 8; self->ep_template.rcvprio = 8; self->ep_template.ipv4only = 1; /* Clear statistic entries */ memset(&self->statistics, 0, sizeof (self->statistics)); /* Should be pretty much enough space for just the number */ sprintf(self->socket_name, "%d", fd); /* Security attribute */ self->sec_attr = NULL; self->sec_attr_size = 0; self->inbuffersz = 4096; self->outbuffersz = 4096; /* The transport-specific options are not initialised immediately, rather, they are allocated later on when needed. */ for (i = 0; i != NN_MAX_TRANSPORT; ++i) self->optsets [i] = NULL; /* Create the specific socket type itself. */ rc = socktype->create ((void*) self, &self->sockbase); errnum_assert (rc == 0, -rc); self->socktype = socktype; /* Launch the state machine. */ nn_ctx_enter (&self->ctx); nn_fsm_start (&self->fsm); nn_ctx_leave (&self->ctx); return 0; } void nn_sock_stopped (struct nn_sock *self) { /* TODO: Do the following in a more sane way. */ self->fsm.stopped.fsm = &self->fsm; self->fsm.stopped.src = NN_FSM_ACTION; self->fsm.stopped.srcptr = NULL; self->fsm.stopped.type = NN_SOCK_ACTION_STOPPED; nn_ctx_raise (self->fsm.ctx, &self->fsm.stopped); } /* Stop the socket. This will prevent new calls from aquiring a hold on the socket, cause endpoints to shut down, and wake any threads waiting to recv or send data. */ void nn_sock_stop (struct nn_sock *self) { nn_ctx_enter (&self->ctx); nn_fsm_stop (&self->fsm); nn_ctx_leave (&self->ctx); } int nn_sock_term (struct nn_sock *self) { int rc; int i; /* NOTE: nn_sock_stop must have already been called. */ /* Some endpoints may still be alive. Here we are going to wait till they are all closed. This loop is not interruptible, because making it so would leave a partially cleaned up socket, and we don't have a way to defer resource deallocation. */ for (;;) { rc = nn_sem_wait (&self->termsem); if (nn_slow (rc == -EINTR)) continue; errnum_assert (rc == 0, -rc); break; } /* Also, wait for all holds on the socket to be released. */ for (;;) { rc = nn_sem_wait (&self->relesem); if (nn_slow (rc == -EINTR)) continue; errnum_assert (rc == 0, -rc); break; } /* Threads that posted the semaphore(s) can still have the ctx locked for a short while. By simply entering the context and exiting it immediately we can be sure that any such threads have already exited the context. */ nn_ctx_enter (&self->ctx); nn_ctx_leave (&self->ctx); /* At this point, we can be reasonably certain that no other thread has any references to the socket. */ /* Close the event FDs entirely. */ if (!(self->socktype->flags & NN_SOCKTYPE_FLAG_NORECV)) { nn_efd_term (&self->rcvfd); } if (!(self->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) { nn_efd_term (&self->sndfd); } nn_fsm_stopped_noevent (&self->fsm); nn_fsm_term (&self->fsm); nn_sem_term (&self->termsem); nn_sem_term (&self->relesem); nn_list_term (&self->sdeps); nn_list_term (&self->eps); nn_ctx_term (&self->ctx); /* Destroy any optsets associated with the socket. */ for (i = 0; i != NN_MAX_TRANSPORT; ++i) if (self->optsets [i]) self->optsets [i]->vfptr->destroy (self->optsets [i]); return 0; } struct nn_ctx *nn_sock_getctx (struct nn_sock *self) { return &self->ctx; } int nn_sock_ispeer (struct nn_sock *self, int socktype) { /* If the peer implements a different SP protocol it is not a valid peer. Checking it here ensures that even if faulty protocol implementation allows for cross-protocol communication, it will never happen in practice. */ if ((self->socktype->protocol & 0xfff0) != (socktype & 0xfff0)) return 0; /* As long as the peer speaks the same protocol, socket type itself decides which socket types are to be accepted. */ return self->socktype->ispeer (socktype); } int nn_sock_setopt (struct nn_sock *self, int level, int option, const void *optval, size_t optvallen) { int rc; nn_ctx_enter (&self->ctx); rc = nn_sock_setopt_inner (self, level, option, optval, optvallen); nn_ctx_leave (&self->ctx); return rc; } static int nn_sock_setopt_inner (struct nn_sock *self, int level, int option, const void *optval, size_t optvallen) { struct nn_optset *optset; int val; /* Protocol-specific socket options. */ if (level > NN_SOL_SOCKET) { if (self->sockbase->vfptr->setopt == NULL) { return -ENOPROTOOPT; } return self->sockbase->vfptr->setopt (self->sockbase, level, option, optval, optvallen); } /* Transport-specific options. */ if (level < NN_SOL_SOCKET) { optset = nn_sock_optset (self, level); if (!optset) return -ENOPROTOOPT; return optset->vfptr->setopt (optset, option, optval, optvallen); } nn_assert (level == NN_SOL_SOCKET); /* Special-casing socket name for now as it's the only string option */ if (option == NN_SOCKET_NAME) { if (optvallen > 63) return -EINVAL; memcpy (self->socket_name, optval, optvallen); self->socket_name [optvallen] = 0; return 0; } /* At this point we assume that all options are of type int. */ if (optvallen != sizeof (int)) return -EINVAL; val = *(int*) optval; /* Generic socket-level options. */ switch (option) { case NN_SNDBUF: if (val <= 0) return -EINVAL; self->sndbuf = val; return 0; case NN_RCVBUF: if (val <= 0) return -EINVAL; self->rcvbuf = val; return 0; case NN_RCVMAXSIZE: if (val < -1) return -EINVAL; self->rcvmaxsize = val; return 0; case NN_SNDTIMEO: self->sndtimeo = val; return 0; case NN_RCVTIMEO: self->rcvtimeo = val; return 0; case NN_RECONNECT_IVL: if (val < 0) return -EINVAL; self->reconnect_ivl = val; return 0; case NN_RECONNECT_IVL_MAX: if (val < 0) return -EINVAL; self->reconnect_ivl_max = val; return 0; case NN_SNDPRIO: if (val < 1 || val > 16) return -EINVAL; self->ep_template.sndprio = val; return 0; case NN_RCVPRIO: if (val < 1 || val > 16) return -EINVAL; self->ep_template.rcvprio = val; return 0; case NN_IPV4ONLY: if (val != 0 && val != 1) return -EINVAL; self->ep_template.ipv4only = val; return 0; case NN_MAXTTL: if (val < 1 || val > 255) return -EINVAL; self->maxttl = val; return 0; case NN_LINGER: /* Ignored, retained for compatibility. */ return 0; } return -ENOPROTOOPT; } int nn_sock_getopt (struct nn_sock *self, int level, int option, void *optval, size_t *optvallen) { int rc; nn_ctx_enter (&self->ctx); rc = nn_sock_getopt_inner (self, level, option, optval, optvallen); nn_ctx_leave (&self->ctx); return rc; } int nn_sock_getopt_inner (struct nn_sock *self, int level, int option, void *optval, size_t *optvallen) { struct nn_optset *optset; int intval; nn_fd fd; /* Protocol-specific socket options. */ if (level > NN_SOL_SOCKET) { if (self->sockbase->vfptr->getopt == NULL) { return -ENOPROTOOPT; } return self->sockbase->vfptr->getopt (self->sockbase, level, option, optval, optvallen); } /* Transport-specific options. */ if (level < NN_SOL_SOCKET) { optset = nn_sock_optset (self, level); if (!optset) return -ENOPROTOOPT; return optset->vfptr->getopt (optset, option, optval, optvallen); } nn_assert (level == NN_SOL_SOCKET); /* Generic socket-level options. */ switch (option) { case NN_DOMAIN: intval = self->socktype->domain; break; case NN_PROTOCOL: intval = self->socktype->protocol; break; case NN_LINGER: intval = 0; break; case NN_SNDBUF: intval = self->sndbuf; break; case NN_RCVBUF: intval = self->rcvbuf; break; case NN_RCVMAXSIZE: intval = self->rcvmaxsize; break; case NN_SNDTIMEO: intval = self->sndtimeo; break; case NN_RCVTIMEO: intval = self->rcvtimeo; break; case NN_RECONNECT_IVL: intval = self->reconnect_ivl; break; case NN_RECONNECT_IVL_MAX: intval = self->reconnect_ivl_max; break; case NN_SNDPRIO: intval = self->ep_template.sndprio; break; case NN_RCVPRIO: intval = self->ep_template.rcvprio; break; case NN_IPV4ONLY: intval = self->ep_template.ipv4only; break; case NN_MAXTTL: intval = self->maxttl; break; case NN_SNDFD: if (self->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND) return -ENOPROTOOPT; fd = nn_efd_getfd (&self->sndfd); memcpy (optval, &fd, *optvallen < sizeof (nn_fd) ? *optvallen : sizeof (nn_fd)); *optvallen = sizeof (nn_fd); return 0; case NN_RCVFD: if (self->socktype->flags & NN_SOCKTYPE_FLAG_NORECV) return -ENOPROTOOPT; fd = nn_efd_getfd (&self->rcvfd); memcpy (optval, &fd, *optvallen < sizeof (nn_fd) ? *optvallen : sizeof (nn_fd)); *optvallen = sizeof (nn_fd); return 0; case NN_SOCKET_NAME: strncpy (optval, self->socket_name, *optvallen); *optvallen = strlen(self->socket_name); return 0; default: return -ENOPROTOOPT; } memcpy (optval, &intval, *optvallen < sizeof (int) ? *optvallen : sizeof (int)); *optvallen = sizeof (int); return 0; } int nn_sock_add_ep (struct nn_sock *self, const struct nn_transport *transport, int bind, const char *addr) { int rc; struct nn_ep *ep; int eid; nn_ctx_enter (&self->ctx); /* Instantiate the endpoint. */ ep = nn_alloc (sizeof (struct nn_ep), "endpoint"); rc = nn_ep_init (ep, NN_SOCK_SRC_EP, self, self->eid, transport, bind, addr); if (nn_slow (rc < 0)) { nn_free (ep); nn_ctx_leave (&self->ctx); return rc; } nn_ep_start (ep); /* Increase the endpoint ID for the next endpoint. */ eid = self->eid; ++self->eid; /* Add it to the list of active endpoints. */ nn_list_insert (&self->eps, &ep->item, nn_list_end (&self->eps)); nn_ctx_leave (&self->ctx); return eid; } int nn_sock_rm_ep (struct nn_sock *self, int eid) { struct nn_list_item *it; struct nn_ep *ep; nn_ctx_enter (&self->ctx); /* Find the specified enpoint. */ ep = NULL; for (it = nn_list_begin (&self->eps); it != nn_list_end (&self->eps); it = nn_list_next (&self->eps, it)) { ep = nn_cont (it, struct nn_ep, item); if (ep->eid == eid) break; ep = NULL; } /* The endpoint doesn't exist. */ if (!ep) { nn_ctx_leave (&self->ctx); return -EINVAL; } /* Move the endpoint from the list of active endpoints to the list of shutting down endpoints. */ nn_list_erase (&self->eps, &ep->item); nn_list_insert (&self->sdeps, &ep->item, nn_list_end (&self->sdeps)); /* Ask the endpoint to stop. Actual terminatation may be delayed by the transport. */ nn_ep_stop (ep); nn_ctx_leave (&self->ctx); return 0; } int nn_sock_send (struct nn_sock *self, struct nn_msg *msg, int flags) { int rc; uint64_t deadline; uint64_t now; int timeout; /* Some sockets types cannot be used for sending messages. */ if (nn_slow (self->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) return -ENOTSUP; nn_ctx_enter (&self->ctx); /* Compute the deadline for SNDTIMEO timer. */ if (self->sndtimeo < 0) { deadline = -1; timeout = -1; } else { deadline = nn_clock_ms() + self->sndtimeo; timeout = self->sndtimeo; } while (1) { switch (self->state) { case NN_SOCK_STATE_ACTIVE: case NN_SOCK_STATE_INIT: break; case NN_SOCK_STATE_STOPPING_EPS: case NN_SOCK_STATE_STOPPING: case NN_SOCK_STATE_FINI: /* Socket closed or closing. Should we return something else here; recvmsg(2) for example returns no data in this case, like read(2). The use of indexed file descriptors is further problematic, as an FD can be reused leading to situations where technically the outstanding operation should refer to some other socket entirely. */ nn_ctx_leave (&self->ctx); return -EBADF; } /* Try to send the message in a non-blocking way. */ rc = self->sockbase->vfptr->send (self->sockbase, msg); if (nn_fast (rc == 0)) { nn_ctx_leave (&self->ctx); return 0; } nn_assert (rc < 0); /* Any unexpected error is forwarded to the caller. */ if (nn_slow (rc != -EAGAIN)) { nn_ctx_leave (&self->ctx); return rc; } /* If the message cannot be sent at the moment and the send call is non-blocking, return immediately. */ if (nn_fast (flags & NN_DONTWAIT)) { nn_ctx_leave (&self->ctx); return -EAGAIN; } /* With blocking send, wait while there are new pipes available for sending. */ nn_ctx_leave (&self->ctx); rc = nn_efd_wait (&self->sndfd, timeout); if (nn_slow (rc == -ETIMEDOUT)) return -ETIMEDOUT; if (nn_slow (rc == -EINTR)) return -EINTR; if (nn_slow (rc == -EBADF)) return -EBADF; errnum_assert (rc == 0, rc); nn_ctx_enter (&self->ctx); /* * Double check if pipes are still available for sending */ if (!nn_efd_wait (&self->sndfd, 0)) { self->flags |= NN_SOCK_FLAG_OUT; } /* If needed, re-compute the timeout to reflect the time that have already elapsed. */ if (self->sndtimeo >= 0) { now = nn_clock_ms(); timeout = (int) (now > deadline ? 0 : deadline - now); } } } int nn_sock_recv (struct nn_sock *self, struct nn_msg *msg, int flags) { int rc; uint64_t deadline; uint64_t now; int timeout; /* Some sockets types cannot be used for receiving messages. */ if (nn_slow (self->socktype->flags & NN_SOCKTYPE_FLAG_NORECV)) return -ENOTSUP; nn_ctx_enter (&self->ctx); /* Compute the deadline for RCVTIMEO timer. */ if (self->rcvtimeo < 0) { deadline = -1; timeout = -1; } else { deadline = nn_clock_ms() + self->rcvtimeo; timeout = self->rcvtimeo; } while (1) { switch (self->state) { case NN_SOCK_STATE_ACTIVE: case NN_SOCK_STATE_INIT: break; case NN_SOCK_STATE_STOPPING_EPS: case NN_SOCK_STATE_STOPPING: case NN_SOCK_STATE_FINI: /* Socket closed or closing. Should we return something else here; recvmsg(2) for example returns no data in this case, like read(2). The use of indexed file descriptors is further problematic, as an FD can be reused leading to situations where technically the outstanding operation should refer to some other socket entirely. */ nn_ctx_leave (&self->ctx); return -EBADF; } /* Try to receive the message in a non-blocking way. */ rc = self->sockbase->vfptr->recv (self->sockbase, msg); if (nn_fast (rc == 0)) { nn_ctx_leave (&self->ctx); return 0; } nn_assert (rc < 0); /* Any unexpected error is forwarded to the caller. */ if (nn_slow (rc != -EAGAIN)) { nn_ctx_leave (&self->ctx); return rc; } /* If the message cannot be received at the moment and the recv call is non-blocking, return immediately. */ if (nn_fast (flags & NN_DONTWAIT)) { nn_ctx_leave (&self->ctx); return -EAGAIN; } /* With blocking recv, wait while there are new pipes available for receiving. */ nn_ctx_leave (&self->ctx); rc = nn_efd_wait (&self->rcvfd, timeout); if (nn_slow (rc == -ETIMEDOUT)) return -ETIMEDOUT; if (nn_slow (rc == -EINTR)) return -EINTR; if (nn_slow (rc == -EBADF)) return -EBADF; errnum_assert (rc == 0, rc); nn_ctx_enter (&self->ctx); /* * Double check if pipes are still available for receiving */ if (!nn_efd_wait (&self->rcvfd, 0)) { self->flags |= NN_SOCK_FLAG_IN; } /* If needed, re-compute the timeout to reflect the time that have already elapsed. */ if (self->rcvtimeo >= 0) { now = nn_clock_ms(); timeout = (int) (now > deadline ? 0 : deadline - now); } } } int nn_sock_add (struct nn_sock *self, struct nn_pipe *pipe) { int rc; rc = self->sockbase->vfptr->add (self->sockbase, pipe); if (nn_slow (rc >= 0)) { nn_sock_stat_increment (self, NN_STAT_CURRENT_CONNECTIONS, 1); } return rc; } void nn_sock_rm (struct nn_sock *self, struct nn_pipe *pipe) { self->sockbase->vfptr->rm (self->sockbase, pipe); nn_sock_stat_increment (self, NN_STAT_CURRENT_CONNECTIONS, -1); } static void nn_sock_onleave (struct nn_ctx *self) { struct nn_sock *sock; int events; sock = nn_cont (self, struct nn_sock, ctx); /* If nn_close() was already called there's no point in adjusting the snd/rcv file descriptors. */ if (nn_slow (sock->state != NN_SOCK_STATE_ACTIVE)) return; /* Check whether socket is readable and/or writable at the moment. */ events = sock->sockbase->vfptr->events (sock->sockbase); errnum_assert (events >= 0, -events); /* Signal/unsignal IN as needed. */ if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NORECV)) { if (events & NN_SOCKBASE_EVENT_IN) { if (!(sock->flags & NN_SOCK_FLAG_IN)) { sock->flags |= NN_SOCK_FLAG_IN; nn_efd_signal (&sock->rcvfd); } } else { if (sock->flags & NN_SOCK_FLAG_IN) { sock->flags &= ~NN_SOCK_FLAG_IN; nn_efd_unsignal (&sock->rcvfd); } } } /* Signal/unsignal OUT as needed. */ if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) { if (events & NN_SOCKBASE_EVENT_OUT) { if (!(sock->flags & NN_SOCK_FLAG_OUT)) { sock->flags |= NN_SOCK_FLAG_OUT; nn_efd_signal (&sock->sndfd); } } else { if (sock->flags & NN_SOCK_FLAG_OUT) { sock->flags &= ~NN_SOCK_FLAG_OUT; nn_efd_unsignal (&sock->sndfd); } } } } static struct nn_optset *nn_sock_optset (struct nn_sock *self, int id) { int index; const struct nn_transport *tp; /* Transport IDs are negative and start from -1. */ index = (-id) - 1; /* Check for invalid indices. */ if (nn_slow (index < 0 || index >= NN_MAX_TRANSPORT)) return NULL; /* If the option set already exists return it. */ if (nn_fast (self->optsets [index] != NULL)) return self->optsets [index]; /* If the option set doesn't exist yet, create it. */ tp = nn_global_transport (id); if (nn_slow (!tp)) return NULL; if (nn_slow (!tp->optset)) return NULL; self->optsets [index] = tp->optset (); return self->optsets [index]; } static void nn_sock_shutdown (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_sock *sock; struct nn_list_item *it; struct nn_ep *ep; sock = nn_cont (self, struct nn_sock, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_assert (sock->state == NN_SOCK_STATE_ACTIVE); /* Close sndfd and rcvfd. This should make any current select/poll using SNDFD and/or RCVFD exit. */ if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NORECV)) { nn_efd_stop (&sock->rcvfd); } if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) { nn_efd_stop (&sock->sndfd); } /* Ask all the associated endpoints to stop. */ it = nn_list_begin (&sock->eps); while (it != nn_list_end (&sock->eps)) { ep = nn_cont (it, struct nn_ep, item); it = nn_list_next (&sock->eps, it); nn_list_erase (&sock->eps, &ep->item); nn_list_insert (&sock->sdeps, &ep->item, nn_list_end (&sock->sdeps)); nn_ep_stop (ep); } sock->state = NN_SOCK_STATE_STOPPING_EPS; goto finish2; } if (nn_slow (sock->state == NN_SOCK_STATE_STOPPING_EPS)) { if (!(src == NN_SOCK_SRC_EP && type == NN_EP_STOPPED)) { /* If we got here waiting for EPs to teardown, but src is not an EP, then it isn't safe for us to do anything, because we just need to wait for the EPs to finish up their thing. Just bail. */ return; } /* Endpoint is stopped. Now we can safely deallocate it. */ ep = (struct nn_ep*) srcptr; nn_list_erase (&sock->sdeps, &ep->item); nn_ep_term (ep); nn_free (ep); finish2: /* If all the endpoints are deallocated, we can start stopping protocol-specific part of the socket. If there' no stop function we can consider it stopped straight away. */ if (!nn_list_empty (&sock->sdeps)) return; nn_assert (nn_list_empty (&sock->eps)); sock->state = NN_SOCK_STATE_STOPPING; if (!sock->sockbase->vfptr->stop) goto finish1; sock->sockbase->vfptr->stop (sock->sockbase); return; } if (nn_slow (sock->state == NN_SOCK_STATE_STOPPING)) { /* We get here when the deallocation of the socket was delayed by the specific socket type. */ nn_assert (src == NN_FSM_ACTION && type == NN_SOCK_ACTION_STOPPED); finish1: /* Protocol-specific part of the socket is stopped. We can safely deallocate it. */ sock->sockbase->vfptr->destroy (sock->sockbase); sock->state = NN_SOCK_STATE_FINI; /* Now we can unblock the application thread blocked in the nn_close() call. */ nn_sem_post (&sock->termsem); return; } nn_fsm_bad_state(sock->state, src, type); } static void nn_sock_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_sock *sock; struct nn_ep *ep; sock = nn_cont (self, struct nn_sock, fsm); switch (sock->state) { /******************************************************************************/ /* INIT state. */ /******************************************************************************/ case NN_SOCK_STATE_INIT: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: sock->state = NN_SOCK_STATE_ACTIVE; return; default: nn_fsm_bad_action (sock->state, src, type); } default: nn_fsm_bad_source (sock->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_SOCK_STATE_ACTIVE: switch (src) { case NN_FSM_ACTION: switch (type) { default: nn_fsm_bad_action (sock->state, src, type); } case NN_SOCK_SRC_EP: switch (type) { case NN_EP_STOPPED: /* This happens when an endpoint is closed using nn_shutdown() function. */ ep = (struct nn_ep*) srcptr; nn_list_erase (&sock->sdeps, &ep->item); nn_ep_term (ep); nn_free (ep); return; default: nn_fsm_bad_action (sock->state, src, type); } default: /* The assumption is that all the other events come from pipes. */ switch (type) { case NN_PIPE_IN: sock->sockbase->vfptr->in (sock->sockbase, (struct nn_pipe*) srcptr); return; case NN_PIPE_OUT: sock->sockbase->vfptr->out (sock->sockbase, (struct nn_pipe*) srcptr); return; default: nn_fsm_bad_action (sock->state, src, type); } } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (sock->state, src, type); } } /******************************************************************************/ /* State machine actions. */ /******************************************************************************/ void nn_sock_report_error (struct nn_sock *self, struct nn_ep *ep, int errnum) { if (!nn_global_print_errors()) return; if (errnum == 0) return; if (ep) { fprintf(stderr, "nanomsg: socket.%s[%s]: Error: %s\n", self->socket_name, nn_ep_getaddr(ep), nn_strerror(errnum)); } else { fprintf(stderr, "nanomsg: socket.%s: Error: %s\n", self->socket_name, nn_strerror(errnum)); } } void nn_sock_stat_increment (struct nn_sock *self, int name, int64_t increment) { switch (name) { case NN_STAT_ESTABLISHED_CONNECTIONS: nn_assert (increment > 0); self->statistics.established_connections += increment; break; case NN_STAT_ACCEPTED_CONNECTIONS: nn_assert (increment > 0); self->statistics.accepted_connections += increment; break; case NN_STAT_DROPPED_CONNECTIONS: nn_assert (increment > 0); self->statistics.dropped_connections += increment; break; case NN_STAT_BROKEN_CONNECTIONS: nn_assert (increment > 0); self->statistics.broken_connections += increment; break; case NN_STAT_CONNECT_ERRORS: nn_assert (increment > 0); self->statistics.connect_errors += increment; break; case NN_STAT_BIND_ERRORS: nn_assert (increment > 0); self->statistics.bind_errors += increment; break; case NN_STAT_ACCEPT_ERRORS: nn_assert (increment > 0); self->statistics.accept_errors += increment; break; case NN_STAT_MESSAGES_SENT: nn_assert (increment > 0); self->statistics.messages_sent += increment; break; case NN_STAT_MESSAGES_RECEIVED: nn_assert (increment > 0); self->statistics.messages_received += increment; break; case NN_STAT_BYTES_SENT: nn_assert (increment >= 0); self->statistics.bytes_sent += increment; break; case NN_STAT_BYTES_RECEIVED: nn_assert (increment >= 0); self->statistics.bytes_received += increment; break; case NN_STAT_CURRENT_CONNECTIONS: nn_assert (increment > 0 || self->statistics.current_connections >= -increment); nn_assert(increment < INT_MAX && increment > -INT_MAX); self->statistics.current_connections += (int) increment; break; case NN_STAT_INPROGRESS_CONNECTIONS: nn_assert (increment > 0 || self->statistics.inprogress_connections >= -increment); nn_assert(increment < INT_MAX && increment > -INT_MAX); self->statistics.inprogress_connections += (int) increment; break; case NN_STAT_CURRENT_SND_PRIORITY: /* This is an exception, we don't want to increment priority */ nn_assert((increment > 0 && increment <= 16) || increment == -1); self->statistics.current_snd_priority = (int) increment; break; case NN_STAT_CURRENT_EP_ERRORS: nn_assert (increment > 0 || self->statistics.current_ep_errors >= -increment); nn_assert(increment < INT_MAX && increment > -INT_MAX); self->statistics.current_ep_errors += (int) increment; break; } } int nn_sock_hold (struct nn_sock *self) { switch (self->state) { case NN_SOCK_STATE_ACTIVE: case NN_SOCK_STATE_INIT: self->holds++; return 0; case NN_SOCK_STATE_STOPPING: case NN_SOCK_STATE_STOPPING_EPS: case NN_SOCK_STATE_FINI: default: return -EBADF; } } void nn_sock_rele (struct nn_sock *self) { self->holds--; if (self->holds == 0) { nn_sem_post (&self->relesem); } } nanomsg-1.1.5/src/core/sock.h000066400000000000000000000146421336111550300160140ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_SOCK_INCLUDED #define NN_SOCK_INCLUDED #include "../protocol.h" #include "../transport.h" #include "../aio/ctx.h" #include "../aio/fsm.h" #include "../utils/efd.h" #include "../utils/sem.h" #include "../utils/list.h" struct nn_pipe; /* The maximum implemented transport ID. */ #define NN_MAX_TRANSPORT 4 struct nn_sock { /* Socket state machine. */ struct nn_fsm fsm; int state; /* Pointer to the instance of the specific socket type. */ struct nn_sockbase *sockbase; /* Pointer to the socket type metadata. */ const struct nn_socktype *socktype; int flags; struct nn_ctx ctx; struct nn_efd sndfd; struct nn_efd rcvfd; struct nn_sem termsem; struct nn_sem relesem; /* List of all endpoints associated with the socket. */ struct nn_list eps; /* List of all endpoint being in the process of shutting down. */ struct nn_list sdeps; /* Next endpoint ID to assign to a new endpoint. */ int eid; /* Count of active holds against the socket. */ int holds; /* Socket-level socket options. */ int sndbuf; int rcvbuf; int rcvmaxsize; int sndtimeo; int rcvtimeo; int reconnect_ivl; int reconnect_ivl_max; int maxttl; /* Endpoint-specific options. */ struct nn_ep_options ep_template; /* Transport-specific socket options. */ struct nn_optset *optsets [NN_MAX_TRANSPORT]; struct { /***** The ever-incrementing counters *****/ /* Successfully established nn_connect() connections */ uint64_t established_connections; /* Successfully accepted connections */ uint64_t accepted_connections; /* Forcedly closed connections */ uint64_t dropped_connections; /* Connections closed by peer */ uint64_t broken_connections; /* Errors trying to establish active connection */ uint64_t connect_errors; /* Errors binding to specified port */ uint64_t bind_errors; /* Errors accepting connections at nn_bind()'ed endpoint */ uint64_t accept_errors; /* Messages sent */ uint64_t messages_sent; /* Messages received */ uint64_t messages_received; /* Bytes sent (sum length of data in messages sent) */ uint64_t bytes_sent; /* Bytes recevied (sum length of data in messages received) */ uint64_t bytes_received; /***** Level-style values *****/ /* Number of currently established connections */ int current_connections; /* Number of connections currently in progress */ int inprogress_connections; /* The currently set priority for sending data */ int current_snd_priority; /* Number of endpoints having last_errno set to non-zero value */ int current_ep_errors; } statistics; /* The socket name for statistics */ char socket_name[64]; /* Win32 Security Attribute */ void * sec_attr; size_t sec_attr_size; int outbuffersz; int inbuffersz; }; /* Initialise the socket. */ int nn_sock_init (struct nn_sock *self, const struct nn_socktype *socktype, int fd); /* Called by nn_close() to stop activity on the socket. It doesn't block. */ void nn_sock_stop (struct nn_sock *self); /* Called by nn_close() to deallocate the socket. It's a blocking function and can return -EINTR. */ int nn_sock_term (struct nn_sock *self); /* Called by sockbase when stopping is done. */ void nn_sock_stopped (struct nn_sock *self); /* Returns the AIO context associated with the socket. */ struct nn_ctx *nn_sock_getctx (struct nn_sock *self); /* Returns 1 if the specified socket type is a valid peer for this socket, 0 otherwise. */ int nn_sock_ispeer (struct nn_sock *self, int socktype); /* Add new endpoint to the socket. */ int nn_sock_add_ep (struct nn_sock *self, const struct nn_transport *transport, int bind, const char *addr); /* Remove the endpoint with the specified ID from the socket. */ int nn_sock_rm_ep (struct nn_sock *self, int eid); /* Send a message to the socket. */ int nn_sock_send (struct nn_sock *self, struct nn_msg *msg, int flags); /* Receive a message from the socket. */ int nn_sock_recv (struct nn_sock *self, struct nn_msg *msg, int flags); /* Set a socket option. */ int nn_sock_setopt (struct nn_sock *self, int level, int option, const void *optval, size_t optvallen); /* Retrieve a socket option. This function is to be called from the API. */ int nn_sock_getopt (struct nn_sock *self, int level, int option, void *optval, size_t *optvallen); /* Retrieve a socket option. This function is to be called from within the socket. */ int nn_sock_getopt_inner (struct nn_sock *self, int level, int option, void *optval, size_t *optvallen); /* Used by pipes. */ int nn_sock_add (struct nn_sock *self, struct nn_pipe *pipe); void nn_sock_rm (struct nn_sock *self, struct nn_pipe *pipe); /* Monitoring callbacks */ void nn_sock_report_error(struct nn_sock *self, struct nn_ep *ep, int errnum); void nn_sock_stat_increment(struct nn_sock *self, int name, int64_t increment); /* Holds and releases. */ int nn_sock_hold (struct nn_sock *self); void nn_sock_rele (struct nn_sock *self); #endif nanomsg-1.1.5/src/core/sockbase.c000066400000000000000000000037641336111550300166450ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "../protocol.h" #include "sock.h" #include "../utils/err.h" #include "../utils/attr.h" void nn_sockbase_init (struct nn_sockbase *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { self->vfptr = vfptr; self->sock = (struct nn_sock*) hint; } void nn_sockbase_term (NN_UNUSED struct nn_sockbase *self) { } void nn_sockbase_stopped (struct nn_sockbase *self) { nn_sock_stopped (self->sock); } struct nn_ctx *nn_sockbase_getctx (struct nn_sockbase *self) { return nn_sock_getctx (self->sock); } int nn_sockbase_getopt (struct nn_sockbase *self, int option, void *optval, size_t *optvallen) { return nn_sock_getopt_inner (self->sock, NN_SOL_SOCKET, option, optval, optvallen); } void nn_sockbase_stat_increment (struct nn_sockbase *self, int name, int increment) { nn_sock_stat_increment (self->sock, name, increment); } nanomsg-1.1.5/src/core/symbol.c000066400000000000000000000205601336111550300163510ustar00rootroot00000000000000/* Copyright (c) 2013 Evan Wies Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright (c) 2016 Bent Cardan. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "../nn.h" #include "../inproc.h" #include "../ipc.h" #include "../tcp.h" #include "../pair.h" #include "../pubsub.h" #include "../reqrep.h" #include "../pipeline.h" #include "../survey.h" #include "../bus.h" #include "../ws.h" #include #define NN_SYM(sym, namespace, typ, unit) \ { sym, #sym, NN_NS_ ## namespace, NN_TYPE_ ## typ, NN_UNIT_ ## unit } static const struct nn_symbol_properties sym_value_names [] = { NN_SYM(NN_NS_NAMESPACE, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_VERSION, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_DOMAIN, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_TRANSPORT, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_PROTOCOL, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_OPTION_LEVEL, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_SOCKET_OPTION, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_TRANSPORT_OPTION, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_OPTION_TYPE, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_OPTION_UNIT, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_FLAG, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_ERROR, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_LIMIT, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_EVENT, NAMESPACE, NONE, NONE), NN_SYM(NN_NS_STATISTIC, NAMESPACE, NONE, NONE), NN_SYM(NN_TYPE_NONE, OPTION_TYPE, NONE, NONE), NN_SYM(NN_TYPE_INT, OPTION_TYPE, NONE, NONE), NN_SYM(NN_TYPE_STR, OPTION_TYPE, NONE, NONE), NN_SYM(NN_UNIT_NONE, OPTION_UNIT, NONE, NONE), NN_SYM(NN_UNIT_BYTES, OPTION_UNIT, NONE, NONE), NN_SYM(NN_UNIT_MILLISECONDS, OPTION_UNIT, NONE, NONE), NN_SYM(NN_UNIT_PRIORITY, OPTION_UNIT, NONE, NONE), NN_SYM(NN_UNIT_BOOLEAN, OPTION_UNIT, NONE, NONE), NN_SYM(NN_UNIT_COUNTER, OPTION_UNIT, NONE, NONE), NN_SYM(NN_UNIT_MESSAGES, OPTION_UNIT, NONE, NONE), NN_SYM(NN_VERSION_CURRENT, VERSION, NONE, NONE), NN_SYM(NN_VERSION_REVISION, VERSION, NONE, NONE), NN_SYM(NN_VERSION_AGE, VERSION, NONE, NONE), NN_SYM(AF_SP, DOMAIN, NONE, NONE), NN_SYM(AF_SP_RAW, DOMAIN, NONE, NONE), NN_SYM(NN_INPROC, TRANSPORT, NONE, NONE), NN_SYM(NN_IPC, TRANSPORT, NONE, NONE), NN_SYM(NN_TCP, TRANSPORT, NONE, NONE), NN_SYM(NN_WS, TRANSPORT, NONE, NONE), NN_SYM(NN_PAIR, PROTOCOL, NONE, NONE), NN_SYM(NN_PUB, PROTOCOL, NONE, NONE), NN_SYM(NN_SUB, PROTOCOL, NONE, NONE), NN_SYM(NN_REP, PROTOCOL, NONE, NONE), NN_SYM(NN_REQ, PROTOCOL, NONE, NONE), NN_SYM(NN_PUSH, PROTOCOL, NONE, NONE), NN_SYM(NN_PULL, PROTOCOL, NONE, NONE), NN_SYM(NN_SURVEYOR, PROTOCOL, NONE, NONE), NN_SYM(NN_RESPONDENT, PROTOCOL, NONE, NONE), NN_SYM(NN_BUS, PROTOCOL, NONE, NONE), NN_SYM(NN_SOCKADDR_MAX, LIMIT, NONE, NONE), NN_SYM(NN_SOL_SOCKET, OPTION_LEVEL, NONE, NONE), NN_SYM(NN_LINGER, SOCKET_OPTION, INT, MILLISECONDS), NN_SYM(NN_SNDBUF, SOCKET_OPTION, INT, BYTES), NN_SYM(NN_RCVBUF, SOCKET_OPTION, INT, BYTES), NN_SYM(NN_RCVMAXSIZE, SOCKET_OPTION, INT, BYTES), NN_SYM(NN_SNDTIMEO, SOCKET_OPTION, INT, MILLISECONDS), NN_SYM(NN_RCVTIMEO, SOCKET_OPTION, INT, MILLISECONDS), NN_SYM(NN_RECONNECT_IVL, SOCKET_OPTION, INT, MILLISECONDS), NN_SYM(NN_RECONNECT_IVL_MAX, SOCKET_OPTION, INT, MILLISECONDS), NN_SYM(NN_SNDPRIO, SOCKET_OPTION, INT, PRIORITY), NN_SYM(NN_RCVPRIO, SOCKET_OPTION, INT, PRIORITY), NN_SYM(NN_SNDFD, SOCKET_OPTION, INT, NONE), NN_SYM(NN_RCVFD, SOCKET_OPTION, INT, NONE), NN_SYM(NN_DOMAIN, SOCKET_OPTION, INT, NONE), NN_SYM(NN_PROTOCOL, SOCKET_OPTION, INT, NONE), NN_SYM(NN_IPV4ONLY, SOCKET_OPTION, INT, BOOLEAN), NN_SYM(NN_SOCKET_NAME, SOCKET_OPTION, STR, NONE), NN_SYM(NN_MAXTTL, SOCKET_OPTION, INT, NONE), NN_SYM(NN_SUB_SUBSCRIBE, TRANSPORT_OPTION, STR, NONE), NN_SYM(NN_SUB_UNSUBSCRIBE, TRANSPORT_OPTION, STR, NONE), NN_SYM(NN_REQ_RESEND_IVL, TRANSPORT_OPTION, INT, MILLISECONDS), NN_SYM(NN_SURVEYOR_DEADLINE, TRANSPORT_OPTION, INT, MILLISECONDS), NN_SYM(NN_TCP_NODELAY, TRANSPORT_OPTION, INT, BOOLEAN), NN_SYM(NN_WS_MSG_TYPE, TRANSPORT_OPTION, INT, NONE), NN_SYM(NN_DONTWAIT, FLAG, NONE, NONE), NN_SYM(NN_WS_MSG_TYPE_TEXT, FLAG, NONE, NONE), NN_SYM(NN_WS_MSG_TYPE_BINARY, FLAG, NONE, NONE), NN_SYM(NN_POLLIN, EVENT, NONE, NONE), NN_SYM(NN_POLLOUT, EVENT, NONE, NONE), NN_SYM(EADDRINUSE, ERROR, NONE, NONE), NN_SYM(EADDRNOTAVAIL, ERROR, NONE, NONE), NN_SYM(EAFNOSUPPORT, ERROR, NONE, NONE), NN_SYM(EAGAIN, ERROR, NONE, NONE), NN_SYM(EBADF, ERROR, NONE, NONE), NN_SYM(ECONNREFUSED, ERROR, NONE, NONE), NN_SYM(EFAULT, ERROR, NONE, NONE), NN_SYM(EFSM, ERROR, NONE, NONE), NN_SYM(EINPROGRESS, ERROR, NONE, NONE), NN_SYM(EINTR, ERROR, NONE, NONE), NN_SYM(EINVAL, ERROR, NONE, NONE), NN_SYM(EMFILE, ERROR, NONE, NONE), NN_SYM(ENAMETOOLONG, ERROR, NONE, NONE), NN_SYM(ENETDOWN, ERROR, NONE, NONE), NN_SYM(ENOBUFS, ERROR, NONE, NONE), NN_SYM(ENODEV, ERROR, NONE, NONE), NN_SYM(ENOMEM, ERROR, NONE, NONE), NN_SYM(ENOPROTOOPT, ERROR, NONE, NONE), NN_SYM(ENOTSOCK, ERROR, NONE, NONE), NN_SYM(ENOTSUP, ERROR, NONE, NONE), NN_SYM(EPROTO, ERROR, NONE, NONE), NN_SYM(EPROTONOSUPPORT, ERROR, NONE, NONE), NN_SYM(ETERM, ERROR, NONE, NONE), NN_SYM(ETIMEDOUT, ERROR, NONE, NONE), NN_SYM(EACCES, ERROR, NONE, NONE), NN_SYM(ECONNABORTED, ERROR, NONE, NONE), NN_SYM(ECONNRESET, ERROR, NONE, NONE), NN_SYM(EHOSTUNREACH, ERROR, NONE, NONE), NN_SYM(EMSGSIZE, ERROR, NONE, NONE), NN_SYM(ENETRESET, ERROR, NONE, NONE), NN_SYM(ENETUNREACH, ERROR, NONE, NONE), NN_SYM(ENOTCONN, ERROR, NONE, NONE), NN_SYM(NN_STAT_ESTABLISHED_CONNECTIONS, STATISTIC, INT, COUNTER), NN_SYM(NN_STAT_ACCEPTED_CONNECTIONS, STATISTIC, INT, COUNTER), NN_SYM(NN_STAT_DROPPED_CONNECTIONS, STATISTIC, INT, COUNTER), NN_SYM(NN_STAT_BROKEN_CONNECTIONS, STATISTIC, INT, COUNTER), NN_SYM(NN_STAT_CONNECT_ERRORS, STATISTIC, INT, COUNTER), NN_SYM(NN_STAT_BIND_ERRORS, STATISTIC, INT, COUNTER), NN_SYM(NN_STAT_ACCEPT_ERRORS, STATISTIC, INT, COUNTER), NN_SYM(NN_STAT_MESSAGES_SENT, STATISTIC, INT, MESSAGES), NN_SYM(NN_STAT_MESSAGES_RECEIVED, STATISTIC, INT, MESSAGES), NN_SYM(NN_STAT_BYTES_SENT, STATISTIC, INT, BYTES), NN_SYM(NN_STAT_BYTES_RECEIVED, STATISTIC, INT, BYTES), NN_SYM(NN_STAT_CURRENT_CONNECTIONS, STATISTIC, INT, NONE), NN_SYM(NN_STAT_INPROGRESS_CONNECTIONS, STATISTIC, INT, NONE), NN_SYM(NN_STAT_CURRENT_SND_PRIORITY, STATISTIC, INT, PRIORITY), NN_SYM(NN_STAT_CURRENT_EP_ERRORS, STATISTIC, INT, NONE) }; const int SYM_VALUE_NAMES_LEN = (sizeof (sym_value_names) / sizeof (sym_value_names [0])); const char *nn_symbol (int i, int *value) { const struct nn_symbol_properties *svn; if (i < 0 || i >= SYM_VALUE_NAMES_LEN) { errno = EINVAL; return NULL; } svn = &sym_value_names [i]; if (value) *value = svn->value; return svn->name; } int nn_symbol_info (int i, struct nn_symbol_properties *buf, int buflen) { if (i < 0 || i >= SYM_VALUE_NAMES_LEN) { return 0; } if (buflen > (int)sizeof (struct nn_symbol_properties)) { buflen = (int)sizeof (struct nn_symbol_properties); } memcpy(buf, &sym_value_names [i], buflen); return buflen; } nanomsg-1.1.5/src/devices/000077500000000000000000000000001336111550300153675ustar00rootroot00000000000000nanomsg-1.1.5/src/devices/device.c000066400000000000000000000220271336111550300167750ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #include "../nn.h" #include "../utils/err.h" #include "../utils/fast.h" #include "../utils/fd.h" #include "../utils/attr.h" #include "../utils/thread.h" #include "device.h" #include #ifndef NN_HAVE_WINDOWS #define NN_BAD_FD -1 #else #define NN_BAD_FD INVALID_SOCKET #endif int nn_custom_device(struct nn_device_recipe *device, int s1, int s2, int flags) { return nn_device_entry (device, s1, s2, flags); } int nn_device (int s1, int s2) { return nn_custom_device (&nn_ordinary_device, s1, s2, 0); } int nn_device_entry (struct nn_device_recipe *device, int s1, int s2, NN_UNUSED int flags) { int rc; int op1; int op2; nn_fd s1rcv; nn_fd s1snd; nn_fd s2rcv; nn_fd s2snd; size_t opsz; /* At least one socket must be specified. */ if (device->required_checks & NN_CHECK_AT_LEAST_ONE_SOCKET) { if (s1 < 0 && s2 < 0) { errno = EBADF; return -1; } } /* Handle the case when there's only one socket in the device. */ if (device->required_checks & NN_CHECK_ALLOW_LOOPBACK) { if (s2 < 0) return nn_device_loopback (device, s1); if (s1 < 0) return nn_device_loopback (device, s2); } /* Check whether both sockets are "raw" sockets. */ if (device->required_checks & NN_CHECK_REQUIRE_RAW_SOCKETS) { opsz = sizeof (op1); rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_DOMAIN, &op1, &opsz); if (rc != 0) return -1; nn_assert (opsz == sizeof (op1)); opsz = sizeof (op2); rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_DOMAIN, &op2, &opsz); if (rc != 0) return -1; nn_assert (opsz == sizeof (op2)); if (op1 != AF_SP_RAW || op2 != AF_SP_RAW) { errno = EINVAL; return -1; } } /* Check whether both sockets are from the same protocol. */ if (device->required_checks & NN_CHECK_SAME_PROTOCOL_FAMILY) { opsz = sizeof (op1); rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_PROTOCOL, &op1, &opsz); if (rc != 0) return -1; nn_assert (opsz == sizeof (op1)); opsz = sizeof (op2); rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_PROTOCOL, &op2, &opsz); if (rc != 0) return -1; nn_assert (opsz == sizeof (op2)); if (op1 / 16 != op2 / 16) { errno = EINVAL; return -1; } } /* Get the file descriptors for polling. */ opsz = sizeof (s1rcv); rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_RCVFD, &s1rcv, &opsz); if (rc < 0) { if (nn_errno () != ENOPROTOOPT) return -1; s1rcv = NN_BAD_FD; } else { nn_assert (rc == 0); nn_assert (opsz == sizeof (s1rcv)); } opsz = sizeof (s1snd); rc = nn_getsockopt (s1, NN_SOL_SOCKET, NN_SNDFD, &s1snd, &opsz); if (rc < 0) { if (nn_errno () != ENOPROTOOPT) return -1; s1snd = NN_BAD_FD; } else { nn_assert (rc == 0); nn_assert (opsz == sizeof (s1snd)); } opsz = sizeof (s2rcv); rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_RCVFD, &s2rcv, &opsz); if (rc < 0) { if (nn_errno () != ENOPROTOOPT) return -1; s2rcv = NN_BAD_FD; } else { nn_assert (rc == 0); nn_assert (opsz == sizeof (s2rcv)); } opsz = sizeof (s2snd); rc = nn_getsockopt (s2, NN_SOL_SOCKET, NN_SNDFD, &s2snd, &opsz); if (rc < 0) { if (nn_errno () != ENOPROTOOPT) return -1; s2snd = NN_BAD_FD; } else { nn_assert (rc == 0); nn_assert (opsz == sizeof (s2snd)); } if (device->required_checks & NN_CHECK_SOCKET_DIRECTIONALITY) { /* Check the directionality of the sockets. */ if (s1rcv != NN_BAD_FD && s2snd == NN_BAD_FD) { errno = EINVAL; return -1; } if (s1snd != NN_BAD_FD && s2rcv == NN_BAD_FD) { errno = EINVAL; return -1; } if (s2rcv != NN_BAD_FD && s1snd == NN_BAD_FD) { errno = EINVAL; return -1; } if (s2snd != NN_BAD_FD && s1rcv == NN_BAD_FD) { errno = EINVAL; return -1; } } /* Two-directional device. */ if (device->required_checks & NN_CHECK_ALLOW_BIDIRECTIONAL) { if (s1rcv != NN_BAD_FD && s1snd != NN_BAD_FD && s2rcv != NN_BAD_FD && s2snd != NN_BAD_FD) return nn_device_twoway (device, s1, s2); } if (device->required_checks & NN_CHECK_ALLOW_UNIDIRECTIONAL) { /* Single-directional device passing messages from s1 to s2. */ if (s1rcv != NN_BAD_FD && s1snd == NN_BAD_FD && s2rcv == NN_BAD_FD && s2snd != NN_BAD_FD) return nn_device_oneway (device, s1, s2); /* Single-directional device passing messages from s2 to s1. */ if (s1rcv == NN_BAD_FD && s1snd != NN_BAD_FD && s2rcv != NN_BAD_FD && s2snd == NN_BAD_FD) return nn_device_oneway (device, s2, s1); } /* This should never happen. */ nn_assert (0); } int nn_device_loopback (struct nn_device_recipe *device, int s) { int rc; int op; size_t opsz; /* Check whether the socket is a "raw" socket. */ opsz = sizeof (op); rc = nn_getsockopt (s, NN_SOL_SOCKET, NN_DOMAIN, &op, &opsz); if (nn_slow (rc != 0)) return -1; nn_assert (opsz == sizeof (op)); if (op != AF_SP_RAW) { errno = EINVAL; return -1; } for (;;) { rc = nn_device_mvmsg (device, s, s, 0); if (nn_slow (rc < 0)) return -1; } } struct nn_device_forwarder_args { struct nn_device_recipe *device; int s1; int s2; int rc; int err; }; static void nn_device_forwarder (void *a) { struct nn_device_forwarder_args *args = a; for (;;) { args->rc = nn_device_mvmsg (args->device, args->s1, args->s2, 0); if (nn_slow (args->rc < 0)) { args->err = nn_errno (); return; } } } int nn_device_twoway (struct nn_device_recipe *device, int s1, int s2) { struct nn_thread t1; struct nn_thread t2; struct nn_device_forwarder_args a1; struct nn_device_forwarder_args a2; a1.device = device; a1.s1 = s1; a1.s2 = s2; a2.device = device; a2.s1 = s2; a2.s2 = s1; nn_thread_init (&t1, nn_device_forwarder, &a1); nn_thread_init (&t2, nn_device_forwarder, &a2); nn_thread_term (&t1); nn_thread_term (&t2); if (a1.rc != 0) { errno = a1.err; return (a1.rc); } errno = a2.err; return a2.rc; } int nn_device_oneway (struct nn_device_recipe *device, int s1, int s2) { int rc; while (1) { rc = nn_device_mvmsg (device, s1, s2, 0); if (nn_slow (rc < 0)) return -1; } } int nn_device_mvmsg (struct nn_device_recipe *device, int from, int to, int flags) { int rc; void *body; void *control; struct nn_iovec iov; struct nn_msghdr hdr; iov.iov_base = &body; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; hdr.msg_control = &control; hdr.msg_controllen = NN_MSG; rc = nn_recvmsg (from, &hdr, flags); if (nn_slow (rc < 0)) { /* any error is fatal */ return -1; } rc = device->nn_device_rewritemsg (device, from, to, flags, &hdr, rc); if (nn_slow (rc == -1)) return -1; else if (rc == 0) return 0; nn_assert(rc == 1); rc = nn_sendmsg (to, &hdr, flags); if (nn_slow (rc < 0)) { /* any error is fatal */ return -1; } return 0; } int nn_device_rewritemsg (NN_UNUSED struct nn_device_recipe *device, NN_UNUSED int from, NN_UNUSED int to, NN_UNUSED int flags, NN_UNUSED struct nn_msghdr *msghdr, NN_UNUSED int bytes) { return 1; /* always forward */ } nanomsg-1.1.5/src/devices/device.h000066400000000000000000000112061336111550300167770ustar00rootroot00000000000000/* Copyright (c) 2014 Drew Crawford. All rights reserved. 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. */ /* Base class for device. */ struct nn_device_recipe { /* NN_CHECK flags. */ int required_checks; /* The entry function. This checks the inputs according to the required_checks flag, chooses the polling function, and starts the device. You can override this function to implement additional checks.*/ int(*nn_device_entry) (struct nn_device_recipe *device, int s1, int s2, int flags); /* The two-way poll function. */ int (*nn_device_twoway) (struct nn_device_recipe *device, int s1, int s2); /* The one-way poll function. */ int (*nn_device_oneway) (struct nn_device_recipe *device, int s1, int s2); int (*nn_device_loopback) (struct nn_device_recipe *device, int s); /* The movemsg function. */ int (*nn_device_mvmsg) (struct nn_device_recipe *device, int from, int to, int flags); /* The message intercept function. This function gives you an opportunity to modify or cancel an nn_msghdr as it passes from one socket to the other. from - the socket that the msghdr was received from to - the socket where it is going flags - the flags that are being used for send and receive functions msghdr - the nn_msghdr that was received from the from socket bytes - the actual received length of the msg. The nn_msghdr->msg_iov->iov_len is not valid because it contains NN_MSG return values: 1 indicates that the msghdr should be forwarded. 0 indicates that the msghdr should *not* be forwarded, e.g. the message is dropped in the device -1 indicates an error. Set errno. */ int (*nn_device_rewritemsg) (struct nn_device_recipe *device, int from, int to, int flags, struct nn_msghdr *msghdr, int bytes); }; /* Default implementations of the functions. */ int nn_device_loopback (struct nn_device_recipe *device, int s); int nn_device_twoway (struct nn_device_recipe *device, int s1, int s2); int nn_device_oneway (struct nn_device_recipe *device, int s1, int s2); int nn_device_mvmsg (struct nn_device_recipe *device, int from, int to, int flags); int nn_device_entry(struct nn_device_recipe *device, int s1, int s2, int flags); int nn_device_rewritemsg(struct nn_device_recipe *device, int from, int to, int flags, struct nn_msghdr *msghdr, int bytes); /* At least one socket must be passed to the device. */ #define NN_CHECK_AT_LEAST_ONE_SOCKET (1 << 0) /* Loopback devices are allowed. */ #define NN_CHECK_ALLOW_LOOPBACK (1 << 1) /* Bidirectional devices are allowed. */ #define NN_CHECK_ALLOW_BIDIRECTIONAL (1 << 2) /* Unidirectional devices are allowed. */ #define NN_CHECK_ALLOW_UNIDIRECTIONAL (1<<3) /* Both sockets must be raw. */ #define NN_CHECK_REQUIRE_RAW_SOCKETS (1 << 4) /* Both sockets must be same protocol family. */ #define NN_CHECK_SAME_PROTOCOL_FAMILY (1 << 5) /* Check socket directionality. */ #define NN_CHECK_SOCKET_DIRECTIONALITY (1 << 6) /* Allows spawning a custom device from a recipe */ int nn_custom_device(struct nn_device_recipe *device, int s1, int s2, int flags); static struct nn_device_recipe nn_ordinary_device = { NN_CHECK_AT_LEAST_ONE_SOCKET | NN_CHECK_ALLOW_LOOPBACK | NN_CHECK_ALLOW_BIDIRECTIONAL | NN_CHECK_REQUIRE_RAW_SOCKETS | NN_CHECK_SAME_PROTOCOL_FAMILY | NN_CHECK_SOCKET_DIRECTIONALITY | NN_CHECK_ALLOW_UNIDIRECTIONAL, nn_device_entry, nn_device_twoway, nn_device_oneway, nn_device_loopback, nn_device_mvmsg, nn_device_rewritemsg }; nanomsg-1.1.5/src/inproc.h000066400000000000000000000024271336111550300154150ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef INPROC_H_INCLUDED #define INPROC_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #define NN_INPROC -1 #ifdef __cplusplus } #endif #endif nanomsg-1.1.5/src/ipc.h000066400000000000000000000026501336111550300146740ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef IPC_H_INCLUDED #define IPC_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #define NN_IPC -2 /* The object set here must be valid as long as you are using the socket */ #define NN_IPC_SEC_ATTR 1 #define NN_IPC_OUTBUFSZ 2 #define NN_IPC_INBUFSZ 3 #ifdef __cplusplus } #endif #endif nanomsg-1.1.5/src/nn.h000066400000000000000000000320051336111550300145310ustar00rootroot00000000000000/* Copyright (c) 2012-2014 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #ifndef NN_H_INCLUDED #define NN_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #include #include #include /* Handle DSO symbol visibility. */ #if !defined(NN_EXPORT) # if defined(_WIN32) && !defined(NN_STATIC_LIB) # if defined NN_SHARED_LIB # define NN_EXPORT __declspec(dllexport) # else # define NN_EXPORT __declspec(dllimport) # endif # else # define NN_EXPORT extern # endif #endif /******************************************************************************/ /* ABI versioning support. */ /******************************************************************************/ /* Don't change this unless you know exactly what you're doing and have */ /* read and understand the following documents: */ /* www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html */ /* www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html */ /* The current interface version. */ #define NN_VERSION_CURRENT 5 /* The latest revision of the current interface. */ #define NN_VERSION_REVISION 1 /* How many past interface versions are still supported. */ #define NN_VERSION_AGE 0 /******************************************************************************/ /* Errors. */ /******************************************************************************/ /* A number random enough not to collide with different errno ranges on */ /* different OSes. The assumption is that error_t is at least 32-bit type. */ #define NN_HAUSNUMERO 156384712 /* On some platforms some standard POSIX errnos are not defined. */ #ifndef ENOTSUP #define ENOTSUP (NN_HAUSNUMERO + 1) #endif #ifndef EPROTONOSUPPORT #define EPROTONOSUPPORT (NN_HAUSNUMERO + 2) #endif #ifndef ENOBUFS #define ENOBUFS (NN_HAUSNUMERO + 3) #endif #ifndef ENETDOWN #define ENETDOWN (NN_HAUSNUMERO + 4) #endif #ifndef EADDRINUSE #define EADDRINUSE (NN_HAUSNUMERO + 5) #endif #ifndef EADDRNOTAVAIL #define EADDRNOTAVAIL (NN_HAUSNUMERO + 6) #endif #ifndef ECONNREFUSED #define ECONNREFUSED (NN_HAUSNUMERO + 7) #endif #ifndef EINPROGRESS #define EINPROGRESS (NN_HAUSNUMERO + 8) #endif #ifndef ENOTSOCK #define ENOTSOCK (NN_HAUSNUMERO + 9) #endif #ifndef EAFNOSUPPORT #define EAFNOSUPPORT (NN_HAUSNUMERO + 10) #endif #ifndef EPROTO #define EPROTO (NN_HAUSNUMERO + 11) #endif #ifndef EAGAIN #define EAGAIN (NN_HAUSNUMERO + 12) #endif #ifndef EBADF #define EBADF (NN_HAUSNUMERO + 13) #endif #ifndef EINVAL #define EINVAL (NN_HAUSNUMERO + 14) #endif #ifndef EMFILE #define EMFILE (NN_HAUSNUMERO + 15) #endif #ifndef EFAULT #define EFAULT (NN_HAUSNUMERO + 16) #endif #ifndef EACCES #define EACCES (NN_HAUSNUMERO + 17) #endif #ifndef EACCESS #define EACCESS (EACCES) #endif #ifndef ENETRESET #define ENETRESET (NN_HAUSNUMERO + 18) #endif #ifndef ENETUNREACH #define ENETUNREACH (NN_HAUSNUMERO + 19) #endif #ifndef EHOSTUNREACH #define EHOSTUNREACH (NN_HAUSNUMERO + 20) #endif #ifndef ENOTCONN #define ENOTCONN (NN_HAUSNUMERO + 21) #endif #ifndef EMSGSIZE #define EMSGSIZE (NN_HAUSNUMERO + 22) #endif #ifndef ETIMEDOUT #define ETIMEDOUT (NN_HAUSNUMERO + 23) #endif #ifndef ECONNABORTED #define ECONNABORTED (NN_HAUSNUMERO + 24) #endif #ifndef ECONNRESET #define ECONNRESET (NN_HAUSNUMERO + 25) #endif #ifndef ENOPROTOOPT #define ENOPROTOOPT (NN_HAUSNUMERO + 26) #endif #ifndef EISCONN #define EISCONN (NN_HAUSNUMERO + 27) #define NN_EISCONN_DEFINED #endif #ifndef ESOCKTNOSUPPORT #define ESOCKTNOSUPPORT (NN_HAUSNUMERO + 28) #endif /* Native nanomsg error codes. */ #ifndef ETERM #define ETERM (NN_HAUSNUMERO + 53) #endif #ifndef EFSM #define EFSM (NN_HAUSNUMERO + 54) #endif /* This function retrieves the errno as it is known to the library. */ /* The goal of this function is to make the code 100% portable, including */ /* where the library is compiled with certain CRT library (on Windows) and */ /* linked to an application that uses different CRT library. */ NN_EXPORT int nn_errno (void); /* Resolves system errors and native errors to human-readable string. */ NN_EXPORT const char *nn_strerror (int errnum); /* Returns the symbol name (e.g. "NN_REQ") and value at a specified index. */ /* If the index is out-of-range, returns NULL and sets errno to EINVAL */ /* General usage is to start at i=0 and iterate until NULL is returned. */ NN_EXPORT const char *nn_symbol (int i, int *value); /* Constants that are returned in `ns` member of nn_symbol_properties */ #define NN_NS_NAMESPACE 0 #define NN_NS_VERSION 1 #define NN_NS_DOMAIN 2 #define NN_NS_TRANSPORT 3 #define NN_NS_PROTOCOL 4 #define NN_NS_OPTION_LEVEL 5 #define NN_NS_SOCKET_OPTION 6 #define NN_NS_TRANSPORT_OPTION 7 #define NN_NS_OPTION_TYPE 8 #define NN_NS_OPTION_UNIT 9 #define NN_NS_FLAG 10 #define NN_NS_ERROR 11 #define NN_NS_LIMIT 12 #define NN_NS_EVENT 13 #define NN_NS_STATISTIC 14 /* Constants that are returned in `type` member of nn_symbol_properties */ #define NN_TYPE_NONE 0 #define NN_TYPE_INT 1 #define NN_TYPE_STR 2 /* Constants that are returned in the `unit` member of nn_symbol_properties */ #define NN_UNIT_NONE 0 #define NN_UNIT_BYTES 1 #define NN_UNIT_MILLISECONDS 2 #define NN_UNIT_PRIORITY 3 #define NN_UNIT_BOOLEAN 4 #define NN_UNIT_MESSAGES 5 #define NN_UNIT_COUNTER 6 /* Structure that is returned from nn_symbol */ struct nn_symbol_properties { /* The constant value */ int value; /* The constant name */ const char* name; /* The constant namespace, or zero for namespaces themselves */ int ns; /* The option type for socket option constants */ int type; /* The unit for the option value for socket option constants */ int unit; }; /* Fills in nn_symbol_properties structure and returns it's length */ /* If the index is out-of-range, returns 0 */ /* General usage is to start at i=0 and iterate until zero is returned. */ NN_EXPORT int nn_symbol_info (int i, struct nn_symbol_properties *buf, int buflen); /******************************************************************************/ /* Helper function for shutting down multi-threaded applications. */ /******************************************************************************/ NN_EXPORT void nn_term (void); /******************************************************************************/ /* Zero-copy support. */ /******************************************************************************/ #define NN_MSG ((size_t) -1) NN_EXPORT void *nn_allocmsg (size_t size, int type); NN_EXPORT void *nn_reallocmsg (void *msg, size_t size); NN_EXPORT int nn_freemsg (void *msg); /******************************************************************************/ /* Socket definition. */ /******************************************************************************/ 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; }; struct nn_cmsghdr { size_t cmsg_len; int cmsg_level; int cmsg_type; }; /* Internal stuff. Not to be used directly. */ NN_EXPORT struct nn_cmsghdr *nn_cmsg_nxthdr_ ( const struct nn_msghdr *mhdr, const struct nn_cmsghdr *cmsg); #define NN_CMSG_ALIGN_(len) \ (((len) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) /* POSIX-defined msghdr manipulation. */ #define NN_CMSG_FIRSTHDR(mhdr) \ nn_cmsg_nxthdr_ ((struct nn_msghdr*) (mhdr), NULL) #define NN_CMSG_NXTHDR(mhdr, cmsg) \ nn_cmsg_nxthdr_ ((struct nn_msghdr*) (mhdr), (struct nn_cmsghdr*) (cmsg)) #define NN_CMSG_DATA(cmsg) \ ((unsigned char*) (((struct nn_cmsghdr*) (cmsg)) + 1)) /* Extensions to POSIX defined by RFC 3542. */ #define NN_CMSG_SPACE(len) \ (NN_CMSG_ALIGN_ (len) + NN_CMSG_ALIGN_ (sizeof (struct nn_cmsghdr))) #define NN_CMSG_LEN(len) \ (NN_CMSG_ALIGN_ (sizeof (struct nn_cmsghdr)) + (len)) /* SP address families. */ #define AF_SP 1 #define AF_SP_RAW 2 /* Max size of an SP address. */ #define NN_SOCKADDR_MAX 128 /* Socket option levels: Negative numbers are reserved for transports, positive for socket types. */ #define NN_SOL_SOCKET 0 /* Generic socket options (NN_SOL_SOCKET level). */ #define NN_LINGER 1 #define NN_SNDBUF 2 #define NN_RCVBUF 3 #define NN_SNDTIMEO 4 #define NN_RCVTIMEO 5 #define NN_RECONNECT_IVL 6 #define NN_RECONNECT_IVL_MAX 7 #define NN_SNDPRIO 8 #define NN_RCVPRIO 9 #define NN_SNDFD 10 #define NN_RCVFD 11 #define NN_DOMAIN 12 #define NN_PROTOCOL 13 #define NN_IPV4ONLY 14 #define NN_SOCKET_NAME 15 #define NN_RCVMAXSIZE 16 #define NN_MAXTTL 17 /* Send/recv options. */ #define NN_DONTWAIT 1 /* Ancillary data. */ #define PROTO_SP 1 #define SP_HDR 1 NN_EXPORT int nn_socket (int domain, int protocol); NN_EXPORT int nn_close (int s); NN_EXPORT int nn_setsockopt (int s, int level, int option, const void *optval, size_t optvallen); NN_EXPORT int nn_getsockopt (int s, int level, int option, void *optval, size_t *optvallen); NN_EXPORT int nn_bind (int s, const char *addr); NN_EXPORT int nn_connect (int s, const char *addr); NN_EXPORT int nn_shutdown (int s, int how); NN_EXPORT int nn_send (int s, const void *buf, size_t len, int flags); NN_EXPORT int nn_recv (int s, void *buf, size_t len, int flags); NN_EXPORT int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags); NN_EXPORT int nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags); /******************************************************************************/ /* Socket mutliplexing support. */ /******************************************************************************/ #define NN_POLLIN 1 #define NN_POLLOUT 2 struct nn_pollfd { int fd; short events; short revents; }; NN_EXPORT int nn_poll (struct nn_pollfd *fds, int nfds, int timeout); /******************************************************************************/ /* Built-in support for devices. */ /******************************************************************************/ NN_EXPORT int nn_device (int s1, int s2); /******************************************************************************/ /* Statistics. */ /******************************************************************************/ /* Transport statistics */ #define NN_STAT_ESTABLISHED_CONNECTIONS 101 #define NN_STAT_ACCEPTED_CONNECTIONS 102 #define NN_STAT_DROPPED_CONNECTIONS 103 #define NN_STAT_BROKEN_CONNECTIONS 104 #define NN_STAT_CONNECT_ERRORS 105 #define NN_STAT_BIND_ERRORS 106 #define NN_STAT_ACCEPT_ERRORS 107 #define NN_STAT_CURRENT_CONNECTIONS 201 #define NN_STAT_INPROGRESS_CONNECTIONS 202 #define NN_STAT_CURRENT_EP_ERRORS 203 /* The socket-internal statistics */ #define NN_STAT_MESSAGES_SENT 301 #define NN_STAT_MESSAGES_RECEIVED 302 #define NN_STAT_BYTES_SENT 303 #define NN_STAT_BYTES_RECEIVED 304 /* Protocol statistics */ #define NN_STAT_CURRENT_SND_PRIORITY 401 NN_EXPORT uint64_t nn_get_statistic (int s, int stat); #ifdef __cplusplus } #endif #endif nanomsg-1.1.5/src/pair.h000066400000000000000000000025001336111550300150460ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef PAIR_H_INCLUDED #define PAIR_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #define NN_PROTO_PAIR 1 #define NN_PAIR (NN_PROTO_PAIR * 16 + 0) #ifdef __cplusplus } #endif #endif nanomsg-1.1.5/src/pipeline.h000066400000000000000000000026721336111550300157320ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. 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. */ #ifndef PIPELINE_H_INCLUDED #define PIPELINE_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #define NN_PROTO_PIPELINE 5 #define NN_PUSH (NN_PROTO_PIPELINE * 16 + 0) #define NN_PULL (NN_PROTO_PIPELINE * 16 + 1) #ifdef __cplusplus } #endif #endif nanomsg-1.1.5/src/pkgconfig.in000066400000000000000000000005271336111550300162500ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} includedir=${prefix}/include libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ Name: @CMAKE_PROJECT_NAME@ Description: @NN_DESCRIPTION@ URL: http://nanomsg.org/ Version: @NN_PACKAGE_VERSION@ Requires: Libs: -L${libdir} -l@CMAKE_PROJECT_NAME@ Libs.private:@NN_REQUIRED_LFLAGS@ Cflags: -I${includedir} nanomsg-1.1.5/src/protocol.h000066400000000000000000000171501336111550300157630ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_PROTOCOL_INCLUDED #define NN_PROTOCOL_INCLUDED #include "utils/msg.h" #include "utils/list.h" #include #include struct nn_ctx; /******************************************************************************/ /* Pipe class. */ /******************************************************************************/ /* Any combination of following flags can be returned from successful call to nn_pipe_send or nn_pipe_recv. */ /* This flag means that the pipe can't be used for receiving (when returned from nn_pipe_recv()) or sending (when returned from nn_pipe_send()). Protocol implementation should not send/recv messages from the pipe until the pipe is revived by in()/out() function. */ #define NN_PIPE_RELEASE 1 /* Specifies that received message is already split into header and body. This flag is used only by inproc transport to avoid merging and re-splitting the messages passed with a single process. */ #define NN_PIPE_PARSED 2 /* Events generated by the pipe. */ #define NN_PIPE_IN 33987 #define NN_PIPE_OUT 33988 struct nn_pipe; /* Associates opaque pointer to protocol-specific data with the pipe. */ void nn_pipe_setdata (struct nn_pipe *self, void *data); /* Retrieves the opaque pointer associated with the pipe. */ void *nn_pipe_getdata (struct nn_pipe *self); /* Send the message to the pipe. If successful, pipe takes ownership of the messages. */ int nn_pipe_send (struct nn_pipe *self, struct nn_msg *msg); /* Receive a message from a pipe. 'msg' should not be initialised prior to the call. It will be initialised when the call succeeds. */ int nn_pipe_recv (struct nn_pipe *self, struct nn_msg *msg); /* Get option for pipe. Mostly useful for endpoint-specific options */ void nn_pipe_getopt (struct nn_pipe *self, int level, int option, void *optval, size_t *optvallen); /******************************************************************************/ /* Base class for all socket types. */ /******************************************************************************/ struct nn_sockbase; /* Any combination of these events can be returned from 'events' virtual function. */ #define NN_SOCKBASE_EVENT_IN 1 #define NN_SOCKBASE_EVENT_OUT 2 /* To be implemented by individual socket types. */ struct nn_sockbase_vfptr { /* Ask socket to stop. */ void (*stop) (struct nn_sockbase *self); /* Deallocate the socket. */ void (*destroy) (struct nn_sockbase *self); /* Management of pipes. 'add' registers a new pipe. The pipe cannot be used to send to or to be received from at the moment. 'rm' unregisters the pipe. The pipe should not be used after this call as it may already be deallocated. 'in' informs the socket that pipe is readable. 'out' informs it that it is writable. */ int (*add) (struct nn_sockbase *self, struct nn_pipe *pipe); void (*rm) (struct nn_sockbase *self, struct nn_pipe *pipe); void (*in) (struct nn_sockbase *self, struct nn_pipe *pipe); void (*out) (struct nn_sockbase *self, struct nn_pipe *pipe); /* Return any combination of event flags defined above, thus specifying whether the socket should be readable, writable, both or none. */ int (*events) (struct nn_sockbase *self); /* Send a message to the socket. Returns -EAGAIN if it cannot be done at the moment or zero in case of success. */ int (*send) (struct nn_sockbase *self, struct nn_msg *msg); /* Receive a message from the socket. Returns -EAGAIN if it cannot be done at the moment or zero in case of success. */ int (*recv) (struct nn_sockbase *self, struct nn_msg *msg); /* Set a protocol specific option. */ int (*setopt) (struct nn_sockbase *self, int level, int option, const void *optval, size_t optvallen); /* Retrieve a protocol specific option. */ int (*getopt) (struct nn_sockbase *self, int level, int option, void *optval, size_t *optvallen); }; struct nn_sockbase { const struct nn_sockbase_vfptr *vfptr; struct nn_sock *sock; }; /* Initialise the socket base class. 'hint' is the opaque value passed to the nn_transport's 'create' function. */ void nn_sockbase_init (struct nn_sockbase *self, const struct nn_sockbase_vfptr *vfptr, void *hint); /* Terminate the socket base class. */ void nn_sockbase_term (struct nn_sockbase *self); /* Call this function when stopping is done. */ void nn_sockbase_stopped (struct nn_sockbase *self); /* Returns the AIO context associated with the socket. This function is useful when socket type implementation needs to create async objects, such as timers. */ struct nn_ctx *nn_sockbase_getctx (struct nn_sockbase *self); /* Retrieve a NN_SOL_SOCKET-level option. */ int nn_sockbase_getopt (struct nn_sockbase *self, int option, void *optval, size_t *optvallen); /* Add some statistics for socket */ void nn_sockbase_stat_increment (struct nn_sockbase *self, int name, int increment); /******************************************************************************/ /* The socktype class. */ /******************************************************************************/ /* This structure defines a class factory for individual socket types. */ /* Specifies that the socket type can be never used to receive messages. */ #define NN_SOCKTYPE_FLAG_NORECV 1 /* Specifies that the socket type can be never used to send messages. */ #define NN_SOCKTYPE_FLAG_NOSEND 2 struct nn_socktype { /* Domain and protocol IDs as specified in nn_socket() function. */ int domain; int protocol; /* Any combination of the flags defined above. */ int flags; /* Function to create specific socket type. 'sockbase' is the output parameter to return reference to newly created socket. This function is called under global lock, so it is not possible that two sockets are being created in parallel. */ int (*create) (void *hint, struct nn_sockbase **sockbase); /* Returns 1 if the supplied socket type is a valid peer for this socket, 0 otherwise. Note that the validation is done only within a single SP protocol. Peers speaking other SP protocols are discarded by the core and socket is not even asked to validate them. */ int (*ispeer) (int socktype); }; #endif nanomsg-1.1.5/src/protocols/000077500000000000000000000000001336111550300157715ustar00rootroot00000000000000nanomsg-1.1.5/src/protocols/README000066400000000000000000000001761336111550300166550ustar00rootroot00000000000000This directory contains all the available scalability protocol implementations, such as publish/subscribe, request/reply etc. nanomsg-1.1.5/src/protocols/bus/000077500000000000000000000000001336111550300165625ustar00rootroot00000000000000nanomsg-1.1.5/src/protocols/bus/bus.c000066400000000000000000000073731336111550300175310ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xbus.h" #include "../../nn.h" #include "../../bus.h" #include "../../utils/cont.h" #include "../../utils/alloc.h" #include "../../utils/err.h" struct nn_bus { struct nn_xbus xbus; }; /* Private functions. */ static void nn_bus_init (struct nn_bus *self, const struct nn_sockbase_vfptr *vfptr, void *hint); static void nn_bus_term (struct nn_bus *self); /* Implementation of nn_sockbase's virtual functions. */ static void nn_bus_destroy (struct nn_sockbase *self); static int nn_bus_send (struct nn_sockbase *self, struct nn_msg *msg); static int nn_bus_recv (struct nn_sockbase *self, struct nn_msg *msg); static const struct nn_sockbase_vfptr nn_bus_sockbase_vfptr = { NULL, nn_bus_destroy, nn_xbus_add, nn_xbus_rm, nn_xbus_in, nn_xbus_out, nn_xbus_events, nn_bus_send, nn_bus_recv, NULL, NULL }; static void nn_bus_init (struct nn_bus *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_xbus_init (&self->xbus, vfptr, hint); } static void nn_bus_term (struct nn_bus *self) { nn_xbus_term (&self->xbus); } static void nn_bus_destroy (struct nn_sockbase *self) { struct nn_bus *bus; bus = nn_cont (self, struct nn_bus, xbus.sockbase); nn_bus_term (bus); nn_free (bus); } static int nn_bus_send (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_bus *bus; bus = nn_cont (self, struct nn_bus, xbus.sockbase); /* Check for malformed messages. */ if (nn_chunkref_size (&msg->sphdr)) return -EINVAL; /* Send the message. */ rc = nn_xbus_send (&bus->xbus.sockbase, msg); errnum_assert (rc == 0, -rc); return 0; } static int nn_bus_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_bus *bus; bus = nn_cont (self, struct nn_bus, xbus.sockbase); /* Get next message. */ rc = nn_xbus_recv (&bus->xbus.sockbase, msg); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc == 0, -rc); nn_assert (nn_chunkref_size (&msg->sphdr) == sizeof (uint64_t)); /* Discard the header. */ nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, 0); return 0; } static int nn_bus_create (void *hint, struct nn_sockbase **sockbase) { struct nn_bus *self; self = nn_alloc (sizeof (struct nn_bus), "socket (bus)"); alloc_assert (self); nn_bus_init (self, &nn_bus_sockbase_vfptr, hint); *sockbase = &self->xbus.sockbase; return 0; } struct nn_socktype nn_bus_socktype = { AF_SP, NN_BUS, 0, nn_bus_create, nn_xbus_ispeer, }; nanomsg-1.1.5/src/protocols/bus/xbus.c000066400000000000000000000141461336111550300177150ustar00rootroot00000000000000/* Copyright (c) 2013-2014 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xbus.h" #include "../../nn.h" #include "../../bus.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/alloc.h" #include "../../utils/attr.h" #include #include /* To make the algorithm super efficient we directly cast pipe pointers to pipe IDs (rather than maintaining a hash table). For this to work, it is neccessary for the pointer to fit in 64-bit ID. */ CT_ASSERT (sizeof (uint64_t) >= sizeof (struct nn_pipe*)); /* Implementation of nn_sockbase's virtual functions. */ static void nn_xbus_destroy (struct nn_sockbase *self); static const struct nn_sockbase_vfptr nn_xbus_sockbase_vfptr = { NULL, nn_xbus_destroy, nn_xbus_add, nn_xbus_rm, nn_xbus_in, nn_xbus_out, nn_xbus_events, nn_xbus_send, nn_xbus_recv, NULL, NULL }; void nn_xbus_init (struct nn_xbus *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_sockbase_init (&self->sockbase, vfptr, hint); nn_dist_init (&self->outpipes); nn_fq_init (&self->inpipes); } void nn_xbus_term (struct nn_xbus *self) { nn_fq_term (&self->inpipes); nn_dist_term (&self->outpipes); nn_sockbase_term (&self->sockbase); } static void nn_xbus_destroy (struct nn_sockbase *self) { struct nn_xbus *xbus; xbus = nn_cont (self, struct nn_xbus, sockbase); nn_xbus_term (xbus); nn_free (xbus); } int nn_xbus_add (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xbus *xbus; struct nn_xbus_data *data; int rcvprio; size_t sz; xbus = nn_cont (self, struct nn_xbus, sockbase); sz = sizeof (rcvprio); nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz); nn_assert (sz == sizeof (rcvprio)); nn_assert (rcvprio >= 1 && rcvprio <= 16); data = nn_alloc (sizeof (struct nn_xbus_data), "pipe data (xbus)"); alloc_assert (data); nn_fq_add (&xbus->inpipes, &data->initem, pipe, rcvprio); nn_dist_add (&xbus->outpipes, &data->outitem, pipe); nn_pipe_setdata (pipe, data); return 0; } void nn_xbus_rm (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xbus *xbus; struct nn_xbus_data *data; xbus = nn_cont (self, struct nn_xbus, sockbase); data = nn_pipe_getdata (pipe); nn_fq_rm (&xbus->inpipes, &data->initem); nn_dist_rm (&xbus->outpipes, &data->outitem); nn_free (data); } void nn_xbus_in (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xbus *xbus; struct nn_xbus_data *data; xbus = nn_cont (self, struct nn_xbus, sockbase); data = nn_pipe_getdata (pipe); nn_fq_in (&xbus->inpipes, &data->initem); } void nn_xbus_out (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xbus *xbus; struct nn_xbus_data *data; xbus = nn_cont (self, struct nn_xbus, sockbase); data = nn_pipe_getdata (pipe); nn_dist_out (&xbus->outpipes, &data->outitem); } int nn_xbus_events (struct nn_sockbase *self) { return (nn_fq_can_recv (&nn_cont (self, struct nn_xbus, sockbase)->inpipes) ? NN_SOCKBASE_EVENT_IN : 0) | NN_SOCKBASE_EVENT_OUT; } int nn_xbus_send (struct nn_sockbase *self, struct nn_msg *msg) { size_t hdrsz; struct nn_pipe *exclude; hdrsz = nn_chunkref_size (&msg->sphdr); if (hdrsz == 0) exclude = NULL; else if (hdrsz == sizeof (uint64_t)) { memcpy (&exclude, nn_chunkref_data (&msg->sphdr), sizeof (exclude)); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, 0); } else return -EINVAL; return nn_dist_send (&nn_cont (self, struct nn_xbus, sockbase)->outpipes, msg, exclude); } int nn_xbus_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_xbus *xbus; struct nn_pipe *pipe; xbus = nn_cont (self, struct nn_xbus, sockbase); while (1) { /* Get next message in fair-queued manner. */ rc = nn_fq_recv (&xbus->inpipes, msg, &pipe); if (nn_slow (rc < 0)) return rc; /* The message should have no header. Drop malformed messages. */ if (nn_chunkref_size (&msg->sphdr) == 0) break; nn_msg_term (msg); } /* Add pipe ID to the message header. */ nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, sizeof (uint64_t)); memset (nn_chunkref_data (&msg->sphdr), 0, sizeof (uint64_t)); memcpy (nn_chunkref_data (&msg->sphdr), &pipe, sizeof (pipe)); return 0; } static int nn_xbus_create (void *hint, struct nn_sockbase **sockbase) { struct nn_xbus *self; self = nn_alloc (sizeof (struct nn_xbus), "socket (bus)"); alloc_assert (self); nn_xbus_init (self, &nn_xbus_sockbase_vfptr, hint); *sockbase = &self->sockbase; return 0; } int nn_xbus_ispeer (int socktype) { return socktype == NN_BUS ? 1 : 0; } struct nn_socktype nn_xbus_socktype = { AF_SP_RAW, NN_BUS, 0, nn_xbus_create, nn_xbus_ispeer, }; nanomsg-1.1.5/src/protocols/bus/xbus.h000066400000000000000000000041641336111550300177210ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_XBUS_INCLUDED #define NN_XBUS_INCLUDED #include "../../protocol.h" #include "../utils/dist.h" #include "../utils/fq.h" struct nn_xbus_data { struct nn_dist_data outitem; struct nn_fq_data initem; }; struct nn_xbus { struct nn_sockbase sockbase; struct nn_dist outpipes; struct nn_fq inpipes; }; void nn_xbus_init (struct nn_xbus *self, const struct nn_sockbase_vfptr *vfptr, void *hint); void nn_xbus_term (struct nn_xbus *self); int nn_xbus_add (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xbus_rm (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xbus_in (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xbus_out (struct nn_sockbase *self, struct nn_pipe *pipe); int nn_xbus_events (struct nn_sockbase *self); int nn_xbus_send (struct nn_sockbase *self, struct nn_msg *msg); int nn_xbus_recv (struct nn_sockbase *self, struct nn_msg *msg); int nn_xbus_ispeer (int socktype); #endif nanomsg-1.1.5/src/protocols/pair/000077500000000000000000000000001336111550300167245ustar00rootroot00000000000000nanomsg-1.1.5/src/protocols/pair/pair.c000066400000000000000000000025631336111550300200310ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xpair.h" #include "../../nn.h" #include "../../pair.h" struct nn_socktype nn_pair_socktype = { AF_SP, NN_PAIR, 0, nn_xpair_create, nn_xpair_ispeer, }; nanomsg-1.1.5/src/protocols/pair/xpair.c000066400000000000000000000115221336111550300202140ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xpair.h" #include "../../nn.h" #include "../../pair.h" #include "../utils/excl.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/alloc.h" #include "../../utils/attr.h" struct nn_xpair { struct nn_sockbase sockbase; struct nn_excl excl; }; /* Private functions. */ static void nn_xpair_init (struct nn_xpair *self, const struct nn_sockbase_vfptr *vfptr, void *hint); static void nn_xpair_term (struct nn_xpair *self); /* Implementation of nn_sockbase's virtual functions. */ static void nn_xpair_destroy (struct nn_sockbase *self); static int nn_xpair_add (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpair_rm (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpair_in (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpair_out (struct nn_sockbase *self, struct nn_pipe *pipe); static int nn_xpair_events (struct nn_sockbase *self); static int nn_xpair_send (struct nn_sockbase *self, struct nn_msg *msg); static int nn_xpair_recv (struct nn_sockbase *self, struct nn_msg *msg); static const struct nn_sockbase_vfptr nn_xpair_sockbase_vfptr = { NULL, nn_xpair_destroy, nn_xpair_add, nn_xpair_rm, nn_xpair_in, nn_xpair_out, nn_xpair_events, nn_xpair_send, nn_xpair_recv, NULL, NULL }; static void nn_xpair_init (struct nn_xpair *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_sockbase_init (&self->sockbase, vfptr, hint); nn_excl_init (&self->excl); } static void nn_xpair_term (struct nn_xpair *self) { nn_excl_term (&self->excl); nn_sockbase_term (&self->sockbase); } void nn_xpair_destroy (struct nn_sockbase *self) { struct nn_xpair *xpair; xpair = nn_cont (self, struct nn_xpair, sockbase); nn_xpair_term (xpair); nn_free (xpair); } static int nn_xpair_add (struct nn_sockbase *self, struct nn_pipe *pipe) { return nn_excl_add (&nn_cont (self, struct nn_xpair, sockbase)->excl, pipe); } static void nn_xpair_rm (struct nn_sockbase *self, struct nn_pipe *pipe) { nn_excl_rm (&nn_cont (self, struct nn_xpair, sockbase)->excl, pipe); } static void nn_xpair_in (struct nn_sockbase *self, struct nn_pipe *pipe) { nn_excl_in (&nn_cont (self, struct nn_xpair, sockbase)->excl, pipe); } static void nn_xpair_out (struct nn_sockbase *self, struct nn_pipe *pipe) { nn_excl_out (&nn_cont (self, struct nn_xpair, sockbase)->excl, pipe); } static int nn_xpair_events (struct nn_sockbase *self) { struct nn_xpair *xpair; int events; xpair = nn_cont (self, struct nn_xpair, sockbase); events = 0; if (nn_excl_can_recv (&xpair->excl)) events |= NN_SOCKBASE_EVENT_IN; if (nn_excl_can_send (&xpair->excl)) events |= NN_SOCKBASE_EVENT_OUT; return events; } static int nn_xpair_send (struct nn_sockbase *self, struct nn_msg *msg) { return nn_excl_send (&nn_cont (self, struct nn_xpair, sockbase)->excl, msg); } static int nn_xpair_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; rc = nn_excl_recv (&nn_cont (self, struct nn_xpair, sockbase)->excl, msg); /* Discard NN_PIPEBASE_PARSED flag. */ return rc < 0 ? rc : 0; } int nn_xpair_create (void *hint, struct nn_sockbase **sockbase) { struct nn_xpair *self; self = nn_alloc (sizeof (struct nn_xpair), "socket (pair)"); alloc_assert (self); nn_xpair_init (self, &nn_xpair_sockbase_vfptr, hint); *sockbase = &self->sockbase; return 0; } int nn_xpair_ispeer (int socktype) { return socktype == NN_PAIR ? 1 : 0; } struct nn_socktype nn_xpair_socktype = { AF_SP_RAW, NN_PAIR, 0, nn_xpair_create, nn_xpair_ispeer, }; nanomsg-1.1.5/src/protocols/pair/xpair.h000066400000000000000000000025031336111550300202200ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_XPAIR_INCLUDED #define NN_XPAIR_INCLUDED #include "../../protocol.h" int nn_xpair_create (void *hint, struct nn_sockbase **sockbase); int nn_xpair_ispeer (int socktype); #endif nanomsg-1.1.5/src/protocols/pipeline/000077500000000000000000000000001336111550300175765ustar00rootroot00000000000000nanomsg-1.1.5/src/protocols/pipeline/pull.c000066400000000000000000000026151336111550300207220ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xpull.h" #include "../../nn.h" #include "../../pipeline.h" struct nn_socktype nn_pull_socktype = { AF_SP, NN_PULL, NN_SOCKTYPE_FLAG_NOSEND, nn_xpull_create, nn_xpull_ispeer, }; nanomsg-1.1.5/src/protocols/pipeline/push.c000066400000000000000000000026151336111550300207250ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xpush.h" #include "../../nn.h" #include "../../pipeline.h" struct nn_socktype nn_push_socktype = { AF_SP, NN_PUSH, NN_SOCKTYPE_FLAG_NORECV, nn_xpush_create, nn_xpush_ispeer, }; nanomsg-1.1.5/src/protocols/pipeline/xpull.c000066400000000000000000000125151336111550300211120ustar00rootroot00000000000000/* Copyright (c) 2012-2014 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. 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. */ #include "xpull.h" #include "../../nn.h" #include "../../pipeline.h" #include "../utils/fq.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/alloc.h" #include "../../utils/attr.h" struct nn_xpull_data { struct nn_fq_data fq; }; struct nn_xpull { struct nn_sockbase sockbase; struct nn_fq fq; }; /* Private functions. */ static void nn_xpull_init (struct nn_xpull *self, const struct nn_sockbase_vfptr *vfptr, void *hint); static void nn_xpull_term (struct nn_xpull *self); /* Implementation of nn_sockbase's virtual functions. */ static void nn_xpull_destroy (struct nn_sockbase *self); static int nn_xpull_add (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpull_rm (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpull_in (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpull_out (struct nn_sockbase *self, struct nn_pipe *pipe); static int nn_xpull_events (struct nn_sockbase *self); static int nn_xpull_recv (struct nn_sockbase *self, struct nn_msg *msg); static const struct nn_sockbase_vfptr nn_xpull_sockbase_vfptr = { NULL, nn_xpull_destroy, nn_xpull_add, nn_xpull_rm, nn_xpull_in, nn_xpull_out, nn_xpull_events, NULL, nn_xpull_recv, NULL, NULL }; static void nn_xpull_init (struct nn_xpull *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_sockbase_init (&self->sockbase, vfptr, hint); nn_fq_init (&self->fq); } static void nn_xpull_term (struct nn_xpull *self) { nn_fq_term (&self->fq); nn_sockbase_term (&self->sockbase); } void nn_xpull_destroy (struct nn_sockbase *self) { struct nn_xpull *xpull; xpull = nn_cont (self, struct nn_xpull, sockbase); nn_xpull_term (xpull); nn_free (xpull); } static int nn_xpull_add (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xpull *xpull; struct nn_xpull_data *data; int rcvprio; size_t sz; xpull = nn_cont (self, struct nn_xpull, sockbase); sz = sizeof (rcvprio); nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz); nn_assert (sz == sizeof (rcvprio)); nn_assert (rcvprio >= 1 && rcvprio <= 16); data = nn_alloc (sizeof (struct nn_xpull_data), "pipe data (pull)"); alloc_assert (data); nn_pipe_setdata (pipe, data); nn_fq_add (&xpull->fq, &data->fq, pipe, rcvprio); return 0; } static void nn_xpull_rm (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xpull *xpull; struct nn_xpull_data *data; xpull = nn_cont (self, struct nn_xpull, sockbase); data = nn_pipe_getdata (pipe); nn_fq_rm (&xpull->fq, &data->fq); nn_free (data); } static void nn_xpull_in (NN_UNUSED struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xpull *xpull; struct nn_xpull_data *data; xpull = nn_cont (self, struct nn_xpull, sockbase); data = nn_pipe_getdata (pipe); nn_fq_in (&xpull->fq, &data->fq); } static void nn_xpull_out (NN_UNUSED struct nn_sockbase *self, NN_UNUSED struct nn_pipe *pipe) { /* We are not going to send any messages, so there's no point is maintaining a list of pipes ready for sending. */ } static int nn_xpull_events (struct nn_sockbase *self) { return nn_fq_can_recv (&nn_cont (self, struct nn_xpull, sockbase)->fq) ? NN_SOCKBASE_EVENT_IN : 0; } static int nn_xpull_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; rc = nn_fq_recv (&nn_cont (self, struct nn_xpull, sockbase)->fq, msg, NULL); /* Discard NN_PIPEBASE_PARSED flag. */ return rc < 0 ? rc : 0; } int nn_xpull_create (void *hint, struct nn_sockbase **sockbase) { struct nn_xpull *self; self = nn_alloc (sizeof (struct nn_xpull), "socket (pull)"); alloc_assert (self); nn_xpull_init (self, &nn_xpull_sockbase_vfptr, hint); *sockbase = &self->sockbase; return 0; } int nn_xpull_ispeer (int socktype) { return socktype == NN_PUSH ? 1 : 0; } struct nn_socktype nn_xpull_socktype = { AF_SP_RAW, NN_PULL, NN_SOCKTYPE_FLAG_NOSEND, nn_xpull_create, nn_xpull_ispeer, }; nanomsg-1.1.5/src/protocols/pipeline/xpull.h000066400000000000000000000025031336111550300211130ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_XPULL_INCLUDED #define NN_XPULL_INCLUDED #include "../../protocol.h" int nn_xpull_create (void *hint, struct nn_sockbase **sockbase); int nn_xpull_ispeer (int socktype); #endif nanomsg-1.1.5/src/protocols/pipeline/xpush.c000066400000000000000000000126151336111550300211160ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xpush.h" #include "../../nn.h" #include "../../pipeline.h" #include "../utils/lb.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/alloc.h" #include "../../utils/attr.h" struct nn_xpush_data { struct nn_lb_data lb; }; struct nn_xpush { struct nn_sockbase sockbase; struct nn_lb lb; }; /* Private functions. */ static void nn_xpush_init (struct nn_xpush *self, const struct nn_sockbase_vfptr *vfptr, void *hint); static void nn_xpush_term (struct nn_xpush *self); /* Implementation of nn_sockbase's virtual functions. */ static void nn_xpush_destroy (struct nn_sockbase *self); static int nn_xpush_add (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpush_rm (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpush_in (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpush_out (struct nn_sockbase *self, struct nn_pipe *pipe); static int nn_xpush_events (struct nn_sockbase *self); static int nn_xpush_send (struct nn_sockbase *self, struct nn_msg *msg); static const struct nn_sockbase_vfptr nn_xpush_sockbase_vfptr = { NULL, nn_xpush_destroy, nn_xpush_add, nn_xpush_rm, nn_xpush_in, nn_xpush_out, nn_xpush_events, nn_xpush_send, NULL, NULL, NULL }; static void nn_xpush_init (struct nn_xpush *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_sockbase_init (&self->sockbase, vfptr, hint); nn_lb_init (&self->lb); } static void nn_xpush_term (struct nn_xpush *self) { nn_lb_term (&self->lb); nn_sockbase_term (&self->sockbase); } void nn_xpush_destroy (struct nn_sockbase *self) { struct nn_xpush *xpush; xpush = nn_cont (self, struct nn_xpush, sockbase); nn_xpush_term (xpush); nn_free (xpush); } static int nn_xpush_add (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xpush *xpush; struct nn_xpush_data *data; int sndprio; size_t sz; xpush = nn_cont (self, struct nn_xpush, sockbase); sz = sizeof (sndprio); nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_SNDPRIO, &sndprio, &sz); nn_assert (sz == sizeof (sndprio)); nn_assert (sndprio >= 1 && sndprio <= 16); data = nn_alloc (sizeof (struct nn_xpush_data), "pipe data (push)"); alloc_assert (data); nn_pipe_setdata (pipe, data); nn_lb_add (&xpush->lb, &data->lb, pipe, sndprio); return 0; } static void nn_xpush_rm (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xpush *xpush; struct nn_xpush_data *data; xpush = nn_cont (self, struct nn_xpush, sockbase); data = nn_pipe_getdata (pipe); nn_lb_rm (&xpush->lb, &data->lb); nn_free (data); nn_sockbase_stat_increment (self, NN_STAT_CURRENT_SND_PRIORITY, nn_lb_get_priority (&xpush->lb)); } static void nn_xpush_in (NN_UNUSED struct nn_sockbase *self, NN_UNUSED struct nn_pipe *pipe) { /* We are not going to receive any messages, so there's no need to store the list of inbound pipes. */ } static void nn_xpush_out (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xpush *xpush; struct nn_xpush_data *data; xpush = nn_cont (self, struct nn_xpush, sockbase); data = nn_pipe_getdata (pipe); nn_lb_out (&xpush->lb, &data->lb); nn_sockbase_stat_increment (self, NN_STAT_CURRENT_SND_PRIORITY, nn_lb_get_priority (&xpush->lb)); } static int nn_xpush_events (struct nn_sockbase *self) { return nn_lb_can_send (&nn_cont (self, struct nn_xpush, sockbase)->lb) ? NN_SOCKBASE_EVENT_OUT : 0; } static int nn_xpush_send (struct nn_sockbase *self, struct nn_msg *msg) { return nn_lb_send (&nn_cont (self, struct nn_xpush, sockbase)->lb, msg, NULL); } int nn_xpush_create (void *hint, struct nn_sockbase **sockbase) { struct nn_xpush *self; self = nn_alloc (sizeof (struct nn_xpush), "socket (push)"); alloc_assert (self); nn_xpush_init (self, &nn_xpush_sockbase_vfptr, hint); *sockbase = &self->sockbase; return 0; } int nn_xpush_ispeer (int socktype) { return socktype == NN_PULL ? 1 : 0; } struct nn_socktype nn_xpush_socktype = { AF_SP_RAW, NN_PUSH, NN_SOCKTYPE_FLAG_NORECV, nn_xpush_create, nn_xpush_ispeer, }; nanomsg-1.1.5/src/protocols/pipeline/xpush.h000066400000000000000000000025041336111550300211170ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_XPUSH_INCLUDED #define NN_XPUSH_INCLUDED #include "../../protocol.h" int nn_xpush_create (void *hint, struct nn_sockbase **sockbase); int nn_xpush_ispeer (int socktype); #endif nanomsg-1.1.5/src/protocols/pubsub/000077500000000000000000000000001336111550300172715ustar00rootroot00000000000000nanomsg-1.1.5/src/protocols/pubsub/pub.c000066400000000000000000000025111336111550300202220ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "xpub.h" #include "../../nn.h" #include "../../pubsub.h" struct nn_socktype nn_pub_socktype = { AF_SP, NN_PUB, NN_SOCKTYPE_FLAG_NORECV, nn_xpub_create, nn_xpub_ispeer, }; nanomsg-1.1.5/src/protocols/pubsub/sub.c000066400000000000000000000025111336111550300202250ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "xsub.h" #include "../../nn.h" #include "../../pubsub.h" struct nn_socktype nn_sub_socktype = { AF_SP, NN_SUB, NN_SOCKTYPE_FLAG_NOSEND, nn_xsub_create, nn_xsub_ispeer, }; nanomsg-1.1.5/src/protocols/pubsub/trie.c000066400000000000000000000510601336111550300204020ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include #include #include #include "trie.h" #include "../../utils/alloc.h" #include "../../utils/fast.h" #include "../../utils/err.h" /* Double check that the size of node structure is as small as we believe it to be. */ CT_ASSERT (sizeof (struct nn_trie_node) == 24); /* Forward declarations. */ static struct nn_trie_node *nn_node_compact (struct nn_trie_node *self); static int nn_node_check_prefix (struct nn_trie_node *self, const uint8_t *data, size_t size); static struct nn_trie_node **nn_node_child (struct nn_trie_node *self, int index); static struct nn_trie_node **nn_node_next (struct nn_trie_node *self, uint8_t c); static int nn_node_unsubscribe (struct nn_trie_node **self, const uint8_t *data, size_t size); static void nn_node_term (struct nn_trie_node *self); static int nn_node_has_subscribers (struct nn_trie_node *self); static void nn_node_dump (struct nn_trie_node *self, int indent); static void nn_node_indent (int indent); static void nn_node_putchar (uint8_t c); void nn_trie_init (struct nn_trie *self) { self->root = NULL; } void nn_trie_term (struct nn_trie *self) { nn_node_term (self->root); } void nn_trie_dump (struct nn_trie *self) { nn_node_dump (self->root, 0); } void nn_node_dump (struct nn_trie_node *self, int indent) { int i; int children; if (!self) { nn_node_indent (indent); printf ("NULL\n"); return; } nn_node_indent (indent); printf ("===================\n"); nn_node_indent (indent); printf ("refcount=%d\n", (int) self->refcount); nn_node_indent (indent); printf ("prefix_len=%d\n", (int) self->prefix_len); nn_node_indent (indent); if (self->type == NN_TRIE_DENSE_TYPE) printf ("type=dense\n"); else printf ("type=sparse\n"); nn_node_indent (indent); printf ("prefix=\""); for (i = 0; i != self->prefix_len; ++i) nn_node_putchar (self->prefix [i]); printf ("\"\n"); if (self->type <= 8) { nn_node_indent (indent); printf ("sparse.children=\""); for (i = 0; i != self->type; ++i) nn_node_putchar (self->u.sparse.children [i]); printf ("\"\n"); children = self->type; } else { nn_node_indent (indent); printf ("dense.min='%c' (%d)\n", (char) self->u.dense.min, (int) self->u.dense.min); nn_node_indent (indent); printf ("dense.max='%c' (%d)\n", (char) self->u.dense.max, (int) self->u.dense.max); nn_node_indent (indent); printf ("dense.nbr=%d\n", (int) self->u.dense.nbr); children = self->u.dense.max - self->u.dense.min + 1; } for (i = 0; i != children; ++i) nn_node_dump (((struct nn_trie_node**) (self + 1)) [i], indent + 1); nn_node_indent (indent); printf ("===================\n"); } void nn_node_indent (int indent) { int i; for (i = 0; i != indent * 4; ++i) nn_node_putchar (' '); } void nn_node_putchar (uint8_t c) { if (c < 32 || c > 127) putchar ('?'); else putchar (c); } void nn_node_term (struct nn_trie_node *self) { int children; int i; /* Trivial case of the recursive algorithm. */ if (!self) return; /* Recursively destroy the child nodes. */ children = self->type <= NN_TRIE_SPARSE_MAX ? self->type : (self->u.dense.max - self->u.dense.min + 1); for (i = 0; i != children; ++i) nn_node_term (*nn_node_child (self, i)); /* Deallocate this node. */ nn_free (self); } int nn_node_check_prefix (struct nn_trie_node *self, const uint8_t *data, size_t size) { /* Check how many characters from the data match the prefix. */ int i; for (i = 0; i != self->prefix_len; ++i) { if (!size || self->prefix [i] != *data) return i; ++data; --size; } return self->prefix_len; } struct nn_trie_node **nn_node_child (struct nn_trie_node *self, int index) { /* Finds pointer to the n-th child of the node. */ return ((struct nn_trie_node**) (self + 1)) + index; } struct nn_trie_node **nn_node_next (struct nn_trie_node *self, uint8_t c) { /* Finds the pointer to the next node based on the supplied character. If there is no such pointer, it returns NULL. */ int i; if (self->type == 0) return NULL; /* Sparse mode. */ if (self->type <= 8) { for (i = 0; i != self->type; ++i) if (self->u.sparse.children [i] == c) return nn_node_child (self, i); return NULL; } /* Dense mode. */ if (c < self->u.dense.min || c > self->u.dense.max) return NULL; return nn_node_child (self, c - self->u.dense.min); } struct nn_trie_node *nn_node_compact (struct nn_trie_node *self) { /* Tries to merge the node with the child node. Returns pointer to the compacted node. */ struct nn_trie_node *ch; /* Node that is a subscription cannot be compacted. */ if (nn_node_has_subscribers (self)) return self; /* Only a node with a single child can be compacted. */ if (self->type != 1) return self; /* Check whether combined prefixes would fix into a single node. */ ch = *nn_node_child (self, 0); if (self->prefix_len + ch->prefix_len + 1 > NN_TRIE_PREFIX_MAX) return self; /* Concatenate the prefixes. */ memmove (ch->prefix + self->prefix_len + 1, ch->prefix, ch->prefix_len); memcpy (ch->prefix, self->prefix, self->prefix_len); ch->prefix [self->prefix_len] = self->u.sparse.children [0]; ch->prefix_len += self->prefix_len + 1; /* Get rid of the obsolete parent node. */ nn_free (self); /* Return the new compacted node. */ return ch; } int nn_trie_subscribe (struct nn_trie *self, const uint8_t *data, size_t size) { int i; struct nn_trie_node **node; struct nn_trie_node **n; struct nn_trie_node *ch; struct nn_trie_node *old_node; int pos; uint8_t c; uint8_t c2; uint8_t new_min; uint8_t new_max; int old_children; int new_children; int inserted; int more_nodes; /* Step 1 -- Traverse the trie. */ node = &self->root; while (1) { /* If there are no more nodes on the path, go to step 4. */ if (!*node) goto step4; /* Check whether prefix matches the new subscription. */ pos = nn_node_check_prefix (*node, data, size); data += pos; size -= pos; /* If only part of the prefix matches, go to step 2. */ if (pos < (*node)->prefix_len) goto step2; /* Even if whole prefix matches and there's no more data to match, go directly to step 5. */ if (!size) goto step5; /* Move to the next node. If it is not present, go to step 3. */ n = nn_node_next (*node, *data); if (!n || !*n) goto step3; node = n; ++data; --size; } /* Step 2 -- Split the prefix into two parts if required. */ step2: ch = *node; *node = nn_alloc (sizeof (struct nn_trie_node) + sizeof (struct nn_trie_node*), "trie node"); assert (*node); (*node)->refcount = 0; (*node)->prefix_len = pos; (*node)->type = 1; memcpy ((*node)->prefix, ch->prefix, pos); (*node)->u.sparse.children [0] = ch->prefix [pos]; ch->prefix_len -= (pos + 1); memmove (ch->prefix, ch->prefix + pos + 1, ch->prefix_len); ch = nn_node_compact (ch); *nn_node_child (*node, 0) = ch; /* Step 3 -- Adjust the child array to accommodate the new character. */ step3: /* If there are no more data in the subscription, there's nothing to adjust in the child array. Proceed directly to the step 5. */ if (!size) goto step5; /* If the new branch fits into sparse array... */ if ((*node)->type < NN_TRIE_SPARSE_MAX) { *node = nn_realloc (*node, sizeof (struct nn_trie_node) + ((*node)->type + 1) * sizeof (struct nn_trie_node*)); assert (*node); (*node)->u.sparse.children [(*node)->type] = *data; ++(*node)->type; node = nn_node_child (*node, (*node)->type - 1); *node = NULL; ++data; --size; goto step4; } /* If the node is already a dense array, resize it to fit the next character. */ if ((*node)->type == NN_TRIE_DENSE_TYPE) { c = *data; if (c < (*node)->u.dense.min || c > (*node)->u.dense.max) { new_min = (*node)->u.dense.min < c ? (*node)->u.dense.min : c; new_max = (*node)->u.dense.max > c ? (*node)->u.dense.max : c; *node = nn_realloc (*node, sizeof (struct nn_trie_node) + (new_max - new_min + 1) * sizeof (struct nn_trie_node*)); assert (*node); old_children = (*node)->u.dense.max - (*node)->u.dense.min + 1; new_children = new_max - new_min + 1; if ((*node)->u.dense.min != new_min) { inserted = (*node)->u.dense.min - new_min; memmove (nn_node_child (*node, inserted), nn_node_child (*node, 0), old_children * sizeof (struct nn_trie_node*)); memset (nn_node_child (*node, 0), 0, inserted * sizeof (struct nn_trie_node*)); } else { memset (nn_node_child (*node, old_children), 0, (new_children - old_children) * sizeof (struct nn_trie_node*)); } (*node)->u.dense.min = new_min; (*node)->u.dense.max = new_max; } ++(*node)->u.dense.nbr; node = nn_node_child (*node, c - (*node)->u.dense.min); ++data; --size; goto step4; } /* This is a sparse array, but no more children can be added to it. We have to convert it into a dense array. */ { /* First, determine the range of children. */ new_min = 255; new_max = 0; for (i = 0; i != (*node)->type; ++i) { c2 = (*node)->u.sparse.children [i]; new_min = new_min < c2 ? new_min : c2; new_max = new_max > c2 ? new_max : c2; } new_min = new_min < *data ? new_min : *data; new_max = new_max > *data ? new_max : *data; /* Create a new mode, while keeping the old one for a while. */ old_node = *node; *node = (struct nn_trie_node*) nn_alloc (sizeof (struct nn_trie_node) + (new_max - new_min + 1) * sizeof (struct nn_trie_node*), "trie node"); assert (*node); /* Fill in the new node. */ (*node)->refcount = 0; (*node)->prefix_len = old_node->prefix_len; (*node)->type = NN_TRIE_DENSE_TYPE; memcpy ((*node)->prefix, old_node->prefix, old_node->prefix_len); (*node)->u.dense.min = new_min; (*node)->u.dense.max = new_max; (*node)->u.dense.nbr = old_node->type + 1; memset (*node + 1, 0, (new_max - new_min + 1) * sizeof (struct nn_trie_node*)); for (i = 0; i != old_node->type; ++i) *nn_node_child (*node, old_node->u.sparse.children [i] - new_min) = *nn_node_child (old_node, i); node = nn_node_next (*node, *data); ++data; --size; /* Get rid of the obsolete old node. */ nn_free (old_node); } /* Step 4 -- Create new nodes for remaining part of the subscription. */ step4: assert (!*node); while (1) { /* Create a new node to hold the next part of the subscription. */ more_nodes = size > NN_TRIE_PREFIX_MAX; *node = nn_alloc (sizeof (struct nn_trie_node) + (more_nodes ? sizeof (struct nn_trie_node*) : 0), "trie node"); assert (*node); /* Fill in the new node. */ (*node)->refcount = 0; (*node)->type = more_nodes ? 1 : 0; (*node)->prefix_len = size < (uint8_t) NN_TRIE_PREFIX_MAX ? (uint8_t) size : (uint8_t) NN_TRIE_PREFIX_MAX; memcpy ((*node)->prefix, data, (*node)->prefix_len); data += (*node)->prefix_len; size -= (*node)->prefix_len; if (!more_nodes) break; (*node)->u.sparse.children [0] = *data; node = nn_node_child (*node, 0); ++data; --size; } /* Step 5 -- Create the subscription as such. */ step5: ++(*node)->refcount; /* Return 1 in case of a fresh subscription. */ return (*node)->refcount == 1 ? 1 : 0; } int nn_trie_match (struct nn_trie *self, const uint8_t *data, size_t size) { struct nn_trie_node *node; struct nn_trie_node **tmp; node = self->root; while (1) { /* If we are at the end of the trie, return. */ if (!node) return 0; /* Check whether whole prefix matches the data. If not so, the whole string won't match. */ if (nn_node_check_prefix (node, data, size) != node->prefix_len) return 0; /* Skip the prefix. */ data += node->prefix_len; size -= node->prefix_len; /* If all the data are matched, return. */ if (nn_node_has_subscribers (node)) return 1; /* Move to the next node. */ tmp = nn_node_next (node, *data); node = tmp ? *tmp : NULL; ++data; --size; } } int nn_trie_unsubscribe (struct nn_trie *self, const uint8_t *data, size_t size) { return nn_node_unsubscribe (&self->root, data, size); } static int nn_node_unsubscribe (struct nn_trie_node **self, const uint8_t *data, size_t size) { int i; int j; int index; int new_min; struct nn_trie_node **ch; struct nn_trie_node *new_node; struct nn_trie_node *ch2; if (!size) goto found; /* If prefix does not match the data, return. */ if (nn_node_check_prefix (*self, data, size) != (*self)->prefix_len) return 0; /* Skip the prefix. */ data += (*self)->prefix_len; size -= (*self)->prefix_len; if (!size) goto found; /* Move to the next node. */ ch = nn_node_next (*self, *data); if (!ch) return 0; /* TODO: This should be an error. */ /* Recursive traversal of the trie happens here. If the subscription wasn't really removed, nothing have changed in the trie and no additional pruning is needed. */ if (nn_node_unsubscribe (ch, data + 1, size - 1) == 0) return 0; /* Subscription removal is already done. Now we are going to compact the trie. However, if the following node remains in place, there's nothing to compact here. */ if (*ch) return 1; /* Sparse array. */ if ((*self)->type < NN_TRIE_DENSE_TYPE) { /* Get the indices of the removed child. */ for (index = 0; index != (*self)->type; ++index) if ((*self)->u.sparse.children [index] == *data) break; assert (index != (*self)->type); /* Remove the destroyed child from both lists of children. */ memmove ( (*self)->u.sparse.children + index, (*self)->u.sparse.children + index + 1, (*self)->type - index - 1); memmove ( nn_node_child (*self, index), nn_node_child (*self, index + 1), ((*self)->type - index - 1) * sizeof (struct nn_trie_node*)); --(*self)->type; *self = nn_realloc (*self, sizeof (struct nn_trie_node) + ((*self)->type * sizeof (struct nn_trie_node*))); assert (*self); /* If there are no more children and no refcount, we can delete the node altogether. */ if (!(*self)->type && !nn_node_has_subscribers (*self)) { nn_free (*self); *self = NULL; return 1; } /* Try to merge the node with the following node. */ *self = nn_node_compact (*self); return 1; } /* Dense array. */ /* In this case the array stays dense. We have to adjust the limits of the array, if appropriate. */ if ((*self)->u.dense.nbr > NN_TRIE_SPARSE_MAX + 1) { /* If the removed item is the leftmost one, trim the array from the left side. */ if (*data == (*self)->u.dense.min) { for (i = 0; i != (*self)->u.dense.max - (*self)->u.dense.min + 1; ++i) if (*nn_node_child (*self, i)) break; new_min = i + (*self)->u.dense.min; memmove (nn_node_child (*self, 0), nn_node_child (*self, i), ((*self)->u.dense.max - new_min + 1) * sizeof (struct nn_trie_node*)); (*self)->u.dense.min = new_min; --(*self)->u.dense.nbr; *self = nn_realloc (*self, sizeof (struct nn_trie_node) + ((*self)->u.dense.max - new_min + 1) * sizeof (struct nn_trie_node*)); assert (*self); return 1; } /* If the removed item is the rightmost one, trim the array from the right side. */ if (*data == (*self)->u.dense.max) { for (i = (*self)->u.dense.max - (*self)->u.dense.min; i != 0; --i) if (*nn_node_child (*self, i)) break; (*self)->u.dense.max = i + (*self)->u.dense.min; --(*self)->u.dense.nbr; *self = nn_realloc (*self, sizeof (struct nn_trie_node) + ((*self)->u.dense.max - (*self)->u.dense.min + 1) * sizeof (struct nn_trie_node*)); assert (*self); return 1; } /* If the item is removed from the middle of the array, do nothing. */ --(*self)->u.dense.nbr; return 1; } /* Convert dense array into sparse array. */ { new_node = nn_alloc (sizeof (struct nn_trie_node) + NN_TRIE_SPARSE_MAX * sizeof (struct nn_trie_node*), "trie node"); assert (new_node); new_node->refcount = 0; new_node->prefix_len = (*self)->prefix_len; memcpy (new_node->prefix, (*self)->prefix, new_node->prefix_len); new_node->type = NN_TRIE_SPARSE_MAX; j = 0; for (i = 0; i != (*self)->u.dense.max - (*self)->u.dense.min + 1; ++i) { ch2 = *nn_node_child (*self, i); if (ch2) { new_node->u.sparse.children [j] = i + (*self)->u.dense.min; *nn_node_child (new_node, j) = ch2; ++j; } } assert (j == NN_TRIE_SPARSE_MAX); nn_free (*self); *self = new_node; return 1; } found: /* We are at the end of the subscription here. */ /* Subscription doesn't exist. */ if (nn_slow (!*self || !nn_node_has_subscribers (*self))) return -EINVAL; /* Subscription exists. Unsubscribe. */ --(*self)->refcount; /* If reference count has dropped to zero we can try to compact the node. */ if (!(*self)->refcount) { /* If there are no children, we can delete the node altogether. */ if (!(*self)->type) { nn_free (*self); *self = NULL; return 1; } /* Try to merge the node with the following node. */ *self = nn_node_compact (*self); return 1; } return 0; } int nn_node_has_subscribers (struct nn_trie_node *node) { /* Returns 1 when there are no subscribers associated with the node. */ return node->refcount ? 1 : 0; } nanomsg-1.1.5/src/protocols/pubsub/trie.h000066400000000000000000000110421336111550300204030ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_TRIE_INCLUDED #define NN_TRIE_INCLUDED #include #include /* This class implements highly memory-efficient patricia trie. */ /* Maximum length of the prefix. */ #define NN_TRIE_PREFIX_MAX 10 /* Maximum number of children in the sparse mode. */ #define NN_TRIE_SPARSE_MAX 8 /* 'type' is set to this value when in the dense mode. */ #define NN_TRIE_DENSE_TYPE (NN_TRIE_SPARSE_MAX + 1) /* This structure represents a node in patricia trie. It's a header to be followed by the array of pointers to child nodes. Each node represents the string composed of all the prefixes on the way from the trie root, including the prefix in that node. */ struct nn_trie_node { /* Number of subscriptions to the given string. */ uint32_t refcount; /* Number of elements is a sparse array, or NN_TRIE_DENSE_TYPE in case the array of children is dense. */ uint8_t type; /* The node adds more characters to the string, compared to the parent node. If there is only a single character added, it's represented directly in the child array. If there's more than one character added, all but the last one are stored as a 'prefix'. */ uint8_t prefix_len; uint8_t prefix [NN_TRIE_PREFIX_MAX]; /* The array of characters pointing to individual children of the node. Actual pointers to child nodes are stored in the memory following nn_trie_node structure. */ union { /* Sparse array means that individual children are identified by characters stored in 'children' array. The number of characters in the array is specified in the 'type' field. */ struct { uint8_t children [NN_TRIE_SPARSE_MAX]; } sparse; /* Dense array means that the array of node pointers following the structure corresponds to a continuous list of characters starting by 'min' character and ending by 'max' character. The characters in the range that have no corresponding child node are represented by NULL pointers. 'nbr' is the count of child nodes. */ struct { uint8_t min; uint8_t max; uint16_t nbr; /* There are 4 bytes of padding here. */ } dense; } u; }; /* The structure is followed by the array of pointers to children. */ struct nn_trie { /* The root node of the trie (representing the empty subscription). */ struct nn_trie_node *root; }; /* Initialise an empty trie. */ void nn_trie_init (struct nn_trie *self); /* Release all the resources associated with the trie. */ void nn_trie_term (struct nn_trie *self); /* Add the string to the trie. If the string is not yet there, 1 is returned. If it already exists in the trie, its reference count is incremented and 0 is returned. */ int nn_trie_subscribe (struct nn_trie *self, const uint8_t *data, size_t size); /* Remove the string from the trie. If the string was actually removed, 1 is returned. If reference count was decremented without falling to zero, 0 is returned. */ int nn_trie_unsubscribe (struct nn_trie *self, const uint8_t *data, size_t size); /* Checks the supplied string. If it matches it returns 1, if it does not it returns 0. */ int nn_trie_match (struct nn_trie *self, const uint8_t *data, size_t size); /* Debugging interface. */ void nn_trie_dump (struct nn_trie *self); #endif nanomsg-1.1.5/src/protocols/pubsub/xpub.c000066400000000000000000000117171336111550300204220ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xpub.h" #include "../../nn.h" #include "../../pubsub.h" #include "../utils/dist.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/alloc.h" #include "../../utils/attr.h" #include struct nn_xpub_data { struct nn_dist_data item; }; struct nn_xpub { /* The generic socket base class. */ struct nn_sockbase sockbase; /* Distributor. */ struct nn_dist outpipes; }; /* Private functions. */ static void nn_xpub_init (struct nn_xpub *self, const struct nn_sockbase_vfptr *vfptr, void *hint); static void nn_xpub_term (struct nn_xpub *self); /* Implementation of nn_sockbase's virtual functions. */ static void nn_xpub_destroy (struct nn_sockbase *self); static int nn_xpub_add (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpub_rm (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpub_in (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xpub_out (struct nn_sockbase *self, struct nn_pipe *pipe); static int nn_xpub_events (struct nn_sockbase *self); static int nn_xpub_send (struct nn_sockbase *self, struct nn_msg *msg); static const struct nn_sockbase_vfptr nn_xpub_sockbase_vfptr = { NULL, nn_xpub_destroy, nn_xpub_add, nn_xpub_rm, nn_xpub_in, nn_xpub_out, nn_xpub_events, nn_xpub_send, NULL, NULL, NULL }; static void nn_xpub_init (struct nn_xpub *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_sockbase_init (&self->sockbase, vfptr, hint); nn_dist_init (&self->outpipes); } static void nn_xpub_term (struct nn_xpub *self) { nn_dist_term (&self->outpipes); nn_sockbase_term (&self->sockbase); } void nn_xpub_destroy (struct nn_sockbase *self) { struct nn_xpub *xpub; xpub = nn_cont (self, struct nn_xpub, sockbase); nn_xpub_term (xpub); nn_free (xpub); } static int nn_xpub_add (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xpub *xpub; struct nn_xpub_data *data; xpub = nn_cont (self, struct nn_xpub, sockbase); data = nn_alloc (sizeof (struct nn_xpub_data), "pipe data (pub)"); alloc_assert (data); nn_dist_add (&xpub->outpipes, &data->item, pipe); nn_pipe_setdata (pipe, data); return 0; } static void nn_xpub_rm (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xpub *xpub; struct nn_xpub_data *data; xpub = nn_cont (self, struct nn_xpub, sockbase); data = nn_pipe_getdata (pipe); nn_dist_rm (&xpub->outpipes, &data->item); nn_free (data); } static void nn_xpub_in (NN_UNUSED struct nn_sockbase *self, NN_UNUSED struct nn_pipe *pipe) { /* We shouldn't get any messages from subscribers. */ nn_assert (0); } static void nn_xpub_out (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xpub *xpub; struct nn_xpub_data *data; xpub = nn_cont (self, struct nn_xpub, sockbase); data = nn_pipe_getdata (pipe); nn_dist_out (&xpub->outpipes, &data->item); } static int nn_xpub_events (NN_UNUSED struct nn_sockbase *self) { return NN_SOCKBASE_EVENT_OUT; } static int nn_xpub_send (struct nn_sockbase *self, struct nn_msg *msg) { return nn_dist_send (&nn_cont (self, struct nn_xpub, sockbase)->outpipes, msg, NULL); } int nn_xpub_create (void *hint, struct nn_sockbase **sockbase) { struct nn_xpub *self; self = nn_alloc (sizeof (struct nn_xpub), "socket (xpub)"); alloc_assert (self); nn_xpub_init (self, &nn_xpub_sockbase_vfptr, hint); *sockbase = &self->sockbase; return 0; } int nn_xpub_ispeer (int socktype) { return socktype == NN_SUB ? 1 : 0; } struct nn_socktype nn_xpub_socktype = { AF_SP_RAW, NN_PUB, NN_SOCKTYPE_FLAG_NORECV, nn_xpub_create, nn_xpub_ispeer, }; nanomsg-1.1.5/src/protocols/pubsub/xpub.h000066400000000000000000000025001336111550300204150ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_XPUB_INCLUDED #define NN_XPUB_INCLUDED #include "../../protocol.h" int nn_xpub_create (void *hint, struct nn_sockbase **sockbase); int nn_xpub_ispeer (int socktype); #endif nanomsg-1.1.5/src/protocols/pubsub/xsub.c000066400000000000000000000152031336111550300204170ustar00rootroot00000000000000/* Copyright (c) 2012-2014 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xsub.h" #include "trie.h" #include "../../nn.h" #include "../../pubsub.h" #include "../utils/fq.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/alloc.h" #include "../../utils/attr.h" struct nn_xsub_data { struct nn_fq_data fq; }; struct nn_xsub { struct nn_sockbase sockbase; struct nn_fq fq; struct nn_trie trie; }; /* Private functions. */ static void nn_xsub_init (struct nn_xsub *self, const struct nn_sockbase_vfptr *vfptr, void *hint); static void nn_xsub_term (struct nn_xsub *self); /* Implementation of nn_sockbase's virtual functions. */ static void nn_xsub_destroy (struct nn_sockbase *self); static int nn_xsub_add (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xsub_rm (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xsub_in (struct nn_sockbase *self, struct nn_pipe *pipe); static void nn_xsub_out (struct nn_sockbase *self, struct nn_pipe *pipe); static int nn_xsub_events (struct nn_sockbase *self); static int nn_xsub_recv (struct nn_sockbase *self, struct nn_msg *msg); static int nn_xsub_setopt (struct nn_sockbase *self, int level, int option, const void *optval, size_t optvallen); static const struct nn_sockbase_vfptr nn_xsub_sockbase_vfptr = { NULL, nn_xsub_destroy, nn_xsub_add, nn_xsub_rm, nn_xsub_in, nn_xsub_out, nn_xsub_events, NULL, nn_xsub_recv, nn_xsub_setopt, NULL }; static void nn_xsub_init (struct nn_xsub *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_sockbase_init (&self->sockbase, vfptr, hint); nn_fq_init (&self->fq); nn_trie_init (&self->trie); } static void nn_xsub_term (struct nn_xsub *self) { nn_trie_term (&self->trie); nn_fq_term (&self->fq); nn_sockbase_term (&self->sockbase); } void nn_xsub_destroy (struct nn_sockbase *self) { struct nn_xsub *xsub; xsub = nn_cont (self, struct nn_xsub, sockbase); nn_xsub_term (xsub); nn_free (xsub); } static int nn_xsub_add (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xsub *xsub; struct nn_xsub_data *data; int rcvprio; size_t sz; xsub = nn_cont (self, struct nn_xsub, sockbase); sz = sizeof (rcvprio); nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz); nn_assert (sz == sizeof (rcvprio)); nn_assert (rcvprio >= 1 && rcvprio <= 16); data = nn_alloc (sizeof (struct nn_xsub_data), "pipe data (sub)"); alloc_assert (data); nn_pipe_setdata (pipe, data); nn_fq_add (&xsub->fq, &data->fq, pipe, rcvprio); return 0; } static void nn_xsub_rm (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xsub *xsub; struct nn_xsub_data *data; xsub = nn_cont (self, struct nn_xsub, sockbase); data = nn_pipe_getdata (pipe); nn_fq_rm (&xsub->fq, &data->fq); nn_free (data); } static void nn_xsub_in (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xsub *xsub; struct nn_xsub_data *data; xsub = nn_cont (self, struct nn_xsub, sockbase); data = nn_pipe_getdata (pipe); nn_fq_in (&xsub->fq, &data->fq); } static void nn_xsub_out (NN_UNUSED struct nn_sockbase *self, NN_UNUSED struct nn_pipe *pipe) { /* We are not going to send any messages until subscription forwarding is implemented, so there's no point is maintaining a list of pipes ready for sending. */ } static int nn_xsub_events (struct nn_sockbase *self) { return nn_fq_can_recv (&nn_cont (self, struct nn_xsub, sockbase)->fq) ? NN_SOCKBASE_EVENT_IN : 0; } static int nn_xsub_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_xsub *xsub; xsub = nn_cont (self, struct nn_xsub, sockbase); /* Loop while a matching message is found or when there are no more messages to receive. */ while (1) { rc = nn_fq_recv (&xsub->fq, msg, NULL); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc >= 0, -rc); rc = nn_trie_match (&xsub->trie, nn_chunkref_data (&msg->body), nn_chunkref_size (&msg->body)); if (rc == 0) { nn_msg_term (msg); continue; } if (rc == 1) return 0; errnum_assert (0, -rc); } } static int nn_xsub_setopt (struct nn_sockbase *self, int level, int option, const void *optval, size_t optvallen) { int rc; struct nn_xsub *xsub; xsub = nn_cont (self, struct nn_xsub, sockbase); if (level != NN_SUB) return -ENOPROTOOPT; if (option == NN_SUB_SUBSCRIBE) { rc = nn_trie_subscribe (&xsub->trie, optval, optvallen); if (rc >= 0) return 0; return rc; } if (option == NN_SUB_UNSUBSCRIBE) { rc = nn_trie_unsubscribe (&xsub->trie, optval, optvallen); if (rc >= 0) return 0; return rc; } return -ENOPROTOOPT; } int nn_xsub_create (void *hint, struct nn_sockbase **sockbase) { struct nn_xsub *self; self = nn_alloc (sizeof (struct nn_xsub), "socket (xsub)"); alloc_assert (self); nn_xsub_init (self, &nn_xsub_sockbase_vfptr, hint); *sockbase = &self->sockbase; return 0; } int nn_xsub_ispeer (int socktype) { return socktype == NN_PUB ? 1 : 0; } struct nn_socktype nn_xsub_socktype = { AF_SP_RAW, NN_SUB, NN_SOCKTYPE_FLAG_NOSEND, nn_xsub_create, nn_xsub_ispeer, }; nanomsg-1.1.5/src/protocols/pubsub/xsub.h000066400000000000000000000024771336111550300204350ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_XSUB_INCLUDED #define NN_XSUB_INCLUDED #include "../../protocol.h" int nn_xsub_create (void *hint, struct nn_sockbase **sockbase); int nn_xsub_ispeer (int socktype); #endif nanomsg-1.1.5/src/protocols/reqrep/000077500000000000000000000000001336111550300172675ustar00rootroot00000000000000nanomsg-1.1.5/src/protocols/reqrep/rep.c000066400000000000000000000104551336111550300202260ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "rep.h" #include "xrep.h" #include "../../nn.h" #include "../../reqrep.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/alloc.h" #include "../../utils/chunkref.h" #include "../../utils/wire.h" #include #include #define NN_REP_INPROGRESS 1 static const struct nn_sockbase_vfptr nn_rep_sockbase_vfptr = { NULL, nn_rep_destroy, nn_xrep_add, nn_xrep_rm, nn_xrep_in, nn_xrep_out, nn_rep_events, nn_rep_send, nn_rep_recv, NULL, NULL }; void nn_rep_init (struct nn_rep *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_xrep_init (&self->xrep, vfptr, hint); self->flags = 0; } void nn_rep_term (struct nn_rep *self) { if (self->flags & NN_REP_INPROGRESS) nn_chunkref_term (&self->backtrace); nn_xrep_term (&self->xrep); } void nn_rep_destroy (struct nn_sockbase *self) { struct nn_rep *rep; rep = nn_cont (self, struct nn_rep, xrep.sockbase); nn_rep_term (rep); nn_free (rep); } int nn_rep_events (struct nn_sockbase *self) { struct nn_rep *rep; int events; rep = nn_cont (self, struct nn_rep, xrep.sockbase); events = nn_xrep_events (&rep->xrep.sockbase); if (!(rep->flags & NN_REP_INPROGRESS)) events &= ~NN_SOCKBASE_EVENT_OUT; return events; } int nn_rep_send (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_rep *rep; rep = nn_cont (self, struct nn_rep, xrep.sockbase); /* If no request was received, there's nowhere to send the reply to. */ if (nn_slow (!(rep->flags & NN_REP_INPROGRESS))) return -EFSM; /* Move the stored backtrace into the message header. */ nn_assert (nn_chunkref_size (&msg->sphdr) == 0); nn_chunkref_term (&msg->sphdr); nn_chunkref_mv (&msg->sphdr, &rep->backtrace); rep->flags &= ~NN_REP_INPROGRESS; /* Send the reply. If it cannot be sent because of pushback, drop it silently. */ rc = nn_xrep_send (&rep->xrep.sockbase, msg); errnum_assert (rc == 0 || rc == -EAGAIN, -rc); return 0; } int nn_rep_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_rep *rep; rep = nn_cont (self, struct nn_rep, xrep.sockbase); /* If a request is already being processed, cancel it. */ if (nn_slow (rep->flags & NN_REP_INPROGRESS)) { nn_chunkref_term (&rep->backtrace); rep->flags &= ~NN_REP_INPROGRESS; } /* Receive the request. */ rc = nn_xrep_recv (&rep->xrep.sockbase, msg); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc == 0, -rc); /* Store the backtrace. */ nn_chunkref_mv (&rep->backtrace, &msg->sphdr); nn_chunkref_init (&msg->sphdr, 0); rep->flags |= NN_REP_INPROGRESS; return 0; } static int nn_rep_create (void *hint, struct nn_sockbase **sockbase) { struct nn_rep *self; self = nn_alloc (sizeof (struct nn_rep), "socket (rep)"); alloc_assert (self); nn_rep_init (self, &nn_rep_sockbase_vfptr, hint); *sockbase = &self->xrep.sockbase; return 0; } struct nn_socktype nn_rep_socktype = { AF_SP, NN_REP, 0, nn_rep_create, nn_xrep_ispeer, }; nanomsg-1.1.5/src/protocols/reqrep/rep.h000066400000000000000000000035651336111550300202370ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_REP_INCLUDED #define NN_REP_INCLUDED #include "../../protocol.h" #include "xrep.h" struct nn_rep { struct nn_xrep xrep; uint32_t flags; struct nn_chunkref backtrace; }; /* Some users may want to extend the REP protocol similar to how REP extends XREP. Expose these methods to improve extensibility. */ void nn_rep_init (struct nn_rep *self, const struct nn_sockbase_vfptr *vfptr, void *hint); void nn_rep_term (struct nn_rep *self); /* Implementation of nn_sockbase's virtual functions. */ void nn_rep_destroy (struct nn_sockbase *self); int nn_rep_events (struct nn_sockbase *self); int nn_rep_send (struct nn_sockbase *self, struct nn_msg *msg); int nn_rep_recv (struct nn_sockbase *self, struct nn_msg *msg); #endif nanomsg-1.1.5/src/protocols/reqrep/req.c000066400000000000000000000505551336111550300202340ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "req.h" #include "xreq.h" #include "../../nn.h" #include "../../reqrep.h" #include "../../aio/fsm.h" #include "../../aio/timer.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/alloc.h" #include "../../utils/random.h" #include "../../utils/wire.h" #include "../../utils/attr.h" #include #include /* Default re-send interval is 1 minute. */ #define NN_REQ_DEFAULT_RESEND_IVL 60000 #define NN_REQ_STATE_IDLE 1 #define NN_REQ_STATE_PASSIVE 2 #define NN_REQ_STATE_DELAYED 3 #define NN_REQ_STATE_ACTIVE 4 #define NN_REQ_STATE_TIMED_OUT 5 #define NN_REQ_STATE_CANCELLING 6 #define NN_REQ_STATE_STOPPING_TIMER 7 #define NN_REQ_STATE_DONE 8 #define NN_REQ_STATE_STOPPING 9 #define NN_REQ_ACTION_START 1 #define NN_REQ_ACTION_IN 2 #define NN_REQ_ACTION_OUT 3 #define NN_REQ_ACTION_SENT 4 #define NN_REQ_ACTION_RECEIVED 5 #define NN_REQ_ACTION_PIPE_RM 6 #define NN_REQ_SRC_RESEND_TIMER 1 static const struct nn_sockbase_vfptr nn_req_sockbase_vfptr = { nn_req_stop, nn_req_destroy, nn_xreq_add, nn_req_rm, nn_req_in, nn_req_out, nn_req_events, nn_req_csend, nn_req_crecv, nn_req_setopt, nn_req_getopt }; void nn_req_init (struct nn_req *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_xreq_init (&self->xreq, vfptr, hint); nn_fsm_init_root (&self->fsm, nn_req_handler, nn_req_shutdown, nn_sockbase_getctx (&self->xreq.sockbase)); self->state = NN_REQ_STATE_IDLE; /* Start assigning request IDs beginning with a random number. This way there should be no key clashes even if the executable is re-started. */ nn_random_generate (&self->lastid, sizeof (self->lastid)); self->task.sent_to = NULL; nn_msg_init (&self->task.request, 0); nn_msg_init (&self->task.reply, 0); nn_timer_init (&self->task.timer, NN_REQ_SRC_RESEND_TIMER, &self->fsm); self->resend_ivl = NN_REQ_DEFAULT_RESEND_IVL; nn_task_init (&self->task, self->lastid); /* Start the state machine. */ nn_fsm_start (&self->fsm); } void nn_req_term (struct nn_req *self) { nn_timer_term (&self->task.timer); nn_task_term (&self->task); nn_msg_term (&self->task.reply); nn_msg_term (&self->task.request); nn_fsm_term (&self->fsm); nn_xreq_term (&self->xreq); } void nn_req_stop (struct nn_sockbase *self) { struct nn_req *req; req = nn_cont (self, struct nn_req, xreq.sockbase); nn_fsm_stop (&req->fsm); } void nn_req_destroy (struct nn_sockbase *self) { struct nn_req *req; req = nn_cont (self, struct nn_req, xreq.sockbase); nn_req_term (req); nn_free (req); } int nn_req_inprogress (struct nn_req *self) { /* Return 1 if there's a request submitted. 0 otherwise. */ return self->state == NN_REQ_STATE_IDLE || self->state == NN_REQ_STATE_PASSIVE || self->state == NN_REQ_STATE_STOPPING ? 0 : 1; } void nn_req_in (struct nn_sockbase *self, struct nn_pipe *pipe) { int rc; struct nn_req *req; uint32_t reqid; req = nn_cont (self, struct nn_req, xreq.sockbase); /* Pass the pipe to the raw REQ socket. */ nn_xreq_in (&req->xreq.sockbase, pipe); while (1) { /* Get new reply. */ rc = nn_xreq_recv (&req->xreq.sockbase, &req->task.reply); if (nn_slow (rc == -EAGAIN)) return; errnum_assert (rc == 0, -rc); /* No request was sent. Getting a reply doesn't make sense. */ if (nn_slow (!nn_req_inprogress (req))) { nn_msg_term (&req->task.reply); continue; } /* Ignore malformed replies. */ if (nn_slow (nn_chunkref_size (&req->task.reply.sphdr) != sizeof (uint32_t))) { nn_msg_term (&req->task.reply); continue; } /* Ignore replies with incorrect request IDs. */ reqid = nn_getl (nn_chunkref_data (&req->task.reply.sphdr)); if (nn_slow (!(reqid & 0x80000000))) { nn_msg_term (&req->task.reply); continue; } if (nn_slow (reqid != (req->task.id | 0x80000000))) { nn_msg_term (&req->task.reply); continue; } /* Trim the request ID. */ nn_chunkref_term (&req->task.reply.sphdr); nn_chunkref_init (&req->task.reply.sphdr, 0); /* TODO: Deallocate the request here? */ /* Notify the state machine. */ if (req->state == NN_REQ_STATE_ACTIVE) nn_fsm_action (&req->fsm, NN_REQ_ACTION_IN); return; } } void nn_req_out (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_req *req; req = nn_cont (self, struct nn_req, xreq.sockbase); /* Add the pipe to the underlying raw socket. */ nn_xreq_out (&req->xreq.sockbase, pipe); /* Notify the state machine. */ if (req->state == NN_REQ_STATE_DELAYED) nn_fsm_action (&req->fsm, NN_REQ_ACTION_OUT); } int nn_req_events (struct nn_sockbase *self) { int rc; struct nn_req *req; req = nn_cont (self, struct nn_req, xreq.sockbase); /* OUT is signalled all the time because sending a request while another one is being processed cancels the old one. */ rc = NN_SOCKBASE_EVENT_OUT; /* In DONE state the reply is stored in 'reply' field. */ if (req->state == NN_REQ_STATE_DONE) rc |= NN_SOCKBASE_EVENT_IN; return rc; } int nn_req_csend (struct nn_sockbase *self, struct nn_msg *msg) { struct nn_req *req; req = nn_cont (self, struct nn_req, xreq.sockbase); /* Generate new request ID for the new request and put it into message header. The most important bit is set to 1 to indicate that this is the bottom of the backtrace stack. */ ++req->task.id; nn_assert (nn_chunkref_size (&msg->sphdr) == 0); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, 4); nn_putl (nn_chunkref_data (&msg->sphdr), req->task.id | 0x80000000); /* Store the message so that it can be re-sent if there's no reply. */ nn_msg_term (&req->task.request); nn_msg_mv (&req->task.request, msg); /* Notify the state machine. */ nn_fsm_action (&req->fsm, NN_REQ_ACTION_SENT); return 0; } int nn_req_crecv (struct nn_sockbase *self, struct nn_msg *msg) { struct nn_req *req; req = nn_cont (self, struct nn_req, xreq.sockbase); /* No request was sent. Waiting for a reply doesn't make sense. */ if (nn_slow (!nn_req_inprogress (req))) return -EFSM; /* If reply was not yet recieved, wait further. */ if (nn_slow (req->state != NN_REQ_STATE_DONE)) return -EAGAIN; /* If the reply was already received, just pass it to the caller. */ nn_msg_mv (msg, &req->task.reply); nn_msg_init (&req->task.reply, 0); /* Notify the state machine. */ nn_fsm_action (&req->fsm, NN_REQ_ACTION_RECEIVED); return 0; } int nn_req_setopt (struct nn_sockbase *self, int level, int option, const void *optval, size_t optvallen) { struct nn_req *req; req = nn_cont (self, struct nn_req, xreq.sockbase); if (level != NN_REQ) return -ENOPROTOOPT; if (option == NN_REQ_RESEND_IVL) { if (nn_slow (optvallen != sizeof (int))) return -EINVAL; req->resend_ivl = *(int*) optval; return 0; } return -ENOPROTOOPT; } int nn_req_getopt (struct nn_sockbase *self, int level, int option, void *optval, size_t *optvallen) { struct nn_req *req; req = nn_cont (self, struct nn_req, xreq.sockbase); if (level != NN_REQ) return -ENOPROTOOPT; if (option == NN_REQ_RESEND_IVL) { if (nn_slow (*optvallen < sizeof (int))) return -EINVAL; *(int*) optval = req->resend_ivl; *optvallen = sizeof (int); return 0; } return -ENOPROTOOPT; } void nn_req_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_req *req; req = nn_cont (self, struct nn_req, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_timer_stop (&req->task.timer); req->state = NN_REQ_STATE_STOPPING; } if (nn_slow (req->state == NN_REQ_STATE_STOPPING)) { if (!nn_timer_isidle (&req->task.timer)) return; req->state = NN_REQ_STATE_IDLE; nn_fsm_stopped_noevent (&req->fsm); nn_sockbase_stopped (&req->xreq.sockbase); return; } nn_fsm_bad_state(req->state, src, type); } void nn_req_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_req *req; req = nn_cont (self, struct nn_req, fsm); switch (req->state) { /******************************************************************************/ /* IDLE state. */ /* The socket was created recently. Intermediate state. */ /* Pass straight to the PASSIVE state. */ /******************************************************************************/ case NN_REQ_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: req->state = NN_REQ_STATE_PASSIVE; return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* PASSIVE state. */ /* No request is submitted. */ /******************************************************************************/ case NN_REQ_STATE_PASSIVE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: nn_req_action_send (req, 1); return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* DELAYED state. */ /* Request was submitted but it could not be sent to the network because */ /* there was no peer available at the moment. Now we are waiting for the */ /* peer to arrive to send the request to it. */ /******************************************************************************/ case NN_REQ_STATE_DELAYED: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_OUT: nn_req_action_send (req, 0); return; case NN_REQ_ACTION_SENT: return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Request was submitted. Waiting for reply. */ /******************************************************************************/ case NN_REQ_STATE_ACTIVE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_IN: /* Reply arrived. */ nn_timer_stop (&req->task.timer); req->task.sent_to = NULL; req->state = NN_REQ_STATE_STOPPING_TIMER; return; case NN_REQ_ACTION_SENT: /* New request was sent while the old one was still being processed. Cancel the old request first. */ nn_timer_stop (&req->task.timer); req->task.sent_to = NULL; req->state = NN_REQ_STATE_CANCELLING; return; case NN_REQ_ACTION_PIPE_RM: /* Pipe that we sent request to is removed */ nn_timer_stop (&req->task.timer); req->task.sent_to = NULL; /* Pretend we timed out so request resent immediately */ req->state = NN_REQ_STATE_TIMED_OUT; return; default: nn_fsm_bad_action (req->state, src, type); } case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_TIMEOUT: nn_timer_stop (&req->task.timer); req->task.sent_to = NULL; req->state = NN_REQ_STATE_TIMED_OUT; return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* TIMED_OUT state. */ /* Waiting for reply has timed out. Stopping the timer. Afterwards, we'll */ /* re-send the request. */ /******************************************************************************/ case NN_REQ_STATE_TIMED_OUT: switch (src) { case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_STOPPED: nn_req_action_send (req, 1); return; default: nn_fsm_bad_action (req->state, src, type); } case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: req->state = NN_REQ_STATE_CANCELLING; return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* CANCELLING state. */ /* Request was canceled. Waiting till the timer is stopped. Note that */ /* cancelling is done by sending a new request. Thus there's already */ /* a request waiting to be sent in this state. */ /******************************************************************************/ case NN_REQ_STATE_CANCELLING: switch (src) { case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_STOPPED: /* Timer is stopped. Now we can send the delayed request. */ nn_req_action_send (req, 1); return; default: nn_fsm_bad_action (req->state, src, type); } case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: /* No need to do anything here. Old delayed request is just replaced by the new one that will be sent once the timer is closed. */ return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* STOPPING_TIMER state. */ /* Reply was delivered. Waiting till the timer is stopped. */ /******************************************************************************/ case NN_REQ_STATE_STOPPING_TIMER: switch (src) { case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_STOPPED: req->state = NN_REQ_STATE_DONE; return; default: nn_fsm_bad_action (req->state, src, type); } case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: req->state = NN_REQ_STATE_CANCELLING; return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* DONE state. */ /* Reply was received but not yet retrieved by the user. */ /******************************************************************************/ case NN_REQ_STATE_DONE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_RECEIVED: req->state = NN_REQ_STATE_PASSIVE; return; case NN_REQ_ACTION_SENT: nn_req_action_send (req, 1); return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (req->state, src, type); } } /******************************************************************************/ /* State machine actions. */ /******************************************************************************/ void nn_req_action_send (struct nn_req *self, int allow_delay) { int rc; struct nn_msg msg; struct nn_pipe *to; /* Send the request. */ nn_msg_cp (&msg, &self->task.request); rc = nn_xreq_send_to (&self->xreq.sockbase, &msg, &to); /* If the request cannot be sent at the moment wait till new outbound pipe arrives. */ if (nn_slow (rc == -EAGAIN)) { nn_assert (allow_delay == 1); nn_msg_term (&msg); self->state = NN_REQ_STATE_DELAYED; return; } /* Request was successfully sent. Set up the re-send timer in case the request gets lost somewhere further out in the topology. */ if (nn_fast (rc == 0)) { nn_timer_start (&self->task.timer, self->resend_ivl); nn_assert (to); self->task.sent_to = to; self->state = NN_REQ_STATE_ACTIVE; return; } /* Unexpected error. */ errnum_assert (0, -rc); } static int nn_req_create (void *hint, struct nn_sockbase **sockbase) { struct nn_req *self; self = nn_alloc (sizeof (struct nn_req), "socket (req)"); alloc_assert (self); nn_req_init (self, &nn_req_sockbase_vfptr, hint); *sockbase = &self->xreq.sockbase; return 0; } void nn_req_rm (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_req *req; req = nn_cont (self, struct nn_req, xreq.sockbase); nn_xreq_rm (self, pipe); if (nn_slow (pipe == req->task.sent_to)) { nn_fsm_action (&req->fsm, NN_REQ_ACTION_PIPE_RM); } } struct nn_socktype nn_req_socktype = { AF_SP, NN_REQ, 0, nn_req_create, nn_xreq_ispeer, }; nanomsg-1.1.5/src/protocols/reqrep/req.h000066400000000000000000000060651336111550300202360ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_REQ_INCLUDED #define NN_REQ_INCLUDED #include "xreq.h" #include "task.h" #include "../../protocol.h" #include "../../aio/fsm.h" struct nn_req { /* The base class. Raw REQ socket. */ struct nn_xreq xreq; /* The state machine. */ struct nn_fsm fsm; int state; /* Last request ID assigned. */ uint32_t lastid; /* Protocol-specific socket options. */ int resend_ivl; /* The request being processed. */ struct nn_task task; }; /* Some users may want to extend the REQ protocol similar to how REQ extends XREQ. Expose these methods to improve extensibility. */ void nn_req_init (struct nn_req *self, const struct nn_sockbase_vfptr *vfptr, void *hint); void nn_req_term (struct nn_req *self); int nn_req_inprogress (struct nn_req *self); void nn_req_handler (struct nn_fsm *self, int src, int type, void *srcptr); void nn_req_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); void nn_req_action_send (struct nn_req *self, int allow_delay); /* Implementation of nn_sockbase's virtual functions. */ void nn_req_stop (struct nn_sockbase *self); void nn_req_destroy (struct nn_sockbase *self); void nn_req_in (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_req_out (struct nn_sockbase *self, struct nn_pipe *pipe); int nn_req_events (struct nn_sockbase *self); int nn_req_csend (struct nn_sockbase *self, struct nn_msg *msg); void nn_req_rm (struct nn_sockbase *self, struct nn_pipe *pipe); int nn_req_crecv (struct nn_sockbase *self, struct nn_msg *msg); int nn_req_setopt (struct nn_sockbase *self, int level, int option, const void *optval, size_t optvallen); int nn_req_getopt (struct nn_sockbase *self, int level, int option, void *optval, size_t *optvallen); int nn_req_csend (struct nn_sockbase *self, struct nn_msg *msg); int nn_req_crecv (struct nn_sockbase *self, struct nn_msg *msg); #endif nanomsg-1.1.5/src/protocols/reqrep/task.c000066400000000000000000000025311336111550300203760ustar00rootroot00000000000000/* Copyright (c) 2014 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "task.h" #include "../../utils/attr.h" void nn_task_init (struct nn_task *self, uint32_t id) { self->id = id; } void nn_task_term (NN_UNUSED struct nn_task *self) { } nanomsg-1.1.5/src/protocols/reqrep/task.h000066400000000000000000000040751336111550300204100ustar00rootroot00000000000000/* Copyright (c) 2014 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_TASK_INCLUDED #define NN_TASK_INCLUDED #include "../../reqrep.h" #include "../../aio/fsm.h" #include "../../aio/timer.h" #include "../../utils/msg.h" struct nn_task { /* ID of the request being currently processed. Replies for different requests are considered stale and simply dropped. */ uint32_t id; /* Stored request, so that it can be re-sent if needed. */ struct nn_msg request; /* Stored reply, so that user can retrieve it later on. */ struct nn_msg reply; /* Timer used to wait while request should be re-sent. */ struct nn_timer timer; /* Pipe the current request has been sent to. This is an optimisation so that request can be re-sent immediately if the pipe disappears. */ struct nn_pipe *sent_to; }; void nn_task_init (struct nn_task *self, uint32_t id); void nn_task_term (struct nn_task *self); #endif nanomsg-1.1.5/src/protocols/reqrep/xrep.c000066400000000000000000000200141336111550300204060ustar00rootroot00000000000000/* Copyright (c) 2012-2014 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xrep.h" #include "../../nn.h" #include "../../reqrep.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/alloc.h" #include "../../utils/random.h" #include "../../utils/wire.h" #include "../../utils/attr.h" #include /* Private functions. */ static void nn_xrep_destroy (struct nn_sockbase *self); static const struct nn_sockbase_vfptr nn_xrep_sockbase_vfptr = { NULL, nn_xrep_destroy, nn_xrep_add, nn_xrep_rm, nn_xrep_in, nn_xrep_out, nn_xrep_events, nn_xrep_send, nn_xrep_recv, NULL, NULL }; void nn_xrep_init (struct nn_xrep *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_sockbase_init (&self->sockbase, vfptr, hint); /* Start assigning keys beginning with a random number. This way there are no key clashes even if the executable is re-started. */ nn_random_generate (&self->next_key, sizeof (self->next_key)); nn_hash_init (&self->outpipes); nn_fq_init (&self->inpipes); } void nn_xrep_term (struct nn_xrep *self) { nn_fq_term (&self->inpipes); nn_hash_term (&self->outpipes); nn_sockbase_term (&self->sockbase); } static void nn_xrep_destroy (struct nn_sockbase *self) { struct nn_xrep *xrep; xrep = nn_cont (self, struct nn_xrep, sockbase); nn_xrep_term (xrep); nn_free (xrep); } int nn_xrep_add (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xrep *xrep; struct nn_xrep_data *data; int rcvprio; size_t sz; xrep = nn_cont (self, struct nn_xrep, sockbase); sz = sizeof (rcvprio); nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz); nn_assert (sz == sizeof (rcvprio)); nn_assert (rcvprio >= 1 && rcvprio <= 16); data = nn_alloc (sizeof (struct nn_xrep_data), "pipe data (xrep)"); alloc_assert (data); data->pipe = pipe; nn_hash_item_init (&data->outitem); data->flags = 0; nn_hash_insert (&xrep->outpipes, xrep->next_key & 0x7fffffff, &data->outitem); ++xrep->next_key; nn_fq_add (&xrep->inpipes, &data->initem, pipe, rcvprio); nn_pipe_setdata (pipe, data); return 0; } void nn_xrep_rm (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xrep *xrep; struct nn_xrep_data *data; xrep = nn_cont (self, struct nn_xrep, sockbase); data = nn_pipe_getdata (pipe); nn_fq_rm (&xrep->inpipes, &data->initem); nn_hash_erase (&xrep->outpipes, &data->outitem); nn_hash_item_term (&data->outitem); nn_free (data); } void nn_xrep_in (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xrep *xrep; struct nn_xrep_data *data; xrep = nn_cont (self, struct nn_xrep, sockbase); data = nn_pipe_getdata (pipe); nn_fq_in (&xrep->inpipes, &data->initem); } void nn_xrep_out (NN_UNUSED struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xrep_data *data; data = nn_pipe_getdata (pipe); data->flags |= NN_XREP_OUT; } int nn_xrep_events (struct nn_sockbase *self) { return (nn_fq_can_recv (&nn_cont (self, struct nn_xrep, sockbase)->inpipes) ? NN_SOCKBASE_EVENT_IN : 0) | NN_SOCKBASE_EVENT_OUT; } int nn_xrep_send (struct nn_sockbase *self, struct nn_msg *msg) { int rc; uint32_t key; struct nn_xrep *xrep; struct nn_xrep_data *data; xrep = nn_cont (self, struct nn_xrep, sockbase); /* We treat invalid peer ID as if the peer was non-existent. */ if (nn_slow (nn_chunkref_size (&msg->sphdr) < sizeof (uint32_t))) { nn_msg_term (msg); return 0; } /* Retrieve the destination peer ID. Trim it from the header. */ key = nn_getl (nn_chunkref_data (&msg->sphdr)); nn_chunkref_trim (&msg->sphdr, 4); /* Find the appropriate pipe to send the message to. If there's none, or if it's not ready for sending, silently drop the message. */ data = nn_cont (nn_hash_get (&xrep->outpipes, key), struct nn_xrep_data, outitem); if (!data || !(data->flags & NN_XREP_OUT)) { nn_msg_term (msg); return 0; } /* Send the message. */ rc = nn_pipe_send (data->pipe, msg); errnum_assert (rc >= 0, -rc); if (rc & NN_PIPE_RELEASE) data->flags &= ~NN_XREP_OUT; return 0; } int nn_xrep_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_xrep *xrep; struct nn_pipe *pipe; int i; int maxttl; void *data; size_t sz; struct nn_chunkref ref; struct nn_xrep_data *pipedata; xrep = nn_cont (self, struct nn_xrep, sockbase); rc = nn_fq_recv (&xrep->inpipes, msg, &pipe); if (nn_slow (rc < 0)) return rc; if (!(rc & NN_PIPE_PARSED)) { sz = sizeof (maxttl); rc = nn_sockbase_getopt (self, NN_MAXTTL, &maxttl, &sz); errnum_assert (rc == 0, -rc); /* Determine the size of the message header. */ data = nn_chunkref_data (&msg->body); sz = nn_chunkref_size (&msg->body); i = 0; while (1) { /* Ignore the malformed requests without the bottom of the stack. */ if (nn_slow ((i + 1) * sizeof (uint32_t) > sz)) { nn_msg_term (msg); return -EAGAIN; } /* If the bottom of the backtrace stack is reached, proceed. */ if (nn_getl ((uint8_t*)(((uint32_t*) data) + i)) & 0x80000000) break; ++i; } ++i; /* If we encountered too many hops, just toss the message */ if (i > maxttl) { nn_msg_term (msg); return -EAGAIN; } /* Split the header and the body. */ nn_assert (nn_chunkref_size (&msg->sphdr) == 0); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, i * sizeof (uint32_t)); memcpy (nn_chunkref_data (&msg->sphdr), data, i * sizeof (uint32_t)); nn_chunkref_trim (&msg->body, i * sizeof (uint32_t)); } /* Prepend the header by the pipe key. */ pipedata = nn_pipe_getdata (pipe); nn_chunkref_init (&ref, nn_chunkref_size (&msg->sphdr) + sizeof (uint32_t)); nn_putl (nn_chunkref_data (&ref), pipedata->outitem.key); memcpy (((uint8_t*) nn_chunkref_data (&ref)) + sizeof (uint32_t), nn_chunkref_data (&msg->sphdr), nn_chunkref_size (&msg->sphdr)); nn_chunkref_term (&msg->sphdr); nn_chunkref_mv (&msg->sphdr, &ref); return 0; } static int nn_xrep_create (void *hint, struct nn_sockbase **sockbase) { struct nn_xrep *self; self = nn_alloc (sizeof (struct nn_xrep), "socket (xrep)"); alloc_assert (self); nn_xrep_init (self, &nn_xrep_sockbase_vfptr, hint); *sockbase = &self->sockbase; return 0; } int nn_xrep_ispeer (int socktype) { return socktype == NN_REQ ? 1 : 0; } struct nn_socktype nn_xrep_socktype = { AF_SP_RAW, NN_REP, 0, nn_xrep_create, nn_xrep_ispeer, }; nanomsg-1.1.5/src/protocols/reqrep/xrep.h000066400000000000000000000045341336111550300204240ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_XREP_INCLUDED #define NN_XREP_INCLUDED #include "../../protocol.h" #include "../../utils/hash.h" #include "../utils/fq.h" #include #define NN_XREP_OUT 1 struct nn_xrep_data { struct nn_pipe *pipe; struct nn_hash_item outitem; struct nn_fq_data initem; uint32_t flags; }; struct nn_xrep { struct nn_sockbase sockbase; /* Key to be assigned to the next added pipe. */ uint32_t next_key; /* Map of all registered pipes indexed by the peer ID. */ struct nn_hash outpipes; /* Fair-queuer to get messages from. */ struct nn_fq inpipes; }; void nn_xrep_init (struct nn_xrep *self, const struct nn_sockbase_vfptr *vfptr, void *hint); void nn_xrep_term (struct nn_xrep *self); int nn_xrep_add (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xrep_rm (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xrep_in (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xrep_out (struct nn_sockbase *self, struct nn_pipe *pipe); int nn_xrep_events (struct nn_sockbase *self); int nn_xrep_send (struct nn_sockbase *self, struct nn_msg *msg); int nn_xrep_recv (struct nn_sockbase *self, struct nn_msg *msg); int nn_xrep_ispeer (int socktype); #endif nanomsg-1.1.5/src/protocols/reqrep/xreq.c000066400000000000000000000143461336111550300204220ustar00rootroot00000000000000/* Copyright (c) 2012-2014 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xreq.h" #include "../../nn.h" #include "../../reqrep.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/alloc.h" #include "../../utils/attr.h" struct nn_xreq_data { struct nn_lb_data lb; struct nn_fq_data fq; }; /* Private functions. */ static void nn_xreq_destroy (struct nn_sockbase *self); static const struct nn_sockbase_vfptr nn_xreq_sockbase_vfptr = { NULL, nn_xreq_destroy, nn_xreq_add, nn_xreq_rm, nn_xreq_in, nn_xreq_out, nn_xreq_events, nn_xreq_send, nn_xreq_recv, NULL, NULL }; void nn_xreq_init (struct nn_xreq *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_sockbase_init (&self->sockbase, vfptr, hint); nn_lb_init (&self->lb); nn_fq_init (&self->fq); } void nn_xreq_term (struct nn_xreq *self) { nn_fq_term (&self->fq); nn_lb_term (&self->lb); nn_sockbase_term (&self->sockbase); } static void nn_xreq_destroy (struct nn_sockbase *self) { struct nn_xreq *xreq; xreq = nn_cont (self, struct nn_xreq, sockbase); nn_xreq_term (xreq); nn_free (xreq); } int nn_xreq_add (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xreq *xreq; struct nn_xreq_data *data; int sndprio; int rcvprio; size_t sz; xreq = nn_cont (self, struct nn_xreq, sockbase); sz = sizeof (sndprio); nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_SNDPRIO, &sndprio, &sz); nn_assert (sz == sizeof (sndprio)); nn_assert (sndprio >= 1 && sndprio <= 16); sz = sizeof (rcvprio); nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz); nn_assert (sz == sizeof (rcvprio)); nn_assert (rcvprio >= 1 && rcvprio <= 16); data = nn_alloc (sizeof (struct nn_xreq_data), "pipe data (req)"); alloc_assert (data); nn_pipe_setdata (pipe, data); nn_lb_add (&xreq->lb, &data->lb, pipe, sndprio); nn_fq_add (&xreq->fq, &data->fq, pipe, rcvprio); return 0; } void nn_xreq_rm (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xreq *xreq; struct nn_xreq_data *data; xreq = nn_cont (self, struct nn_xreq, sockbase); data = nn_pipe_getdata (pipe); nn_lb_rm (&xreq->lb, &data->lb); nn_fq_rm (&xreq->fq, &data->fq); nn_free (data); nn_sockbase_stat_increment (self, NN_STAT_CURRENT_SND_PRIORITY, nn_lb_get_priority (&xreq->lb)); } void nn_xreq_in (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xreq *xreq; struct nn_xreq_data *data; xreq = nn_cont (self, struct nn_xreq, sockbase); data = nn_pipe_getdata (pipe); nn_fq_in (&xreq->fq, &data->fq); } void nn_xreq_out (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xreq *xreq; struct nn_xreq_data *data; xreq = nn_cont (self, struct nn_xreq, sockbase); data = nn_pipe_getdata (pipe); nn_lb_out (&xreq->lb, &data->lb); nn_sockbase_stat_increment (self, NN_STAT_CURRENT_SND_PRIORITY, nn_lb_get_priority (&xreq->lb)); } int nn_xreq_events (struct nn_sockbase *self) { struct nn_xreq *xreq; xreq = nn_cont (self, struct nn_xreq, sockbase); return (nn_fq_can_recv (&xreq->fq) ? NN_SOCKBASE_EVENT_IN : 0) | (nn_lb_can_send (&xreq->lb) ? NN_SOCKBASE_EVENT_OUT : 0); } int nn_xreq_send (struct nn_sockbase *self, struct nn_msg *msg) { return nn_xreq_send_to (self, msg, NULL); } int nn_xreq_send_to (struct nn_sockbase *self, struct nn_msg *msg, struct nn_pipe **to) { int rc; /* If request cannot be sent due to the pushback, drop it silenly. */ rc = nn_lb_send (&nn_cont (self, struct nn_xreq, sockbase)->lb, msg, to); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc >= 0, -rc); return 0; } int nn_xreq_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; rc = nn_fq_recv (&nn_cont (self, struct nn_xreq, sockbase)->fq, msg, NULL); if (rc == -EAGAIN) return -EAGAIN; errnum_assert (rc >= 0, -rc); if (!(rc & NN_PIPE_PARSED)) { /* Ignore malformed replies. */ if (nn_slow (nn_chunkref_size (&msg->body) < sizeof (uint32_t))) { nn_msg_term (msg); return -EAGAIN; } /* Split the message into the header and the body. */ nn_assert (nn_chunkref_size (&msg->sphdr) == 0); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, sizeof (uint32_t)); memcpy (nn_chunkref_data (&msg->sphdr), nn_chunkref_data (&msg->body), sizeof (uint32_t)); nn_chunkref_trim (&msg->body, sizeof (uint32_t)); } return 0; } static int nn_xreq_create (void *hint, struct nn_sockbase **sockbase) { struct nn_xreq *self; self = nn_alloc (sizeof (struct nn_xreq), "socket (xreq)"); alloc_assert (self); nn_xreq_init (self, &nn_xreq_sockbase_vfptr, hint); *sockbase = &self->sockbase; return 0; } int nn_xreq_ispeer (int socktype) { return socktype == NN_REP ? 1 : 0; } struct nn_socktype nn_xreq_socktype = { AF_SP_RAW, NN_REQ, 0, nn_xreq_create, nn_xreq_ispeer, }; nanomsg-1.1.5/src/protocols/reqrep/xreq.h000066400000000000000000000041561336111550300204250ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_XREQ_INCLUDED #define NN_XREQ_INCLUDED #include "../../protocol.h" #include "../utils/lb.h" #include "../utils/fq.h" struct nn_xreq { struct nn_sockbase sockbase; struct nn_lb lb; struct nn_fq fq; }; void nn_xreq_init (struct nn_xreq *self, const struct nn_sockbase_vfptr *vfptr, void *hint); void nn_xreq_term (struct nn_xreq *self); int nn_xreq_add (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xreq_rm (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xreq_in (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xreq_out (struct nn_sockbase *self, struct nn_pipe *pipe); int nn_xreq_events (struct nn_sockbase *self); int nn_xreq_send (struct nn_sockbase *self, struct nn_msg *msg); int nn_xreq_send_to (struct nn_sockbase *self, struct nn_msg *msg, struct nn_pipe **to); int nn_xreq_recv (struct nn_sockbase *self, struct nn_msg *msg); int nn_xreq_ispeer (int socktype); #endif nanomsg-1.1.5/src/protocols/survey/000077500000000000000000000000001336111550300173265ustar00rootroot00000000000000nanomsg-1.1.5/src/protocols/survey/respondent.c000066400000000000000000000132051336111550300216540ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xrespondent.h" #include "../../nn.h" #include "../../survey.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/alloc.h" #include "../../utils/wire.h" #include #define NN_RESPONDENT_INPROGRESS 1 struct nn_respondent { struct nn_xrespondent xrespondent; uint32_t flags; struct nn_chunkref backtrace; }; /* Private functions. */ static void nn_respondent_init (struct nn_respondent *self, const struct nn_sockbase_vfptr *vfptr, void *hint); static void nn_respondent_term (struct nn_respondent *self); /* Implementation of nn_sockbase's virtual functions. */ static void nn_respondent_destroy (struct nn_sockbase *self); static int nn_respondent_events (struct nn_sockbase *self); static int nn_respondent_send (struct nn_sockbase *self, struct nn_msg *msg); static int nn_respondent_recv (struct nn_sockbase *self, struct nn_msg *msg); static const struct nn_sockbase_vfptr nn_respondent_sockbase_vfptr = { NULL, nn_respondent_destroy, nn_xrespondent_add, nn_xrespondent_rm, nn_xrespondent_in, nn_xrespondent_out, nn_respondent_events, nn_respondent_send, nn_respondent_recv, NULL, NULL }; static void nn_respondent_init (struct nn_respondent *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_xrespondent_init (&self->xrespondent, vfptr, hint); self->flags = 0; } static void nn_respondent_term (struct nn_respondent *self) { if (self->flags & NN_RESPONDENT_INPROGRESS) nn_chunkref_term (&self->backtrace); nn_xrespondent_term (&self->xrespondent); } void nn_respondent_destroy (struct nn_sockbase *self) { struct nn_respondent *respondent; respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase); nn_respondent_term (respondent); nn_free (respondent); } static int nn_respondent_events (struct nn_sockbase *self) { int events; struct nn_respondent *respondent; respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase); events = nn_xrespondent_events (&respondent->xrespondent.sockbase); if (!(respondent->flags & NN_RESPONDENT_INPROGRESS)) events &= ~NN_SOCKBASE_EVENT_OUT; return events; } static int nn_respondent_send (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_respondent *respondent; respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase); /* If there's no survey going on, report EFSM error. */ if (nn_slow (!(respondent->flags & NN_RESPONDENT_INPROGRESS))) return -EFSM; /* Tag the message with survey ID. */ nn_assert (nn_chunkref_size (&msg->sphdr) == 0); nn_chunkref_term (&msg->sphdr); nn_chunkref_mv (&msg->sphdr, &respondent->backtrace); /* Remember that no survey is being processed. */ respondent->flags &= ~NN_RESPONDENT_INPROGRESS; /* Try to send the message. If it cannot be sent due to pushback, drop it silently. */ rc = nn_xrespondent_send (&respondent->xrespondent.sockbase, msg); errnum_assert (rc == 0 || rc == -EAGAIN, -rc); return 0; } static int nn_respondent_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_respondent *respondent; respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase); /* Cancel current survey and clean up backtrace, if it exists. */ if (nn_slow (respondent->flags & NN_RESPONDENT_INPROGRESS)) { nn_chunkref_term (&respondent->backtrace); respondent->flags &= ~NN_RESPONDENT_INPROGRESS; } /* Get next survey. */ rc = nn_xrespondent_recv (&respondent->xrespondent.sockbase, msg); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc == 0, -rc); /* Store the backtrace. */ nn_chunkref_mv (&respondent->backtrace, &msg->sphdr); nn_chunkref_init (&msg->sphdr, 0); /* Remember that survey is being processed. */ respondent->flags |= NN_RESPONDENT_INPROGRESS; return 0; } static int nn_respondent_create (void *hint, struct nn_sockbase **sockbase) { struct nn_respondent *self; self = nn_alloc (sizeof (struct nn_respondent), "socket (respondent)"); alloc_assert (self); nn_respondent_init (self, &nn_respondent_sockbase_vfptr, hint); *sockbase = &self->xrespondent.sockbase; return 0; } struct nn_socktype nn_respondent_socktype = { AF_SP, NN_RESPONDENT, 0, nn_respondent_create, nn_xrespondent_ispeer, }; nanomsg-1.1.5/src/protocols/survey/surveyor.c000066400000000000000000000410371336111550300213750ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2015 Garrett D'Amore 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. */ #include "xsurveyor.h" #include "../../nn.h" #include "../../survey.h" #include "../../aio/fsm.h" #include "../../aio/timer.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/wire.h" #include "../../utils/alloc.h" #include "../../utils/random.h" #include "../../utils/attr.h" #include #define NN_SURVEYOR_DEFAULT_DEADLINE 1000 #define NN_SURVEYOR_STATE_IDLE 1 #define NN_SURVEYOR_STATE_PASSIVE 2 #define NN_SURVEYOR_STATE_ACTIVE 3 #define NN_SURVEYOR_STATE_CANCELLING 4 #define NN_SURVEYOR_STATE_STOPPING_TIMER 5 #define NN_SURVEYOR_STATE_STOPPING 6 #define NN_SURVEYOR_ACTION_START 1 #define NN_SURVEYOR_ACTION_CANCEL 2 #define NN_SURVEYOR_SRC_DEADLINE_TIMER 1 #define NN_SURVEYOR_TIMEDOUT 1 struct nn_surveyor { /* The underlying raw SP socket. */ struct nn_xsurveyor xsurveyor; /* The state machine. */ struct nn_fsm fsm; int state; /* Survey ID of the current survey. */ uint32_t surveyid; /* Timer for timing out the survey. */ struct nn_timer timer; /* When starting the survey, the message is temporarily stored here. */ struct nn_msg tosend; /* Protocol-specific socket options. */ int deadline; /* Flag if surveyor has timed out */ int timedout; }; /* Private functions. */ static void nn_surveyor_init (struct nn_surveyor *self, const struct nn_sockbase_vfptr *vfptr, void *hint); static void nn_surveyor_term (struct nn_surveyor *self); static void nn_surveyor_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_surveyor_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static int nn_surveyor_inprogress (struct nn_surveyor *self); static void nn_surveyor_resend (struct nn_surveyor *self); /* Implementation of nn_sockbase's virtual functions. */ static void nn_surveyor_stop (struct nn_sockbase *self); static void nn_surveyor_destroy (struct nn_sockbase *self); static int nn_surveyor_events (struct nn_sockbase *self); static int nn_surveyor_send (struct nn_sockbase *self, struct nn_msg *msg); static int nn_surveyor_recv (struct nn_sockbase *self, struct nn_msg *msg); static int nn_surveyor_setopt (struct nn_sockbase *self, int level, int option, const void *optval, size_t optvallen); static int nn_surveyor_getopt (struct nn_sockbase *self, int level, int option, void *optval, size_t *optvallen); static const struct nn_sockbase_vfptr nn_surveyor_sockbase_vfptr = { nn_surveyor_stop, nn_surveyor_destroy, nn_xsurveyor_add, nn_xsurveyor_rm, nn_xsurveyor_in, nn_xsurveyor_out, nn_surveyor_events, nn_surveyor_send, nn_surveyor_recv, nn_surveyor_setopt, nn_surveyor_getopt }; static void nn_surveyor_init (struct nn_surveyor *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_xsurveyor_init (&self->xsurveyor, vfptr, hint); nn_fsm_init_root (&self->fsm, nn_surveyor_handler, nn_surveyor_shutdown, nn_sockbase_getctx (&self->xsurveyor.sockbase)); self->state = NN_SURVEYOR_STATE_IDLE; /* Start assigning survey IDs beginning with a random number. This way there should be no key clashes even if the executable is re-started. */ nn_random_generate (&self->surveyid, sizeof (self->surveyid)); nn_timer_init (&self->timer, NN_SURVEYOR_SRC_DEADLINE_TIMER, &self->fsm); nn_msg_init (&self->tosend, 0); self->deadline = NN_SURVEYOR_DEFAULT_DEADLINE; self->timedout = 0; /* Start the state machine. */ nn_fsm_start (&self->fsm); } static void nn_surveyor_term (struct nn_surveyor *self) { nn_msg_term (&self->tosend); nn_timer_term (&self->timer); nn_fsm_term (&self->fsm); nn_xsurveyor_term (&self->xsurveyor); } void nn_surveyor_stop (struct nn_sockbase *self) { struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase); nn_fsm_stop (&surveyor->fsm); } void nn_surveyor_destroy (struct nn_sockbase *self) { struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase); nn_surveyor_term (surveyor); nn_free (surveyor); } static int nn_surveyor_inprogress (struct nn_surveyor *self) { /* Return 1 if there's a survey going on. 0 otherwise. */ return self->state == NN_SURVEYOR_STATE_IDLE || self->state == NN_SURVEYOR_STATE_PASSIVE || self->state == NN_SURVEYOR_STATE_STOPPING ? 0 : 1; } static int nn_surveyor_events (struct nn_sockbase *self) { int rc; struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase); /* Determine the actual readability/writability of the socket. */ rc = nn_xsurveyor_events (&surveyor->xsurveyor.sockbase); /* If there's no survey going on we'll signal IN to interrupt polling when the survey expires. nn_recv() will return -EFSM afterwards. */ if (!nn_surveyor_inprogress (surveyor)) rc |= NN_SOCKBASE_EVENT_IN; return rc; } static int nn_surveyor_send (struct nn_sockbase *self, struct nn_msg *msg) { struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase); /* Generate new survey ID. */ ++surveyor->surveyid; surveyor->surveyid |= 0x80000000; /* Tag the survey body with survey ID. */ nn_assert (nn_chunkref_size (&msg->sphdr) == 0); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, 4); nn_putl (nn_chunkref_data (&msg->sphdr), surveyor->surveyid); /* Store the survey, so that it can be sent later on. */ nn_msg_term (&surveyor->tosend); nn_msg_mv (&surveyor->tosend, msg); nn_msg_init (msg, 0); /* Cancel any ongoing survey, if any. */ if (nn_slow (nn_surveyor_inprogress (surveyor))) { /* First check whether the survey can be sent at all. */ if (!(nn_xsurveyor_events (&surveyor->xsurveyor.sockbase) & NN_SOCKBASE_EVENT_OUT)) return -EAGAIN; /* Cancel the current survey. */ nn_fsm_action (&surveyor->fsm, NN_SURVEYOR_ACTION_CANCEL); return 0; } /* Notify the state machine that the survey was started. */ nn_fsm_action (&surveyor->fsm, NN_SURVEYOR_ACTION_START); return 0; } static int nn_surveyor_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_surveyor *surveyor; uint32_t surveyid; surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase); /* If no survey is going on return EFSM error. */ if (nn_slow (!nn_surveyor_inprogress (surveyor))) { if (surveyor->timedout == NN_SURVEYOR_TIMEDOUT) { surveyor->timedout = 0; return -ETIMEDOUT; } else return -EFSM; } while (1) { /* Get next response. */ rc = nn_xsurveyor_recv (&surveyor->xsurveyor.sockbase, msg); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc == 0, -rc); /* Get the survey ID. Ignore any stale responses. */ /* TODO: This should be done asynchronously! */ if (nn_slow (nn_chunkref_size (&msg->sphdr) != sizeof (uint32_t))) continue; surveyid = nn_getl (nn_chunkref_data (&msg->sphdr)); if (nn_slow (surveyid != surveyor->surveyid)) continue; /* Discard the header and return the message to the user. */ nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, 0); break; } return 0; } static int nn_surveyor_setopt (struct nn_sockbase *self, int level, int option, const void *optval, size_t optvallen) { struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase); if (level != NN_SURVEYOR) return -ENOPROTOOPT; if (option == NN_SURVEYOR_DEADLINE) { if (nn_slow (optvallen != sizeof (int))) return -EINVAL; surveyor->deadline = *(int*) optval; return 0; } return -ENOPROTOOPT; } static int nn_surveyor_getopt (struct nn_sockbase *self, int level, int option, void *optval, size_t *optvallen) { struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase); if (level != NN_SURVEYOR) return -ENOPROTOOPT; if (option == NN_SURVEYOR_DEADLINE) { if (nn_slow (*optvallen < sizeof (int))) return -EINVAL; *(int*) optval = surveyor->deadline; *optvallen = sizeof (int); return 0; } return -ENOPROTOOPT; } static void nn_surveyor_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, fsm); if (nn_slow (src== NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_timer_stop (&surveyor->timer); surveyor->state = NN_SURVEYOR_STATE_STOPPING; } if (nn_slow (surveyor->state == NN_SURVEYOR_STATE_STOPPING)) { if (!nn_timer_isidle (&surveyor->timer)) return; surveyor->state = NN_SURVEYOR_STATE_IDLE; nn_fsm_stopped_noevent (&surveyor->fsm); nn_sockbase_stopped (&surveyor->xsurveyor.sockbase); return; } nn_fsm_bad_state(surveyor->state, src, type); } static void nn_surveyor_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, fsm); switch (surveyor->state) { /******************************************************************************/ /* IDLE state. */ /* The socket was created recently. */ /******************************************************************************/ case NN_SURVEYOR_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: surveyor->state = NN_SURVEYOR_STATE_PASSIVE; return; default: nn_fsm_bad_action (surveyor->state, src, type); } default: nn_fsm_bad_source (surveyor->state, src, type); } /******************************************************************************/ /* PASSIVE state. */ /* There's no survey going on. */ /******************************************************************************/ case NN_SURVEYOR_STATE_PASSIVE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_SURVEYOR_ACTION_START: nn_surveyor_resend (surveyor); nn_timer_start (&surveyor->timer, surveyor->deadline); surveyor->state = NN_SURVEYOR_STATE_ACTIVE; return; default: nn_fsm_bad_action (surveyor->state, src, type); } default: nn_fsm_bad_source (surveyor->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Survey was sent, waiting for responses. */ /******************************************************************************/ case NN_SURVEYOR_STATE_ACTIVE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_SURVEYOR_ACTION_CANCEL: nn_timer_stop (&surveyor->timer); surveyor->state = NN_SURVEYOR_STATE_CANCELLING; return; default: nn_fsm_bad_action (surveyor->state, src, type); } case NN_SURVEYOR_SRC_DEADLINE_TIMER: switch (type) { case NN_TIMER_TIMEOUT: nn_timer_stop (&surveyor->timer); surveyor->state = NN_SURVEYOR_STATE_STOPPING_TIMER; surveyor->timedout = NN_SURVEYOR_TIMEDOUT; return; default: nn_fsm_bad_action (surveyor->state, src, type); } default: nn_fsm_bad_source (surveyor->state, src, type); } /******************************************************************************/ /* CANCELLING state. */ /* Survey was cancelled, but the old timer haven't stopped yet. The new */ /* survey thus haven't been sent and is stored in 'tosend'. */ /******************************************************************************/ case NN_SURVEYOR_STATE_CANCELLING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_SURVEYOR_ACTION_CANCEL: return; default: nn_fsm_bad_action (surveyor->state, src, type); } case NN_SURVEYOR_SRC_DEADLINE_TIMER: switch (type) { case NN_TIMER_STOPPED: nn_surveyor_resend (surveyor); nn_timer_start (&surveyor->timer, surveyor->deadline); surveyor->state = NN_SURVEYOR_STATE_ACTIVE; return; default: nn_fsm_bad_action (surveyor->state, src, type); } default: nn_fsm_bad_source (surveyor->state, src, type); } /******************************************************************************/ /* STOPPING_TIMER state. */ /* Survey timeout expired. Now we are stopping the timer. */ /******************************************************************************/ case NN_SURVEYOR_STATE_STOPPING_TIMER: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_SURVEYOR_ACTION_CANCEL: surveyor->state = NN_SURVEYOR_STATE_CANCELLING; return; default: nn_fsm_bad_action (surveyor->state, src, type); } case NN_SURVEYOR_SRC_DEADLINE_TIMER: switch (type) { case NN_TIMER_STOPPED: surveyor->state = NN_SURVEYOR_STATE_PASSIVE; return; default: nn_fsm_bad_action (surveyor->state, src, type); } default: nn_fsm_bad_source (surveyor->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (surveyor->state, src, type); } } static void nn_surveyor_resend (struct nn_surveyor *self) { int rc; struct nn_msg msg; nn_msg_cp (&msg, &self->tosend); rc = nn_xsurveyor_send (&self->xsurveyor.sockbase, &msg); errnum_assert (rc == 0, -rc); } static int nn_surveyor_create (void *hint, struct nn_sockbase **sockbase) { struct nn_surveyor *self; self = nn_alloc (sizeof (struct nn_surveyor), "socket (surveyor)"); alloc_assert (self); nn_surveyor_init (self, &nn_surveyor_sockbase_vfptr, hint); *sockbase = &self->xsurveyor.sockbase; return 0; } struct nn_socktype nn_surveyor_socktype = { AF_SP, NN_SURVEYOR, 0, nn_surveyor_create, nn_xsurveyor_ispeer, }; nanomsg-1.1.5/src/protocols/survey/xrespondent.c000066400000000000000000000210131336111550300220400ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xrespondent.h" #include "../../nn.h" #include "../../survey.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/alloc.h" #include "../../utils/random.h" #include "../../utils/wire.h" #include "../../utils/attr.h" /* Private functions. */ static void nn_xrespondent_destroy (struct nn_sockbase *self); /* Implementation of nn_sockbase's virtual functions. */ static const struct nn_sockbase_vfptr nn_xrespondent_sockbase_vfptr = { NULL, nn_xrespondent_destroy, nn_xrespondent_add, nn_xrespondent_rm, nn_xrespondent_in, nn_xrespondent_out, nn_xrespondent_events, nn_xrespondent_send, nn_xrespondent_recv, NULL, NULL }; void nn_xrespondent_init (struct nn_xrespondent *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_sockbase_init (&self->sockbase, vfptr, hint); /* Pipes IDs should be random. See RFC for info. */ nn_random_generate (&self->next_key, sizeof (self->next_key)); nn_hash_init (&self->outpipes); nn_fq_init (&self->inpipes); } void nn_xrespondent_term (struct nn_xrespondent *self) { nn_fq_term (&self->inpipes); nn_hash_term (&self->outpipes); nn_sockbase_term (&self->sockbase); } static void nn_xrespondent_destroy (struct nn_sockbase *self) { struct nn_xrespondent *xrespondent; xrespondent = nn_cont (self, struct nn_xrespondent, sockbase); nn_xrespondent_term (xrespondent); nn_free (xrespondent); } int nn_xrespondent_add (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xrespondent *xrespondent; struct nn_xrespondent_data *data; int rcvprio; size_t sz; xrespondent = nn_cont (self, struct nn_xrespondent, sockbase); sz = sizeof (rcvprio); nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz); nn_assert (sz == sizeof (rcvprio)); nn_assert (rcvprio >= 1 && rcvprio <= 16); data = nn_alloc (sizeof (*data), "pipe data (xrespondent)"); alloc_assert (data); data->pipe = pipe; nn_hash_item_init (&data->outitem); data->flags = 0; nn_hash_insert (&xrespondent->outpipes, xrespondent->next_key & 0x7fffffff, &data->outitem); xrespondent->next_key++; nn_fq_add (&xrespondent->inpipes, &data->initem, pipe, rcvprio); nn_pipe_setdata (pipe, data); return 0; } void nn_xrespondent_rm (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xrespondent *xrespondent; struct nn_xrespondent_data *data; xrespondent = nn_cont (self, struct nn_xrespondent, sockbase); data = nn_pipe_getdata (pipe); nn_fq_rm (&xrespondent->inpipes, &data->initem); nn_hash_erase (&xrespondent->outpipes, &data->outitem); nn_hash_item_term (&data->outitem); nn_free (data); } void nn_xrespondent_in (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xrespondent *xrespondent; struct nn_xrespondent_data *data; xrespondent = nn_cont (self, struct nn_xrespondent, sockbase); data = nn_pipe_getdata (pipe); nn_fq_in (&xrespondent->inpipes, &data->initem); } void nn_xrespondent_out (NN_UNUSED struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xrespondent_data *data; data = nn_pipe_getdata (pipe); data->flags |= NN_XRESPONDENT_OUT; } int nn_xrespondent_events (struct nn_sockbase *self) { return (nn_fq_can_recv (&nn_cont (self, struct nn_xrespondent, sockbase)->inpipes) ? NN_SOCKBASE_EVENT_IN : 0) | NN_SOCKBASE_EVENT_OUT; } int nn_xrespondent_send (struct nn_sockbase *self, struct nn_msg *msg) { int rc; uint32_t key; struct nn_xrespondent *xrespondent; struct nn_xrespondent_data *data; xrespondent = nn_cont (self, struct nn_xrespondent, sockbase); /* We treat invalid peer ID as if the peer was non-existent. */ if (nn_slow (nn_chunkref_size (&msg->sphdr) < sizeof (uint32_t))) { nn_msg_term (msg); return 0; } /* Retrieve destination peer ID. Trim it from the header. */ key = nn_getl (nn_chunkref_data (&msg->sphdr)); nn_chunkref_trim (&msg->sphdr, 4); /* Find the appropriate pipe to send the message to. If there's none, or if it's not ready for sending, silently drop the message. */ data = nn_cont (nn_hash_get (&xrespondent->outpipes, key), struct nn_xrespondent_data, outitem); if (!data || !(data->flags & NN_XRESPONDENT_OUT)) { nn_msg_term (msg); return 0; } /* Send the message. */ rc = nn_pipe_send (data->pipe, msg); errnum_assert (rc >= 0, -rc); if (rc & NN_PIPE_RELEASE) data->flags &= ~NN_XRESPONDENT_OUT; return 0; } int nn_xrespondent_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_xrespondent *xrespondent; struct nn_pipe *pipe; int i; size_t sz; void *data; struct nn_chunkref ref; struct nn_xrespondent_data *pipedata; int maxttl; xrespondent = nn_cont (self, struct nn_xrespondent, sockbase); rc = nn_fq_recv (&xrespondent->inpipes, msg, &pipe); if (nn_slow (rc < 0)) return rc; /* Split the header (including survey ID) from the body, if needed. */ if (!(rc & NN_PIPE_PARSED)) { sz = sizeof (maxttl); rc = nn_sockbase_getopt (self, NN_MAXTTL, &maxttl, &sz); errnum_assert (rc == 0, -rc); /* Determine the size of the message header. */ data = nn_chunkref_data (&msg->body); sz = nn_chunkref_size (&msg->body); i = 0; while (1) { /* Ignore the malformed surveys without the bottom of the stack. */ if (nn_slow ((i + 1) * sizeof (uint32_t) > sz)) { nn_msg_term (msg); return -EAGAIN; } /* If the bottom of the backtrace stack is reached, proceed. */ if (nn_getl ((uint8_t*)(((uint32_t*) data) + i)) & 0x80000000) break; ++i; } ++i; /* Ignore messages with too many hops. */ if (i > maxttl) { nn_msg_term (msg); return -EAGAIN; } nn_assert (nn_chunkref_size (&msg->sphdr) == 0); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, i * sizeof (uint32_t)); memcpy (nn_chunkref_data (&msg->sphdr), data, i * sizeof (uint32_t)); nn_chunkref_trim (&msg->body, i * sizeof (uint32_t)); } /* Prepend the header by the pipe key. */ pipedata = nn_pipe_getdata (pipe); nn_chunkref_init (&ref, nn_chunkref_size (&msg->sphdr) + sizeof (uint32_t)); nn_putl (nn_chunkref_data (&ref), pipedata->outitem.key); memcpy (((uint8_t *) nn_chunkref_data (&ref)) + sizeof (uint32_t), nn_chunkref_data (&msg->sphdr), nn_chunkref_size (&msg->sphdr)); nn_chunkref_term (&msg->sphdr); nn_chunkref_mv (&msg->sphdr, &ref); return 0; } static int nn_xrespondent_create (void *hint, struct nn_sockbase **sockbase) { struct nn_xrespondent *self; self = nn_alloc (sizeof (struct nn_xrespondent), "socket (xrespondent)"); alloc_assert (self); nn_xrespondent_init (self, &nn_xrespondent_sockbase_vfptr, hint); *sockbase = &self->sockbase; return 0; } int nn_xrespondent_ispeer (int socktype) { return socktype == NN_SURVEYOR ? 1 : 0; } struct nn_socktype nn_xrespondent_socktype = { AF_SP_RAW, NN_RESPONDENT, 0, nn_xrespondent_create, nn_xrespondent_ispeer, }; nanomsg-1.1.5/src/protocols/survey/xrespondent.h000066400000000000000000000047621336111550300220610ustar00rootroot00000000000000/* Copyright (c) 201-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_XRESPONDENT_INCLUDED #define NN_XRESPONDENT_INCLUDED #include "../../protocol.h" #include "../../utils/hash.h" #include "../utils/fq.h" #define NN_XRESPONDENT_OUT 1 struct nn_xrespondent_data { struct nn_pipe *pipe; struct nn_hash_item outitem; struct nn_fq_data initem; uint32_t flags; }; struct nn_xrespondent { struct nn_sockbase sockbase; /* Key to be assigned to the next added pipe. */ uint32_t next_key; /* Map of all registered pipes indexed by the peer ID. */ struct nn_hash outpipes; /* Fair-queuer to get surveys from. */ struct nn_fq inpipes; }; void nn_xrespondent_init (struct nn_xrespondent *self, const struct nn_sockbase_vfptr *vfptr, void *hint); void nn_xrespondent_term (struct nn_xrespondent *self); int nn_xrespondent_add (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xrespondent_rm (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xrespondent_in (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xrespondent_out (struct nn_sockbase *self, struct nn_pipe *pipe); int nn_xrespondent_events (struct nn_sockbase *self); int nn_xrespondent_send (struct nn_sockbase *self, struct nn_msg *msg); int nn_xrespondent_recv (struct nn_sockbase *self, struct nn_msg *msg); int nn_xrespondent_ispeer (int socktype); #endif nanomsg-1.1.5/src/protocols/survey/xsurveyor.c000066400000000000000000000137751336111550300215750ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "xsurveyor.h" #include "../../nn.h" #include "../../survey.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/alloc.h" #include "../../utils/attr.h" #include /* Private functions. */ static void nn_xsurveyor_destroy (struct nn_sockbase *self); /* Implementation of nn_sockbase's virtual functions. */ static const struct nn_sockbase_vfptr nn_xsurveyor_sockbase_vfptr = { NULL, nn_xsurveyor_destroy, nn_xsurveyor_add, nn_xsurveyor_rm, nn_xsurveyor_in, nn_xsurveyor_out, nn_xsurveyor_events, nn_xsurveyor_send, nn_xsurveyor_recv, NULL, NULL }; void nn_xsurveyor_init (struct nn_xsurveyor *self, const struct nn_sockbase_vfptr *vfptr, void *hint) { nn_sockbase_init (&self->sockbase, vfptr, hint); nn_dist_init (&self->outpipes); nn_fq_init (&self->inpipes); } void nn_xsurveyor_term (struct nn_xsurveyor *self) { nn_fq_term (&self->inpipes); nn_dist_term (&self->outpipes); nn_sockbase_term (&self->sockbase); } static void nn_xsurveyor_destroy (struct nn_sockbase *self) { struct nn_xsurveyor *xsurveyor; xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase); nn_xsurveyor_term (xsurveyor); nn_free (xsurveyor); } int nn_xsurveyor_add (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xsurveyor *xsurveyor; struct nn_xsurveyor_data *data; int rcvprio; size_t sz; xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase); sz = sizeof (rcvprio); nn_pipe_getopt (pipe, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, &sz); nn_assert (sz == sizeof (rcvprio)); nn_assert (rcvprio >= 1 && rcvprio <= 16); data = nn_alloc (sizeof (struct nn_xsurveyor_data), "pipe data (xsurveyor)"); alloc_assert (data); data->pipe = pipe; nn_fq_add (&xsurveyor->inpipes, &data->initem, pipe, rcvprio); nn_dist_add (&xsurveyor->outpipes, &data->outitem, pipe); nn_pipe_setdata (pipe, data); return 0; } void nn_xsurveyor_rm (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xsurveyor *xsurveyor; struct nn_xsurveyor_data *data; xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase); data = nn_pipe_getdata (pipe); nn_fq_rm (&xsurveyor->inpipes, &data->initem); nn_dist_rm (&xsurveyor->outpipes, &data->outitem); nn_free (data); } void nn_xsurveyor_in (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xsurveyor *xsurveyor; struct nn_xsurveyor_data *data; xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase); data = nn_pipe_getdata (pipe); nn_fq_in (&xsurveyor->inpipes, &data->initem); } void nn_xsurveyor_out (struct nn_sockbase *self, struct nn_pipe *pipe) { struct nn_xsurveyor *xsurveyor; struct nn_xsurveyor_data *data; xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase); data = nn_pipe_getdata (pipe); nn_dist_out (&xsurveyor->outpipes, &data->outitem); } int nn_xsurveyor_events (struct nn_sockbase *self) { struct nn_xsurveyor *xsurveyor; int events; xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase); events = NN_SOCKBASE_EVENT_OUT; if (nn_fq_can_recv (&xsurveyor->inpipes)) events |= NN_SOCKBASE_EVENT_IN; return events; } int nn_xsurveyor_send (struct nn_sockbase *self, struct nn_msg *msg) { return nn_dist_send ( &nn_cont (self, struct nn_xsurveyor, sockbase)->outpipes, msg, NULL); } int nn_xsurveyor_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_xsurveyor *xsurveyor; xsurveyor = nn_cont (self, struct nn_xsurveyor, sockbase); rc = nn_fq_recv (&xsurveyor->inpipes, msg, NULL); if (nn_slow (rc < 0)) return rc; /* Split the header from the body, if needed. */ if (!(rc & NN_PIPE_PARSED)) { if (nn_slow (nn_chunkref_size (&msg->body) < sizeof (uint32_t))) { nn_msg_term (msg); return -EAGAIN; } nn_assert (nn_chunkref_size (&msg->sphdr) == 0); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, sizeof (uint32_t)); memcpy (nn_chunkref_data (&msg->sphdr), nn_chunkref_data (&msg->body), sizeof (uint32_t)); nn_chunkref_trim (&msg->body, sizeof (uint32_t)); } return 0; } static int nn_xsurveyor_create (void *hint, struct nn_sockbase **sockbase) { struct nn_xsurveyor *self; self = nn_alloc (sizeof (struct nn_xsurveyor), "socket (xsurveyor)"); alloc_assert (self); nn_xsurveyor_init (self, &nn_xsurveyor_sockbase_vfptr, hint); *sockbase = &self->sockbase; return 0; } int nn_xsurveyor_ispeer (int socktype) { return socktype == NN_RESPONDENT ? 1 : 0; } struct nn_socktype nn_xsurveyor_socktype = { AF_SP_RAW, NN_SURVEYOR, 0, nn_xsurveyor_create, nn_xsurveyor_ispeer, }; nanomsg-1.1.5/src/protocols/survey/xsurveyor.h000066400000000000000000000050231336111550300215650ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_XSURVEYOR_INCLUDED #define NN_XSURVEYOR_INCLUDED #include "../../protocol.h" #include "../utils/dist.h" #include "../utils/fq.h" struct nn_xsurveyor_data { struct nn_pipe *pipe; struct nn_dist_data outitem; struct nn_fq_data initem; }; struct nn_xsurveyor { /* The generic socket base class. */ struct nn_sockbase sockbase; /* Distributor to send messages. */ struct nn_dist outpipes; /* Fair-queuer to receive messages. */ struct nn_fq inpipes; }; void nn_xsurveyor_init (struct nn_xsurveyor *self, const struct nn_sockbase_vfptr *vfptr, void *hint); void nn_xsurveyor_term (struct nn_xsurveyor *self); int nn_xsurveyor_add (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xsurveyor_rm (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xsurveyor_in (struct nn_sockbase *self, struct nn_pipe *pipe); void nn_xsurveyor_out (struct nn_sockbase *self, struct nn_pipe *pipe); int nn_xsurveyor_events (struct nn_sockbase *self); int nn_xsurveyor_send (struct nn_sockbase *self, struct nn_msg *msg); int nn_xsurveyor_recv (struct nn_sockbase *self, struct nn_msg *msg); int nn_xsurveyor_setopt (struct nn_sockbase *self, int level, int option, const void *optval, size_t optvallen); int nn_xsurveyor_getopt (struct nn_sockbase *self, int level, int option, void *optval, size_t *optvallen); int nn_xsurveyor_ispeer (int socktype); #endif nanomsg-1.1.5/src/protocols/utils/000077500000000000000000000000001336111550300171315ustar00rootroot00000000000000nanomsg-1.1.5/src/protocols/utils/README000066400000000000000000000001241336111550300200060ustar00rootroot00000000000000This directory contains the utilities that can be used when creating new protocols. nanomsg-1.1.5/src/protocols/utils/dist.c000066400000000000000000000064561336111550300202530ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "dist.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/attr.h" #include void nn_dist_init (struct nn_dist *self) { self->count = 0; nn_list_init (&self->pipes); } void nn_dist_term (struct nn_dist *self) { nn_assert (self->count == 0); nn_list_term (&self->pipes); } void nn_dist_add (NN_UNUSED struct nn_dist *self, struct nn_dist_data *data, struct nn_pipe *pipe) { data->pipe = pipe; nn_list_item_init (&data->item); } void nn_dist_rm (struct nn_dist *self, struct nn_dist_data *data) { if (nn_list_item_isinlist (&data->item)) { --self->count; nn_list_erase (&self->pipes, &data->item); } nn_list_item_term (&data->item); } void nn_dist_out (struct nn_dist *self, struct nn_dist_data *data) { ++self->count; nn_list_insert (&self->pipes, &data->item, nn_list_end (&self->pipes)); } int nn_dist_send (struct nn_dist *self, struct nn_msg *msg, struct nn_pipe *exclude) { int rc; struct nn_list_item *it; struct nn_dist_data *data; struct nn_msg copy; /* TODO: We can optimise for the case when there's only one outbound pipe here. No message copying is needed in such case. */ /* In the specific case when there are no outbound pipes. There's nowhere to send the message to. Deallocate it. */ if (nn_slow (self->count) == 0) { nn_msg_term (msg); return 0; } /* Send the message to all the subscribers. */ nn_msg_bulkcopy_start (msg, self->count); it = nn_list_begin (&self->pipes); while (it != nn_list_end (&self->pipes)) { data = nn_cont (it, struct nn_dist_data, item); nn_msg_bulkcopy_cp (©, msg); if (nn_fast (data->pipe == exclude)) { nn_msg_term (©); } else { rc = nn_pipe_send (data->pipe, ©); errnum_assert (rc >= 0, -rc); if (rc & NN_PIPE_RELEASE) { --self->count; it = nn_list_erase (&self->pipes, it); continue; } } it = nn_list_next (&self->pipes, it); } nn_msg_term (msg); return 0; } nanomsg-1.1.5/src/protocols/utils/dist.h000066400000000000000000000037771336111550300202630ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_DIST_INCLUDED #define NN_DIST_INCLUDED #include "../../protocol.h" #include "../../utils/list.h" /* Distributor. Sends messages to all the pipes. */ struct nn_dist_data { struct nn_list_item item; struct nn_pipe *pipe; }; struct nn_dist { uint32_t count; struct nn_list pipes; }; void nn_dist_init (struct nn_dist *self); void nn_dist_term (struct nn_dist *self); void nn_dist_add (struct nn_dist *self, struct nn_dist_data *data, struct nn_pipe *pipe); void nn_dist_rm (struct nn_dist *self, struct nn_dist_data *data); void nn_dist_out (struct nn_dist *self, struct nn_dist_data *data); /* Sends the message to all the attached pipes except the one specified by 'exclude' parameter. If 'exclude' is NULL, message is sent to all attached pipes. */ int nn_dist_send (struct nn_dist *self, struct nn_msg *msg, struct nn_pipe *exclude); #endif nanomsg-1.1.5/src/protocols/utils/excl.c000066400000000000000000000060061336111550300202320ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "excl.h" #include "../../utils/fast.h" #include "../../utils/err.h" #include "../../utils/attr.h" void nn_excl_init (struct nn_excl *self) { self->pipe = NULL; self->inpipe = NULL; self->outpipe = NULL; } void nn_excl_term (struct nn_excl *self) { nn_assert (!self->pipe); nn_assert (!self->inpipe); nn_assert (!self->outpipe); } int nn_excl_add (struct nn_excl *self, struct nn_pipe *pipe) { /* If there's a connection being used, reject any new connection. */ if (self->pipe) return -EISCONN; /* Remember that this pipe is the active one. */ self->pipe = pipe; return 0; } void nn_excl_rm (struct nn_excl *self, NN_UNUSED struct nn_pipe *pipe) { nn_assert (self->pipe); self->pipe = NULL; self->inpipe = NULL; self->outpipe = NULL; } void nn_excl_in (struct nn_excl *self, struct nn_pipe *pipe) { nn_assert (!self->inpipe); nn_assert (pipe == self->pipe); self->inpipe = pipe; } void nn_excl_out (struct nn_excl *self, struct nn_pipe *pipe) { nn_assert (!self->outpipe); nn_assert (pipe == self->pipe); self->outpipe = pipe; } int nn_excl_send (struct nn_excl *self, struct nn_msg *msg) { int rc; if (nn_slow (!self->outpipe)) return -EAGAIN; rc = nn_pipe_send (self->outpipe, msg); errnum_assert (rc >= 0, -rc); if (rc & NN_PIPE_RELEASE) self->outpipe = NULL; return rc & ~NN_PIPE_RELEASE; } int nn_excl_recv (struct nn_excl *self, struct nn_msg *msg) { int rc; if (nn_slow (!self->inpipe)) return -EAGAIN; rc = nn_pipe_recv (self->inpipe, msg); errnum_assert (rc >= 0, -rc); if (rc & NN_PIPE_RELEASE) self->inpipe = NULL; return rc & ~NN_PIPE_RELEASE; } int nn_excl_can_send (struct nn_excl *self) { return self->outpipe ? 1 : 0; } int nn_excl_can_recv (struct nn_excl *self) { return self->inpipe ? 1 : 0; } nanomsg-1.1.5/src/protocols/utils/excl.h000066400000000000000000000044601336111550300202410ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_EXCL_INCLUDED #define NN_EXCL_INCLUDED #include "../../protocol.h" #include /* This is an object to handle a single pipe. To be used by socket types that can work with precisely one connection, e.g. PAIR. */ struct nn_excl { /* The pipe being used at the moment. All other pipes will be rejected until this one terminates. NULL if there is no connected pipe. */ struct nn_pipe *pipe; /* Pipe ready for receiving. It's either equal to 'pipe' or NULL. */ struct nn_pipe *inpipe; /* Pipe ready for sending. It's either equal to 'pipe' or NULL. */ struct nn_pipe *outpipe; }; void nn_excl_init (struct nn_excl *self); void nn_excl_term (struct nn_excl *self); int nn_excl_add (struct nn_excl *self, struct nn_pipe *pipe); void nn_excl_rm (struct nn_excl *self, struct nn_pipe *pipe); void nn_excl_in (struct nn_excl *self, struct nn_pipe *pipe); void nn_excl_out (struct nn_excl *self, struct nn_pipe *pipe); int nn_excl_send (struct nn_excl *self, struct nn_msg *msg); int nn_excl_recv (struct nn_excl *self, struct nn_msg *msg); int nn_excl_can_send (struct nn_excl *self); int nn_excl_can_recv (struct nn_excl *self); #endif nanomsg-1.1.5/src/protocols/utils/fq.c000066400000000000000000000047521336111550300177130ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "fq.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include void nn_fq_init (struct nn_fq *self) { nn_priolist_init (&self->priolist); } void nn_fq_term (struct nn_fq *self) { nn_priolist_term (&self->priolist); } void nn_fq_add (struct nn_fq *self, struct nn_fq_data *data, struct nn_pipe *pipe, int priority) { nn_priolist_add (&self->priolist, &data->priodata, pipe, priority); } void nn_fq_rm (struct nn_fq *self, struct nn_fq_data *data) { nn_priolist_rm (&self->priolist, &data->priodata); } void nn_fq_in (struct nn_fq *self, struct nn_fq_data *data) { nn_priolist_activate (&self->priolist, &data->priodata); } int nn_fq_can_recv (struct nn_fq *self) { return nn_priolist_is_active (&self->priolist); } int nn_fq_recv (struct nn_fq *self, struct nn_msg *msg, struct nn_pipe **pipe) { int rc; struct nn_pipe *p; /* Pipe is NULL only when there are no avialable pipes. */ p = nn_priolist_getpipe (&self->priolist); if (nn_slow (!p)) return -EAGAIN; /* Receive the messsage. */ rc = nn_pipe_recv (p, msg); errnum_assert (rc >= 0, -rc); /* Return the pipe data to the user, if required. */ if (pipe) *pipe = p; /* Move to the next pipe. */ nn_priolist_advance (&self->priolist, rc & NN_PIPE_RELEASE); return rc & ~NN_PIPE_RELEASE; } nanomsg-1.1.5/src/protocols/utils/fq.h000066400000000000000000000035301336111550300177110ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_FQ_INCLUDED #define NN_FQ_INCLUDED #include "../../protocol.h" #include "priolist.h" /* Fair-queuer. Retrieves messages from a set of pipes in round-robin manner. */ struct nn_fq_data { struct nn_priolist_data priodata; }; struct nn_fq { struct nn_priolist priolist; }; void nn_fq_init (struct nn_fq *self); void nn_fq_term (struct nn_fq *self); void nn_fq_add (struct nn_fq *self, struct nn_fq_data *data, struct nn_pipe *pipe, int priority); void nn_fq_rm (struct nn_fq *self, struct nn_fq_data *data); void nn_fq_in (struct nn_fq *self, struct nn_fq_data *data); int nn_fq_can_recv (struct nn_fq *self); int nn_fq_recv (struct nn_fq *self, struct nn_msg *msg, struct nn_pipe **pipe); #endif nanomsg-1.1.5/src/protocols/utils/lb.c000066400000000000000000000050471336111550300177000ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "lb.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include void nn_lb_init (struct nn_lb *self) { nn_priolist_init (&self->priolist); } void nn_lb_term (struct nn_lb *self) { nn_priolist_term (&self->priolist); } void nn_lb_add (struct nn_lb *self, struct nn_lb_data *data, struct nn_pipe *pipe, int priority) { nn_priolist_add (&self->priolist, &data->priodata, pipe, priority); } void nn_lb_rm (struct nn_lb *self, struct nn_lb_data *data) { nn_priolist_rm (&self->priolist, &data->priodata); } void nn_lb_out (struct nn_lb *self, struct nn_lb_data *data) { nn_priolist_activate (&self->priolist, &data->priodata); } int nn_lb_can_send (struct nn_lb *self) { return nn_priolist_is_active (&self->priolist); } int nn_lb_get_priority (struct nn_lb *self) { return nn_priolist_get_priority (&self->priolist); } int nn_lb_send (struct nn_lb *self, struct nn_msg *msg, struct nn_pipe **to) { int rc; struct nn_pipe *pipe; /* Pipe is NULL only when there are no avialable pipes. */ pipe = nn_priolist_getpipe (&self->priolist); if (nn_slow (!pipe)) return -EAGAIN; /* Send the messsage. */ rc = nn_pipe_send (pipe, msg); errnum_assert (rc >= 0, -rc); /* Move to the next pipe. */ nn_priolist_advance (&self->priolist, rc & NN_PIPE_RELEASE); if (to != NULL) *to = pipe; return rc & ~NN_PIPE_RELEASE; } nanomsg-1.1.5/src/protocols/utils/lb.h000066400000000000000000000035571336111550300177110ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_LB_INCLUDED #define NN_LB_INCLUDED #include "../../protocol.h" #include "priolist.h" /* A load balancer. Round-robins messages to a set of pipes. */ struct nn_lb_data { struct nn_priolist_data priodata; }; struct nn_lb { struct nn_priolist priolist; }; void nn_lb_init (struct nn_lb *self); void nn_lb_term (struct nn_lb *self); void nn_lb_add (struct nn_lb *self, struct nn_lb_data *data, struct nn_pipe *pipe, int priority); void nn_lb_rm (struct nn_lb *self, struct nn_lb_data *data); void nn_lb_out (struct nn_lb *self, struct nn_lb_data *data); int nn_lb_can_send (struct nn_lb *self); int nn_lb_get_priority (struct nn_lb *self); int nn_lb_send (struct nn_lb *self, struct nn_msg *msg, struct nn_pipe **to); #endif nanomsg-1.1.5/src/protocols/utils/priolist.c000066400000000000000000000130541336111550300211450ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. 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. */ #include "priolist.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/err.h" #include "../../utils/attr.h" #include void nn_priolist_init (struct nn_priolist *self) { int i; for (i = 0; i != NN_PRIOLIST_SLOTS; ++i) { nn_list_init (&self->slots [i].pipes); self->slots [i].current = NULL; } self->current = -1; } void nn_priolist_term (struct nn_priolist *self) { int i; for (i = 0; i != NN_PRIOLIST_SLOTS; ++i) nn_list_term (&self->slots [i].pipes); } void nn_priolist_add (NN_UNUSED struct nn_priolist *self, struct nn_priolist_data *data, struct nn_pipe *pipe, int priority) { data->pipe = pipe; data->priority = priority; nn_list_item_init (&data->item); } void nn_priolist_rm (struct nn_priolist *self, struct nn_priolist_data *data) { struct nn_priolist_slot *slot; struct nn_list_item *it; /* Non-active pipes don't need any special processing. */ if (!nn_list_item_isinlist (&data->item)) { nn_list_item_term (&data->item); return; } /* If the pipe being removed is not current, we can simply erase it from the list. */ slot = &self->slots [data->priority - 1]; if (slot->current != data) { nn_list_erase (&slot->pipes, &data->item); nn_list_item_term (&data->item); return; } /* Advance the current pointer (with wrap-over). */ it = nn_list_erase (&slot->pipes, &data->item); slot->current = nn_cont (it, struct nn_priolist_data, item); nn_list_item_term (&data->item); if (!slot->current) { it = nn_list_begin (&slot->pipes); slot->current = nn_cont (it, struct nn_priolist_data, item); } /* If we are not messing with the current slot, we are done. */ if (self->current != data->priority) return; /* Otherwise, the current slot may have become empty and we have switch to lower priority slots. */ while (nn_list_empty (&self->slots [self->current - 1].pipes)) { ++self->current; if (self->current > NN_PRIOLIST_SLOTS) { self->current = -1; return; } } } void nn_priolist_activate (struct nn_priolist *self, struct nn_priolist_data *data) { struct nn_priolist_slot *slot; slot = &self->slots [data->priority - 1]; /* If there are already some elements in this slot, current pipe is not going to change. */ if (!nn_list_empty (&slot->pipes)) { nn_list_insert (&slot->pipes, &data->item, nn_list_end (&slot->pipes)); return; } /* Add first pipe into the slot. If there are no pipes in priolist at all this slot becomes current. */ nn_list_insert (&slot->pipes, &data->item, nn_list_end (&slot->pipes)); slot->current = data; if (self->current == -1) { self->current = data->priority; return; } /* If the current priority is lower than the one of the newly activated pipe, this slot becomes current. */ if (self->current > data->priority) { self->current = data->priority; return; } /* Current doesn't change otherwise. */ } int nn_priolist_is_active (struct nn_priolist *self) { return self->current == -1 ? 0 : 1; } struct nn_pipe *nn_priolist_getpipe (struct nn_priolist *self) { if (nn_slow (self->current == -1)) return NULL; return self->slots [self->current - 1].current->pipe; } void nn_priolist_advance (struct nn_priolist *self, int release) { struct nn_priolist_slot *slot; struct nn_list_item *it; nn_assert (self->current > 0); slot = &self->slots [self->current - 1]; /* Move slot's current pointer to the next pipe. */ if (release) it = nn_list_erase (&slot->pipes, &slot->current->item); else it = nn_list_next (&slot->pipes, &slot->current->item); if (!it) it = nn_list_begin (&slot->pipes); slot->current = nn_cont (it, struct nn_priolist_data, item); /* If there are no more pipes in this slot, find a non-empty slot with lower priority. */ while (nn_list_empty (&slot->pipes)) { ++self->current; if (self->current > NN_PRIOLIST_SLOTS) { self->current = -1; return; } slot = &self->slots [self->current - 1]; } } int nn_priolist_get_priority (struct nn_priolist *self) { return self->current; } nanomsg-1.1.5/src/protocols/utils/priolist.h000066400000000000000000000073171336111550300211570ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_PRIOLIST_INCLUDED #define NN_PRIOLIST_INCLUDED #include "../../protocol.h" #include "../../utils/list.h" /* Prioritised list of pipes. */ #define NN_PRIOLIST_SLOTS 16 struct nn_priolist_data { /* The underlying pipe itself. */ struct nn_pipe *pipe; /* Priority the pipe is assigned. Using this value we can find the nn_priolist_slot object that owns this pipe. */ int priority; /* The structure is a member in nn_priolist_slot's 'pipes' list. */ struct nn_list_item item; }; struct nn_priolist_slot { /* The list of pipes on particular priority level. */ struct nn_list pipes; /* Pointer to the current pipe within the priority level. If there's no pipe available, the field is set to NULL. */ struct nn_priolist_data *current; }; struct nn_priolist { /* Each slot holds pipes for a particular priority level. */ struct nn_priolist_slot slots [NN_PRIOLIST_SLOTS]; /* The index of the slot holding the current pipe. It should be the highest-priority non-empty slot available. If there's no available pipe, this field is set to -1. */ int current; }; /* Initialise the list. */ void nn_priolist_init (struct nn_priolist *self); /* Terminate the list. The list must be empty before it's terminated. */ void nn_priolist_term (struct nn_priolist *self); /* Add a new pipe to the list with a particular priority level. The pipe is not active at this point. Use nn_priolist_activate to activate it. */ void nn_priolist_add (struct nn_priolist *self, struct nn_priolist_data *data, struct nn_pipe *pipe, int priority); /* Remove the pipe from the list. */ void nn_priolist_rm (struct nn_priolist *self, struct nn_priolist_data *data); /* Activates a non-active pipe. The pipe must be added to the list prior to calling this function. */ void nn_priolist_activate (struct nn_priolist *self, struct nn_priolist_data *data); /* Returns 1 if there's at least a single active pipe in the list, 0 otherwise. */ int nn_priolist_is_active (struct nn_priolist *self); /* Get the pointer to the current pipe. If there's no pipe in the list, NULL is returned. */ struct nn_pipe *nn_priolist_getpipe (struct nn_priolist *self); /* Moves to the next pipe in the list. If 'release' is set to 1, the current pipe is removed from the list. To re-insert it into the list use nn_priolist_activate function. */ void nn_priolist_advance (struct nn_priolist *self, int release); /* Returns current priority. Used for statistics only */ int nn_priolist_get_priority (struct nn_priolist *self); #endif nanomsg-1.1.5/src/pubsub.h000066400000000000000000000026521336111550300154230ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef PUBSUB_H_INCLUDED #define PUBSUB_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #define NN_PROTO_PUBSUB 2 #define NN_PUB (NN_PROTO_PUBSUB * 16 + 0) #define NN_SUB (NN_PROTO_PUBSUB * 16 + 1) #define NN_SUB_SUBSCRIBE 1 #define NN_SUB_UNSUBSCRIBE 2 #ifdef __cplusplus } #endif #endif nanomsg-1.1.5/src/reqrep.h000066400000000000000000000030411336111550300154120ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef REQREP_H_INCLUDED #define REQREP_H_INCLUDED #include "nn.h" #ifdef __cplusplus extern "C" { #endif #define NN_PROTO_REQREP 3 #define NN_REQ (NN_PROTO_REQREP * 16 + 0) #define NN_REP (NN_PROTO_REQREP * 16 + 1) #define NN_REQ_RESEND_IVL 1 typedef union nn_req_handle { int i; void *ptr; } nn_req_handle; #ifdef __cplusplus } #endif #endif nanomsg-1.1.5/src/survey.h000066400000000000000000000031161336111550300154540ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2015 Garrett D'Amore 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. */ #ifndef SURVEY_H_INCLUDED #define SURVEY_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #define NN_PROTO_SURVEY 6 /* NB: Version 0 used 16 + 0/1. That version lacked backtraces, and so is wire-incompatible with this version. */ #define NN_SURVEYOR (NN_PROTO_SURVEY * 16 + 2) #define NN_RESPONDENT (NN_PROTO_SURVEY * 16 + 3) #define NN_SURVEYOR_DEADLINE 1 #ifdef __cplusplus } #endif #endif nanomsg-1.1.5/src/tcp.h000066400000000000000000000024501336111550300147050ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef TCP_H_INCLUDED #define TCP_H_INCLUDED #ifdef __cplusplus extern "C" { #endif #define NN_TCP -3 #define NN_TCP_NODELAY 1 #ifdef __cplusplus } #endif #endif nanomsg-1.1.5/src/transport.h000066400000000000000000000212771336111550300161630ustar00rootroot00000000000000/* Copyright (c) 2012-2014 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_TRANSPORT_INCLUDED #define NN_TRANSPORT_INCLUDED #include "nn.h" #include "aio/fsm.h" #include "utils/list.h" #include "utils/msg.h" #include /* This is the API between the nanomsg core and individual transports. */ struct nn_sock; /******************************************************************************/ /* Container for transport-specific socket options. */ /******************************************************************************/ struct nn_optset; struct nn_optset_vfptr { void (*destroy) (struct nn_optset *self); int (*setopt) (struct nn_optset *self, int option, const void *optval, size_t optvallen); int (*getopt) (struct nn_optset *self, int option, void *optval, size_t *optvallen); }; struct nn_optset { const struct nn_optset_vfptr *vfptr; }; /******************************************************************************/ /* The base class for endpoints. */ /******************************************************************************/ /* The best way to think about endpoints is that endpoint is an object created by each nn_bind() or nn_connect() call. Each endpoint is associated with exactly one address string (e.g. "tcp://127.0.0.1:5555"). */ struct nn_ep; struct nn_ep_ops { /* Ask the endpoint to stop itself. The endpoint is allowed to linger to send the pending outbound data. When done, it reports the fact by invoking nn_ep_stopped() function. */ void (*stop) (void *); /* Deallocate the endpoint object. It will already have been stopped. */ void (*destroy) (void *); }; /* Set up an ep for use by a transport. The final opaque argument is passed as the first argument to the ops entry points. */ void nn_ep_tran_setup (struct nn_ep *, const struct nn_ep_ops *, void *); /* Notify the user that stopping is done. */ void nn_ep_stopped (struct nn_ep *); /* Returns the AIO context associated with the endpoint. */ struct nn_ctx *nn_ep_getctx (struct nn_ep *); /* Returns the address string associated with this endpoint. */ const char *nn_ep_getaddr (struct nn_ep *self); /* Retrieve value of a socket option. */ void nn_ep_getopt (struct nn_ep *, int level, int option, void *optval, size_t *optvallen); /* Returns 1 if the specified socket type is a valid peer for this socket, or 0 otherwise. */ int nn_ep_ispeer (struct nn_ep *, int socktype); /* Returns 1 if the ep's are valid peers for each other, 0 otherwise. */ int nn_ep_ispeer_ep (struct nn_ep *, struct nn_ep *); /* Notifies a monitoring system the error on this endpoint */ void nn_ep_set_error(struct nn_ep*, int errnum); /* Notifies a monitoring system that error is gone */ void nn_ep_clear_error(struct nn_ep *); /* Increments statistics counters in the socket structure */ void nn_ep_stat_increment(struct nn_ep *, int name, int increment); /******************************************************************************/ /* The base class for pipes. */ /******************************************************************************/ /* Pipe represents one "connection", i.e. perfectly ordered uni- or bi-directional stream of messages. One endpoint can create multiple pipes (for example, bound TCP socket is an endpoint, individual accepted TCP connections are represented by pipes. */ struct nn_pipebase; /* This value is returned by pipe's send and recv functions to signalise that more sends/recvs are not possible at the moment. From that moment on, the core will stop invoking the function. To re-establish the message flow nn_pipebase_received (respectively nn_pipebase_sent) should be called. */ #define NN_PIPEBASE_RELEASE 1 /* Specifies that received message is already split into header and body. This flag is used only by inproc transport to avoid merging and re-splitting the messages passed with a single process. */ #define NN_PIPEBASE_PARSED 2 struct nn_pipebase_vfptr { /* Send a message to the network. The function can return either error (negative number) or any combination of the flags defined above. */ int (*send) (struct nn_pipebase *self, struct nn_msg *msg); /* Receive a message from the network. The function can return either error (negative number) or any combination of the flags defined above. */ int (*recv) (struct nn_pipebase *self, struct nn_msg *msg); }; /* Endpoint specific options. Same restrictions as for nn_pipebase apply */ struct nn_ep_options { int sndprio; int rcvprio; int ipv4only; }; /* The member of this structure are used internally by the core. Never use or modify them directly from the transport. */ struct nn_pipebase { struct nn_fsm fsm; const struct nn_pipebase_vfptr *vfptr; uint8_t state; uint8_t instate; uint8_t outstate; struct nn_sock *sock; void *data; struct nn_fsm_event in; struct nn_fsm_event out; struct nn_ep_options options; }; /* Initialise the pipe. */ void nn_pipebase_init (struct nn_pipebase *self, const struct nn_pipebase_vfptr *vfptr, struct nn_ep *ep); /* Terminate the pipe. */ void nn_pipebase_term (struct nn_pipebase *self); /* Call this function once the connection is established. */ int nn_pipebase_start (struct nn_pipebase *self); /* Call this function once the connection is broken. */ void nn_pipebase_stop (struct nn_pipebase *self); /* Call this function when new message was fully received. */ void nn_pipebase_received (struct nn_pipebase *self); /* Call this function when current outgoing message was fully sent. */ void nn_pipebase_sent (struct nn_pipebase *self); /* Retrieve value of a socket option. */ void nn_pipebase_getopt (struct nn_pipebase *self, int level, int option, void *optval, size_t *optvallen); /* Returns 1 is the specified socket type is a valid peer for this socket, or 0 otherwise. */ int nn_pipebase_ispeer (struct nn_pipebase *self, int socktype); /******************************************************************************/ /* The transport class. */ /******************************************************************************/ struct nn_transport { /* Name of the transport as it appears in the connection strings ("tcp", "ipc", "inproc" etc. */ const char *name; /* ID of the transport. */ int id; /* Following methods are guarded by a global critical section. Two of these function will never be invoked in parallel. The first is called when the library is initialised, the second one when it is terminated, i.e. when there are no more open sockets. Either of them can be set to NULL if no specific initialisation/termination is needed. */ void (*init) (void); void (*term) (void); /* Each of these functions creates an endpoint and sets up the newly established endpoint in 'ep' parameter using nn_ep_tran_setup (). These functions are guarded by a socket-wide critical section. Two of these function will never be invoked in parallel on the same socket. */ int (*bind) (struct nn_ep *); int (*connect) (struct nn_ep *); /* Create an object to hold transport-specific socket options. Set this member to NULL in case there are no transport-specific socket options available. */ struct nn_optset *(*optset) (void); }; #endif nanomsg-1.1.5/src/transports/000077500000000000000000000000001336111550300161645ustar00rootroot00000000000000nanomsg-1.1.5/src/transports/README000066400000000000000000000001601336111550300170410ustar00rootroot00000000000000This directory contains all the available transport mechanisms such as in-process message transfer, IPC or TCP. nanomsg-1.1.5/src/transports/inproc/000077500000000000000000000000001336111550300174565ustar00rootroot00000000000000nanomsg-1.1.5/src/transports/inproc/binproc.c000066400000000000000000000205141336111550300212600ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "binproc.h" #include "sinproc.h" #include "cinproc.h" #include "ins.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/alloc.h" #define NN_BINPROC_STATE_IDLE 1 #define NN_BINPROC_STATE_ACTIVE 2 #define NN_BINPROC_STATE_STOPPING 3 #define NN_BINPROC_SRC_SINPROC 1 /* Implementation of nn_ep interface. */ static void nn_binproc_stop (void *); static void nn_binproc_destroy (void *); static const struct nn_ep_ops nn_binproc_ops = { nn_binproc_stop, nn_binproc_destroy }; /* Private functions. */ static void nn_binproc_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_binproc_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_binproc_connect (struct nn_ins_item *self, struct nn_ins_item *peer); int nn_binproc_create (struct nn_ep *ep) { int rc; struct nn_binproc *self; self = nn_alloc (sizeof (struct nn_binproc), "binproc"); alloc_assert (self); nn_ins_item_init (&self->item, ep); nn_fsm_init_root (&self->fsm, nn_binproc_handler, nn_binproc_shutdown, nn_ep_getctx (ep)); self->state = NN_BINPROC_STATE_IDLE; nn_list_init (&self->sinprocs); /* Start the state machine. */ nn_fsm_start (&self->fsm); /* Register the inproc endpoint into a global repository. */ rc = nn_ins_bind (&self->item, nn_binproc_connect); if (rc < 0) { nn_list_term (&self->sinprocs); /* TODO: Now, this is ugly! We are getting the state machine into the idle state manually. How should it be done correctly? */ self->fsm.state = 1; nn_fsm_term (&self->fsm); nn_ins_item_term (&self->item); nn_free (self); return rc; } nn_ep_tran_setup (ep, &nn_binproc_ops, self); return 0; } static void nn_binproc_stop (void *self) { struct nn_binproc *binproc = self; nn_fsm_stop (&binproc->fsm); } static void nn_binproc_destroy (void *self) { struct nn_binproc *binproc = self; nn_list_term (&binproc->sinprocs); nn_fsm_term (&binproc->fsm); nn_ins_item_term (&binproc->item); nn_free (binproc); } static void nn_binproc_connect (struct nn_ins_item *self, struct nn_ins_item *peer) { struct nn_binproc *binproc; struct nn_cinproc *cinproc; struct nn_sinproc *sinproc; binproc = nn_cont (self, struct nn_binproc, item); cinproc = nn_cont (peer, struct nn_cinproc, item); nn_assert_state (binproc, NN_BINPROC_STATE_ACTIVE); sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc"); alloc_assert (sinproc); nn_sinproc_init (sinproc, NN_BINPROC_SRC_SINPROC, binproc->item.ep, &binproc->fsm); nn_list_insert (&binproc->sinprocs, &sinproc->item, nn_list_end (&binproc->sinprocs)); nn_sinproc_connect (sinproc, &cinproc->fsm); nn_ep_stat_increment (binproc->item.ep, NN_STAT_ACCEPTED_CONNECTIONS, 1); } static void nn_binproc_shutdown (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_binproc *binproc; struct nn_list_item *it; struct nn_sinproc *sinproc; binproc = nn_cont (self, struct nn_binproc, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { /* First, unregister the endpoint from the global repository of inproc endpoints. This way, new connections cannot be created anymore. */ nn_ins_unbind (&binproc->item); /* Stop the existing connections. */ for (it = nn_list_begin (&binproc->sinprocs); it != nn_list_end (&binproc->sinprocs); it = nn_list_next (&binproc->sinprocs, it)) { sinproc = nn_cont (it, struct nn_sinproc, item); nn_sinproc_stop (sinproc); } binproc->state = NN_BINPROC_STATE_STOPPING; goto finish; } if (binproc->state == NN_BINPROC_STATE_STOPPING) { nn_assert (src == NN_BINPROC_SRC_SINPROC && type == NN_SINPROC_STOPPED); sinproc = (struct nn_sinproc*) srcptr; nn_list_erase (&binproc->sinprocs, &sinproc->item); nn_sinproc_term (sinproc); nn_free (sinproc); finish: if (!nn_list_empty (&binproc->sinprocs)) return; binproc->state = NN_BINPROC_STATE_IDLE; nn_fsm_stopped_noevent (&binproc->fsm); nn_ep_stopped (binproc->item.ep); return; } nn_fsm_bad_state(binproc->state, src, type); } static void nn_binproc_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_binproc *binproc; struct nn_sinproc *peer; struct nn_sinproc *sinproc; binproc = nn_cont (self, struct nn_binproc, fsm); switch (binproc->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_BINPROC_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: binproc->state = NN_BINPROC_STATE_ACTIVE; return; default: nn_fsm_bad_action (binproc->state, src, type); } default: nn_fsm_bad_source (binproc->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_BINPROC_STATE_ACTIVE: switch (src) { case NN_SINPROC_SRC_PEER: switch (type) { case NN_SINPROC_CONNECT: peer = (struct nn_sinproc*) srcptr; sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc"); alloc_assert (sinproc); nn_sinproc_init (sinproc, NN_BINPROC_SRC_SINPROC, binproc->item.ep, &binproc->fsm); nn_list_insert (&binproc->sinprocs, &sinproc->item, nn_list_end (&binproc->sinprocs)); nn_sinproc_accept (sinproc, peer); return; default: nn_fsm_bad_action (binproc->state, src, type); } case NN_BINPROC_SRC_SINPROC: sinproc = srcptr; switch (type) { case NN_SINPROC_STOPPED: nn_list_erase (&binproc->sinprocs, &sinproc->item); nn_sinproc_term (sinproc); nn_free (sinproc); return; case NN_SINPROC_DISCONNECT: nn_sinproc_stop (sinproc); return; } return; default: nn_fsm_bad_source (binproc->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (binproc->state, src, type); } } nanomsg-1.1.5/src/transports/inproc/binproc.h000066400000000000000000000032541336111550300212670ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_BINPROC_INCLUDED #define NN_BINPROC_INCLUDED #include "ins.h" #include "../../transport.h" #include "../../aio/fsm.h" #include "../../utils/list.h" struct nn_cinproc; struct nn_binproc { /* The state machine. */ struct nn_fsm fsm; int state; /* This object is registered with nn_ins. */ struct nn_ins_item item; /* The list of inproc sessions owned by this object. */ struct nn_list sinprocs; }; int nn_binproc_create (struct nn_ep *); #endif nanomsg-1.1.5/src/transports/inproc/cinproc.c000066400000000000000000000202101336111550300212520ustar00rootroot00000000000000 /* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "cinproc.h" #include "binproc.h" #include "ins.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/alloc.h" #include "../../utils/attr.h" #include #define NN_CINPROC_STATE_IDLE 1 #define NN_CINPROC_STATE_ACTIVE 2 #define NN_CINPROC_STATE_STOPPING 3 #define NN_CINPROC_ACTION_CONNECT 1 #define NN_CINPROC_SRC_SINPROC 1 /* Implementation of nn_ep callback interface. */ static void nn_cinproc_stop (void *); static void nn_cinproc_destroy (void *); static const struct nn_ep_ops nn_cinproc_ops = { nn_cinproc_stop, nn_cinproc_destroy }; /* Private functions. */ static void nn_cinproc_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_cinproc_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_cinproc_connect (struct nn_ins_item *self, struct nn_ins_item *peer); int nn_cinproc_create (struct nn_ep *ep) { struct nn_cinproc *self; self = nn_alloc (sizeof (struct nn_cinproc), "cinproc"); alloc_assert (self); nn_ep_tran_setup (ep, &nn_cinproc_ops, self); nn_ins_item_init (&self->item, ep); nn_fsm_init_root (&self->fsm, nn_cinproc_handler, nn_cinproc_shutdown, nn_ep_getctx (ep)); self->state = NN_CINPROC_STATE_IDLE; nn_list_init (&self->sinprocs); nn_ep_stat_increment (ep, NN_STAT_INPROGRESS_CONNECTIONS, 1); /* Start the state machine. */ nn_fsm_start (&self->fsm); /* Register the inproc endpoint into a global repository. */ nn_ins_connect (&self->item, nn_cinproc_connect); return 0; } static void nn_cinproc_stop (void *self) { struct nn_cinproc *cinproc = self; nn_fsm_stop (&cinproc->fsm); } static void nn_cinproc_destroy (void *self) { struct nn_cinproc *cinproc = self; nn_list_term (&cinproc->sinprocs); nn_fsm_term (&cinproc->fsm); nn_ins_item_term (&cinproc->item); nn_free (cinproc); } static void nn_cinproc_connect (struct nn_ins_item *self, struct nn_ins_item *peer) { struct nn_cinproc *cinproc; struct nn_binproc *binproc; struct nn_sinproc *sinproc; cinproc = nn_cont (self, struct nn_cinproc, item); binproc = nn_cont (peer, struct nn_binproc, item); nn_assert_state (cinproc, NN_CINPROC_STATE_ACTIVE); sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc"); alloc_assert (sinproc); nn_sinproc_init (sinproc, NN_CINPROC_SRC_SINPROC, cinproc->item.ep, &cinproc->fsm); nn_list_insert (&cinproc->sinprocs, &sinproc->item, nn_list_end (&cinproc->sinprocs)); nn_sinproc_connect (sinproc, &binproc->fsm); nn_ep_stat_increment (cinproc->item.ep, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_ep_stat_increment (cinproc->item.ep, NN_STAT_ESTABLISHED_CONNECTIONS, 1); } static void nn_cinproc_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_cinproc *cinproc; struct nn_sinproc *sinproc; struct nn_list_item *it; cinproc = nn_cont (self, struct nn_cinproc, fsm); if (src == NN_FSM_ACTION && type == NN_FSM_STOP) { /* First, unregister the endpoint from the global repository of inproc endpoints. This way, new connections cannot be created anymore. */ nn_ins_disconnect (&cinproc->item); /* Stop the existing connection. */ for (it = nn_list_begin (&cinproc->sinprocs); it != nn_list_end (&cinproc->sinprocs); it = nn_list_next (&cinproc->sinprocs, it)) { sinproc = nn_cont (it, struct nn_sinproc, item); nn_sinproc_stop (sinproc); } cinproc->state = NN_CINPROC_STATE_STOPPING; goto finish; } if (cinproc->state == NN_CINPROC_STATE_STOPPING) { sinproc = (struct nn_sinproc *) srcptr; nn_list_erase (&cinproc->sinprocs, &sinproc->item); nn_sinproc_term (sinproc); nn_free (sinproc); finish: if (!nn_list_empty (&cinproc->sinprocs)) return; cinproc->state = NN_CINPROC_STATE_IDLE; nn_fsm_stopped_noevent (&cinproc->fsm); nn_ep_stopped (cinproc->item.ep); return; } nn_fsm_bad_state(cinproc->state, src, type); } static void nn_cinproc_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_cinproc *cinproc; struct nn_sinproc *sinproc; struct nn_sinproc *peer; cinproc = nn_cont (self, struct nn_cinproc, fsm); switch (cinproc->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_CINPROC_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: cinproc->state = NN_CINPROC_STATE_ACTIVE; return; default: nn_fsm_bad_action (cinproc->state, src, type); } default: nn_fsm_bad_source (cinproc->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_CINPROC_STATE_ACTIVE: switch (src) { case NN_SINPROC_SRC_PEER: peer = (struct nn_sinproc*) srcptr; switch (type) { case NN_SINPROC_CONNECT: sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc"); alloc_assert (sinproc); nn_sinproc_init (sinproc, NN_CINPROC_SRC_SINPROC, cinproc->item.ep, &cinproc->fsm); nn_list_insert (&cinproc->sinprocs, &sinproc->item, nn_list_end (&cinproc->sinprocs)); nn_sinproc_accept (sinproc, peer); nn_ep_stat_increment (cinproc->item.ep, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_ep_stat_increment (cinproc->item.ep, NN_STAT_ESTABLISHED_CONNECTIONS, 1); return; default: nn_fsm_bad_action (cinproc->state, src, type); } case NN_CINPROC_SRC_SINPROC: switch (type) { case NN_SINPROC_DISCONNECT: nn_ep_stat_increment (cinproc->item.ep, NN_STAT_INPROGRESS_CONNECTIONS, 1); return; } return; default: nn_fsm_bad_source (cinproc->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (cinproc->state, src, type); } } nanomsg-1.1.5/src/transports/inproc/cinproc.h000066400000000000000000000032271336111550300212700ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_CINPROC_INCLUDED #define NN_CINPROC_INCLUDED #include "ins.h" #include "sinproc.h" #include "../../transport.h" #include "../../aio/fsm.h" #include "../../utils/list.h" struct nn_cinproc { /* The state machine. */ struct nn_fsm fsm; int state; /* This object is registered with nn_ins. */ struct nn_ins_item item; /* The actual inproc session. */ struct nn_list sinprocs; }; int nn_cinproc_create (struct nn_ep *); #endif nanomsg-1.1.5/src/transports/inproc/inproc.c000066400000000000000000000037501336111550300211210ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "ins.h" #include "binproc.h" #include "cinproc.h" #include "../../inproc.h" #include /* nn_transport interface. */ static void nn_inproc_init (void); static void nn_inproc_term (void); static int nn_inproc_bind (struct nn_ep *); static int nn_inproc_connect (struct nn_ep *); struct nn_transport nn_inproc = { "inproc", NN_INPROC, nn_inproc_init, nn_inproc_term, nn_inproc_bind, nn_inproc_connect, NULL, }; static void nn_inproc_init (void) { nn_ins_init (); } static void nn_inproc_term (void) { nn_ins_term (); } static int nn_inproc_bind (struct nn_ep *ep) { return nn_binproc_create (ep); } static int nn_inproc_connect (struct nn_ep *ep) { return nn_cinproc_create (ep); } nanomsg-1.1.5/src/transports/inproc/ins.c000066400000000000000000000120341336111550300204130ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. 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. */ #include "ins.h" #include "../../utils/mutex.h" #include "../../utils/alloc.h" #include "../../utils/list.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/err.h" struct nn_ins { /* Synchronises access to this object. */ struct nn_mutex sync; /* List of all bound inproc endpoints. */ /* TODO: O(n) lookup, shouldn't we do better? Hash? */ struct nn_list bound; /* List of all connected inproc endpoints. */ /* TODO: O(n) lookup, shouldn't we do better? Hash? */ struct nn_list connected; }; /* Global instance of the nn_ins object. It contains the lists of all inproc endpoints in the current process. */ static struct nn_ins self; void nn_ins_item_init (struct nn_ins_item *self, struct nn_ep *ep) { self->ep = ep; nn_list_item_init (&self->item); } void nn_ins_item_term (struct nn_ins_item *self) { nn_list_item_term (&self->item); } void nn_ins_init (void) { nn_mutex_init (&self.sync); nn_list_init (&self.bound); nn_list_init (&self.connected); } void nn_ins_term (void) { nn_list_term (&self.connected); nn_list_term (&self.bound); nn_mutex_term (&self.sync); } int nn_ins_bind (struct nn_ins_item *item, nn_ins_fn fn) { struct nn_list_item *it; struct nn_ins_item *bitem; struct nn_ins_item *citem; nn_mutex_lock (&self.sync); /* Check whether the endpoint isn't already bound. */ /* TODO: This is an O(n) algorithm! */ for (it = nn_list_begin (&self.bound); it != nn_list_end (&self.bound); it = nn_list_next (&self.bound, it)) { bitem = nn_cont (it, struct nn_ins_item, item); if (strncmp (nn_ep_getaddr(bitem->ep), nn_ep_getaddr(item->ep), NN_SOCKADDR_MAX) == 0) { nn_mutex_unlock (&self.sync); return -EADDRINUSE; } } /* Insert the entry into the endpoint repository. */ nn_list_insert (&self.bound, &item->item, nn_list_end (&self.bound)); /* During this process new pipes may be created. */ for (it = nn_list_begin (&self.connected); it != nn_list_end (&self.connected); it = nn_list_next (&self.connected, it)) { citem = nn_cont (it, struct nn_ins_item, item); if (strncmp (nn_ep_getaddr(item->ep), nn_ep_getaddr(citem->ep), NN_SOCKADDR_MAX) == 0) { /* Check whether the two sockets are compatible. */ if (!nn_ep_ispeer_ep (item->ep, citem->ep)) continue; fn (item, citem); } } nn_mutex_unlock (&self.sync); return 0; } void nn_ins_connect (struct nn_ins_item *item, nn_ins_fn fn) { struct nn_list_item *it; struct nn_ins_item *bitem; nn_mutex_lock (&self.sync); /* Insert the entry into the endpoint repository. */ nn_list_insert (&self.connected, &item->item, nn_list_end (&self.connected)); /* During this process a pipe may be created. */ for (it = nn_list_begin (&self.bound); it != nn_list_end (&self.bound); it = nn_list_next (&self.bound, it)) { bitem = nn_cont (it, struct nn_ins_item, item); if (strncmp (nn_ep_getaddr(item->ep), nn_ep_getaddr(bitem->ep), NN_SOCKADDR_MAX) == 0) { /* Check whether the two sockets are compatible. */ if (!nn_ep_ispeer_ep (item->ep, bitem->ep)) break; /* Call back to cinproc to create actual connection. */ fn (item, bitem); break; } } nn_mutex_unlock (&self.sync); } void nn_ins_disconnect (struct nn_ins_item *item) { nn_mutex_lock (&self.sync); nn_list_erase (&self.connected, &item->item); nn_mutex_unlock (&self.sync); } void nn_ins_unbind (struct nn_ins_item *item) { nn_mutex_lock (&self.sync); nn_list_erase (&self.bound, &item->item); nn_mutex_unlock (&self.sync); } nanomsg-1.1.5/src/transports/inproc/ins.h000066400000000000000000000041241336111550300204210ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_INS_INCLUDED #define NN_INS_INCLUDED #include "../../transport.h" #include "../../utils/list.h" /* Inproc naming system. A global repository of inproc endpoints. */ struct nn_ins_item { /* Every ins_item is either in the list of bound or connected endpoints. */ struct nn_list_item item; struct nn_ep *ep; /* This is the local cache of the endpoint's protocol ID. This way we can check the value without actually locking the object. */ int protocol; }; void nn_ins_item_init (struct nn_ins_item *self, struct nn_ep *ep); void nn_ins_item_term (struct nn_ins_item *self); void nn_ins_init (void); void nn_ins_term (void); typedef void (*nn_ins_fn) (struct nn_ins_item *self, struct nn_ins_item *peer); int nn_ins_bind (struct nn_ins_item *item, nn_ins_fn fn); void nn_ins_connect (struct nn_ins_item *item, nn_ins_fn fn); void nn_ins_disconnect (struct nn_ins_item *item); void nn_ins_unbind (struct nn_ins_item *item); #endif nanomsg-1.1.5/src/transports/inproc/msgqueue.c000066400000000000000000000107101336111550300214540ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "msgqueue.h" #include "../../utils/alloc.h" #include "../../utils/fast.h" #include "../../utils/err.h" #include void nn_msgqueue_init (struct nn_msgqueue *self, size_t maxmem) { struct nn_msgqueue_chunk *chunk; self->count = 0; self->mem = 0; self->maxmem = maxmem; chunk = nn_alloc (sizeof (struct nn_msgqueue_chunk), "msgqueue chunk"); alloc_assert (chunk); chunk->next = NULL; self->out.chunk = chunk; self->out.pos = 0; self->in.chunk = chunk; self->in.pos = 0; self->cache = NULL; } void nn_msgqueue_term (struct nn_msgqueue *self) { int rc; struct nn_msg msg; /* Deallocate messages in the pipe. */ while (1) { rc = nn_msgqueue_recv (self, &msg); if (rc == -EAGAIN) break; errnum_assert (rc >= 0, -rc); nn_msg_term (&msg); } /* There are no more messages in the pipe so there's at most one chunk in the queue. Deallocate it. */ nn_assert (self->in.chunk == self->out.chunk); nn_free (self->in.chunk); /* Deallocate the cached chunk, if any. */ if (self->cache) nn_free (self->cache); } int nn_msgqueue_empty (struct nn_msgqueue *self) { return self->count == 0 ? 1 : 0; } int nn_msgqueue_send (struct nn_msgqueue *self, struct nn_msg *msg) { size_t msgsz; /* By allowing one message of arbitrary size to be written to the queue, we allow even messages that exceed max buffer size to pass through. Beyond that we'll apply the buffer limit as specified by the user. */ msgsz = nn_chunkref_size (&msg->sphdr) + nn_chunkref_size (&msg->body); if (nn_slow (self->count > 0 && self->mem + msgsz >= self->maxmem)) return -EAGAIN; /* Adjust the statistics. */ ++self->count; self->mem += msgsz; /* Move the content of the message to the pipe. */ nn_msg_mv (&self->out.chunk->msgs [self->out.pos], msg); ++self->out.pos; /* If there's no space for a new message in the pipe, either re-use the cache chunk or allocate a new chunk if it does not exist. */ if (nn_slow (self->out.pos == NN_MSGQUEUE_GRANULARITY)) { if (nn_slow (!self->cache)) { self->cache = nn_alloc (sizeof (struct nn_msgqueue_chunk), "msgqueue chunk"); alloc_assert (self->cache); self->cache->next = NULL; } self->out.chunk->next = self->cache; self->out.chunk = self->cache; self->cache = NULL; self->out.pos = 0; } return 0; } int nn_msgqueue_recv (struct nn_msgqueue *self, struct nn_msg *msg) { struct nn_msgqueue_chunk *o; /* If there is no message in the queue. */ if (nn_slow (!self->count)) return -EAGAIN; /* Move the message from the pipe to the user. */ nn_msg_mv (msg, &self->in.chunk->msgs [self->in.pos]); /* Move to the next position. */ ++self->in.pos; if (nn_slow (self->in.pos == NN_MSGQUEUE_GRANULARITY)) { o = self->in.chunk; self->in.chunk = self->in.chunk->next; self->in.pos = 0; if (nn_fast (!self->cache)) self->cache = o; else nn_free (o); } /* Adjust the statistics. */ --self->count; self->mem -= (nn_chunkref_size (&msg->sphdr) + nn_chunkref_size (&msg->body)); return 0; } nanomsg-1.1.5/src/transports/inproc/msgqueue.h000066400000000000000000000057201336111550300214660ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_MSGQUEUE_INCLUDED #define NN_MSGQUEUE_INCLUDED #include "../../utils/msg.h" #include /* This class is a simple uni-directional message queue. */ /* It's not 128 so that chunk including its footer fits into a memory page. */ #define NN_MSGQUEUE_GRANULARITY 126 struct nn_msgqueue_chunk { struct nn_msg msgs [NN_MSGQUEUE_GRANULARITY]; struct nn_msgqueue_chunk *next; }; struct nn_msgqueue { /* Pointer to the position where next message should be written into the message queue. */ struct { struct nn_msgqueue_chunk *chunk; int pos; } out; /* Pointer to the first unread message in the message queue. */ struct { struct nn_msgqueue_chunk *chunk; int pos; } in; /* Number of messages in the queue. */ size_t count; /* Amount of memory used by messages in the queue. */ size_t mem; /* Maximal queue size (in bytes). */ size_t maxmem; /* One empty chunk is always cached so that in case of steady stream of messages through the pipe there are no memory allocations. */ struct nn_msgqueue_chunk *cache; }; /* Initialise the message pipe. maxmem is the maximal queue size in bytes. */ void nn_msgqueue_init (struct nn_msgqueue *self, size_t maxmem); /* Terminate the message pipe. */ void nn_msgqueue_term (struct nn_msgqueue *self); /* Returns 1 if there are no messages in the queue, 0 otherwise. */ int nn_msgqueue_empty (struct nn_msgqueue *self); /* Writes a message to the pipe. -EAGAIN is returned if the message cannot be sent because the queue is full. */ int nn_msgqueue_send (struct nn_msgqueue *self, struct nn_msg *msg); /* Reads a message from the pipe. -EAGAIN is returned if there's no message to receive. */ int nn_msgqueue_recv (struct nn_msgqueue *self, struct nn_msg *msg); #endif nanomsg-1.1.5/src/transports/inproc/sinproc.c000066400000000000000000000432261336111550300213060ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #include "sinproc.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/attr.h" #include #define NN_SINPROC_STATE_IDLE 1 #define NN_SINPROC_STATE_CONNECTING 2 #define NN_SINPROC_STATE_READY 3 #define NN_SINPROC_STATE_ACTIVE 4 #define NN_SINPROC_STATE_DISCONNECTED 5 #define NN_SINPROC_STATE_STOPPING_PEER 6 #define NN_SINPROC_STATE_STOPPING 7 #define NN_SINPROC_ACTION_READY 1 #define NN_SINPROC_ACTION_ACCEPTED 2 /* Set when SENT event was sent to the peer but RECEIVED haven't been passed back yet. */ #define NN_SINPROC_FLAG_SENDING 1 /* Set when SENT event was received, but the new message cannot be written to the queue yet, i.e. RECEIVED event haven't been returned to the peer yet. */ #define NN_SINPROC_FLAG_RECEIVING 2 /* Private functions. */ static void nn_sinproc_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_sinproc_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static int nn_sinproc_send (struct nn_pipebase *self, struct nn_msg *msg); static int nn_sinproc_recv (struct nn_pipebase *self, struct nn_msg *msg); const struct nn_pipebase_vfptr nn_sinproc_pipebase_vfptr = { nn_sinproc_send, nn_sinproc_recv }; void nn_sinproc_init (struct nn_sinproc *self, int src, struct nn_ep *ep, struct nn_fsm *owner) { int rcvbuf; size_t sz; nn_fsm_init (&self->fsm, nn_sinproc_handler, nn_sinproc_shutdown, src, self, owner); self->state = NN_SINPROC_STATE_IDLE; self->flags = 0; self->peer = NULL; nn_pipebase_init (&self->pipebase, &nn_sinproc_pipebase_vfptr, ep); sz = sizeof (rcvbuf); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RCVBUF, &rcvbuf, &sz); nn_assert (sz == sizeof (rcvbuf)); nn_msgqueue_init (&self->msgqueue, rcvbuf); nn_msg_init (&self->msg, 0); nn_fsm_event_init (&self->event_connect); nn_fsm_event_init (&self->event_sent); nn_fsm_event_init (&self->event_received); nn_fsm_event_init (&self->event_disconnect); nn_list_item_init (&self->item); } void nn_sinproc_term (struct nn_sinproc *self) { nn_list_item_term (&self->item); nn_fsm_event_term (&self->event_disconnect); nn_fsm_event_term (&self->event_received); nn_fsm_event_term (&self->event_sent); nn_fsm_event_term (&self->event_connect); nn_msg_term (&self->msg); nn_msgqueue_term (&self->msgqueue); nn_pipebase_term (&self->pipebase); nn_fsm_term (&self->fsm); } int nn_sinproc_isidle (struct nn_sinproc *self) { return nn_fsm_isidle (&self->fsm); } void nn_sinproc_connect (struct nn_sinproc *self, struct nn_fsm *peer) { nn_fsm_start (&self->fsm); /* Start the connecting handshake with the peer. */ nn_fsm_raiseto (&self->fsm, peer, &self->event_connect, NN_SINPROC_SRC_PEER, NN_SINPROC_CONNECT, self); } void nn_sinproc_accept (struct nn_sinproc *self, struct nn_sinproc *peer) { nn_assert (!self->peer); self->peer = peer; /* Start the connecting handshake with the peer. */ nn_fsm_raiseto (&self->fsm, &peer->fsm, &self->event_connect, NN_SINPROC_SRC_PEER, NN_SINPROC_READY, self); /* Notify the state machine. */ nn_fsm_start (&self->fsm); nn_fsm_action (&self->fsm, NN_SINPROC_ACTION_READY); } void nn_sinproc_stop (struct nn_sinproc *self) { nn_fsm_stop (&self->fsm); } static int nn_sinproc_send (struct nn_pipebase *self, struct nn_msg *msg) { struct nn_sinproc *sinproc; struct nn_msg nmsg; sinproc = nn_cont (self, struct nn_sinproc, pipebase); /* If the peer have already closed the connection, we cannot send anymore. */ if (sinproc->state == NN_SINPROC_STATE_DISCONNECTED) return -ECONNRESET; /* Sanity checks. */ nn_assert_state (sinproc, NN_SINPROC_STATE_ACTIVE); nn_assert (!(sinproc->flags & NN_SINPROC_FLAG_SENDING)); nn_msg_init (&nmsg, nn_chunkref_size (&msg->sphdr) + nn_chunkref_size (&msg->body)); memcpy (nn_chunkref_data (&nmsg.body), nn_chunkref_data (&msg->sphdr), nn_chunkref_size (&msg->sphdr)); memcpy ((char *)nn_chunkref_data (&nmsg.body) + nn_chunkref_size (&msg->sphdr), nn_chunkref_data (&msg->body), nn_chunkref_size (&msg->body)); nn_msg_term (msg); /* Expose the message to the peer. */ nn_msg_term (&sinproc->msg); nn_msg_mv (&sinproc->msg, &nmsg); /* Notify the peer that there's a message to get. */ sinproc->flags |= NN_SINPROC_FLAG_SENDING; nn_fsm_raiseto (&sinproc->fsm, &sinproc->peer->fsm, &sinproc->peer->event_sent, NN_SINPROC_SRC_PEER, NN_SINPROC_SENT, sinproc); return 0; } static int nn_sinproc_recv (struct nn_pipebase *self, struct nn_msg *msg) { int rc; struct nn_sinproc *sinproc; sinproc = nn_cont (self, struct nn_sinproc, pipebase); /* Sanity check. */ nn_assert (sinproc->state == NN_SINPROC_STATE_ACTIVE || sinproc->state == NN_SINPROC_STATE_DISCONNECTED); /* Move the message to the caller. */ rc = nn_msgqueue_recv (&sinproc->msgqueue, msg); errnum_assert (rc == 0, -rc); /* If there was a message from peer lingering because of the exceeded buffer limit, try to enqueue it once again. */ if (sinproc->state != NN_SINPROC_STATE_DISCONNECTED) { if (nn_slow (sinproc->flags & NN_SINPROC_FLAG_RECEIVING)) { rc = nn_msgqueue_send (&sinproc->msgqueue, &sinproc->peer->msg); nn_assert (rc == 0 || rc == -EAGAIN); if (rc == 0) { errnum_assert (rc == 0, -rc); nn_msg_init (&sinproc->peer->msg, 0); nn_fsm_raiseto (&sinproc->fsm, &sinproc->peer->fsm, &sinproc->peer->event_received, NN_SINPROC_SRC_PEER, NN_SINPROC_RECEIVED, sinproc); sinproc->flags &= ~NN_SINPROC_FLAG_RECEIVING; } } } if (!nn_msgqueue_empty (&sinproc->msgqueue)) nn_pipebase_received (&sinproc->pipebase); return 0; } static void nn_sinproc_shutdown_events (struct nn_sinproc *self, int src, int type, NN_UNUSED void *srcptr) { /* ******************************* */ /* Any-state events */ /* ******************************* */ switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_STOP: if (self->state != NN_SINPROC_STATE_IDLE && self->state != NN_SINPROC_STATE_DISCONNECTED) { nn_pipebase_stop (&self->pipebase); nn_assert (self->fsm.state == 2 || self->fsm.state == 3); nn_fsm_raiseto (&self->fsm, &self->peer->fsm, &self->peer->event_disconnect, NN_SINPROC_SRC_PEER, NN_SINPROC_DISCONNECT, self); self->state = NN_SINPROC_STATE_STOPPING_PEER; } else { self->state = NN_SINPROC_STATE_STOPPING; } return; default: break; } case NN_SINPROC_SRC_PEER: switch (type) { case NN_SINPROC_RECEIVED: return; } } /* ******************************* */ /* Regular events */ /* ******************************* */ switch (self->state) { case NN_SINPROC_STATE_STOPPING_PEER: switch (src) { case NN_SINPROC_SRC_PEER: switch (type) { case NN_SINPROC_DISCONNECT: self->state = NN_SINPROC_STATE_STOPPING; return; default: /* We could get a notification about state that was queued earlier, or about a sent message. We do not care about those anymore, we're closing! */ return; } default: nn_fsm_bad_source (self->state, src, type); } default: nn_fsm_bad_state (self->state, src, type); } nn_fsm_bad_action (self->state, src, type); } static void nn_sinproc_shutdown (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_sinproc *sinproc; sinproc = nn_cont (self, struct nn_sinproc, fsm); nn_assert (sinproc->fsm.state == 3); nn_sinproc_shutdown_events (sinproc, src, type, srcptr); /* *************** */ /* States to check */ /* *************** */ /* Have we got notification that peer is stopped */ if (nn_slow (sinproc->state != NN_SINPROC_STATE_STOPPING)) { return; } /* Are all events processed? We can't cancel them unfortunately */ if (nn_fsm_event_active (&sinproc->event_received) || nn_fsm_event_active (&sinproc->event_disconnect)) { return; } /* These events are deemed to be impossible here */ nn_assert (!nn_fsm_event_active (&sinproc->event_connect)); nn_assert (!nn_fsm_event_active (&sinproc->event_sent)); /* ********************************************** */ /* All checks are successful. Just stop right now */ /* ********************************************** */ nn_fsm_stopped (&sinproc->fsm, NN_SINPROC_STOPPED); return; } static void nn_sinproc_handler (struct nn_fsm *self, int src, int type, void *srcptr) { int rc; struct nn_sinproc *sinproc; int empty; sinproc = nn_cont (self, struct nn_sinproc, fsm); switch (sinproc->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_SINPROC_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: sinproc->state = NN_SINPROC_STATE_CONNECTING; return; default: nn_fsm_bad_action (sinproc->state, src, type); } default: nn_fsm_bad_source (sinproc->state, src, type); } /******************************************************************************/ /* CONNECTING state. */ /* CONNECT request was sent to the peer. Now we are waiting for the */ /* acknowledgement. */ /******************************************************************************/ case NN_SINPROC_STATE_CONNECTING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_SINPROC_ACTION_READY: sinproc->state = NN_SINPROC_STATE_READY; return; default: nn_fsm_bad_action (sinproc->state, src, type); } case NN_SINPROC_SRC_PEER: switch (type) { case NN_SINPROC_READY: sinproc->peer = (struct nn_sinproc*) srcptr; rc = nn_pipebase_start (&sinproc->pipebase); errnum_assert (rc == 0, -rc); sinproc->state = NN_SINPROC_STATE_ACTIVE; nn_fsm_raiseto (&sinproc->fsm, &sinproc->peer->fsm, &sinproc->event_connect, NN_SINPROC_SRC_PEER, NN_SINPROC_ACCEPTED, self); return; default: nn_fsm_bad_action (sinproc->state, src, type); } default: nn_fsm_bad_source (sinproc->state, src, type); } /******************************************************************************/ /* READY state. */ /* */ /******************************************************************************/ case NN_SINPROC_STATE_READY: switch (src) { case NN_SINPROC_SRC_PEER: switch (type) { case NN_SINPROC_READY: /* This means both peers sent READY so they are both ready for receiving messages */ rc = nn_pipebase_start (&sinproc->pipebase); errnum_assert (rc == 0, -rc); sinproc->state = NN_SINPROC_STATE_ACTIVE; return; case NN_SINPROC_ACCEPTED: rc = nn_pipebase_start (&sinproc->pipebase); /* We can fail this due to excl_add saying we are already connected. */ if (rc != 0) { nn_pipebase_stop (&sinproc->pipebase); sinproc->state = NN_SINPROC_STATE_DISCONNECTED; sinproc->peer = NULL; nn_fsm_raise (&sinproc->fsm, &sinproc->event_disconnect, NN_SINPROC_DISCONNECT); return; } errnum_assert (rc == 0, -rc); sinproc->state = NN_SINPROC_STATE_ACTIVE; return; default: nn_fsm_bad_action (sinproc->state, src, type); } default: nn_fsm_bad_source (sinproc->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_SINPROC_STATE_ACTIVE: switch (src) { case NN_SINPROC_SRC_PEER: switch (type) { case NN_SINPROC_SENT: empty = nn_msgqueue_empty (&sinproc->msgqueue); /* Push the message to the inbound message queue. */ rc = nn_msgqueue_send (&sinproc->msgqueue, &sinproc->peer->msg); if (rc == -EAGAIN) { sinproc->flags |= NN_SINPROC_FLAG_RECEIVING; return; } errnum_assert (rc == 0, -rc); nn_msg_init (&sinproc->peer->msg, 0); /* Notify the user that there's a message to receive. */ if (empty) nn_pipebase_received (&sinproc->pipebase); /* Notify the peer that the message was received. */ nn_fsm_raiseto (&sinproc->fsm, &sinproc->peer->fsm, &sinproc->peer->event_received, NN_SINPROC_SRC_PEER, NN_SINPROC_RECEIVED, sinproc); return; case NN_SINPROC_RECEIVED: nn_assert (sinproc->flags & NN_SINPROC_FLAG_SENDING); nn_pipebase_sent (&sinproc->pipebase); sinproc->flags &= ~NN_SINPROC_FLAG_SENDING; return; case NN_SINPROC_DISCONNECT: nn_pipebase_stop (&sinproc->pipebase); nn_fsm_raiseto (&sinproc->fsm, &sinproc->peer->fsm, &sinproc->peer->event_disconnect, NN_SINPROC_SRC_PEER, NN_SINPROC_DISCONNECT, sinproc); sinproc->state = NN_SINPROC_STATE_DISCONNECTED; sinproc->peer = NULL; nn_fsm_raise (&sinproc->fsm, &sinproc->event_disconnect, NN_SINPROC_DISCONNECT); return; default: nn_fsm_bad_action (sinproc->state, src, type); } default: nn_fsm_bad_source (sinproc->state, src, type); } /******************************************************************************/ /* DISCONNECTED state. */ /* The peer have already closed the connection, but the object was not yet */ /* asked to stop. */ /******************************************************************************/ case NN_SINPROC_STATE_DISCONNECTED: switch (src) { case NN_SINPROC_SRC_PEER: switch (type) { case NN_SINPROC_RECEIVED: /* This case can safely be ignored. It may happen when nn_close() comes before the already enqueued NN_SINPROC_RECEIVED has been delivered. */ return; default: nn_fsm_bad_action (sinproc->state, src, type); }; default: nn_fsm_bad_source (sinproc->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (sinproc->state, src, type); } } nanomsg-1.1.5/src/transports/inproc/sinproc.h000066400000000000000000000065531336111550300213150ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_SINPROC_INCLUDED #define NN_SINPROC_INCLUDED #include "msgqueue.h" #include "../../transport.h" #include "../../aio/fsm.h" #include "../../utils/msg.h" #include "../../utils/list.h" #define NN_SINPROC_CONNECT 1 #define NN_SINPROC_READY 2 #define NN_SINPROC_ACCEPTED 3 #define NN_SINPROC_SENT 4 #define NN_SINPROC_RECEIVED 5 #define NN_SINPROC_DISCONNECT 6 #define NN_SINPROC_STOPPED 7 /* We use a random value here to prevent accidental clashes with the peer's internal source IDs. */ #define NN_SINPROC_SRC_PEER 27713 struct nn_sinproc { /* The state machine. */ struct nn_fsm fsm; int state; /* Any combination of the flags defined in the .c file. */ int flags; /* Pointer to the peer inproc session, if connected. NULL otherwise. */ struct nn_sinproc *peer; /* Pipe connecting this inproc connection to the nanomsg core. */ struct nn_pipebase pipebase; /* Inbound message queue. The messages contained are meant to be received by the user later on. */ struct nn_msgqueue msgqueue; /* This message is the one being sent from this session to the peer session. It holds the data only temporarily, until the peer moves it to its msgqueue. */ struct nn_msg msg; /* Outbound events. I.e. event sent by this sinproc to the peer sinproc. */ struct nn_fsm_event event_connect; /* Inbound events. I.e. events sent by the peer sinproc to this inproc. */ struct nn_fsm_event event_sent; struct nn_fsm_event event_received; struct nn_fsm_event event_disconnect; /* This member is used only if we are on the bound side. binproc object has a list of sinprocs it handles. */ struct nn_list_item item; }; void nn_sinproc_init (struct nn_sinproc *self, int src, struct nn_ep *ep, struct nn_fsm *owner); void nn_sinproc_term (struct nn_sinproc *self); int nn_sinproc_isidle (struct nn_sinproc *self); /* Connect and accept are two different ways to start the state machine. */ void nn_sinproc_connect (struct nn_sinproc *self, struct nn_fsm *peer); void nn_sinproc_accept (struct nn_sinproc *self, struct nn_sinproc *peer); void nn_sinproc_stop (struct nn_sinproc *self); #endif nanomsg-1.1.5/src/transports/ipc/000077500000000000000000000000001336111550300167375ustar00rootroot00000000000000nanomsg-1.1.5/src/transports/ipc/aipc.c000066400000000000000000000256361336111550300200330ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "aipc.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/attr.h" #define NN_AIPC_STATE_IDLE 1 #define NN_AIPC_STATE_ACCEPTING 2 #define NN_AIPC_STATE_ACTIVE 3 #define NN_AIPC_STATE_STOPPING_SIPC 4 #define NN_AIPC_STATE_STOPPING_USOCK 5 #define NN_AIPC_STATE_DONE 6 #define NN_AIPC_STATE_STOPPING_SIPC_FINAL 7 #define NN_AIPC_STATE_STOPPING 8 #define NN_AIPC_SRC_USOCK 1 #define NN_AIPC_SRC_SIPC 2 #define NN_AIPC_SRC_LISTENER 3 /* Private functions. */ static void nn_aipc_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_aipc_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); void nn_aipc_init (struct nn_aipc *self, int src, struct nn_ep *ep, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_aipc_handler, nn_aipc_shutdown, src, self, owner); self->state = NN_AIPC_STATE_IDLE; self->ep = ep; nn_usock_init (&self->usock, NN_AIPC_SRC_USOCK, &self->fsm); self->listener = NULL; self->listener_owner.src = -1; self->listener_owner.fsm = NULL; nn_sipc_init (&self->sipc, NN_AIPC_SRC_SIPC, ep, &self->fsm); nn_fsm_event_init (&self->accepted); nn_fsm_event_init (&self->done); nn_list_item_init (&self->item); } void nn_aipc_term (struct nn_aipc *self) { nn_assert_state (self, NN_AIPC_STATE_IDLE); nn_list_item_term (&self->item); nn_fsm_event_term (&self->done); nn_fsm_event_term (&self->accepted); nn_sipc_term (&self->sipc); nn_usock_term (&self->usock); nn_fsm_term (&self->fsm); } int nn_aipc_isidle (struct nn_aipc *self) { return nn_fsm_isidle (&self->fsm); } void nn_aipc_start (struct nn_aipc *self, struct nn_usock *listener) { #if defined NN_HAVE_WINDOWS size_t sz; #endif nn_assert_state (self, NN_AIPC_STATE_IDLE); /* Take ownership of the listener socket. */ self->listener = listener; self->listener_owner.src = NN_AIPC_SRC_LISTENER; self->listener_owner.fsm = &self->fsm; nn_usock_swap_owner (listener, &self->listener_owner); #if defined NN_HAVE_WINDOWS /* Get/Set security attribute pointer*/ nn_ep_getopt (self->ep, NN_IPC, NN_IPC_SEC_ATTR, &self->usock.sec_attr, &sz); nn_ep_getopt (self->ep, NN_IPC, NN_IPC_OUTBUFSZ, &self->usock.outbuffersz, &sz); nn_ep_getopt (self->ep, NN_IPC, NN_IPC_INBUFSZ, &self->usock.inbuffersz, &sz); #endif /* Start the state machine. */ nn_fsm_start (&self->fsm); } void nn_aipc_stop (struct nn_aipc *self) { nn_fsm_stop (&self->fsm); } static void nn_aipc_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_aipc *aipc; aipc = nn_cont (self, struct nn_aipc, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (!nn_sipc_isidle (&aipc->sipc)) { nn_ep_stat_increment (aipc->ep, NN_STAT_DROPPED_CONNECTIONS, 1); nn_sipc_stop (&aipc->sipc); } aipc->state = NN_AIPC_STATE_STOPPING_SIPC_FINAL; } if (nn_slow (aipc->state == NN_AIPC_STATE_STOPPING_SIPC_FINAL)) { if (!nn_sipc_isidle (&aipc->sipc)) return; nn_usock_stop (&aipc->usock); aipc->state = NN_AIPC_STATE_STOPPING; } if (nn_slow (aipc->state == NN_AIPC_STATE_STOPPING)) { if (!nn_usock_isidle (&aipc->usock)) return; if (aipc->listener) { nn_assert (aipc->listener_owner.fsm); nn_usock_swap_owner (aipc->listener, &aipc->listener_owner); aipc->listener = NULL; aipc->listener_owner.src = -1; aipc->listener_owner.fsm = NULL; } aipc->state = NN_AIPC_STATE_IDLE; nn_fsm_stopped (&aipc->fsm, NN_AIPC_STOPPED); return; } nn_fsm_bad_state(aipc->state, src, type); } static void nn_aipc_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_aipc *aipc; int val; size_t sz; aipc = nn_cont (self, struct nn_aipc, fsm); switch (aipc->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_AIPC_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_usock_accept (&aipc->usock, aipc->listener); aipc->state = NN_AIPC_STATE_ACCEPTING; return; default: nn_fsm_bad_action (aipc->state, src, type); } default: nn_fsm_bad_source (aipc->state, src, type); } /******************************************************************************/ /* ACCEPTING state. */ /* Waiting for incoming connection. */ /******************************************************************************/ case NN_AIPC_STATE_ACCEPTING: switch (src) { case NN_AIPC_SRC_USOCK: switch (type) { case NN_USOCK_ACCEPTED: nn_ep_clear_error (aipc->ep); /* Set the relevant socket options. */ sz = sizeof (val); nn_ep_getopt (aipc->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&aipc->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_ep_getopt (aipc->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&aipc->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); /* Return ownership of the listening socket to the parent. */ nn_usock_swap_owner (aipc->listener, &aipc->listener_owner); aipc->listener = NULL; aipc->listener_owner.src = -1; aipc->listener_owner.fsm = NULL; nn_fsm_raise (&aipc->fsm, &aipc->accepted, NN_AIPC_ACCEPTED); /* Start the sipc state machine. */ nn_usock_activate (&aipc->usock); nn_sipc_start (&aipc->sipc, &aipc->usock); aipc->state = NN_AIPC_STATE_ACTIVE; nn_ep_stat_increment (aipc->ep, NN_STAT_ACCEPTED_CONNECTIONS, 1); return; default: nn_fsm_bad_action (aipc->state, src, type); } case NN_AIPC_SRC_LISTENER: switch (type) { case NN_USOCK_ACCEPT_ERROR: nn_ep_set_error (aipc->ep, nn_usock_geterrno (aipc->listener)); nn_ep_stat_increment (aipc->ep, NN_STAT_ACCEPT_ERRORS, 1); nn_usock_accept (&aipc->usock, aipc->listener); return; default: nn_fsm_bad_action (aipc->state, src, type); } default: nn_fsm_bad_source (aipc->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_AIPC_STATE_ACTIVE: switch (src) { case NN_AIPC_SRC_SIPC: switch (type) { case NN_SIPC_ERROR: nn_sipc_stop (&aipc->sipc); aipc->state = NN_AIPC_STATE_STOPPING_SIPC; nn_ep_stat_increment (aipc->ep, NN_STAT_BROKEN_CONNECTIONS, 1); return; default: nn_fsm_bad_action (aipc->state, src, type); } default: nn_fsm_bad_source (aipc->state, src, type); } /******************************************************************************/ /* STOPPING_SIPC state. */ /******************************************************************************/ case NN_AIPC_STATE_STOPPING_SIPC: switch (src) { case NN_AIPC_SRC_SIPC: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_SIPC_STOPPED: nn_usock_stop (&aipc->usock); aipc->state = NN_AIPC_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (aipc->state, src, type); } default: nn_fsm_bad_source (aipc->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /******************************************************************************/ case NN_AIPC_STATE_STOPPING_USOCK: switch (src) { case NN_AIPC_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: nn_fsm_raise (&aipc->fsm, &aipc->done, NN_AIPC_ERROR); aipc->state = NN_AIPC_STATE_DONE; return; default: nn_fsm_bad_action (aipc->state, src, type); } default: nn_fsm_bad_source (aipc->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (aipc->state, src, type); } } nanomsg-1.1.5/src/transports/ipc/aipc.h000066400000000000000000000052631336111550300200320ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_AIPC_INCLUDED #define NN_AIPC_INCLUDED #include "sipc.h" #include "../../transport.h" #include "../../ipc.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../../utils/list.h" /* State machine handling accepted IPC sockets. */ /* In bipc, some events are just *assumed* to come from a child aipc object. By using non-trivial event codes, we can do more reliable sanity checking in such scenarios. */ #define NN_AIPC_ACCEPTED 34231 #define NN_AIPC_ERROR 34232 #define NN_AIPC_STOPPED 34233 struct nn_aipc { /* The state machine. */ struct nn_fsm fsm; int state; /* Pointer to the associated endpoint. */ struct nn_ep *ep; /* Underlying socket. */ struct nn_usock usock; /* Listening socket. Valid only while accepting new connection. */ struct nn_usock *listener; struct nn_fsm_owner listener_owner; /* State machine that takes care of the connection in the active state. */ struct nn_sipc sipc; /* Events generated by aipc state machine. */ struct nn_fsm_event accepted; struct nn_fsm_event done; /* This member can be used by owner to keep individual aipcs in a list. */ struct nn_list_item item; }; void nn_aipc_init (struct nn_aipc *self, int src, struct nn_ep *ep, struct nn_fsm *owner); void nn_aipc_term (struct nn_aipc *self); int nn_aipc_isidle (struct nn_aipc *self); void nn_aipc_start (struct nn_aipc *self, struct nn_usock *listener); void nn_aipc_stop (struct nn_aipc *self); #endif nanomsg-1.1.5/src/transports/ipc/bipc.c000066400000000000000000000251041336111550300200220ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Franklin "Snaipe" Mathieu Copyright 2016 Garrett D'Amore 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. */ #include "bipc.h" #include "aipc.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/alloc.h" #include "../../utils/list.h" #include "../../utils/fast.h" #include #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #include #include #endif #define NN_BIPC_BACKLOG 10 #define NN_BIPC_STATE_IDLE 1 #define NN_BIPC_STATE_ACTIVE 2 #define NN_BIPC_STATE_STOPPING_AIPC 3 #define NN_BIPC_STATE_STOPPING_USOCK 4 #define NN_BIPC_STATE_STOPPING_AIPCS 5 #define NN_BIPC_SRC_USOCK 1 #define NN_BIPC_SRC_AIPC 2 struct nn_bipc { /* The state machine. */ struct nn_fsm fsm; int state; struct nn_ep *ep; /* The underlying listening IPC socket. */ struct nn_usock usock; /* The connection being accepted at the moment. */ struct nn_aipc *aipc; /* List of accepted connections. */ struct nn_list aipcs; }; /* nn_ep virtual interface implementation. */ static void nn_bipc_stop (void *self); static void nn_bipc_destroy (void *self); const struct nn_ep_ops nn_bipc_ep_ops = { nn_bipc_stop, nn_bipc_destroy }; /* Private functions. */ static void nn_bipc_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_bipc_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static int nn_bipc_listen (struct nn_bipc *self); static void nn_bipc_start_accepting (struct nn_bipc *self); int nn_bipc_create (struct nn_ep *ep) { struct nn_bipc *self; int rc; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_bipc), "bipc"); alloc_assert (self); /* Initialise the structure. */ self->ep = ep; nn_ep_tran_setup (ep, &nn_bipc_ep_ops, self); nn_fsm_init_root (&self->fsm, nn_bipc_handler, nn_bipc_shutdown, nn_ep_getctx (ep)); self->state = NN_BIPC_STATE_IDLE; self->aipc = NULL; nn_list_init (&self->aipcs); /* Start the state machine. */ nn_fsm_start (&self->fsm); nn_usock_init (&self->usock, NN_BIPC_SRC_USOCK, &self->fsm); rc = nn_bipc_listen (self); if (rc != 0) { return rc; } return 0; } static void nn_bipc_stop (void *self) { struct nn_bipc *bipc = self; nn_fsm_stop (&bipc->fsm); } static void nn_bipc_destroy (void *self) { struct nn_bipc *bipc = self; nn_assert_state (bipc, NN_BIPC_STATE_IDLE); nn_list_term (&bipc->aipcs); nn_assert (bipc->aipc == NULL); nn_usock_term (&bipc->usock); nn_fsm_term (&bipc->fsm); nn_free (bipc); } static void nn_bipc_shutdown (struct nn_fsm *self, int src, int type, void *srcptr) { #if defined NN_HAVE_UNIX_SOCKETS const char *addr; int rc; #endif struct nn_bipc *bipc; struct nn_list_item *it; struct nn_aipc *aipc; bipc = nn_cont (self, struct nn_bipc, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (bipc->aipc) { nn_aipc_stop (bipc->aipc); bipc->state = NN_BIPC_STATE_STOPPING_AIPC; } else { bipc->state = NN_BIPC_STATE_STOPPING_USOCK; } } if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_AIPC)) { if (!nn_aipc_isidle (bipc->aipc)) return; nn_aipc_term (bipc->aipc); nn_free (bipc->aipc); bipc->aipc = NULL; /* On *nixes, unlink the domain socket file */ #if defined NN_HAVE_UNIX_SOCKETS addr = nn_ep_getaddr (bipc->ep); rc = unlink(addr); errno_assert (rc == 0 || errno == ENOENT); #endif nn_usock_stop (&bipc->usock); bipc->state = NN_BIPC_STATE_STOPPING_USOCK; } if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_USOCK)) { if (!nn_usock_isidle (&bipc->usock)) return; for (it = nn_list_begin (&bipc->aipcs); it != nn_list_end (&bipc->aipcs); it = nn_list_next (&bipc->aipcs, it)) { aipc = nn_cont (it, struct nn_aipc, item); nn_aipc_stop (aipc); } bipc->state = NN_BIPC_STATE_STOPPING_AIPCS; goto aipcs_stopping; } if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_AIPCS)) { nn_assert (src == NN_BIPC_SRC_AIPC && type == NN_AIPC_STOPPED); aipc = (struct nn_aipc *) srcptr; nn_list_erase (&bipc->aipcs, &aipc->item); nn_aipc_term (aipc); nn_free (aipc); /* If there are no more aipc state machines, we can stop the whole bipc object. */ aipcs_stopping: if (nn_list_empty (&bipc->aipcs)) { bipc->state = NN_BIPC_STATE_IDLE; nn_fsm_stopped_noevent (&bipc->fsm); nn_ep_stopped (bipc->ep); return; } return; } nn_fsm_bad_state(bipc->state, src, type); } static void nn_bipc_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_bipc *bipc; struct nn_aipc *aipc; bipc = nn_cont (self, struct nn_bipc, fsm); switch (bipc->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_BIPC_STATE_IDLE: nn_assert (src == NN_FSM_ACTION); nn_assert (type == NN_FSM_START); bipc->state = NN_BIPC_STATE_ACTIVE; return; /******************************************************************************/ /* ACTIVE state. */ /* The execution is yielded to the aipc state machine in this state. */ /******************************************************************************/ case NN_BIPC_STATE_ACTIVE: if (src == NN_BIPC_SRC_USOCK) { nn_assert (type == NN_USOCK_SHUTDOWN || type == NN_USOCK_STOPPED); return; } /* All other events come from child aipc objects. */ nn_assert (src == NN_BIPC_SRC_AIPC); aipc = (struct nn_aipc*) srcptr; switch (type) { case NN_AIPC_ACCEPTED: nn_list_insert (&bipc->aipcs, &aipc->item, nn_list_end (&bipc->aipcs)); bipc->aipc = NULL; nn_bipc_start_accepting (bipc); return; case NN_AIPC_ERROR: nn_aipc_stop (aipc); return; case NN_AIPC_STOPPED: nn_list_erase (&bipc->aipcs, &aipc->item); nn_aipc_term (aipc); nn_free (aipc); return; default: nn_fsm_bad_action (bipc->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (bipc->state, src, type); } } static int nn_bipc_listen (struct nn_bipc *self) { int rc; struct sockaddr_storage ss; struct sockaddr_un *un; const char *addr; #if defined NN_HAVE_UNIX_SOCKETS int fd; #endif /* First, create the AF_UNIX address. */ addr = nn_ep_getaddr (self->ep); memset (&ss, 0, sizeof (ss)); un = (struct sockaddr_un*) &ss; nn_assert (strlen (addr) < sizeof (un->sun_path)); ss.ss_family = AF_UNIX; strncpy (un->sun_path, addr, sizeof (un->sun_path)); /* Delete the IPC file left over by eventual previous runs of the application. We'll check whether the file is still in use by connecting to the endpoint. On Windows plaform, NamedPipe is used which does not have an underlying file. */ #if defined NN_HAVE_UNIX_SOCKETS fd = socket (AF_UNIX, SOCK_STREAM, 0); if (fd >= 0) { rc = fcntl (fd, F_SETFL, O_NONBLOCK); errno_assert (rc != -1 || errno == EINVAL); rc = connect (fd, (struct sockaddr*) &ss, sizeof (struct sockaddr_un)); if (rc == -1 && errno == ECONNREFUSED) { rc = unlink (addr); errno_assert (rc == 0 || errno == ENOENT); } rc = close (fd); errno_assert (rc == 0); } #endif /* Start listening for incoming connections. */ rc = nn_usock_start (&self->usock, AF_UNIX, SOCK_STREAM, 0); if (rc < 0) { return rc; } rc = nn_usock_bind (&self->usock, (struct sockaddr*) &ss, sizeof (struct sockaddr_un)); if (rc < 0) { nn_usock_stop (&self->usock); return rc; } rc = nn_usock_listen (&self->usock, NN_BIPC_BACKLOG); if (rc < 0) { nn_usock_stop (&self->usock); return rc; } nn_bipc_start_accepting (self); return 0; } /******************************************************************************/ /* State machine actions. */ /******************************************************************************/ static void nn_bipc_start_accepting (struct nn_bipc *self) { nn_assert (self->aipc == NULL); /* Allocate new aipc state machine. */ self->aipc = nn_alloc (sizeof (struct nn_aipc), "aipc"); alloc_assert (self->aipc); nn_aipc_init (self->aipc, NN_BIPC_SRC_AIPC, self->ep, &self->fsm); /* Start waiting for a new incoming connection. */ nn_aipc_start (self->aipc, &self->usock); } nanomsg-1.1.5/src/transports/ipc/bipc.h000066400000000000000000000025461336111550300200340ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_BIPC_INCLUDED #define NN_BIPC_INCLUDED #include "../../transport.h" /* State machine managing bound IPC socket. */ int nn_bipc_create (struct nn_ep *); #endif nanomsg-1.1.5/src/transports/ipc/cipc.c000066400000000000000000000342641336111550300200320ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "cipc.h" #include "sipc.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../utils/backoff.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/alloc.h" #include "../../utils/fast.h" #include "../../utils/attr.h" #include #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #include #endif #define NN_CIPC_STATE_IDLE 1 #define NN_CIPC_STATE_CONNECTING 2 #define NN_CIPC_STATE_ACTIVE 3 #define NN_CIPC_STATE_STOPPING_SIPC 4 #define NN_CIPC_STATE_STOPPING_USOCK 5 #define NN_CIPC_STATE_WAITING 6 #define NN_CIPC_STATE_STOPPING_BACKOFF 7 #define NN_CIPC_STATE_STOPPING_SIPC_FINAL 8 #define NN_CIPC_STATE_STOPPING 9 #define NN_CIPC_SRC_USOCK 1 #define NN_CIPC_SRC_RECONNECT_TIMER 2 #define NN_CIPC_SRC_SIPC 3 struct nn_cipc { /* The state machine. */ struct nn_fsm fsm; int state; struct nn_ep *ep; /* The underlying IPC socket. */ struct nn_usock usock; /* Used to wait before retrying to connect. */ struct nn_backoff retry; /* State machine that handles the active part of the connection lifetime. */ struct nn_sipc sipc; }; /* nn_ep virtual interface implementation. */ static void nn_cipc_stop (void *self); static void nn_cipc_destroy (void *self); const struct nn_ep_ops nn_cipc_ep_ops = { nn_cipc_stop, nn_cipc_destroy }; /* Private functions. */ static void nn_cipc_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_cipc_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_cipc_start_connecting (struct nn_cipc *self); int nn_cipc_create (struct nn_ep *ep) { struct nn_cipc *self; int reconnect_ivl; int reconnect_ivl_max; size_t sz; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_cipc), "cipc"); alloc_assert (self); /* Initialise the structure. */ self->ep = ep; nn_ep_tran_setup (ep, &nn_cipc_ep_ops, self); nn_fsm_init_root (&self->fsm, nn_cipc_handler, nn_cipc_shutdown, nn_ep_getctx (ep)); self->state = NN_CIPC_STATE_IDLE; nn_usock_init (&self->usock, NN_CIPC_SRC_USOCK, &self->fsm); sz = sizeof (reconnect_ivl); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL, &reconnect_ivl, &sz); nn_assert (sz == sizeof (reconnect_ivl)); sz = sizeof (reconnect_ivl_max); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX, &reconnect_ivl_max, &sz); nn_assert (sz == sizeof (reconnect_ivl_max)); if (reconnect_ivl_max == 0) reconnect_ivl_max = reconnect_ivl; nn_backoff_init (&self->retry, NN_CIPC_SRC_RECONNECT_TIMER, reconnect_ivl, reconnect_ivl_max, &self->fsm); nn_sipc_init (&self->sipc, NN_CIPC_SRC_SIPC, ep, &self->fsm); /* Start the state machine. */ nn_fsm_start (&self->fsm); return 0; } static void nn_cipc_stop (void *self) { struct nn_cipc *cipc = self; nn_fsm_stop (&cipc->fsm); } static void nn_cipc_destroy (void *self) { struct nn_cipc *cipc = self; nn_sipc_term (&cipc->sipc); nn_backoff_term (&cipc->retry); nn_usock_term (&cipc->usock); nn_fsm_term (&cipc->fsm); nn_free (cipc); } static void nn_cipc_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_cipc *cipc; cipc = nn_cont (self, struct nn_cipc, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (!nn_sipc_isidle (&cipc->sipc)) { nn_ep_stat_increment (cipc->ep, NN_STAT_DROPPED_CONNECTIONS, 1); nn_sipc_stop (&cipc->sipc); } cipc->state = NN_CIPC_STATE_STOPPING_SIPC_FINAL; } if (nn_slow (cipc->state == NN_CIPC_STATE_STOPPING_SIPC_FINAL)) { if (!nn_sipc_isidle (&cipc->sipc)) return; nn_backoff_stop (&cipc->retry); nn_usock_stop (&cipc->usock); cipc->state = NN_CIPC_STATE_STOPPING; } if (nn_slow (cipc->state == NN_CIPC_STATE_STOPPING)) { if (!nn_backoff_isidle (&cipc->retry) || !nn_usock_isidle (&cipc->usock)) return; cipc->state = NN_CIPC_STATE_IDLE; nn_fsm_stopped_noevent (&cipc->fsm); nn_ep_stopped (cipc->ep); return; } nn_fsm_bad_state(cipc->state, src, type); } static void nn_cipc_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_cipc *cipc; cipc = nn_cont (self, struct nn_cipc, fsm); switch (cipc->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_CIPC_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_cipc_start_connecting (cipc); return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* CONNECTING state. */ /* Non-blocking connect is under way. */ /******************************************************************************/ case NN_CIPC_STATE_CONNECTING: switch (src) { case NN_CIPC_SRC_USOCK: switch (type) { case NN_USOCK_CONNECTED: nn_sipc_start (&cipc->sipc, &cipc->usock); cipc->state = NN_CIPC_STATE_ACTIVE; nn_ep_stat_increment (cipc->ep, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_ep_stat_increment (cipc->ep, NN_STAT_ESTABLISHED_CONNECTIONS, 1); nn_ep_clear_error (cipc->ep); return; case NN_USOCK_ERROR: nn_ep_set_error (cipc->ep, nn_usock_geterrno (&cipc->usock)); nn_usock_stop (&cipc->usock); cipc->state = NN_CIPC_STATE_STOPPING_USOCK; nn_ep_stat_increment (cipc->ep, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_ep_stat_increment (cipc->ep, NN_STAT_CONNECT_ERRORS, 1); return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Connection is established and handled by the sipc state machine. */ /******************************************************************************/ case NN_CIPC_STATE_ACTIVE: switch (src) { case NN_CIPC_SRC_SIPC: switch (type) { case NN_SIPC_ERROR: nn_sipc_stop (&cipc->sipc); cipc->state = NN_CIPC_STATE_STOPPING_SIPC; nn_ep_stat_increment (cipc->ep, NN_STAT_BROKEN_CONNECTIONS, 1); return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* STOPPING_SIPC state. */ /* sipc object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CIPC_STATE_STOPPING_SIPC: switch (src) { case NN_CIPC_SRC_SIPC: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_SIPC_STOPPED: nn_usock_stop (&cipc->usock); cipc->state = NN_CIPC_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /* usock object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CIPC_STATE_STOPPING_USOCK: switch (src) { case NN_CIPC_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: nn_backoff_start (&cipc->retry); cipc->state = NN_CIPC_STATE_WAITING; return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* WAITING state. */ /* Waiting before re-connection is attempted. This way we won't overload */ /* the system by continuous re-connection attemps. */ /******************************************************************************/ case NN_CIPC_STATE_WAITING: switch (src) { case NN_CIPC_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_TIMEOUT: nn_backoff_stop (&cipc->retry); cipc->state = NN_CIPC_STATE_STOPPING_BACKOFF; return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* STOPPING_BACKOFF state. */ /* backoff object was asked to stop, but it haven't stopped yet. */ /******************************************************************************/ case NN_CIPC_STATE_STOPPING_BACKOFF: switch (src) { case NN_CIPC_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_STOPPED: nn_cipc_start_connecting (cipc); return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (cipc->state, src, type); } } /******************************************************************************/ /* State machine actions. */ /******************************************************************************/ static void nn_cipc_start_connecting (struct nn_cipc *self) { int rc; struct sockaddr_storage ss; struct sockaddr_un *un; const char *addr; int val; size_t sz; /* Try to start the underlying socket. */ rc = nn_usock_start (&self->usock, AF_UNIX, SOCK_STREAM, 0); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CIPC_STATE_WAITING; return; } /* Set the relevant socket options. */ sz = sizeof (val); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); /* Create the IPC address from the address string. */ addr = nn_ep_getaddr (self->ep); memset (&ss, 0, sizeof (ss)); un = (struct sockaddr_un*) &ss; nn_assert (strlen (addr) < sizeof (un->sun_path)); ss.ss_family = AF_UNIX; strncpy (un->sun_path, addr, sizeof (un->sun_path)); #if defined NN_HAVE_WINDOWS /* Get/Set security attribute pointer*/ nn_ep_getopt (self->ep, NN_IPC, NN_IPC_SEC_ATTR, &self->usock.sec_attr, &sz); nn_ep_getopt (self->ep, NN_IPC, NN_IPC_OUTBUFSZ, &self->usock.outbuffersz, &sz); nn_ep_getopt (self->ep, NN_IPC, NN_IPC_INBUFSZ, &self->usock.inbuffersz, &sz); #endif /* Start connecting. */ nn_usock_connect (&self->usock, (struct sockaddr*) &ss, sizeof (struct sockaddr_un)); self->state = NN_CIPC_STATE_CONNECTING; nn_ep_stat_increment (self->ep, NN_STAT_INPROGRESS_CONNECTIONS, 1); } nanomsg-1.1.5/src/transports/ipc/cipc.h000066400000000000000000000025131336111550300200270ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_CIPC_INCLUDED #define NN_CIPC_INCLUDED #include "../../transport.h" #include "../../ipc.h" /* State machine managing connected IPC socket. */ int nn_cipc_create (struct nn_ep *ep); #endif nanomsg-1.1.5/src/transports/ipc/ipc.c000066400000000000000000000107111336111550300176560ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "bipc.h" #include "cipc.h" #include "../../ipc.h" #include "../../utils/err.h" #include "../../utils/alloc.h" #include "../../utils/fast.h" #include "../../utils/cont.h" #include #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #include #include #endif /* IPC-specific socket options. */ struct nn_ipc_optset { struct nn_optset base; /* Win32 Security Attribute */ void* sec_attr; int outbuffersz; int inbuffersz; }; static void nn_ipc_optset_destroy (struct nn_optset *self); static int nn_ipc_optset_setopt (struct nn_optset *self, int option, const void *optval, size_t optvallen); static int nn_ipc_optset_getopt (struct nn_optset *self, int option, void *optval, size_t *optvallen); static const struct nn_optset_vfptr nn_ipc_optset_vfptr = { nn_ipc_optset_destroy, nn_ipc_optset_setopt, nn_ipc_optset_getopt }; /* nn_transport interface. */ static int nn_ipc_bind (struct nn_ep *ep); static int nn_ipc_connect (struct nn_ep *ep); static struct nn_optset *nn_ipc_optset (void); struct nn_transport nn_ipc = { "ipc", NN_IPC, NULL, NULL, nn_ipc_bind, nn_ipc_connect, nn_ipc_optset, }; static int nn_ipc_bind (struct nn_ep *ep) { return nn_bipc_create (ep); } static int nn_ipc_connect (struct nn_ep *ep) { return nn_cipc_create (ep); } static struct nn_optset *nn_ipc_optset () { struct nn_ipc_optset *optset; optset = nn_alloc (sizeof (struct nn_ipc_optset), "optset (ipc)"); alloc_assert (optset); optset->base.vfptr = &nn_ipc_optset_vfptr; /* Default values for the IPC options */ optset->sec_attr = NULL; optset->outbuffersz = 4096; optset->inbuffersz = 4096; return &optset->base; } static void nn_ipc_optset_destroy (struct nn_optset *self) { struct nn_ipc_optset *optset; optset = nn_cont (self, struct nn_ipc_optset, base); nn_free (optset); } static int nn_ipc_optset_setopt (struct nn_optset *self, int option, const void *optval, size_t optvallen) { struct nn_ipc_optset *optset; optset = nn_cont (self, struct nn_ipc_optset, base); if (optvallen < sizeof (int)) { return -EINVAL; } switch (option) { case NN_IPC_SEC_ATTR: optset->sec_attr = (void *)optval; return 0; case NN_IPC_OUTBUFSZ: optset->outbuffersz = *(int *)optval; return 0; case NN_IPC_INBUFSZ: optset->inbuffersz = *(int *)optval; return 0; default: return -ENOPROTOOPT; } } static int nn_ipc_optset_getopt (struct nn_optset *self, int option, void *optval, size_t *optvallen) { struct nn_ipc_optset *optset; optset = nn_cont (self, struct nn_ipc_optset, base); switch (option) { case NN_IPC_SEC_ATTR: memcpy(optval, &optset->sec_attr, sizeof(optset->sec_attr)); *optvallen = sizeof(optset->sec_attr); return 0; case NN_IPC_OUTBUFSZ: *(int *)optval = optset->outbuffersz; *optvallen = sizeof (int); return 0; case NN_IPC_INBUFSZ: *(int *)optval = optset->inbuffersz; *optvallen = sizeof (int); return 0; default: return -ENOPROTOOPT; } } nanomsg-1.1.5/src/transports/ipc/sipc.c000066400000000000000000000356641336111550300200570ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "sipc.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/wire.h" #include "../../utils/attr.h" /* Types of messages passed via IPC transport. */ #define NN_SIPC_MSG_NORMAL 1 #define NN_SIPC_MSG_SHMEM 2 /* States of the object as a whole. */ #define NN_SIPC_STATE_IDLE 1 #define NN_SIPC_STATE_PROTOHDR 2 #define NN_SIPC_STATE_STOPPING_STREAMHDR 3 #define NN_SIPC_STATE_ACTIVE 4 #define NN_SIPC_STATE_SHUTTING_DOWN 5 #define NN_SIPC_STATE_DONE 6 #define NN_SIPC_STATE_STOPPING 7 /* Subordinated srcptr objects. */ #define NN_SIPC_SRC_USOCK 1 #define NN_SIPC_SRC_STREAMHDR 2 /* Possible states of the inbound part of the object. */ #define NN_SIPC_INSTATE_HDR 1 #define NN_SIPC_INSTATE_BODY 2 #define NN_SIPC_INSTATE_HASMSG 3 /* Possible states of the outbound part of the object. */ #define NN_SIPC_OUTSTATE_IDLE 1 #define NN_SIPC_OUTSTATE_SENDING 2 /* Stream is a special type of pipe. Implementation of the virtual pipe API. */ static int nn_sipc_send (struct nn_pipebase *self, struct nn_msg *msg); static int nn_sipc_recv (struct nn_pipebase *self, struct nn_msg *msg); const struct nn_pipebase_vfptr nn_sipc_pipebase_vfptr = { nn_sipc_send, nn_sipc_recv }; /* Private functions. */ static void nn_sipc_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_sipc_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); void nn_sipc_init (struct nn_sipc *self, int src, struct nn_ep *ep, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_sipc_handler, nn_sipc_shutdown, src, self, owner); self->state = NN_SIPC_STATE_IDLE; nn_streamhdr_init (&self->streamhdr, NN_SIPC_SRC_STREAMHDR, &self->fsm); self->usock = NULL; self->usock_owner.src = -1; self->usock_owner.fsm = NULL; nn_pipebase_init (&self->pipebase, &nn_sipc_pipebase_vfptr, ep); self->instate = -1; nn_msg_init (&self->inmsg, 0); self->outstate = -1; nn_msg_init (&self->outmsg, 0); nn_fsm_event_init (&self->done); } void nn_sipc_term (struct nn_sipc *self) { nn_assert_state (self, NN_SIPC_STATE_IDLE); nn_fsm_event_term (&self->done); nn_msg_term (&self->outmsg); nn_msg_term (&self->inmsg); nn_pipebase_term (&self->pipebase); nn_streamhdr_term (&self->streamhdr); nn_fsm_term (&self->fsm); } int nn_sipc_isidle (struct nn_sipc *self) { return nn_fsm_isidle (&self->fsm); } void nn_sipc_start (struct nn_sipc *self, struct nn_usock *usock) { /* Take ownership of the underlying socket. */ nn_assert (self->usock == NULL && self->usock_owner.fsm == NULL); self->usock_owner.src = NN_SIPC_SRC_USOCK; self->usock_owner.fsm = &self->fsm; nn_usock_swap_owner (usock, &self->usock_owner); self->usock = usock; /* Launch the state machine. */ nn_fsm_start (&self->fsm); } void nn_sipc_stop (struct nn_sipc *self) { nn_fsm_stop (&self->fsm); } static int nn_sipc_send (struct nn_pipebase *self, struct nn_msg *msg) { struct nn_sipc *sipc; struct nn_iovec iov [3]; sipc = nn_cont (self, struct nn_sipc, pipebase); nn_assert_state (sipc, NN_SIPC_STATE_ACTIVE); nn_assert (sipc->outstate == NN_SIPC_OUTSTATE_IDLE); /* Move the message to the local storage. */ nn_msg_term (&sipc->outmsg); nn_msg_mv (&sipc->outmsg, msg); /* Serialise the message header. */ sipc->outhdr [0] = NN_SIPC_MSG_NORMAL; nn_putll (sipc->outhdr + 1, nn_chunkref_size (&sipc->outmsg.sphdr) + nn_chunkref_size (&sipc->outmsg.body)); /* Start async sending. */ iov [0].iov_base = sipc->outhdr; iov [0].iov_len = sizeof (sipc->outhdr); iov [1].iov_base = nn_chunkref_data (&sipc->outmsg.sphdr); iov [1].iov_len = nn_chunkref_size (&sipc->outmsg.sphdr); iov [2].iov_base = nn_chunkref_data (&sipc->outmsg.body); iov [2].iov_len = nn_chunkref_size (&sipc->outmsg.body); nn_usock_send (sipc->usock, iov, 3); sipc->outstate = NN_SIPC_OUTSTATE_SENDING; return 0; } static int nn_sipc_recv (struct nn_pipebase *self, struct nn_msg *msg) { struct nn_sipc *sipc; sipc = nn_cont (self, struct nn_sipc, pipebase); nn_assert_state (sipc, NN_SIPC_STATE_ACTIVE); nn_assert (sipc->instate == NN_SIPC_INSTATE_HASMSG); /* Move received message to the user. */ nn_msg_mv (msg, &sipc->inmsg); nn_msg_init (&sipc->inmsg, 0); /* Start receiving new message. */ sipc->instate = NN_SIPC_INSTATE_HDR; nn_usock_recv (sipc->usock, sipc->inhdr, sizeof (sipc->inhdr), NULL); return 0; } static void nn_sipc_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_sipc *sipc; sipc = nn_cont (self, struct nn_sipc, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_pipebase_stop (&sipc->pipebase); nn_streamhdr_stop (&sipc->streamhdr); sipc->state = NN_SIPC_STATE_STOPPING; } if (nn_slow (sipc->state == NN_SIPC_STATE_STOPPING)) { if (nn_streamhdr_isidle (&sipc->streamhdr)) { nn_usock_swap_owner (sipc->usock, &sipc->usock_owner); sipc->usock = NULL; sipc->usock_owner.src = -1; sipc->usock_owner.fsm = NULL; sipc->state = NN_SIPC_STATE_IDLE; nn_fsm_stopped (&sipc->fsm, NN_SIPC_STOPPED); return; } return; } nn_fsm_bad_state(sipc->state, src, type); } static void nn_sipc_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { int rc; struct nn_sipc *sipc; uint64_t size; int opt; size_t opt_sz = sizeof (opt); sipc = nn_cont (self, struct nn_sipc, fsm); switch (sipc->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_SIPC_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_streamhdr_start (&sipc->streamhdr, sipc->usock, &sipc->pipebase); sipc->state = NN_SIPC_STATE_PROTOHDR; return; default: nn_fsm_bad_action (sipc->state, src, type); } default: nn_fsm_bad_source (sipc->state, src, type); } /******************************************************************************/ /* PROTOHDR state. */ /******************************************************************************/ case NN_SIPC_STATE_PROTOHDR: switch (src) { case NN_SIPC_SRC_STREAMHDR: switch (type) { case NN_STREAMHDR_OK: /* Before moving to the active state stop the streamhdr state machine. */ nn_streamhdr_stop (&sipc->streamhdr); sipc->state = NN_SIPC_STATE_STOPPING_STREAMHDR; return; case NN_STREAMHDR_ERROR: /* Raise the error and move directly to the DONE state. streamhdr object will be stopped later on. */ sipc->state = NN_SIPC_STATE_DONE; nn_fsm_raise (&sipc->fsm, &sipc->done, NN_SIPC_ERROR); return; default: nn_fsm_bad_action (sipc->state, src, type); } default: nn_fsm_bad_source (sipc->state, src, type); } /******************************************************************************/ /* STOPPING_STREAMHDR state. */ /******************************************************************************/ case NN_SIPC_STATE_STOPPING_STREAMHDR: switch (src) { case NN_SIPC_SRC_STREAMHDR: switch (type) { case NN_STREAMHDR_STOPPED: /* Start the pipe. */ rc = nn_pipebase_start (&sipc->pipebase); if (nn_slow (rc < 0)) { sipc->state = NN_SIPC_STATE_DONE; nn_fsm_raise (&sipc->fsm, &sipc->done, NN_SIPC_ERROR); return; } /* Start receiving a message in asynchronous manner. */ sipc->instate = NN_SIPC_INSTATE_HDR; nn_usock_recv (sipc->usock, &sipc->inhdr, sizeof (sipc->inhdr), NULL); /* Mark the pipe as available for sending. */ sipc->outstate = NN_SIPC_OUTSTATE_IDLE; sipc->state = NN_SIPC_STATE_ACTIVE; return; default: nn_fsm_bad_action (sipc->state, src, type); } default: nn_fsm_bad_source (sipc->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_SIPC_STATE_ACTIVE: switch (src) { case NN_SIPC_SRC_USOCK: switch (type) { case NN_USOCK_SENT: /* The message is now fully sent. */ nn_assert (sipc->outstate == NN_SIPC_OUTSTATE_SENDING); sipc->outstate = NN_SIPC_OUTSTATE_IDLE; nn_msg_term (&sipc->outmsg); nn_msg_init (&sipc->outmsg, 0); nn_pipebase_sent (&sipc->pipebase); return; case NN_USOCK_RECEIVED: switch (sipc->instate) { case NN_SIPC_INSTATE_HDR: /* Message header was received. Check that message size is acceptable by comparing with NN_RCVMAXSIZE; if it's too large, drop the connection. */ nn_assert (sipc->inhdr [0] == NN_SIPC_MSG_NORMAL); size = nn_getll (sipc->inhdr + 1); nn_pipebase_getopt (&sipc->pipebase, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, &opt_sz); if (opt >= 0 && size > (unsigned)opt) { sipc->state = NN_SIPC_STATE_DONE; nn_fsm_raise (&sipc->fsm, &sipc->done, NN_SIPC_ERROR); return; } /* Allocate memory for the message. */ nn_msg_term (&sipc->inmsg); nn_msg_init (&sipc->inmsg, (size_t) size); /* Special case when size of the message body is 0. */ if (!size) { sipc->instate = NN_SIPC_INSTATE_HASMSG; nn_pipebase_received (&sipc->pipebase); return; } /* Start receiving the message body. */ sipc->instate = NN_SIPC_INSTATE_BODY; nn_usock_recv (sipc->usock, nn_chunkref_data (&sipc->inmsg.body), (size_t) size, NULL); return; case NN_SIPC_INSTATE_BODY: /* Message body was received. Notify the owner that it can receive it. */ sipc->instate = NN_SIPC_INSTATE_HASMSG; nn_pipebase_received (&sipc->pipebase); return; default: nn_assert (0); return; } case NN_USOCK_SHUTDOWN: nn_pipebase_stop (&sipc->pipebase); sipc->state = NN_SIPC_STATE_SHUTTING_DOWN; return; case NN_USOCK_ERROR: nn_pipebase_stop (&sipc->pipebase); sipc->state = NN_SIPC_STATE_DONE; nn_fsm_raise (&sipc->fsm, &sipc->done, NN_SIPC_ERROR); return; default: nn_fsm_bad_action (sipc->state, src, type); } default: nn_fsm_bad_source (sipc->state, src, type); } /******************************************************************************/ /* SHUTTING_DOWN state. */ /* The underlying connection is closed. We are just waiting that underlying */ /* usock being closed */ /******************************************************************************/ case NN_SIPC_STATE_SHUTTING_DOWN: switch (src) { case NN_SIPC_SRC_USOCK: switch (type) { case NN_USOCK_ERROR: sipc->state = NN_SIPC_STATE_DONE; nn_fsm_raise (&sipc->fsm, &sipc->done, NN_SIPC_ERROR); return; default: nn_fsm_bad_action (sipc->state, src, type); } default: nn_fsm_bad_source (sipc->state, src, type); } /******************************************************************************/ /* DONE state. */ /* The underlying connection is closed. There's nothing that can be done in */ /* this state except stopping the object. */ /******************************************************************************/ case NN_SIPC_STATE_DONE: nn_fsm_bad_source (sipc->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (sipc->state, src, type); } } nanomsg-1.1.5/src/transports/ipc/sipc.h000066400000000000000000000054621336111550300200550ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_SIPC_INCLUDED #define NN_SIPC_INCLUDED #include "../../transport.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../utils/streamhdr.h" #include "../../utils/msg.h" /* This state machine handles IPC connection from the point where it is established to the point when it is broken. */ #define NN_SIPC_ERROR 1 #define NN_SIPC_STOPPED 2 struct nn_sipc { /* The state machine. */ struct nn_fsm fsm; int state; /* The underlying socket. */ struct nn_usock *usock; /* Child state machine to do protocol header exchange. */ struct nn_streamhdr streamhdr; /* The original owner of the underlying socket. */ struct nn_fsm_owner usock_owner; /* Pipe connecting this IPC connection to the nanomsg core. */ struct nn_pipebase pipebase; /* State of inbound state machine. */ int instate; /* Buffer used to store the header of incoming message. */ uint8_t inhdr [9]; /* Message being received at the moment. */ struct nn_msg inmsg; /* State of the outbound state machine. */ int outstate; /* Buffer used to store the header of outgoing message. */ uint8_t outhdr [9]; /* Message being sent at the moment. */ struct nn_msg outmsg; /* Event raised when the state machine ends. */ struct nn_fsm_event done; }; void nn_sipc_init (struct nn_sipc *self, int src, struct nn_ep *ep, struct nn_fsm *owner); void nn_sipc_term (struct nn_sipc *self); int nn_sipc_isidle (struct nn_sipc *self); void nn_sipc_start (struct nn_sipc *self, struct nn_usock *usock); void nn_sipc_stop (struct nn_sipc *self); #endif nanomsg-1.1.5/src/transports/tcp/000077500000000000000000000000001336111550300167525ustar00rootroot00000000000000nanomsg-1.1.5/src/transports/tcp/atcp.c000066400000000000000000000257121336111550300200540ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "atcp.h" #include "../../tcp.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/attr.h" #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #include #endif #define NN_ATCP_STATE_IDLE 1 #define NN_ATCP_STATE_ACCEPTING 2 #define NN_ATCP_STATE_ACTIVE 3 #define NN_ATCP_STATE_STOPPING_STCP 4 #define NN_ATCP_STATE_STOPPING_USOCK 5 #define NN_ATCP_STATE_DONE 6 #define NN_ATCP_STATE_STOPPING_STCP_FINAL 7 #define NN_ATCP_STATE_STOPPING 8 #define NN_ATCP_SRC_USOCK 1 #define NN_ATCP_SRC_STCP 2 #define NN_ATCP_SRC_LISTENER 3 /* Private functions. */ static void nn_atcp_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_atcp_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); void nn_atcp_init (struct nn_atcp *self, int src, struct nn_ep *ep, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_atcp_handler, nn_atcp_shutdown, src, self, owner); self->state = NN_ATCP_STATE_IDLE; self->ep = ep; nn_usock_init (&self->usock, NN_ATCP_SRC_USOCK, &self->fsm); self->listener = NULL; self->listener_owner.src = -1; self->listener_owner.fsm = NULL; nn_stcp_init (&self->stcp, NN_ATCP_SRC_STCP, ep, &self->fsm); nn_fsm_event_init (&self->accepted); nn_fsm_event_init (&self->done); nn_list_item_init (&self->item); } void nn_atcp_term (struct nn_atcp *self) { nn_assert_state (self, NN_ATCP_STATE_IDLE); nn_list_item_term (&self->item); nn_fsm_event_term (&self->done); nn_fsm_event_term (&self->accepted); nn_stcp_term (&self->stcp); nn_usock_term (&self->usock); nn_fsm_term (&self->fsm); } int nn_atcp_isidle (struct nn_atcp *self) { return nn_fsm_isidle (&self->fsm); } void nn_atcp_start (struct nn_atcp *self, struct nn_usock *listener) { nn_assert_state (self, NN_ATCP_STATE_IDLE); /* Take ownership of the listener socket. */ self->listener = listener; self->listener_owner.src = NN_ATCP_SRC_LISTENER; self->listener_owner.fsm = &self->fsm; nn_usock_swap_owner (listener, &self->listener_owner); /* Start the state machine. */ nn_fsm_start (&self->fsm); } void nn_atcp_stop (struct nn_atcp *self) { nn_fsm_stop (&self->fsm); } static void nn_atcp_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_atcp *atcp; atcp = nn_cont (self, struct nn_atcp, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (!nn_stcp_isidle (&atcp->stcp)) { nn_ep_stat_increment (atcp->ep, NN_STAT_DROPPED_CONNECTIONS, 1); nn_stcp_stop (&atcp->stcp); } atcp->state = NN_ATCP_STATE_STOPPING_STCP_FINAL; } if (nn_slow (atcp->state == NN_ATCP_STATE_STOPPING_STCP_FINAL)) { if (!nn_stcp_isidle (&atcp->stcp)) return; nn_usock_stop (&atcp->usock); atcp->state = NN_ATCP_STATE_STOPPING; } if (nn_slow (atcp->state == NN_ATCP_STATE_STOPPING)) { if (!nn_usock_isidle (&atcp->usock)) return; if (atcp->listener) { nn_assert (atcp->listener_owner.fsm); nn_usock_swap_owner (atcp->listener, &atcp->listener_owner); atcp->listener = NULL; atcp->listener_owner.src = -1; atcp->listener_owner.fsm = NULL; } atcp->state = NN_ATCP_STATE_IDLE; nn_fsm_stopped (&atcp->fsm, NN_ATCP_STOPPED); return; } nn_fsm_bad_action(atcp->state, src, type); } static void nn_atcp_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_atcp *atcp; int val; size_t sz; atcp = nn_cont (self, struct nn_atcp, fsm); switch (atcp->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_ATCP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_usock_accept (&atcp->usock, atcp->listener); atcp->state = NN_ATCP_STATE_ACCEPTING; return; default: nn_fsm_bad_action (atcp->state, src, type); } default: nn_fsm_bad_source (atcp->state, src, type); } /******************************************************************************/ /* ACCEPTING state. */ /* Waiting for incoming connection. */ /******************************************************************************/ case NN_ATCP_STATE_ACCEPTING: switch (src) { case NN_ATCP_SRC_USOCK: switch (type) { case NN_USOCK_ACCEPTED: nn_ep_clear_error (atcp->ep); /* Set the relevant socket options. */ sz = sizeof (val); nn_ep_getopt (atcp->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&atcp->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_ep_getopt (atcp->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&atcp->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); sz = sizeof (val); nn_ep_getopt (atcp->ep, NN_TCP, NN_TCP_NODELAY, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&atcp->usock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val)); /* Return ownership of the listening socket to the parent. */ nn_usock_swap_owner (atcp->listener, &atcp->listener_owner); atcp->listener = NULL; atcp->listener_owner.src = -1; atcp->listener_owner.fsm = NULL; nn_fsm_raise (&atcp->fsm, &atcp->accepted, NN_ATCP_ACCEPTED); /* Start the stcp state machine. */ nn_usock_activate (&atcp->usock); nn_stcp_start (&atcp->stcp, &atcp->usock); atcp->state = NN_ATCP_STATE_ACTIVE; nn_ep_stat_increment (atcp->ep, NN_STAT_ACCEPTED_CONNECTIONS, 1); return; default: nn_fsm_bad_action (atcp->state, src, type); } case NN_ATCP_SRC_LISTENER: switch (type) { case NN_USOCK_ACCEPT_ERROR: nn_ep_set_error (atcp->ep, nn_usock_geterrno(atcp->listener)); nn_ep_stat_increment (atcp->ep, NN_STAT_ACCEPT_ERRORS, 1); nn_usock_accept (&atcp->usock, atcp->listener); return; default: nn_fsm_bad_action (atcp->state, src, type); } default: nn_fsm_bad_source (atcp->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_ATCP_STATE_ACTIVE: switch (src) { case NN_ATCP_SRC_STCP: switch (type) { case NN_STCP_ERROR: nn_stcp_stop (&atcp->stcp); atcp->state = NN_ATCP_STATE_STOPPING_STCP; nn_ep_stat_increment (atcp->ep, NN_STAT_BROKEN_CONNECTIONS, 1); return; default: nn_fsm_bad_action (atcp->state, src, type); } default: nn_fsm_bad_source (atcp->state, src, type); } /******************************************************************************/ /* STOPPING_STCP state. */ /******************************************************************************/ case NN_ATCP_STATE_STOPPING_STCP: switch (src) { case NN_ATCP_SRC_STCP: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_STCP_STOPPED: nn_usock_stop (&atcp->usock); atcp->state = NN_ATCP_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (atcp->state, src, type); } default: nn_fsm_bad_source (atcp->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /******************************************************************************/ case NN_ATCP_STATE_STOPPING_USOCK: switch (src) { case NN_ATCP_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: nn_fsm_raise (&atcp->fsm, &atcp->done, NN_ATCP_ERROR); atcp->state = NN_ATCP_STATE_DONE; return; default: nn_fsm_bad_action (atcp->state, src, type); } default: nn_fsm_bad_source (atcp->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (atcp->state, src, type); } } nanomsg-1.1.5/src/transports/tcp/atcp.h000066400000000000000000000052351336111550300200570ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_ATCP_INCLUDED #define NN_ATCP_INCLUDED #include "stcp.h" #include "../../transport.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../../utils/list.h" /* State machine handling accepted TCP sockets. */ /* In btcp, some events are just *assumed* to come from a child atcp object. By using non-trivial event codes, we can do more reliable sanity checking in such scenarios. */ #define NN_ATCP_ACCEPTED 34231 #define NN_ATCP_ERROR 34232 #define NN_ATCP_STOPPED 34233 struct nn_atcp { /* The state machine. */ struct nn_fsm fsm; int state; /* Pointer to the associated endpoint. */ struct nn_ep *ep; /* Underlying socket. */ struct nn_usock usock; /* Listening socket. Valid only while accepting new connection. */ struct nn_usock *listener; struct nn_fsm_owner listener_owner; /* State machine that takes care of the connection in the active state. */ struct nn_stcp stcp; /* Events generated by atcp state machine. */ struct nn_fsm_event accepted; struct nn_fsm_event done; /* This member can be used by owner to keep individual atcps in a list. */ struct nn_list_item item; }; void nn_atcp_init (struct nn_atcp *self, int src, struct nn_ep *ep, struct nn_fsm *owner); void nn_atcp_term (struct nn_atcp *self); int nn_atcp_isidle (struct nn_atcp *self); void nn_atcp_start (struct nn_atcp *self, struct nn_usock *listener); void nn_atcp_stop (struct nn_atcp *self); #endif nanomsg-1.1.5/src/transports/tcp/btcp.c000066400000000000000000000275071336111550300200610ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "btcp.h" #include "atcp.h" #include "../utils/port.h" #include "../utils/iface.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../utils/backoff.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/alloc.h" #include "../../utils/list.h" #include "../../utils/fast.h" #include #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #include #endif /* The backlog is set relatively high so that there are not too many failed connection attemps during re-connection storms. */ #define NN_BTCP_BACKLOG 100 #define NN_BTCP_STATE_IDLE 1 #define NN_BTCP_STATE_ACTIVE 2 #define NN_BTCP_STATE_STOPPING_ATCP 3 #define NN_BTCP_STATE_STOPPING_USOCK 4 #define NN_BTCP_STATE_STOPPING_ATCPS 5 #define NN_BTCP_SRC_USOCK 1 #define NN_BTCP_SRC_ATCP 2 #define NN_BTCP_SRC_BTCP 3 #define NN_BTCP_TYPE_LISTEN_ERR 1 struct nn_btcp { /* The state machine. */ struct nn_fsm fsm; struct nn_fsm_event listen_error; int state; struct nn_ep *ep; /* The underlying listening TCP socket. */ struct nn_usock usock; /* The connection being accepted at the moment. */ struct nn_atcp *atcp; /* List of accepted connections. */ struct nn_list atcps; }; /* nn_ep virtual interface implementation. */ static void nn_btcp_stop (void *); static void nn_btcp_destroy (void *); const struct nn_ep_ops nn_btcp_ep_ops = { nn_btcp_stop, nn_btcp_destroy }; /* Private functions. */ static void nn_btcp_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_btcp_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static int nn_btcp_listen (struct nn_btcp *self); static void nn_btcp_start_accepting (struct nn_btcp *self); int nn_btcp_create (struct nn_ep *ep) { int rc; struct nn_btcp *self; const char *addr; const char *end; const char *pos; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_btcp), "btcp"); self->ep = ep; alloc_assert (self); nn_ep_tran_setup (ep, &nn_btcp_ep_ops, self); addr = nn_ep_getaddr (ep); /* Parse the port. */ end = addr + strlen (addr); pos = strrchr (addr, ':'); if (pos == NULL) { nn_free (self); return -EINVAL; } ++pos; rc = nn_port_resolve (pos, end - pos); if (rc < 0) { nn_free (self); return -EINVAL; } /* Check whether IPv6 is to be used. */ ipv4onlylen = sizeof (ipv4only); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); /* Parse the address. */ rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen); if (nn_slow (rc < 0)) { nn_free (self); return -ENODEV; } /* Initialise the structure. */ nn_fsm_init_root (&self->fsm, nn_btcp_handler, nn_btcp_shutdown, nn_ep_getctx (ep)); nn_fsm_event_init (&self->listen_error); self->state = NN_BTCP_STATE_IDLE; self->atcp = NULL; nn_list_init (&self->atcps); /* Start the state machine. */ nn_fsm_start (&self->fsm); nn_usock_init (&self->usock, NN_BTCP_SRC_USOCK, &self->fsm); rc = nn_btcp_listen (self); if (rc != 0) { nn_fsm_raise_from_src (&self->fsm, &self->listen_error, NN_BTCP_SRC_BTCP, NN_BTCP_TYPE_LISTEN_ERR); return rc; } return 0; } static void nn_btcp_stop (void *self) { struct nn_btcp *btcp = self; nn_fsm_stop (&btcp->fsm); } static void nn_btcp_destroy (void *self) { struct nn_btcp *btcp = self; nn_assert_state (btcp, NN_BTCP_STATE_IDLE); nn_list_term (&btcp->atcps); nn_assert (btcp->atcp == NULL); nn_usock_term (&btcp->usock); nn_fsm_term (&btcp->fsm); nn_free (btcp); } static void nn_btcp_shutdown (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_btcp *btcp; struct nn_list_item *it; struct nn_atcp *atcp; btcp = nn_cont (self, struct nn_btcp, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (btcp->atcp) { nn_atcp_stop (btcp->atcp); btcp->state = NN_BTCP_STATE_STOPPING_ATCP; } else { btcp->state = NN_BTCP_STATE_STOPPING_USOCK; } } if (nn_slow (btcp->state == NN_BTCP_STATE_STOPPING_ATCP)) { if (!nn_atcp_isidle (btcp->atcp)) return; nn_atcp_term (btcp->atcp); nn_free (btcp->atcp); btcp->atcp = NULL; nn_usock_stop (&btcp->usock); btcp->state = NN_BTCP_STATE_STOPPING_USOCK; } if (nn_slow (btcp->state == NN_BTCP_STATE_STOPPING_USOCK)) { if (!nn_usock_isidle (&btcp->usock)) return; for (it = nn_list_begin (&btcp->atcps); it != nn_list_end (&btcp->atcps); it = nn_list_next (&btcp->atcps, it)) { atcp = nn_cont (it, struct nn_atcp, item); nn_atcp_stop (atcp); } btcp->state = NN_BTCP_STATE_STOPPING_ATCPS; goto atcps_stopping; } if (nn_slow (btcp->state == NN_BTCP_STATE_STOPPING_ATCPS)) { nn_assert (src == NN_BTCP_SRC_ATCP && type == NN_ATCP_STOPPED); atcp = (struct nn_atcp *) srcptr; nn_list_erase (&btcp->atcps, &atcp->item); nn_atcp_term (atcp); nn_free (atcp); /* If there are no more atcp state machines, we can stop the whole btcp object. */ atcps_stopping: if (nn_list_empty (&btcp->atcps)) { btcp->state = NN_BTCP_STATE_IDLE; nn_fsm_stopped_noevent (&btcp->fsm); nn_ep_stopped (btcp->ep); return; } return; } nn_fsm_bad_action(btcp->state, src, type); } static void nn_btcp_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_btcp *btcp; struct nn_atcp *atcp; btcp = nn_cont (self, struct nn_btcp, fsm); switch (btcp->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_BTCP_STATE_IDLE: nn_assert (src == NN_FSM_ACTION); nn_assert (type == NN_FSM_START); btcp->state = NN_BTCP_STATE_ACTIVE; return; /******************************************************************************/ /* ACTIVE state. */ /* The execution is yielded to the atcp state machine in this state. */ /******************************************************************************/ case NN_BTCP_STATE_ACTIVE: if (src == NN_BTCP_SRC_BTCP) { nn_assert (type == NN_BTCP_TYPE_LISTEN_ERR); nn_free (btcp); return; } if (src == NN_BTCP_SRC_USOCK) { /* usock object cleaning up */ nn_assert (type == NN_USOCK_SHUTDOWN || type == NN_USOCK_STOPPED); return; } /* All other events come from child atcp objects. */ nn_assert (src == NN_BTCP_SRC_ATCP); atcp = (struct nn_atcp*) srcptr; switch (type) { case NN_ATCP_ACCEPTED: nn_assert (btcp->atcp == atcp) ; nn_list_insert (&btcp->atcps, &atcp->item, nn_list_end (&btcp->atcps)); btcp->atcp = NULL; nn_btcp_start_accepting (btcp); return; case NN_ATCP_ERROR: nn_atcp_stop (atcp); return; case NN_ATCP_STOPPED: nn_list_erase (&btcp->atcps, &atcp->item); nn_atcp_term (atcp); nn_free (atcp); return; default: nn_fsm_bad_action (btcp->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (btcp->state, src, type); } } static int nn_btcp_listen (struct nn_btcp *self) { int rc; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; const char *addr; const char *end; const char *pos; uint16_t port; /* First, resolve the IP address. */ addr = nn_ep_getaddr (self->ep); memset (&ss, 0, sizeof (ss)); /* Parse the port. */ end = addr + strlen (addr); pos = strrchr (addr, ':'); if (pos == NULL) { return -EINVAL; } ++pos; rc = nn_port_resolve (pos, end - pos); if (rc <= 0) return rc; port = (uint16_t) rc; /* Parse the address. */ ipv4onlylen = sizeof (ipv4only); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen); if (rc < 0) { return rc; } /* Combine the port and the address. */ switch (ss.ss_family) { case AF_INET: ((struct sockaddr_in*) &ss)->sin_port = htons (port); sslen = sizeof (struct sockaddr_in); break; case AF_INET6: ((struct sockaddr_in6*) &ss)->sin6_port = htons (port); sslen = sizeof (struct sockaddr_in6); break; default: nn_assert (0); } /* Start listening for incoming connections. */ rc = nn_usock_start (&self->usock, ss.ss_family, SOCK_STREAM, 0); if (rc < 0) { return rc; } rc = nn_usock_bind (&self->usock, (struct sockaddr*) &ss, (size_t) sslen); if (rc < 0) { nn_usock_stop (&self->usock); return rc; } rc = nn_usock_listen (&self->usock, NN_BTCP_BACKLOG); if (rc < 0) { nn_usock_stop (&self->usock); return rc; } nn_btcp_start_accepting(self); return 0; } /******************************************************************************/ /* State machine actions. */ /******************************************************************************/ static void nn_btcp_start_accepting (struct nn_btcp *self) { nn_assert (self->atcp == NULL); /* Allocate new atcp state machine. */ self->atcp = nn_alloc (sizeof (struct nn_atcp), "atcp"); alloc_assert (self->atcp); nn_atcp_init (self->atcp, NN_BTCP_SRC_ATCP, self->ep, &self->fsm); /* Start waiting for a new incoming connection. */ nn_atcp_start (self->atcp, &self->usock); } nanomsg-1.1.5/src/transports/tcp/btcp.h000066400000000000000000000025471336111550300200630ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_BTCP_INCLUDED #define NN_BTCP_INCLUDED #include "../../transport.h" /* State machine managing bound TCP socket. */ int nn_btcp_create (struct nn_ep *); #endif nanomsg-1.1.5/src/transports/tcp/ctcp.c000066400000000000000000000504561336111550300200610ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "ctcp.h" #include "stcp.h" #include "../../tcp.h" #include "../utils/dns.h" #include "../utils/port.h" #include "../utils/iface.h" #include "../utils/backoff.h" #include "../utils/literal.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/alloc.h" #include "../../utils/fast.h" #include "../../utils/attr.h" #include #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #include #include #endif #define NN_CTCP_STATE_IDLE 1 #define NN_CTCP_STATE_RESOLVING 2 #define NN_CTCP_STATE_STOPPING_DNS 3 #define NN_CTCP_STATE_CONNECTING 4 #define NN_CTCP_STATE_ACTIVE 5 #define NN_CTCP_STATE_STOPPING_STCP 6 #define NN_CTCP_STATE_STOPPING_USOCK 7 #define NN_CTCP_STATE_WAITING 8 #define NN_CTCP_STATE_STOPPING_BACKOFF 9 #define NN_CTCP_STATE_STOPPING_STCP_FINAL 10 #define NN_CTCP_STATE_STOPPING 11 #define NN_CTCP_SRC_USOCK 1 #define NN_CTCP_SRC_RECONNECT_TIMER 2 #define NN_CTCP_SRC_DNS 3 #define NN_CTCP_SRC_STCP 4 struct nn_ctcp { /* The state machine. */ struct nn_fsm fsm; int state; struct nn_ep *ep; /* The underlying TCP socket. */ struct nn_usock usock; /* Used to wait before retrying to connect. */ struct nn_backoff retry; /* State machine that handles the active part of the connection lifetime. */ struct nn_stcp stcp; /* DNS resolver used to convert textual address into actual IP address along with the variable to hold the result. */ struct nn_dns dns; struct nn_dns_result dns_result; }; /* nn_ep virtual interface implementation. */ static void nn_ctcp_stop (void *); static void nn_ctcp_destroy (void *); const struct nn_ep_ops nn_ctcp_ep_ops = { nn_ctcp_stop, nn_ctcp_destroy }; /* Private functions. */ static void nn_ctcp_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_ctcp_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_ctcp_start_resolving (struct nn_ctcp *self); static void nn_ctcp_start_connecting (struct nn_ctcp *self, struct sockaddr_storage *ss, size_t sslen); int nn_ctcp_create (struct nn_ep *ep) { int rc; const char *addr; size_t addrlen; const char *semicolon; const char *hostname; const char *colon; const char *end; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; struct nn_ctcp *self; int reconnect_ivl; int reconnect_ivl_max; size_t sz; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_ctcp), "ctcp"); alloc_assert (self); /* Initalise the endpoint. */ self->ep = ep; nn_ep_tran_setup (ep, &nn_ctcp_ep_ops, self); /* Check whether IPv6 is to be used. */ ipv4onlylen = sizeof (ipv4only); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); /* Start parsing the address. */ addr = nn_ep_getaddr (ep); addrlen = strlen (addr); semicolon = strchr (addr, ';'); hostname = semicolon ? semicolon + 1 : addr; colon = strrchr (addr, ':'); end = addr + addrlen; /* Parse the port. */ if (!colon) { nn_free (self); return -EINVAL; } rc = nn_port_resolve (colon + 1, end - colon - 1); if (rc < 0) { nn_free (self); return -EINVAL; } /* Check whether the host portion of the address is either a literal or a valid hostname. */ if (nn_dns_check_hostname (hostname, colon - hostname) < 0 && nn_literal_resolve (hostname, colon - hostname, ipv4only, &ss, &sslen) < 0) { nn_free (self); return -EINVAL; } /* If local address is specified, check whether it is valid. */ if (semicolon) { rc = nn_iface_resolve (addr, semicolon - addr, ipv4only, &ss, &sslen); if (rc < 0) { nn_free (self); return -ENODEV; } } /* Initialise the structure. */ nn_fsm_init_root (&self->fsm, nn_ctcp_handler, nn_ctcp_shutdown, nn_ep_getctx (ep)); self->state = NN_CTCP_STATE_IDLE; nn_usock_init (&self->usock, NN_CTCP_SRC_USOCK, &self->fsm); sz = sizeof (reconnect_ivl); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL, &reconnect_ivl, &sz); nn_assert (sz == sizeof (reconnect_ivl)); sz = sizeof (reconnect_ivl_max); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX, &reconnect_ivl_max, &sz); nn_assert (sz == sizeof (reconnect_ivl_max)); if (reconnect_ivl_max == 0) reconnect_ivl_max = reconnect_ivl; nn_backoff_init (&self->retry, NN_CTCP_SRC_RECONNECT_TIMER, reconnect_ivl, reconnect_ivl_max, &self->fsm); nn_stcp_init (&self->stcp, NN_CTCP_SRC_STCP, ep, &self->fsm); nn_dns_init (&self->dns, NN_CTCP_SRC_DNS, &self->fsm); /* Start the state machine. */ nn_fsm_start (&self->fsm); return 0; } static void nn_ctcp_stop (void *self) { struct nn_ctcp *ctcp = self; nn_fsm_stop (&ctcp->fsm); } static void nn_ctcp_destroy (void *self) { struct nn_ctcp *ctcp = self; nn_dns_term (&ctcp->dns); nn_stcp_term (&ctcp->stcp); nn_backoff_term (&ctcp->retry); nn_usock_term (&ctcp->usock); nn_fsm_term (&ctcp->fsm); nn_free (ctcp); } static void nn_ctcp_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_ctcp *ctcp; ctcp = nn_cont (self, struct nn_ctcp, fsm); if (src == NN_FSM_ACTION && type == NN_FSM_STOP) { if (!nn_stcp_isidle (&ctcp->stcp)) { nn_ep_stat_increment (ctcp->ep, NN_STAT_DROPPED_CONNECTIONS, 1); nn_stcp_stop (&ctcp->stcp); } ctcp->state = NN_CTCP_STATE_STOPPING_STCP_FINAL; } if (ctcp->state == NN_CTCP_STATE_STOPPING_STCP_FINAL) { if (!nn_stcp_isidle (&ctcp->stcp)) return; nn_backoff_stop (&ctcp->retry); nn_usock_stop (&ctcp->usock); nn_dns_stop (&ctcp->dns); ctcp->state = NN_CTCP_STATE_STOPPING; } if (nn_slow (ctcp->state == NN_CTCP_STATE_STOPPING)) { if (!nn_backoff_isidle (&ctcp->retry) || !nn_usock_isidle (&ctcp->usock) || !nn_dns_isidle (&ctcp->dns)) return; ctcp->state = NN_CTCP_STATE_IDLE; nn_fsm_stopped_noevent (&ctcp->fsm); nn_ep_stopped (ctcp->ep); return; } nn_fsm_bad_state (ctcp->state, src, type); } static void nn_ctcp_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_ctcp *ctcp; ctcp = nn_cont (self, struct nn_ctcp, fsm); switch (ctcp->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_CTCP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_ctcp_start_resolving (ctcp); return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* RESOLVING state. */ /* Name of the host to connect to is being resolved to get an IP address. */ /******************************************************************************/ case NN_CTCP_STATE_RESOLVING: switch (src) { case NN_CTCP_SRC_DNS: switch (type) { case NN_DNS_DONE: nn_dns_stop (&ctcp->dns); ctcp->state = NN_CTCP_STATE_STOPPING_DNS; return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* STOPPING_DNS state. */ /* dns object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CTCP_STATE_STOPPING_DNS: switch (src) { case NN_CTCP_SRC_DNS: switch (type) { case NN_DNS_STOPPED: if (ctcp->dns_result.error == 0) { nn_ctcp_start_connecting (ctcp, &ctcp->dns_result.addr, ctcp->dns_result.addrlen); return; } nn_backoff_start (&ctcp->retry); ctcp->state = NN_CTCP_STATE_WAITING; return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* CONNECTING state. */ /* Non-blocking connect is under way. */ /******************************************************************************/ case NN_CTCP_STATE_CONNECTING: switch (src) { case NN_CTCP_SRC_USOCK: switch (type) { case NN_USOCK_CONNECTED: nn_stcp_start (&ctcp->stcp, &ctcp->usock); ctcp->state = NN_CTCP_STATE_ACTIVE; nn_ep_stat_increment (ctcp->ep, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_ep_stat_increment (ctcp->ep, NN_STAT_ESTABLISHED_CONNECTIONS, 1); nn_ep_clear_error (ctcp->ep); return; case NN_USOCK_ERROR: nn_ep_set_error (ctcp->ep, nn_usock_geterrno (&ctcp->usock)); nn_usock_stop (&ctcp->usock); ctcp->state = NN_CTCP_STATE_STOPPING_USOCK; nn_ep_stat_increment (ctcp->ep, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_ep_stat_increment (ctcp->ep, NN_STAT_CONNECT_ERRORS, 1); return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Connection is established and handled by the stcp state machine. */ /******************************************************************************/ case NN_CTCP_STATE_ACTIVE: switch (src) { case NN_CTCP_SRC_STCP: switch (type) { case NN_STCP_ERROR: nn_stcp_stop (&ctcp->stcp); ctcp->state = NN_CTCP_STATE_STOPPING_STCP; nn_ep_stat_increment (ctcp->ep, NN_STAT_BROKEN_CONNECTIONS, 1); return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* STOPPING_STCP state. */ /* stcp object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CTCP_STATE_STOPPING_STCP: switch (src) { case NN_CTCP_SRC_STCP: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_STCP_STOPPED: nn_usock_stop (&ctcp->usock); ctcp->state = NN_CTCP_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /* usock object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CTCP_STATE_STOPPING_USOCK: switch (src) { case NN_CTCP_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: nn_backoff_start (&ctcp->retry); ctcp->state = NN_CTCP_STATE_WAITING; return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* WAITING state. */ /* Waiting before re-connection is attempted. This way we won't overload */ /* the system by continuous re-connection attemps. */ /******************************************************************************/ case NN_CTCP_STATE_WAITING: switch (src) { case NN_CTCP_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_TIMEOUT: nn_backoff_stop (&ctcp->retry); ctcp->state = NN_CTCP_STATE_STOPPING_BACKOFF; return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* STOPPING_BACKOFF state. */ /* backoff object was asked to stop, but it haven't stopped yet. */ /******************************************************************************/ case NN_CTCP_STATE_STOPPING_BACKOFF: switch (src) { case NN_CTCP_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_STOPPED: nn_ctcp_start_resolving (ctcp); return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (ctcp->state, src, type); } } /******************************************************************************/ /* State machine actions. */ /******************************************************************************/ static void nn_ctcp_start_resolving (struct nn_ctcp *self) { const char *addr; const char *begin; const char *end; int ipv4only; size_t ipv4onlylen; /* Extract the hostname part from address string. */ addr = nn_ep_getaddr (self->ep); begin = strchr (addr, ';'); if (!begin) begin = addr; else ++begin; end = strrchr (addr, ':'); nn_assert (end); /* Check whether IPv6 is to be used. */ ipv4onlylen = sizeof (ipv4only); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); /* TODO: Get the actual value of IPV4ONLY option. */ nn_dns_start (&self->dns, begin, end - begin, ipv4only, &self->dns_result); self->state = NN_CTCP_STATE_RESOLVING; } static void nn_ctcp_start_connecting (struct nn_ctcp *self, struct sockaddr_storage *ss, size_t sslen) { int rc; struct sockaddr_storage remote; size_t remotelen; struct sockaddr_storage local; size_t locallen; const char *addr; const char *end; const char *colon; const char *semicolon; uint16_t port; int ipv4only; size_t ipv4onlylen; int val; size_t sz; /* Create IP address from the address string. */ addr = nn_ep_getaddr (self->ep); memset (&remote, 0, sizeof (remote)); /* Parse the port. */ end = addr + strlen (addr); colon = strrchr (addr, ':'); rc = nn_port_resolve (colon + 1, end - colon - 1); errnum_assert (rc > 0, -rc); port = rc; /* Check whether IPv6 is to be used. */ ipv4onlylen = sizeof (ipv4only); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); /* Parse the local address, if any. */ semicolon = strchr (addr, ';'); memset (&local, 0, sizeof (local)); if (semicolon) rc = nn_iface_resolve (addr, semicolon - addr, ipv4only, &local, &locallen); else rc = nn_iface_resolve ("*", 1, ipv4only, &local, &locallen); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CTCP_STATE_WAITING; return; } /* Combine the remote address and the port. */ remote = *ss; remotelen = sslen; if (remote.ss_family == AF_INET) ((struct sockaddr_in*) &remote)->sin_port = htons (port); else if (remote.ss_family == AF_INET6) ((struct sockaddr_in6*) &remote)->sin6_port = htons (port); else nn_assert (0); /* Try to start the underlying socket. */ rc = nn_usock_start (&self->usock, remote.ss_family, SOCK_STREAM, 0); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CTCP_STATE_WAITING; return; } /* Set the relevant socket options. */ sz = sizeof (val); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); sz = sizeof (val); nn_ep_getopt (self->ep, NN_TCP, NN_TCP_NODELAY, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val)); /* Bind the socket to the local network interface. */ rc = nn_usock_bind (&self->usock, (struct sockaddr*) &local, locallen); if (nn_slow (rc != 0)) { nn_backoff_start (&self->retry); self->state = NN_CTCP_STATE_WAITING; return; } /* Start connecting. */ nn_usock_connect (&self->usock, (struct sockaddr*) &remote, remotelen); self->state = NN_CTCP_STATE_CONNECTING; nn_ep_stat_increment (self->ep, NN_STAT_INPROGRESS_CONNECTIONS, 1); } nanomsg-1.1.5/src/transports/tcp/ctcp.h000066400000000000000000000025531336111550300200610ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_CTCP_INCLUDED #define NN_CTCP_INCLUDED #include "../../transport.h" /* State machine managing connected TCP socket. */ int nn_ctcp_create (struct nn_ep *); #endif nanomsg-1.1.5/src/transports/tcp/stcp.c000066400000000000000000000353721336111550300201010ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "stcp.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/wire.h" #include "../../utils/attr.h" /* States of the object as a whole. */ #define NN_STCP_STATE_IDLE 1 #define NN_STCP_STATE_PROTOHDR 2 #define NN_STCP_STATE_STOPPING_STREAMHDR 3 #define NN_STCP_STATE_ACTIVE 4 #define NN_STCP_STATE_SHUTTING_DOWN 5 #define NN_STCP_STATE_DONE 6 #define NN_STCP_STATE_STOPPING 7 /* Possible states of the inbound part of the object. */ #define NN_STCP_INSTATE_HDR 1 #define NN_STCP_INSTATE_BODY 2 #define NN_STCP_INSTATE_HASMSG 3 /* Possible states of the outbound part of the object. */ #define NN_STCP_OUTSTATE_IDLE 1 #define NN_STCP_OUTSTATE_SENDING 2 /* Subordinate srcptr objects. */ #define NN_STCP_SRC_USOCK 1 #define NN_STCP_SRC_STREAMHDR 2 /* Stream is a special type of pipe. Implementation of the virtual pipe API. */ static int nn_stcp_send (struct nn_pipebase *self, struct nn_msg *msg); static int nn_stcp_recv (struct nn_pipebase *self, struct nn_msg *msg); const struct nn_pipebase_vfptr nn_stcp_pipebase_vfptr = { nn_stcp_send, nn_stcp_recv }; /* Private functions. */ static void nn_stcp_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_stcp_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); void nn_stcp_init (struct nn_stcp *self, int src, struct nn_ep *ep, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_stcp_handler, nn_stcp_shutdown, src, self, owner); self->state = NN_STCP_STATE_IDLE; nn_streamhdr_init (&self->streamhdr, NN_STCP_SRC_STREAMHDR, &self->fsm); self->usock = NULL; self->usock_owner.src = -1; self->usock_owner.fsm = NULL; nn_pipebase_init (&self->pipebase, &nn_stcp_pipebase_vfptr, ep); self->instate = -1; nn_msg_init (&self->inmsg, 0); self->outstate = -1; nn_msg_init (&self->outmsg, 0); nn_fsm_event_init (&self->done); } void nn_stcp_term (struct nn_stcp *self) { nn_assert_state (self, NN_STCP_STATE_IDLE); nn_fsm_event_term (&self->done); nn_msg_term (&self->outmsg); nn_msg_term (&self->inmsg); nn_pipebase_term (&self->pipebase); nn_streamhdr_term (&self->streamhdr); nn_fsm_term (&self->fsm); } int nn_stcp_isidle (struct nn_stcp *self) { return nn_fsm_isidle (&self->fsm); } void nn_stcp_start (struct nn_stcp *self, struct nn_usock *usock) { /* Take ownership of the underlying socket. */ nn_assert (self->usock == NULL && self->usock_owner.fsm == NULL); self->usock_owner.src = NN_STCP_SRC_USOCK; self->usock_owner.fsm = &self->fsm; nn_usock_swap_owner (usock, &self->usock_owner); self->usock = usock; /* Launch the state machine. */ nn_fsm_start (&self->fsm); } void nn_stcp_stop (struct nn_stcp *self) { nn_fsm_stop (&self->fsm); } static int nn_stcp_send (struct nn_pipebase *self, struct nn_msg *msg) { struct nn_stcp *stcp; struct nn_iovec iov [3]; stcp = nn_cont (self, struct nn_stcp, pipebase); nn_assert_state (stcp, NN_STCP_STATE_ACTIVE); nn_assert (stcp->outstate == NN_STCP_OUTSTATE_IDLE); /* Move the message to the local storage. */ nn_msg_term (&stcp->outmsg); nn_msg_mv (&stcp->outmsg, msg); /* Serialise the message header. */ nn_putll (stcp->outhdr, nn_chunkref_size (&stcp->outmsg.sphdr) + nn_chunkref_size (&stcp->outmsg.body)); /* Start async sending. */ iov [0].iov_base = stcp->outhdr; iov [0].iov_len = sizeof (stcp->outhdr); iov [1].iov_base = nn_chunkref_data (&stcp->outmsg.sphdr); iov [1].iov_len = nn_chunkref_size (&stcp->outmsg.sphdr); iov [2].iov_base = nn_chunkref_data (&stcp->outmsg.body); iov [2].iov_len = nn_chunkref_size (&stcp->outmsg.body); nn_usock_send (stcp->usock, iov, 3); stcp->outstate = NN_STCP_OUTSTATE_SENDING; return 0; } static int nn_stcp_recv (struct nn_pipebase *self, struct nn_msg *msg) { struct nn_stcp *stcp; stcp = nn_cont (self, struct nn_stcp, pipebase); nn_assert_state (stcp, NN_STCP_STATE_ACTIVE); nn_assert (stcp->instate == NN_STCP_INSTATE_HASMSG); /* Move received message to the user. */ nn_msg_mv (msg, &stcp->inmsg); nn_msg_init (&stcp->inmsg, 0); /* Start receiving new message. */ stcp->instate = NN_STCP_INSTATE_HDR; nn_usock_recv (stcp->usock, stcp->inhdr, sizeof (stcp->inhdr), NULL); return 0; } static void nn_stcp_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_stcp *stcp; stcp = nn_cont (self, struct nn_stcp, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_pipebase_stop (&stcp->pipebase); nn_streamhdr_stop (&stcp->streamhdr); stcp->state = NN_STCP_STATE_STOPPING; } if (nn_slow (stcp->state == NN_STCP_STATE_STOPPING)) { if (nn_streamhdr_isidle (&stcp->streamhdr)) { nn_usock_swap_owner (stcp->usock, &stcp->usock_owner); stcp->usock = NULL; stcp->usock_owner.src = -1; stcp->usock_owner.fsm = NULL; stcp->state = NN_STCP_STATE_IDLE; nn_fsm_stopped (&stcp->fsm, NN_STCP_STOPPED); return; } return; } nn_fsm_bad_state(stcp->state, src, type); } static void nn_stcp_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { int rc; struct nn_stcp *stcp; uint64_t size; int opt; size_t opt_sz = sizeof (opt); stcp = nn_cont (self, struct nn_stcp, fsm); switch (stcp->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_STCP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_streamhdr_start (&stcp->streamhdr, stcp->usock, &stcp->pipebase); stcp->state = NN_STCP_STATE_PROTOHDR; return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* PROTOHDR state. */ /******************************************************************************/ case NN_STCP_STATE_PROTOHDR: switch (src) { case NN_STCP_SRC_STREAMHDR: switch (type) { case NN_STREAMHDR_OK: /* Before moving to the active state stop the streamhdr state machine. */ nn_streamhdr_stop (&stcp->streamhdr); stcp->state = NN_STCP_STATE_STOPPING_STREAMHDR; return; case NN_STREAMHDR_ERROR: /* Raise the error and move directly to the DONE state. streamhdr object will be stopped later on. */ stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* STOPPING_STREAMHDR state. */ /******************************************************************************/ case NN_STCP_STATE_STOPPING_STREAMHDR: switch (src) { case NN_STCP_SRC_STREAMHDR: switch (type) { case NN_STREAMHDR_STOPPED: /* Start the pipe. */ rc = nn_pipebase_start (&stcp->pipebase); if (nn_slow (rc < 0)) { stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; } /* Start receiving a message in asynchronous manner. */ stcp->instate = NN_STCP_INSTATE_HDR; nn_usock_recv (stcp->usock, &stcp->inhdr, sizeof (stcp->inhdr), NULL); /* Mark the pipe as available for sending. */ stcp->outstate = NN_STCP_OUTSTATE_IDLE; stcp->state = NN_STCP_STATE_ACTIVE; return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_STCP_STATE_ACTIVE: switch (src) { case NN_STCP_SRC_USOCK: switch (type) { case NN_USOCK_SENT: /* The message is now fully sent. */ nn_assert (stcp->outstate == NN_STCP_OUTSTATE_SENDING); stcp->outstate = NN_STCP_OUTSTATE_IDLE; nn_msg_term (&stcp->outmsg); nn_msg_init (&stcp->outmsg, 0); nn_pipebase_sent (&stcp->pipebase); return; case NN_USOCK_RECEIVED: switch (stcp->instate) { case NN_STCP_INSTATE_HDR: /* Message header was received. Check that message size is acceptable by comparing with NN_RCVMAXSIZE; if it's too large, drop the connection. */ size = nn_getll (stcp->inhdr); nn_pipebase_getopt (&stcp->pipebase, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, &opt_sz); if (opt >= 0 && size > (unsigned)opt) { stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; } /* Allocate memory for the message. */ nn_msg_term (&stcp->inmsg); nn_msg_init (&stcp->inmsg, (size_t) size); /* Special case when size of the message body is 0. */ if (!size) { stcp->instate = NN_STCP_INSTATE_HASMSG; nn_pipebase_received (&stcp->pipebase); return; } /* Start receiving the message body. */ stcp->instate = NN_STCP_INSTATE_BODY; nn_usock_recv (stcp->usock, nn_chunkref_data (&stcp->inmsg.body), (size_t) size, NULL); return; case NN_STCP_INSTATE_BODY: /* Message body was received. Notify the owner that it can receive it. */ stcp->instate = NN_STCP_INSTATE_HASMSG; nn_pipebase_received (&stcp->pipebase); return; default: nn_fsm_error("Unexpected socket instate", stcp->state, src, type); } case NN_USOCK_SHUTDOWN: nn_pipebase_stop (&stcp->pipebase); stcp->state = NN_STCP_STATE_SHUTTING_DOWN; return; case NN_USOCK_ERROR: nn_pipebase_stop (&stcp->pipebase); stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* SHUTTING_DOWN state. */ /* The underlying connection is closed. We are just waiting that underlying */ /* usock being closed */ /******************************************************************************/ case NN_STCP_STATE_SHUTTING_DOWN: switch (src) { case NN_STCP_SRC_USOCK: switch (type) { case NN_USOCK_ERROR: stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* DONE state. */ /* The underlying connection is closed. There's nothing that can be done in */ /* this state except stopping the object. */ /******************************************************************************/ case NN_STCP_STATE_DONE: nn_fsm_bad_source (stcp->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (stcp->state, src, type); } } nanomsg-1.1.5/src/transports/tcp/stcp.h000066400000000000000000000054631336111550300201040ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_STCP_INCLUDED #define NN_STCP_INCLUDED #include "../../transport.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../utils/streamhdr.h" #include "../../utils/msg.h" /* This state machine handles TCP connection from the point where it is established to the point when it is broken. */ #define NN_STCP_ERROR 1 #define NN_STCP_STOPPED 2 struct nn_stcp { /* The state machine. */ struct nn_fsm fsm; int state; /* The underlying socket. */ struct nn_usock *usock; /* Child state machine to do protocol header exchange. */ struct nn_streamhdr streamhdr; /* The original owner of the underlying socket. */ struct nn_fsm_owner usock_owner; /* Pipe connecting this TCP connection to the nanomsg core. */ struct nn_pipebase pipebase; /* State of inbound state machine. */ int instate; /* Buffer used to store the header of incoming message. */ uint8_t inhdr [8]; /* Message being received at the moment. */ struct nn_msg inmsg; /* State of the outbound state machine. */ int outstate; /* Buffer used to store the header of outgoing message. */ uint8_t outhdr [8]; /* Message being sent at the moment. */ struct nn_msg outmsg; /* Event raised when the state machine ends. */ struct nn_fsm_event done; }; void nn_stcp_init (struct nn_stcp *self, int src, struct nn_ep *ep, struct nn_fsm *owner); void nn_stcp_term (struct nn_stcp *self); int nn_stcp_isidle (struct nn_stcp *self); void nn_stcp_start (struct nn_stcp *self, struct nn_usock *usock); void nn_stcp_stop (struct nn_stcp *self); #endif nanomsg-1.1.5/src/transports/tcp/tcp.c000066400000000000000000000101751336111550300177100ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "btcp.h" #include "ctcp.h" #include "../../tcp.h" #include "../utils/port.h" #include "../utils/iface.h" #include "../../utils/err.h" #include "../../utils/alloc.h" #include "../../utils/fast.h" #include "../../utils/cont.h" #include #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #endif /* TCP-specific socket options. */ struct nn_tcp_optset { struct nn_optset base; int nodelay; }; static void nn_tcp_optset_destroy (struct nn_optset *self); static int nn_tcp_optset_setopt (struct nn_optset *self, int option, const void *optval, size_t optvallen); static int nn_tcp_optset_getopt (struct nn_optset *self, int option, void *optval, size_t *optvallen); static const struct nn_optset_vfptr nn_tcp_optset_vfptr = { nn_tcp_optset_destroy, nn_tcp_optset_setopt, nn_tcp_optset_getopt }; /* nn_transport interface. */ static int nn_tcp_bind (struct nn_ep *ep); static int nn_tcp_connect (struct nn_ep *ep); static struct nn_optset *nn_tcp_optset (void); struct nn_transport nn_tcp = { "tcp", NN_TCP, NULL, NULL, nn_tcp_bind, nn_tcp_connect, nn_tcp_optset, }; static int nn_tcp_bind (struct nn_ep *ep) { return nn_btcp_create (ep); } static int nn_tcp_connect (struct nn_ep *ep) { return nn_ctcp_create (ep); } static struct nn_optset *nn_tcp_optset () { struct nn_tcp_optset *optset; optset = nn_alloc (sizeof (struct nn_tcp_optset), "optset (tcp)"); alloc_assert (optset); optset->base.vfptr = &nn_tcp_optset_vfptr; /* Default values for TCP socket options. */ optset->nodelay = 0; return &optset->base; } static void nn_tcp_optset_destroy (struct nn_optset *self) { struct nn_tcp_optset *optset; optset = nn_cont (self, struct nn_tcp_optset, base); nn_free (optset); } static int nn_tcp_optset_setopt (struct nn_optset *self, int option, const void *optval, size_t optvallen) { struct nn_tcp_optset *optset; int val; optset = nn_cont (self, struct nn_tcp_optset, base); /* At this point we assume that all options are of type int. */ if (optvallen != sizeof (int)) return -EINVAL; val = *(int*) optval; switch (option) { case NN_TCP_NODELAY: if (nn_slow (val != 0 && val != 1)) return -EINVAL; optset->nodelay = val; return 0; default: return -ENOPROTOOPT; } } static int nn_tcp_optset_getopt (struct nn_optset *self, int option, void *optval, size_t *optvallen) { struct nn_tcp_optset *optset; int intval; optset = nn_cont (self, struct nn_tcp_optset, base); switch (option) { case NN_TCP_NODELAY: intval = optset->nodelay; break; default: return -ENOPROTOOPT; } memcpy (optval, &intval, *optvallen < sizeof (int) ? *optvallen : sizeof (int)); *optvallen = sizeof (int); return 0; } nanomsg-1.1.5/src/transports/utils/000077500000000000000000000000001336111550300173245ustar00rootroot00000000000000nanomsg-1.1.5/src/transports/utils/README000066400000000000000000000001251336111550300202020ustar00rootroot00000000000000This directory contains the utilities that can be used when creating new transports. nanomsg-1.1.5/src/transports/utils/backoff.c000066400000000000000000000041361336111550300210670ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "backoff.h" void nn_backoff_init (struct nn_backoff *self, int src, int minivl, int maxivl, struct nn_fsm *owner) { nn_timer_init (&self->timer, src, owner); self->minivl = minivl; self->maxivl = maxivl; self->n = 1; } void nn_backoff_term (struct nn_backoff *self) { nn_timer_term (&self->timer); } int nn_backoff_isidle (struct nn_backoff *self) { return nn_timer_isidle (&self->timer); } void nn_backoff_start (struct nn_backoff *self) { int timeout; /* Start the timer for the actual n value. If the interval haven't yet exceeded the maximum, double the next timeout value. */ timeout = (self->n - 1) * self->minivl; if (timeout > self->maxivl) timeout = self->maxivl; else self->n *= 2; nn_timer_start (&self->timer, timeout); } void nn_backoff_stop (struct nn_backoff *self) { nn_timer_stop (&self->timer); } void nn_backoff_reset (struct nn_backoff *self) { self->n = 1; } nanomsg-1.1.5/src/transports/utils/backoff.h000066400000000000000000000036201336111550300210710ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_BACKOFF_INCLUDED #define NN_BACKOFF_INCLUDED #include "../../aio/timer.h" /* Timer with exponential backoff. Actual wating time is (2^n-1)*minivl, meaning that first wait is 0 ms long, second one is minivl ms long etc. */ #define NN_BACKOFF_TIMEOUT NN_TIMER_TIMEOUT #define NN_BACKOFF_STOPPED NN_TIMER_STOPPED struct nn_backoff { struct nn_timer timer; int minivl; int maxivl; int n; }; void nn_backoff_init (struct nn_backoff *self, int src, int minivl, int maxivl, struct nn_fsm *owner); void nn_backoff_term (struct nn_backoff *self); int nn_backoff_isidle (struct nn_backoff *self); void nn_backoff_start (struct nn_backoff *self); void nn_backoff_stop (struct nn_backoff *self); void nn_backoff_reset (struct nn_backoff *self); #endif nanomsg-1.1.5/src/transports/utils/base64.c000066400000000000000000000116361336111550300205630ustar00rootroot00000000000000/* Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. 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. */ #include "base64.h" #include int nn_base64_decode (const char *in, size_t in_len, uint8_t *out, size_t out_len) { unsigned ii; unsigned io; unsigned rem; uint32_t v; uint8_t ch; /* Unrolled lookup of ASCII code points. 0xFF represents a non-base64 valid character. */ const uint8_t DECODEMAP [256] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; for (io = 0, ii = 0, v = 0, rem = 0; ii < in_len; ii++) { if (isspace (in [ii])) continue; if (in [ii] == '=') break; ch = DECODEMAP [(int)(in [ii])]; /* Discard invalid characters as per RFC 2045. */ if (ch == 0xFF) break; v = (v << 6) | ch; rem += 6; if (rem >= 8) { rem -= 8; if (io >= out_len) return -ENOBUFS; out [io++] = (v >> rem) & 255; } } if (rem >= 8) { rem -= 8; if (io >= out_len) return -ENOBUFS; out [io++] = (v >> rem) & 255; } return io; } int nn_base64_encode (const uint8_t *in, size_t in_len, char *out, size_t out_len) { unsigned ii; unsigned io; unsigned rem; uint32_t v; uint8_t ch; const uint8_t ENCODEMAP [64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; for (io = 0, ii = 0, v = 0, rem = 0; ii < in_len; ii++) { ch = in [ii]; v = (v << 8) | ch; rem += 8; while (rem >= 6) { rem -= 6; if (io >= out_len) return -ENOBUFS; out [io++] = ENCODEMAP [(v >> rem) & 63]; } } if (rem) { v <<= (6 - rem); if (io >= out_len) return -ENOBUFS; out [io++] = ENCODEMAP [v & 63]; } /* Pad to a multiple of 3. */ while (io & 3) { if (io >= out_len) return -ENOBUFS; out [io++] = '='; } if (io >= out_len) return -ENOBUFS; out [io] = '\0'; return io; } nanomsg-1.1.5/src/transports/utils/base64.h000066400000000000000000000033011336111550300205560ustar00rootroot00000000000000/* Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. 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. */ #ifndef NN_BASE64_INCLUDED #define NN_BASE64_INCLUDED #include "../../utils/err.h" #include #include /* Based on base64.c (Public Domain) by Jon Mayo. Base64 is defined in RFC 2045, section 6.8. */ /* This function encodes an arbitrary byte array into base64 null-terminated string. */ int nn_base64_encode (const uint8_t *in, size_t in_len, char *out, size_t out_len); /* This function decodes a base64 string into supplied buffer. */ int nn_base64_decode (const char *in, size_t in_len, uint8_t *out, size_t out_len); #endif nanomsg-1.1.5/src/transports/utils/dns.c000066400000000000000000000052551336111550300202630ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "dns.h" #include "../../utils/err.h" #include int nn_dns_check_hostname (const char *name, size_t namelen) { int labelsz; /* There has to be at least one label in the hostname. Additionally, hostnames are up to 255 characters long. */ if (namelen < 1 || namelen > 255) return -EINVAL; /* Hyphen can't be used as a first character of the hostname. */ if (*name == '-') return -EINVAL; labelsz = 0; while (1) { /* End of the hostname. */ if (namelen == 0) { /* Success! */ return 0; } /* End of a label. */ if (*name == '.') { /* The old label cannot be empty. */ if (labelsz == 0) return -EINVAL; /* Start new label. */ labelsz = 0; ++name; --namelen; continue; } /* Valid character. */ if ((*name >= 'a' && *name <= 'z') || (*name >= 'A' && *name <= 'Z') || (*name >= '0' && *name <= '9') || *name == '-') { ++name; --namelen; ++labelsz; /* Labels longer than 63 charcters are not permitted. */ if (labelsz > 63) return -EINVAL; continue; } /* Invalid character. */ return -EINVAL; } } #if defined NN_HAVE_GETADDRINFO_A && !defined NN_DISABLE_GETADDRINFO_A #include "dns_getaddrinfo_a.inc" #else #include "dns_getaddrinfo.inc" #endif nanomsg-1.1.5/src/transports/utils/dns.h000066400000000000000000000040411336111550300202600ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_DNS_INCLUDED #define NN_DNS_INCLUDED #include "../../aio/fsm.h" #include /* Checks the hostname according to RFC 952 and RFC 1123. Returns 0 in case the it is valid. */ int nn_dns_check_hostname (const char *name, size_t namelen); /* Events generated by the DNS state machine. */ #define NN_DNS_DONE 1 #define NN_DNS_STOPPED 2 #if defined NN_HAVE_GETADDRINFO_A && !defined NN_DISABLE_GETADDRINFO_A #include "dns_getaddrinfo_a.h" #else #include "dns_getaddrinfo.h" #endif struct nn_dns_result { int error; struct sockaddr_storage addr; size_t addrlen; }; void nn_dns_init (struct nn_dns *self, int src, struct nn_fsm *owner); void nn_dns_term (struct nn_dns *self); int nn_dns_isidle (struct nn_dns *self); void nn_dns_start (struct nn_dns *self, const char *addr, size_t addrlen, int ipv4only, struct nn_dns_result *result); void nn_dns_stop (struct nn_dns *self); #endif nanomsg-1.1.5/src/transports/utils/dns_getaddrinfo.h000066400000000000000000000025351336111550300226340ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #endif struct nn_dns { struct nn_fsm fsm; int state; struct nn_dns_result *result; struct nn_fsm_event done; }; nanomsg-1.1.5/src/transports/utils/dns_getaddrinfo.inc000066400000000000000000000133431336111550300231550ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "literal.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/attr.h" #include #ifndef NN_HAVE_WINDOWS #include #include #include #endif #define NN_DNS_STATE_IDLE 1 #define NN_DNS_STATE_DONE 2 /* Private functions. */ static void nn_dns_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_dns_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); void nn_dns_init (struct nn_dns *self, int src, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_dns_handler, nn_dns_shutdown, src, self, owner); self->state = NN_DNS_STATE_IDLE; nn_fsm_event_init (&self->done); } void nn_dns_term (struct nn_dns *self) { nn_assert_state (self, NN_DNS_STATE_IDLE); nn_fsm_event_term (&self->done); nn_fsm_term (&self->fsm); } int nn_dns_isidle (struct nn_dns *self) { return nn_fsm_isidle (&self->fsm); } void nn_dns_start (struct nn_dns *self, const char *addr, size_t addrlen, int ipv4only, struct nn_dns_result *result) { int rc; struct addrinfo query; struct addrinfo *reply; char hostname [NN_SOCKADDR_MAX]; nn_assert_state (self, NN_DNS_STATE_IDLE); self->result = result; /* Try to resolve the supplied string as a literal address. In this case, there's no DNS lookup involved. */ rc = nn_literal_resolve (addr, addrlen, ipv4only, &self->result->addr, &self->result->addrlen); if (rc == 0) { self->result->error = 0; nn_fsm_start (&self->fsm); return; } errnum_assert (rc == -EINVAL, -rc); /* The name is not a literal. Let's do an actual DNS lookup. */ memset (&query, 0, sizeof (query)); if (ipv4only) query.ai_family = AF_INET; else { query.ai_family = AF_INET6; #ifdef AI_V4MAPPED query.ai_flags = AI_V4MAPPED; #endif } nn_assert (sizeof (hostname) > addrlen); query.ai_socktype = SOCK_STREAM; memcpy (hostname, addr, addrlen); hostname [addrlen] = 0; /* Perform the DNS lookup itself. */ self->result->error = getaddrinfo (hostname, NULL, &query, &reply); if (self->result->error) { nn_fsm_start (&self->fsm); return; } /* Take just the first address and store it. (RFC recommends that we iterate through addresses until one works, but that doesn't match our state model. This is the best we can do.) */ self->result->error = 0; memcpy (&self->result->addr, reply->ai_addr, reply->ai_addrlen); self->result->addrlen = reply->ai_addrlen; freeaddrinfo (reply); nn_fsm_start (&self->fsm); } void nn_dns_stop (struct nn_dns *self) { nn_fsm_stop (&self->fsm); } static void nn_dns_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_dns *dns; dns = nn_cont (self, struct nn_dns, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_fsm_stopped (&dns->fsm, NN_DNS_STOPPED); dns->state = NN_DNS_STATE_IDLE; return; } nn_fsm_bad_state(dns->state, src, type); } static void nn_dns_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_dns *dns; dns = nn_cont (self, struct nn_dns, fsm); switch (dns->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_DNS_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_fsm_raise (&dns->fsm, &dns->done, NN_DNS_DONE); dns->state = NN_DNS_STATE_DONE; return; default: nn_fsm_bad_action (dns->state, src, type); } default: nn_fsm_bad_source (dns->state, src, type); } /******************************************************************************/ /* DONE state. */ /******************************************************************************/ case NN_DNS_STATE_DONE: nn_fsm_bad_source (dns->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (dns->state, src, type); } } nanomsg-1.1.5/src/transports/utils/dns_getaddrinfo_a.h000066400000000000000000000027571336111550300231420ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include #include "../../nn.h" #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #endif struct nn_dns { struct nn_fsm fsm; int state; int error; char hostname [NN_SOCKADDR_MAX]; struct addrinfo request; struct gaicb gcb; struct nn_dns_result *result; struct nn_fsm_event done; }; nanomsg-1.1.5/src/transports/utils/dns_getaddrinfo_a.inc000066400000000000000000000204551336111550300234570ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "literal.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/attr.h" #include "../../aio/ctx.h" #include #define NN_DNS_STATE_IDLE 1 #define NN_DNS_STATE_RESOLVING 2 #define NN_DNS_STATE_DONE 3 #define NN_DNS_STATE_STOPPING 4 #define NN_DNS_ACTION_DONE 1 #define NN_DNS_ACTION_CANCELLED 2 /* Private functions. */ static void nn_dns_notify (union sigval); static void nn_dns_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_dns_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); void nn_dns_init (struct nn_dns *self, int src, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_dns_handler, nn_dns_shutdown, src, self, owner); self->state = NN_DNS_STATE_IDLE; nn_fsm_event_init (&self->done); } void nn_dns_term (struct nn_dns *self) { nn_assert_state (self, NN_DNS_STATE_IDLE); nn_fsm_event_term (&self->done); nn_fsm_term (&self->fsm); } int nn_dns_isidle (struct nn_dns *self) { return nn_fsm_isidle (&self->fsm); } void nn_dns_start (struct nn_dns *self, const char *addr, size_t addrlen, int ipv4only, struct nn_dns_result *result) { int rc; struct gaicb *pgcb; struct sigevent sev; nn_assert_state (self, NN_DNS_STATE_IDLE); self->result = result; /* Try to resolve the supplied string as a literal address. In this case, there's no DNS lookup involved. */ rc = nn_literal_resolve (addr, addrlen, ipv4only, &self->result->addr, &self->result->addrlen); if (rc == 0) { self->result->error = 0; nn_fsm_start (&self->fsm); return; } errnum_assert (rc == -EINVAL, -rc); /* Make a zero-terminated copy of the address string. */ nn_assert (sizeof (self->hostname) > addrlen); memcpy (self->hostname, addr, addrlen); self->hostname [addrlen] = 0; /* Start asynchronous DNS lookup. */ memset (&self->request, 0, sizeof (self->request)); if (ipv4only) self->request.ai_family = AF_INET; else { self->request.ai_family = AF_INET6; #ifdef AI_V4MAPPED self->request.ai_flags = AI_V4MAPPED; #endif } self->request.ai_socktype = SOCK_STREAM; memset (&self->gcb, 0, sizeof (self->gcb)); self->gcb.ar_name = self->hostname; self->gcb.ar_service = NULL; self->gcb.ar_request = &self->request; self->gcb.ar_result = NULL; pgcb = &self->gcb; memset (&sev, 0, sizeof (sev)); sev.sigev_notify = SIGEV_THREAD; sev.sigev_notify_function = nn_dns_notify; sev.sigev_value.sival_ptr = self; rc = getaddrinfo_a (GAI_NOWAIT, &pgcb, 1, &sev); nn_assert (rc == 0); self->result->error = EINPROGRESS; nn_fsm_start (&self->fsm); } void nn_dns_stop (struct nn_dns *self) { nn_fsm_stop (&self->fsm); } static void nn_dns_notify (union sigval sval) { int rc; struct nn_dns *self; self = (struct nn_dns*) sval.sival_ptr; nn_ctx_enter (self->fsm.ctx); rc = gai_error (&self->gcb); if (rc == EAI_CANCELED) { nn_fsm_action (&self->fsm, NN_DNS_ACTION_CANCELLED); } else if (rc != 0) { self->result->error = EINVAL; nn_fsm_action (&self->fsm, NN_DNS_ACTION_DONE); } else { self->result->error = 0; nn_assert (self->gcb.ar_result->ai_addrlen <= sizeof (struct sockaddr_storage)); memcpy (&self->result->addr, self->gcb.ar_result->ai_addr, self->gcb.ar_result->ai_addrlen); self->result->addrlen = (size_t) self->gcb.ar_result->ai_addrlen; freeaddrinfo(self->gcb.ar_result); nn_fsm_action (&self->fsm, NN_DNS_ACTION_DONE); } nn_ctx_leave (self->fsm.ctx); } static void nn_dns_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { int rc; struct nn_dns *dns; dns = nn_cont (self, struct nn_dns, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (dns->state == NN_DNS_STATE_RESOLVING) { rc = gai_cancel (&dns->gcb); if (rc == EAI_CANCELED) { nn_fsm_stopped (&dns->fsm, NN_DNS_STOPPED); dns->state = NN_DNS_STATE_IDLE; return; } if (rc == EAI_NOTCANCELED || rc == EAI_ALLDONE) { dns->state = NN_DNS_STATE_STOPPING; return; } nn_assert (0); } nn_fsm_stopped (&dns->fsm, NN_DNS_STOPPED); dns->state = NN_DNS_STATE_IDLE; return; } if (nn_slow (dns->state == NN_DNS_STATE_STOPPING)) { if (src == NN_FSM_ACTION && (type == NN_DNS_ACTION_CANCELLED || type == NN_DNS_ACTION_DONE)) { nn_fsm_stopped (&dns->fsm, NN_DNS_STOPPED); dns->state = NN_DNS_STATE_IDLE; return; } return; } nn_fsm_bad_state (dns->state, src, type); } static void nn_dns_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_dns *dns; dns = nn_cont (self, struct nn_dns, fsm); switch (dns->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_DNS_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: if (dns->result->error == EINPROGRESS) { dns->state = NN_DNS_STATE_RESOLVING; return; } nn_fsm_raise (&dns->fsm, &dns->done, NN_DNS_DONE); dns->state = NN_DNS_STATE_DONE; return; default: nn_fsm_bad_action (dns->state, src, type); } default: nn_fsm_bad_source (dns->state, src, type); } /******************************************************************************/ /* RESOLVING state. */ /******************************************************************************/ case NN_DNS_STATE_RESOLVING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_DNS_ACTION_DONE: nn_fsm_raise (&dns->fsm, &dns->done, NN_DNS_DONE); dns->state = NN_DNS_STATE_DONE; return; default: nn_fsm_bad_action (dns->state, src, type); } default: nn_fsm_bad_source (dns->state, src, type); } /******************************************************************************/ /* DONE state. */ /******************************************************************************/ case NN_DNS_STATE_DONE: nn_fsm_bad_source (dns->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (dns->state, src, type); } } nanomsg-1.1.5/src/transports/utils/iface.c000066400000000000000000000054761336111550300205530ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2015 Garrett D'Amore 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. */ #include "iface.h" #include "literal.h" #include "../../utils/err.h" #include "../../utils/closefd.h" #include #ifndef NN_HAVE_WINDOWS #include #include #endif /* Private functions. */ static void nn_iface_any (int ipv4only, struct sockaddr_storage *result, size_t *resultlen); /* We no longer resolve interface names. This feature was non-portable and fragile. Only IP addresses may be used. They are provided in the form of string literals. */ int nn_iface_resolve (const char *addr, size_t addrlen, int ipv4only, struct sockaddr_storage *result, size_t *resultlen) { int rc; /* Asterisk is a special name meaning "all interfaces". */ if (addrlen == 1 && addr [0] == '*') { nn_iface_any (ipv4only, result, resultlen); return 0; } rc = nn_literal_resolve (addr, addrlen, ipv4only, result, resultlen); if (rc == -EINVAL) return -ENODEV; errnum_assert (rc == 0, -rc); return 0; } static void nn_iface_any (int ipv4only, struct sockaddr_storage *result, size_t *resultlen) { if (ipv4only) { if (result) { result->ss_family = AF_INET; ((struct sockaddr_in*) result)->sin_addr.s_addr = htonl (INADDR_ANY); } if (resultlen) *resultlen = sizeof (struct sockaddr_in); } else { if (result) { result->ss_family = AF_INET6; memcpy (&((struct sockaddr_in6*) result)->sin6_addr, &in6addr_any, sizeof (in6addr_any)); } if (resultlen) *resultlen = sizeof (struct sockaddr_in6); } } nanomsg-1.1.5/src/transports/utils/iface.h000066400000000000000000000030551336111550300205470ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_IFACE_INCLUDED #define NN_IFACE_INCLUDED #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #endif #include /* Resolves name of a local network interface into the address itself. Name '*' is resolved as 'all interfaces'. */ int nn_iface_resolve (const char *addr, size_t addrlen, int ipv4only, struct sockaddr_storage *result, size_t *resultlen); #endif nanomsg-1.1.5/src/transports/utils/literal.c000066400000000000000000000062261336111550300211320ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "literal.h" #include "../../utils/err.h" #include "../../utils/fast.h" #include #ifndef NN_HAVE_WINDOWS #include #include #endif int nn_literal_resolve (const char *addr, size_t addrlen, int ipv4only, struct sockaddr_storage *result, size_t *resultlen) { int rc; char addrz [INET6_ADDRSTRLEN > INET_ADDRSTRLEN ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN]; struct in_addr inaddr; struct in6_addr in6addr; /* Try to treat the address as a literal string. If the size of the address is larger than longest possible literal, skip the step. If the literal in enclosed in square brackets ignore them. */ if (addrlen > 0 && addr [0] == '[') { if (addr [addrlen - 1] != ']') return -EINVAL; if (addrlen - 2 + 1 > sizeof (addrz)) return -EINVAL; memcpy (addrz, addr + 1, addrlen - 2); addrz [addrlen - 2] = 0; } else { if (addrlen + 1 > sizeof (addrz)) return -EINVAL; memcpy (addrz, addr, addrlen); addrz [addrlen] = 0; } /* Try to interpret the literal as an IPv6 address. */ if (!ipv4only) { rc = inet_pton (AF_INET6, addrz, &in6addr); if (rc == 1) { if (result) { result->ss_family = AF_INET6; ((struct sockaddr_in6*) result)->sin6_addr = in6addr; } if (resultlen) *resultlen = sizeof (struct sockaddr_in6); return 0; } errno_assert (rc == 0); } /* Try to interpret the literal as an IPv4 address. */ rc = inet_pton (AF_INET, addrz, &inaddr); if (rc == 1) { if (result) { result->ss_family = AF_INET; ((struct sockaddr_in*) result)->sin_addr = inaddr; } if (resultlen) *resultlen = sizeof (struct sockaddr_in); return 0; } errno_assert (rc == 0); /* The supplied string is not a valid literal address. */ return -EINVAL; } nanomsg-1.1.5/src/transports/utils/literal.h000066400000000000000000000027521336111550300211370ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_LITERAL_INCLUDED #define NN_LITERAL_INCLUDED #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #endif #include /* Resolves a literal IPv4 or IPv6 address. */ int nn_literal_resolve (const char *addr, size_t addrlen, int ipv4only, struct sockaddr_storage *result, size_t *resultlen); #endif nanomsg-1.1.5/src/transports/utils/port.c000066400000000000000000000033021336111550300204520ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "port.h" #include "../../utils/err.h" int nn_port_resolve (const char *port, size_t portlen) { int res; size_t i; res = 0; for (i = 0; i != portlen; ++i) { if (port [i] < '0' || port [i] > '9') return -EINVAL; res *= 10; res += port [i] - '0'; if (res > 0xffff) return -EINVAL; } /* Port 0 has special meaning (assign an ephemeral port to the socket), thus it is illegal to use it in the connection string. */ if (res == 0) return -EINVAL; return res; } nanomsg-1.1.5/src/transports/utils/port.h000066400000000000000000000026361336111550300204700ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_PORT_INCLUDED #define NN_PORT_INCLUDED #include /* Parse the string containing a port number. Returns port number in integer form or -EINVAL if the string doesn't contain a port number. */ int nn_port_resolve (const char *port, size_t portlen); #endif nanomsg-1.1.5/src/transports/utils/streamhdr.c000066400000000000000000000274521336111550300214730ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #include "streamhdr.h" #include "../../aio/timer.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/wire.h" #include "../../utils/attr.h" #include #include #define NN_STREAMHDR_STATE_IDLE 1 #define NN_STREAMHDR_STATE_SENDING 2 #define NN_STREAMHDR_STATE_RECEIVING 3 #define NN_STREAMHDR_STATE_STOPPING_TIMER_ERROR 4 #define NN_STREAMHDR_STATE_STOPPING_TIMER_DONE 5 #define NN_STREAMHDR_STATE_DONE 6 #define NN_STREAMHDR_STATE_STOPPING 7 #define NN_STREAMHDR_SRC_USOCK 1 #define NN_STREAMHDR_SRC_TIMER 2 /* Private functions. */ static void nn_streamhdr_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_streamhdr_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); void nn_streamhdr_init (struct nn_streamhdr *self, int src, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_streamhdr_handler, nn_streamhdr_shutdown, src, self, owner); self->state = NN_STREAMHDR_STATE_IDLE; nn_timer_init (&self->timer, NN_STREAMHDR_SRC_TIMER, &self->fsm); nn_fsm_event_init (&self->done); self->usock = NULL; self->usock_owner.src = -1; self->usock_owner.fsm = NULL; self->pipebase = NULL; } void nn_streamhdr_term (struct nn_streamhdr *self) { nn_assert_state (self, NN_STREAMHDR_STATE_IDLE); nn_fsm_event_term (&self->done); nn_timer_term (&self->timer); nn_fsm_term (&self->fsm); } int nn_streamhdr_isidle (struct nn_streamhdr *self) { return nn_fsm_isidle (&self->fsm); } void nn_streamhdr_start (struct nn_streamhdr *self, struct nn_usock *usock, struct nn_pipebase *pipebase) { size_t sz; int protocol; /* Take ownership of the underlying socket. */ nn_assert (self->usock == NULL && self->usock_owner.fsm == NULL); self->usock_owner.src = NN_STREAMHDR_SRC_USOCK; self->usock_owner.fsm = &self->fsm; nn_usock_swap_owner (usock, &self->usock_owner); self->usock = usock; self->pipebase = pipebase; /* Get the protocol identifier. */ sz = sizeof (protocol); nn_pipebase_getopt (pipebase, NN_SOL_SOCKET, NN_PROTOCOL, &protocol, &sz); nn_assert (sz == sizeof (protocol)); /* Compose the protocol header. */ memcpy (self->protohdr, "\0SP\0\0\0\0\0", 8); nn_puts (self->protohdr + 4, (uint16_t) protocol); /* Launch the state machine. */ nn_fsm_start (&self->fsm); } void nn_streamhdr_stop (struct nn_streamhdr *self) { nn_fsm_stop (&self->fsm); } static void nn_streamhdr_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_streamhdr *streamhdr; streamhdr = nn_cont (self, struct nn_streamhdr, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_timer_stop (&streamhdr->timer); streamhdr->state = NN_STREAMHDR_STATE_STOPPING; } if (nn_slow (streamhdr->state == NN_STREAMHDR_STATE_STOPPING)) { if (!nn_timer_isidle (&streamhdr->timer)) return; streamhdr->state = NN_STREAMHDR_STATE_IDLE; nn_fsm_stopped (&streamhdr->fsm, NN_STREAMHDR_STOPPED); return; } nn_fsm_bad_state (streamhdr->state, src, type); } static void nn_streamhdr_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_streamhdr *streamhdr; struct nn_iovec iovec; int protocol; streamhdr = nn_cont (self, struct nn_streamhdr, fsm); switch (streamhdr->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_STREAMHDR_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_timer_start (&streamhdr->timer, 1000); iovec.iov_base = streamhdr->protohdr; iovec.iov_len = sizeof (streamhdr->protohdr); nn_usock_send (streamhdr->usock, &iovec, 1); streamhdr->state = NN_STREAMHDR_STATE_SENDING; return; default: nn_fsm_bad_action (streamhdr->state, src, type); } default: nn_fsm_bad_source (streamhdr->state, src, type); } /******************************************************************************/ /* SENDING state. */ /******************************************************************************/ case NN_STREAMHDR_STATE_SENDING: switch (src) { case NN_STREAMHDR_SRC_USOCK: switch (type) { case NN_USOCK_SENT: nn_usock_recv (streamhdr->usock, streamhdr->protohdr, sizeof (streamhdr->protohdr), NULL); streamhdr->state = NN_STREAMHDR_STATE_RECEIVING; return; case NN_USOCK_SHUTDOWN: /* Ignore it. Wait for ERROR event */ return; case NN_USOCK_ERROR: nn_timer_stop (&streamhdr->timer); streamhdr->state = NN_STREAMHDR_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (streamhdr->state, src, type); } case NN_STREAMHDR_SRC_TIMER: switch (type) { case NN_TIMER_TIMEOUT: nn_timer_stop (&streamhdr->timer); streamhdr->state = NN_STREAMHDR_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (streamhdr->state, src, type); } default: nn_fsm_bad_source (streamhdr->state, src, type); } /******************************************************************************/ /* RECEIVING state. */ /******************************************************************************/ case NN_STREAMHDR_STATE_RECEIVING: switch (src) { case NN_STREAMHDR_SRC_USOCK: switch (type) { case NN_USOCK_RECEIVED: /* Here we are checking whether the peer speaks the same protocol as this socket. */ if (memcmp (streamhdr->protohdr, "\0SP\0", 4) != 0) goto invalidhdr; protocol = nn_gets (streamhdr->protohdr + 4); if (!nn_pipebase_ispeer (streamhdr->pipebase, protocol)) goto invalidhdr; nn_timer_stop (&streamhdr->timer); streamhdr->state = NN_STREAMHDR_STATE_STOPPING_TIMER_DONE; return; case NN_USOCK_SHUTDOWN: /* Ignore it. Wait for ERROR event */ return; case NN_USOCK_ERROR: invalidhdr: nn_timer_stop (&streamhdr->timer); streamhdr->state = NN_STREAMHDR_STATE_STOPPING_TIMER_ERROR; return; default: nn_assert (0); return; } case NN_STREAMHDR_SRC_TIMER: switch (type) { case NN_TIMER_TIMEOUT: nn_timer_stop (&streamhdr->timer); streamhdr->state = NN_STREAMHDR_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (streamhdr->state, src, type); } default: nn_fsm_bad_source (streamhdr->state, src, type); } /******************************************************************************/ /* STOPPING_TIMER_ERROR state. */ /******************************************************************************/ case NN_STREAMHDR_STATE_STOPPING_TIMER_ERROR: switch (src) { case NN_STREAMHDR_SRC_USOCK: /* It's safe to ignore usock event when we are stopping, but there is only a subset of events that are plausible. */ return; case NN_STREAMHDR_SRC_TIMER: switch (type) { case NN_TIMER_STOPPED: nn_usock_swap_owner (streamhdr->usock, &streamhdr->usock_owner); streamhdr->usock = NULL; streamhdr->usock_owner.src = -1; streamhdr->usock_owner.fsm = NULL; streamhdr->state = NN_STREAMHDR_STATE_DONE; nn_fsm_raise (&streamhdr->fsm, &streamhdr->done, NN_STREAMHDR_ERROR); return; default: nn_fsm_bad_action (streamhdr->state, src, type); } default: nn_fsm_bad_source (streamhdr->state, src, type); } /******************************************************************************/ /* STOPPING_TIMER_DONE state. */ /******************************************************************************/ case NN_STREAMHDR_STATE_STOPPING_TIMER_DONE: switch (src) { case NN_STREAMHDR_SRC_USOCK: /* It's safe to ignore usock event when we are stopping. */ return; case NN_STREAMHDR_SRC_TIMER: switch (type) { case NN_TIMER_STOPPED: nn_usock_swap_owner (streamhdr->usock, &streamhdr->usock_owner); streamhdr->usock = NULL; streamhdr->usock_owner.src = -1; streamhdr->usock_owner.fsm = NULL; streamhdr->state = NN_STREAMHDR_STATE_DONE; nn_fsm_raise (&streamhdr->fsm, &streamhdr->done, NN_STREAMHDR_OK); return; default: nn_fsm_bad_action (streamhdr->state, src, type); } default: nn_fsm_bad_source (streamhdr->state, src, type); } /******************************************************************************/ /* DONE state. */ /* The header exchange was either done successfully of failed. There's */ /* nothing that can be done in this state except stopping the object. */ /******************************************************************************/ case NN_STREAMHDR_STATE_DONE: nn_fsm_bad_source (streamhdr->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (streamhdr->state, src, type); } } nanomsg-1.1.5/src/transports/utils/streamhdr.h000066400000000000000000000045761336111550300215020ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_STREAMHDR_INCLUDED #define NN_STREAMHDR_INCLUDED #include "../../transport.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../../aio/timer.h" /* This state machine exchanges protocol headers on top of a stream-based bi-directional connection. */ #define NN_STREAMHDR_OK 1 #define NN_STREAMHDR_ERROR 2 #define NN_STREAMHDR_STOPPED 3 struct nn_streamhdr { /* The state machine. */ struct nn_fsm fsm; int state; /* Used to timeout the protocol header exchange. */ struct nn_timer timer; /* The underlying socket. */ struct nn_usock *usock; /* The original owner of the underlying socket. */ struct nn_fsm_owner usock_owner; /* Handle to the pipe. */ struct nn_pipebase *pipebase; /* Protocol header. */ uint8_t protohdr [8]; /* Event fired when the state machine ends. */ struct nn_fsm_event done; }; void nn_streamhdr_init (struct nn_streamhdr *self, int src, struct nn_fsm *owner); void nn_streamhdr_term (struct nn_streamhdr *self); int nn_streamhdr_isidle (struct nn_streamhdr *self); void nn_streamhdr_start (struct nn_streamhdr *self, struct nn_usock *usock, struct nn_pipebase *pipebase); void nn_streamhdr_stop (struct nn_streamhdr *self); #endif nanomsg-1.1.5/src/transports/ws/000077500000000000000000000000001336111550300166155ustar00rootroot00000000000000nanomsg-1.1.5/src/transports/ws/aws.c000066400000000000000000000266111336111550300175610ustar00rootroot00000000000000/* Copyright (c) 2012-2013 250bpm s.r.o. All rights reserved. Copyright (c) 2014-2016 Jack R. Dunaway. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "aws.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/attr.h" #include "../../ws.h" #define NN_AWS_STATE_IDLE 1 #define NN_AWS_STATE_ACCEPTING 2 #define NN_AWS_STATE_ACTIVE 3 #define NN_AWS_STATE_STOPPING_SWS 4 #define NN_AWS_STATE_STOPPING_USOCK 5 #define NN_AWS_STATE_DONE 6 #define NN_AWS_STATE_STOPPING_SWS_FINAL 7 #define NN_AWS_STATE_STOPPING 8 #define NN_AWS_SRC_USOCK 1 #define NN_AWS_SRC_SWS 2 #define NN_AWS_SRC_LISTENER 3 /* Private functions. */ static void nn_aws_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_aws_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); void nn_aws_init (struct nn_aws *self, int src, struct nn_ep *ep, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_aws_handler, nn_aws_shutdown, src, self, owner); self->state = NN_AWS_STATE_IDLE; self->ep = ep; nn_usock_init (&self->usock, NN_AWS_SRC_USOCK, &self->fsm); self->listener = NULL; self->listener_owner.src = -1; self->listener_owner.fsm = NULL; nn_sws_init (&self->sws, NN_AWS_SRC_SWS, ep, &self->fsm); nn_fsm_event_init (&self->accepted); nn_fsm_event_init (&self->done); nn_list_item_init (&self->item); } void nn_aws_term (struct nn_aws *self) { nn_assert_state (self, NN_AWS_STATE_IDLE); nn_list_item_term (&self->item); nn_fsm_event_term (&self->done); nn_fsm_event_term (&self->accepted); nn_sws_term (&self->sws); nn_usock_term (&self->usock); nn_fsm_term (&self->fsm); } int nn_aws_isidle (struct nn_aws *self) { return nn_fsm_isidle (&self->fsm); } void nn_aws_start (struct nn_aws *self, struct nn_usock *listener) { nn_assert_state (self, NN_AWS_STATE_IDLE); /* Take ownership of the listener socket. */ self->listener = listener; self->listener_owner.src = NN_AWS_SRC_LISTENER; self->listener_owner.fsm = &self->fsm; nn_usock_swap_owner (listener, &self->listener_owner); /* Start the state machine. */ nn_fsm_start (&self->fsm); } void nn_aws_stop (struct nn_aws *self) { nn_fsm_stop (&self->fsm); } static void nn_aws_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_aws *aws; aws = nn_cont (self, struct nn_aws, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (!nn_sws_isidle (&aws->sws)) { nn_ep_stat_increment (aws->ep, NN_STAT_DROPPED_CONNECTIONS, 1); nn_sws_stop (&aws->sws); } aws->state = NN_AWS_STATE_STOPPING_SWS_FINAL; } if (nn_slow (aws->state == NN_AWS_STATE_STOPPING_SWS_FINAL)) { if (!nn_sws_isidle (&aws->sws)) return; nn_usock_stop (&aws->usock); aws->state = NN_AWS_STATE_STOPPING; } if (nn_slow (aws->state == NN_AWS_STATE_STOPPING)) { if (!nn_usock_isidle (&aws->usock)) return; if (aws->listener) { nn_assert (aws->listener_owner.fsm); nn_usock_swap_owner (aws->listener, &aws->listener_owner); aws->listener = NULL; aws->listener_owner.src = -1; aws->listener_owner.fsm = NULL; } aws->state = NN_AWS_STATE_IDLE; nn_fsm_stopped (&aws->fsm, NN_AWS_STOPPED); return; } nn_fsm_bad_action (aws->state, src, type); } static void nn_aws_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_aws *aws; int val; size_t sz; uint8_t msg_type; aws = nn_cont (self, struct nn_aws, fsm); switch (aws->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_AWS_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_usock_accept (&aws->usock, aws->listener); aws->state = NN_AWS_STATE_ACCEPTING; return; default: nn_fsm_bad_action (aws->state, src, type); } default: nn_fsm_bad_source (aws->state, src, type); } /******************************************************************************/ /* ACCEPTING state. */ /* Waiting for incoming connection. */ /******************************************************************************/ case NN_AWS_STATE_ACCEPTING: switch (src) { case NN_AWS_SRC_USOCK: switch (type) { case NN_USOCK_ACCEPTED: nn_ep_clear_error (aws->ep); /* Set the relevant socket options. */ sz = sizeof (val); nn_ep_getopt (aws->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&aws->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_ep_getopt (aws->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&aws->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); sz = sizeof (val); nn_ep_getopt (aws->ep, NN_WS, NN_WS_MSG_TYPE, &val, &sz); msg_type = (uint8_t)val; /* Since the WebSocket handshake must poll, the receive timeout is set to zero. Later, it will be set again to the value specified by the socket option. */ val = 0; sz = sizeof (val); nn_usock_setsockopt (&aws->usock, SOL_SOCKET, SO_RCVTIMEO, &val, sizeof (val)); /* Return ownership of the listening socket to the parent. */ nn_usock_swap_owner (aws->listener, &aws->listener_owner); aws->listener = NULL; aws->listener_owner.src = -1; aws->listener_owner.fsm = NULL; nn_fsm_raise (&aws->fsm, &aws->accepted, NN_AWS_ACCEPTED); /* Start the sws state machine. */ nn_usock_activate (&aws->usock); nn_sws_start (&aws->sws, &aws->usock, NN_WS_SERVER, NULL, NULL, msg_type); aws->state = NN_AWS_STATE_ACTIVE; nn_ep_stat_increment (aws->ep, NN_STAT_ACCEPTED_CONNECTIONS, 1); return; default: nn_fsm_bad_action (aws->state, src, type); } case NN_AWS_SRC_LISTENER: switch (type) { case NN_USOCK_ACCEPT_ERROR: nn_ep_set_error (aws->ep, nn_usock_geterrno (aws->listener)); nn_ep_stat_increment (aws->ep, NN_STAT_ACCEPT_ERRORS, 1); nn_usock_accept (&aws->usock, aws->listener); return; default: nn_fsm_bad_action (aws->state, src, type); } default: nn_fsm_bad_source (aws->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_AWS_STATE_ACTIVE: switch (src) { case NN_AWS_SRC_SWS: switch (type) { case NN_SWS_RETURN_CLOSE_HANDSHAKE: /* Peer closed connection without intention to reconnect, or local endpoint failed remote because of invalid data. */ nn_sws_stop (&aws->sws); aws->state = NN_AWS_STATE_STOPPING_SWS; return; case NN_SWS_RETURN_ERROR: nn_sws_stop (&aws->sws); aws->state = NN_AWS_STATE_STOPPING_SWS; nn_ep_stat_increment (aws->ep, NN_STAT_BROKEN_CONNECTIONS, 1); return; default: nn_fsm_bad_action (aws->state, src, type); } default: nn_fsm_bad_source (aws->state, src, type); } /******************************************************************************/ /* STOPPING_SWS state. */ /******************************************************************************/ case NN_AWS_STATE_STOPPING_SWS: switch (src) { case NN_AWS_SRC_SWS: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_SWS_RETURN_STOPPED: nn_usock_stop (&aws->usock); aws->state = NN_AWS_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (aws->state, src, type); } default: nn_fsm_bad_source (aws->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /******************************************************************************/ case NN_AWS_STATE_STOPPING_USOCK: switch (src) { case NN_AWS_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: nn_fsm_raise (&aws->fsm, &aws->done, NN_AWS_ERROR); aws->state = NN_AWS_STATE_DONE; return; default: nn_fsm_bad_action (aws->state, src, type); } default: nn_fsm_bad_source (aws->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (aws->state, src, type); } } nanomsg-1.1.5/src/transports/ws/aws.h000066400000000000000000000053041336111550300175620ustar00rootroot00000000000000/* Copyright (c) 2013 250bpm s.r.o. All rights reserved. Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_AWS_INCLUDED #define NN_AWS_INCLUDED #include "sws.h" #include "../../transport.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../../utils/list.h" /* State machine handling accepted WS sockets. */ /* In bws, some events are just *assumed* to come from a child aws object. By using non-trivial event codes, we can do more reliable sanity checking in such scenarios. */ #define NN_AWS_ACCEPTED 34231 #define NN_AWS_ERROR 34232 #define NN_AWS_STOPPED 34233 struct nn_aws { /* The state machine. */ struct nn_fsm fsm; int state; /* Pointer to the associated endpoint. */ struct nn_ep *ep; /* Underlying socket. */ struct nn_usock usock; /* Listening socket. Valid only while accepting new connection. */ struct nn_usock *listener; struct nn_fsm_owner listener_owner; /* State machine that takes care of the connection in the active state. */ struct nn_sws sws; /* Events generated by aws state machine. */ struct nn_fsm_event accepted; struct nn_fsm_event done; /* This member can be used by owner to keep individual awss in a list. */ struct nn_list_item item; }; void nn_aws_init (struct nn_aws *self, int src, struct nn_ep *ep, struct nn_fsm *owner); void nn_aws_term (struct nn_aws *self); int nn_aws_isidle (struct nn_aws *self); void nn_aws_start (struct nn_aws *self, struct nn_usock *listener); void nn_aws_stop (struct nn_aws *self); #endif nanomsg-1.1.5/src/transports/ws/bws.c000066400000000000000000000263621336111550300175650ustar00rootroot00000000000000/* Copyright (c) 2012-2013 250bpm s.r.o. All rights reserved. Copyright (c) 2014-2016 Jack R. Dunaway. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "bws.h" #include "aws.h" #include "../utils/port.h" #include "../utils/iface.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/alloc.h" #include "../../utils/list.h" #include "../../utils/fast.h" #include #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #include #endif /* The backlog is set relatively high so that there are not too many failed connection attemps during re-connection storms. */ #define NN_BWS_BACKLOG 100 #define NN_BWS_STATE_IDLE 1 #define NN_BWS_STATE_ACTIVE 2 #define NN_BWS_STATE_STOPPING_AWS 3 #define NN_BWS_STATE_STOPPING_USOCK 4 #define NN_BWS_STATE_STOPPING_AWSS 5 #define NN_BWS_SRC_USOCK 1 #define NN_BWS_SRC_AWS 2 struct nn_bws { /* The state machine. */ struct nn_fsm fsm; int state; struct nn_ep *ep; /* The underlying listening WS socket. */ struct nn_usock usock; /* The connection being accepted at the moment. */ struct nn_aws *aws; /* List of accepted connections. */ struct nn_list awss; }; /* nn_ep virtual interface implementation. */ static void nn_bws_stop (void *); static void nn_bws_destroy (void *); const struct nn_ep_ops nn_bws_ep_ops = { nn_bws_stop, nn_bws_destroy }; /* Private functions. */ static void nn_bws_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_bws_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static int nn_bws_listen (struct nn_bws *self); static void nn_bws_start_accepting (struct nn_bws *self); int nn_bws_create (struct nn_ep *ep) { int rc; struct nn_bws *self; const char *addr; const char *end; const char *pos; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_bws), "bws"); alloc_assert (self); self->ep = ep; nn_ep_tran_setup (ep, &nn_bws_ep_ops, self); addr = nn_ep_getaddr (ep); /* Parse the port. */ end = addr + strlen (addr); pos = strrchr (addr, ':'); if (!pos) { return -EINVAL; } ++pos; rc = nn_port_resolve (pos, end - pos); if (rc < 0) { return -EINVAL; } /* Check whether IPv6 is to be used. */ ipv4onlylen = sizeof (ipv4only); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); /* Parse the address. */ rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen); if (rc < 0) { return -ENODEV; } /* Initialise the structure. */ nn_fsm_init_root (&self->fsm, nn_bws_handler, nn_bws_shutdown, nn_ep_getctx (ep)); self->state = NN_BWS_STATE_IDLE; self->aws = NULL; nn_list_init (&self->awss); /* Start the state machine. */ nn_fsm_start (&self->fsm); nn_usock_init (&self->usock, NN_BWS_SRC_USOCK, &self->fsm); rc = nn_bws_listen (self); if (rc != 0) { return rc; } return 0; } static void nn_bws_stop (void *self) { struct nn_bws *bws = self; nn_fsm_stop (&bws->fsm); } static void nn_bws_destroy (void *self) { struct nn_bws *bws = self; nn_assert_state (bws, NN_BWS_STATE_IDLE); nn_list_term (&bws->awss); nn_assert (bws->aws == NULL); nn_usock_term (&bws->usock); nn_fsm_term (&bws->fsm); nn_free (bws); } static void nn_bws_shutdown (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_bws *bws; struct nn_list_item *it; struct nn_aws *aws; bws = nn_cont (self, struct nn_bws, fsm); if (src == NN_FSM_ACTION && type == NN_FSM_STOP) { if (bws->aws) { nn_aws_stop (bws->aws); bws->state = NN_BWS_STATE_STOPPING_AWS; } else { bws->state = NN_BWS_STATE_STOPPING_USOCK; } } if (bws->state == NN_BWS_STATE_STOPPING_AWS) { if (!nn_aws_isidle (bws->aws)) return; nn_aws_term (bws->aws); nn_free (bws->aws); bws->aws = NULL; nn_usock_stop (&bws->usock); bws->state = NN_BWS_STATE_STOPPING_USOCK; } if (bws->state == NN_BWS_STATE_STOPPING_USOCK) { if (!nn_usock_isidle (&bws->usock)) return; for (it = nn_list_begin (&bws->awss); it != nn_list_end (&bws->awss); it = nn_list_next (&bws->awss, it)) { aws = nn_cont (it, struct nn_aws, item); nn_aws_stop (aws); } bws->state = NN_BWS_STATE_STOPPING_AWSS; goto awss_stopping; } if (bws->state == NN_BWS_STATE_STOPPING_AWSS) { nn_assert (src == NN_BWS_SRC_AWS && type == NN_AWS_STOPPED); aws = (struct nn_aws *) srcptr; nn_list_erase (&bws->awss, &aws->item); nn_aws_term (aws); nn_free (aws); /* If there are no more aws state machines, we can stop the whole bws object. */ awss_stopping: if (nn_list_empty (&bws->awss)) { bws->state = NN_BWS_STATE_IDLE; nn_fsm_stopped_noevent (&bws->fsm); nn_ep_stopped (bws->ep); return; } return; } nn_fsm_bad_action (bws->state, src, type); } static void nn_bws_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_bws *bws; struct nn_aws *aws; bws = nn_cont (self, struct nn_bws, fsm); switch (bws->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_BWS_STATE_IDLE: nn_assert (src == NN_FSM_ACTION); nn_assert (type == NN_FSM_START); bws->state = NN_BWS_STATE_ACTIVE; return; /******************************************************************************/ /* ACTIVE state. */ /* The execution is yielded to the aws state machine in this state. */ /******************************************************************************/ case NN_BWS_STATE_ACTIVE: if (src == NN_BWS_SRC_USOCK) { nn_assert (type == NN_USOCK_SHUTDOWN || type == NN_USOCK_STOPPED); return; } /* For all remaining events we'll assume they are coming from one of remaining child aws objects. */ nn_assert (src == NN_BWS_SRC_AWS); aws = (struct nn_aws*) srcptr; switch (type) { case NN_AWS_ACCEPTED: /* Move the newly created connection to the list of existing connections. */ nn_list_insert (&bws->awss, &bws->aws->item, nn_list_end (&bws->awss)); bws->aws = NULL; /* Start waiting for a new incoming connection. */ nn_bws_start_accepting (bws); return; case NN_AWS_ERROR: nn_aws_stop (aws); return; case NN_AWS_STOPPED: nn_list_erase (&bws->awss, &aws->item); nn_aws_term (aws); nn_free (aws); return; default: nn_fsm_bad_action (bws->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (bws->state, src, type); } } static int nn_bws_listen (struct nn_bws *self) { int rc; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; const char *addr; const char *end; const char *pos; uint16_t port; /* First, resolve the IP address. */ addr = nn_ep_getaddr (self->ep); memset (&ss, 0, sizeof (ss)); /* Parse the port. */ end = addr + strlen (addr); pos = strrchr (addr, ':'); nn_assert (pos); ++pos; rc = nn_port_resolve (pos, end - pos); if (rc < 0) { return rc; } port = (uint16_t) rc; /* Parse the address. */ ipv4onlylen = sizeof (ipv4only); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen); if (rc < 0) { return rc; } /* Combine the port and the address. */ if (ss.ss_family == AF_INET) { ((struct sockaddr_in*) &ss)->sin_port = htons (port); sslen = sizeof (struct sockaddr_in); } else if (ss.ss_family == AF_INET6) { ((struct sockaddr_in6*) &ss)->sin6_port = htons (port); sslen = sizeof (struct sockaddr_in6); } else nn_assert (0); /* Start listening for incoming connections. */ rc = nn_usock_start (&self->usock, ss.ss_family, SOCK_STREAM, 0); if (rc < 0) { return rc; } rc = nn_usock_bind (&self->usock, (struct sockaddr*) &ss, (size_t) sslen); if (rc < 0) { nn_usock_stop (&self->usock); return rc; } rc = nn_usock_listen (&self->usock, NN_BWS_BACKLOG); if (rc < 0) { nn_usock_stop (&self->usock); return rc; } nn_bws_start_accepting(self); return 0; } /******************************************************************************/ /* State machine actions. */ /******************************************************************************/ static void nn_bws_start_accepting (struct nn_bws *self) { nn_assert (self->aws == NULL); /* Allocate new aws state machine. */ self->aws = nn_alloc (sizeof (struct nn_aws), "aws"); alloc_assert (self->aws); nn_aws_init (self->aws, NN_BWS_SRC_AWS, self->ep, &self->fsm); /* Start waiting for a new incoming connection. */ nn_aws_start (self->aws, &self->usock); } nanomsg-1.1.5/src/transports/ws/bws.h000066400000000000000000000026431336111550300175660ustar00rootroot00000000000000/* Copyright (c) 2013 250bpm s.r.o. All rights reserved. Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_BWS_INCLUDED #define NN_BWS_INCLUDED #include "../../transport.h" /* State machine managing bound WS socket. */ int nn_bws_create (struct nn_ep *ep); #endif nanomsg-1.1.5/src/transports/ws/cws.c000066400000000000000000000541711336111550300175650ustar00rootroot00000000000000/* Copyright (c) 2012-2013 250bpm s.r.o. All rights reserved. Copyright (c) 2014-2016 Jack R. Dunaway. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "cws.h" #include "sws.h" #include "../../ws.h" #include "../utils/dns.h" #include "../utils/port.h" #include "../utils/iface.h" #include "../utils/backoff.h" #include "../utils/literal.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/alloc.h" #include "../../utils/fast.h" #include "../../utils/attr.h" #include #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #include #include #endif #define NN_CWS_STATE_IDLE 1 #define NN_CWS_STATE_RESOLVING 2 #define NN_CWS_STATE_STOPPING_DNS 3 #define NN_CWS_STATE_CONNECTING 4 #define NN_CWS_STATE_ACTIVE 5 #define NN_CWS_STATE_STOPPING_SWS 6 #define NN_CWS_STATE_STOPPING_USOCK 7 #define NN_CWS_STATE_WAITING 8 #define NN_CWS_STATE_STOPPING_BACKOFF 9 #define NN_CWS_STATE_STOPPING_SWS_FINAL 10 #define NN_CWS_STATE_STOPPING 11 #define NN_CWS_SRC_USOCK 1 #define NN_CWS_SRC_RECONNECT_TIMER 2 #define NN_CWS_SRC_DNS 3 #define NN_CWS_SRC_SWS 4 struct nn_cws { /* The state machine. */ struct nn_fsm fsm; int state; struct nn_ep *ep; /* The underlying WS socket. */ struct nn_usock usock; /* Used to wait before retrying to connect. */ struct nn_backoff retry; /* Defines message validation and framing. */ uint8_t msg_type; /* State machine that handles the active part of the connection lifetime. */ struct nn_sws sws; /* Parsed parts of the connection URI. */ struct nn_chunkref resource; struct nn_chunkref remote_host; struct nn_chunkref nic; int remote_port; size_t remote_hostname_len; /* If a close handshake is performed, this flag signals to not begin automatic reconnect retries. */ int peer_gone; /* DNS resolver used to convert textual address into actual IP address along with the variable to hold the result. */ struct nn_dns dns; struct nn_dns_result dns_result; }; /* nn_ep virtual interface implementation. */ static void nn_cws_stop (void *); static void nn_cws_destroy (void *); const struct nn_ep_ops nn_cws_ep_ops = { nn_cws_stop, nn_cws_destroy }; /* Private functions. */ static void nn_cws_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_cws_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_cws_start_resolving (struct nn_cws *self); static void nn_cws_start_connecting (struct nn_cws *self, struct sockaddr_storage *ss, size_t sslen); int nn_cws_create (struct nn_ep *ep) { int rc; const char *addr; size_t addrlen; const char *semicolon; const char *hostname; size_t hostlen; const char *colon; const char *slash; const char *resource; size_t resourcelen; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; struct nn_cws *self; int reconnect_ivl; int reconnect_ivl_max; int msg_type; size_t sz; /* Allocate the new endpoint object. */ self = nn_alloc (sizeof (struct nn_cws), "cws"); alloc_assert (self); self->ep = ep; self->peer_gone = 0; /* Initalise the endpoint. */ nn_ep_tran_setup (ep, &nn_cws_ep_ops, self); /* Check whether IPv6 is to be used. */ ipv4onlylen = sizeof (ipv4only); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); /* Start parsing the address. */ addr = nn_ep_getaddr (ep); addrlen = strlen (addr); semicolon = strchr (addr, ';'); hostname = semicolon ? semicolon + 1 : addr; colon = strrchr (addr, ':'); slash = colon ? strchr (colon, '/') : strchr (addr, '/'); resource = slash ? slash : addr + addrlen; self->remote_hostname_len = colon ? colon - hostname : resource - hostname; /* Host contains both hostname and port. */ hostlen = resource - hostname; /* Parse the port; assume port 80 if not explicitly declared. */ if (colon != NULL) { rc = nn_port_resolve (colon + 1, resource - colon - 1); if (rc < 0) { nn_free(self); return -EINVAL; } self->remote_port = rc; } else { self->remote_port = 80; } /* Check whether the host portion of the address is either a literal or a valid hostname. */ if (nn_dns_check_hostname (hostname, self->remote_hostname_len) < 0 && nn_literal_resolve (hostname, self->remote_hostname_len, ipv4only, &ss, &sslen) < 0) { nn_free(self); return -EINVAL; } /* If local address is specified, check whether it is valid. */ if (semicolon) { rc = nn_iface_resolve (addr, semicolon - addr, ipv4only, &ss, &sslen); if (rc < 0) { nn_free(self); return -ENODEV; } } /* At this point, the address is valid, so begin allocating resources. */ nn_chunkref_init (&self->remote_host, hostlen + 1); memcpy (nn_chunkref_data (&self->remote_host), hostname, hostlen); ((uint8_t *) nn_chunkref_data (&self->remote_host)) [hostlen] = '\0'; if (semicolon) { nn_chunkref_init (&self->nic, semicolon - addr); memcpy (nn_chunkref_data (&self->nic), addr, semicolon - addr); } else { nn_chunkref_init (&self->nic, 1); memcpy (nn_chunkref_data (&self->nic), "*", 1); } /* The requested resource is used in opening handshake. */ resourcelen = strlen (resource); if (resourcelen) { nn_chunkref_init (&self->resource, resourcelen + 1); strncpy (nn_chunkref_data (&self->resource), resource, resourcelen + 1); } else { /* No resource specified, so allocate base path. */ nn_chunkref_init (&self->resource, 2); strncpy (nn_chunkref_data (&self->resource), "/", 2); } /* Initialise the structure. */ nn_fsm_init_root (&self->fsm, nn_cws_handler, nn_cws_shutdown, nn_ep_getctx (ep)); self->state = NN_CWS_STATE_IDLE; nn_usock_init (&self->usock, NN_CWS_SRC_USOCK, &self->fsm); sz = sizeof (msg_type); nn_ep_getopt (ep, NN_WS, NN_WS_MSG_TYPE, &msg_type, &sz); nn_assert (sz == sizeof (msg_type)); self->msg_type = (uint8_t) msg_type; sz = sizeof (reconnect_ivl); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL, &reconnect_ivl, &sz); nn_assert (sz == sizeof (reconnect_ivl)); sz = sizeof (reconnect_ivl_max); nn_ep_getopt (ep, NN_SOL_SOCKET, NN_RECONNECT_IVL_MAX, &reconnect_ivl_max, &sz); nn_assert (sz == sizeof (reconnect_ivl_max)); if (reconnect_ivl_max == 0) reconnect_ivl_max = reconnect_ivl; nn_backoff_init (&self->retry, NN_CWS_SRC_RECONNECT_TIMER, reconnect_ivl, reconnect_ivl_max, &self->fsm); nn_sws_init (&self->sws, NN_CWS_SRC_SWS, ep, &self->fsm); nn_dns_init (&self->dns, NN_CWS_SRC_DNS, &self->fsm); /* Start the state machine. */ nn_fsm_start (&self->fsm); return 0; } static void nn_cws_stop (void *self) { struct nn_cws *cws = self; nn_fsm_stop (&cws->fsm); } static void nn_cws_destroy (void *self) { struct nn_cws *cws = self; nn_chunkref_term (&cws->resource); nn_chunkref_term (&cws->remote_host); nn_chunkref_term (&cws->nic); nn_dns_term (&cws->dns); nn_sws_term (&cws->sws); nn_backoff_term (&cws->retry); nn_usock_term (&cws->usock); nn_fsm_term (&cws->fsm); nn_free (cws); } static void nn_cws_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_cws *cws; cws = nn_cont (self, struct nn_cws, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (!nn_sws_isidle (&cws->sws)) { nn_ep_stat_increment (cws->ep, NN_STAT_DROPPED_CONNECTIONS, 1); nn_sws_stop (&cws->sws); } cws->state = NN_CWS_STATE_STOPPING_SWS_FINAL; } if (nn_slow (cws->state == NN_CWS_STATE_STOPPING_SWS_FINAL)) { if (!nn_sws_isidle (&cws->sws)) return; nn_backoff_stop (&cws->retry); nn_usock_stop (&cws->usock); nn_dns_stop (&cws->dns); cws->state = NN_CWS_STATE_STOPPING; } if (nn_slow (cws->state == NN_CWS_STATE_STOPPING)) { if (!nn_backoff_isidle (&cws->retry) || !nn_usock_isidle (&cws->usock) || !nn_dns_isidle (&cws->dns)) return; cws->state = NN_CWS_STATE_IDLE; nn_fsm_stopped_noevent (&cws->fsm); nn_ep_stopped (cws->ep); return; } nn_fsm_bad_state (cws->state, src, type); } static void nn_cws_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_cws *cws; cws = nn_cont (self, struct nn_cws, fsm); switch (cws->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_CWS_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_cws_start_resolving (cws); return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* RESOLVING state. */ /* Name of the host to connect to is being resolved to get an IP address. */ /******************************************************************************/ case NN_CWS_STATE_RESOLVING: switch (src) { case NN_CWS_SRC_DNS: switch (type) { case NN_DNS_DONE: nn_dns_stop (&cws->dns); cws->state = NN_CWS_STATE_STOPPING_DNS; return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* STOPPING_DNS state. */ /* dns object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CWS_STATE_STOPPING_DNS: switch (src) { case NN_CWS_SRC_DNS: switch (type) { case NN_DNS_STOPPED: if (cws->dns_result.error == 0) { nn_cws_start_connecting (cws, &cws->dns_result.addr, cws->dns_result.addrlen); return; } nn_backoff_start (&cws->retry); cws->state = NN_CWS_STATE_WAITING; return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* CONNECTING state. */ /* Non-blocking connect is under way. */ /******************************************************************************/ case NN_CWS_STATE_CONNECTING: switch (src) { case NN_CWS_SRC_USOCK: switch (type) { case NN_USOCK_CONNECTED: nn_sws_start (&cws->sws, &cws->usock, NN_WS_CLIENT, nn_chunkref_data (&cws->resource), nn_chunkref_data (&cws->remote_host), cws->msg_type); cws->state = NN_CWS_STATE_ACTIVE; cws->peer_gone = 0; nn_ep_stat_increment (cws->ep, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_ep_stat_increment (cws->ep, NN_STAT_ESTABLISHED_CONNECTIONS, 1); nn_ep_clear_error (cws->ep); return; case NN_USOCK_ERROR: nn_ep_set_error (cws->ep, nn_usock_geterrno (&cws->usock)); nn_usock_stop (&cws->usock); cws->state = NN_CWS_STATE_STOPPING_USOCK; nn_ep_stat_increment (cws->ep, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_ep_stat_increment (cws->ep, NN_STAT_CONNECT_ERRORS, 1); return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Connection is established and handled by the sws state machine. */ /******************************************************************************/ case NN_CWS_STATE_ACTIVE: switch (src) { case NN_CWS_SRC_SWS: switch (type) { case NN_SWS_RETURN_CLOSE_HANDSHAKE: /* Peer closed connection without intention to reconnect, or local endpoint failed remote because of invalid data. */ nn_sws_stop (&cws->sws); cws->state = NN_CWS_STATE_STOPPING_SWS; cws->peer_gone = 1; return; case NN_SWS_RETURN_ERROR: nn_sws_stop (&cws->sws); cws->state = NN_CWS_STATE_STOPPING_SWS; nn_ep_stat_increment (cws->ep, NN_STAT_BROKEN_CONNECTIONS, 1); return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* STOPPING_SWS state. */ /* sws object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CWS_STATE_STOPPING_SWS: switch (src) { case NN_CWS_SRC_SWS: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_SWS_RETURN_STOPPED: nn_usock_stop (&cws->usock); cws->state = NN_CWS_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /* usock object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CWS_STATE_STOPPING_USOCK: switch (src) { case NN_CWS_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: /* If the peer has confirmed itself gone with a Closing Handshake, or if the local endpoint failed the remote, don't try to reconnect. */ if (!cws->peer_gone) { nn_backoff_start (&cws->retry); cws->state = NN_CWS_STATE_WAITING; } return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* WAITING state. */ /* Waiting before re-connection is attempted. This way we won't overload */ /* the system by continuous re-connection attemps. */ /******************************************************************************/ case NN_CWS_STATE_WAITING: switch (src) { case NN_CWS_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_TIMEOUT: nn_backoff_stop (&cws->retry); cws->state = NN_CWS_STATE_STOPPING_BACKOFF; return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* STOPPING_BACKOFF state. */ /* backoff object was asked to stop, but it haven't stopped yet. */ /******************************************************************************/ case NN_CWS_STATE_STOPPING_BACKOFF: switch (src) { case NN_CWS_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_STOPPED: nn_cws_start_resolving (cws); return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (cws->state, src, type); } } /******************************************************************************/ /* State machine actions. */ /******************************************************************************/ static void nn_cws_start_resolving (struct nn_cws *self) { int ipv4only; size_t ipv4onlylen; char *host; /* Check whether IPv6 is to be used. */ ipv4onlylen = sizeof (ipv4only); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); host = nn_chunkref_data (&self->remote_host); nn_assert (strlen (host) > 0); nn_dns_start (&self->dns, host, self->remote_hostname_len, ipv4only, &self->dns_result); self->state = NN_CWS_STATE_RESOLVING; } static void nn_cws_start_connecting (struct nn_cws *self, struct sockaddr_storage *ss, size_t sslen) { int rc; struct sockaddr_storage remote; size_t remotelen; struct sockaddr_storage local; size_t locallen; int ipv4only; int val; size_t sz; memset (&remote, 0, sizeof (remote)); memset (&local, 0, sizeof (local)); /* Check whether IPv6 is to be used. */ sz = sizeof (ipv4only); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &sz); nn_assert (sz == sizeof (ipv4only)); rc = nn_iface_resolve (nn_chunkref_data (&self->nic), nn_chunkref_size (&self->nic), ipv4only, &local, &locallen); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CWS_STATE_WAITING; return; } /* Combine the remote address and the port. */ remote = *ss; remotelen = sslen; if (remote.ss_family == AF_INET) ((struct sockaddr_in*) &remote)->sin_port = htons (self->remote_port); else if (remote.ss_family == AF_INET6) ((struct sockaddr_in6*) &remote)->sin6_port = htons (self->remote_port); else nn_assert (0); /* Try to start the underlying socket. */ rc = nn_usock_start (&self->usock, remote.ss_family, SOCK_STREAM, 0); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CWS_STATE_WAITING; return; } /* Set the relevant socket options. */ sz = sizeof (val); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_ep_getopt (self->ep, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); /* Bind the socket to the local network interface. */ rc = nn_usock_bind (&self->usock, (struct sockaddr*) &local, locallen); if (nn_slow (rc != 0)) { nn_backoff_start (&self->retry); self->state = NN_CWS_STATE_WAITING; return; } /* Start connecting. */ nn_usock_connect (&self->usock, (struct sockaddr*) &remote, remotelen); self->state = NN_CWS_STATE_CONNECTING; nn_ep_stat_increment (self->ep, NN_STAT_INPROGRESS_CONNECTIONS, 1); } nanomsg-1.1.5/src/transports/ws/cws.h000066400000000000000000000026461336111550300175720ustar00rootroot00000000000000/* Copyright (c) 2013 250bpm s.r.o. All rights reserved. Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_CWS_INCLUDED #define NN_CWS_INCLUDED #include "../../transport.h" /* State machine managing connected WS socket. */ int nn_cws_create (struct nn_ep *); #endif nanomsg-1.1.5/src/transports/ws/sha1.c000066400000000000000000000107231336111550300176200ustar00rootroot00000000000000/* Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. 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. */ #include "sha1.h" #define sha1_rol32(num,bits) ((num << bits) | (num >> (32 - bits))) void nn_sha1_init (struct nn_sha1 *self) { /* Detect endianness. */ union { uint32_t i; char c[4]; } test = { 0x00000001 }; self->is_little_endian = test.c[0]; /* Initial state of the hash. */ self->state [0] = 0x67452301; self->state [1] = 0xefcdab89; self->state [2] = 0x98badcfe; self->state [3] = 0x10325476; self->state [4] = 0xc3d2e1f0; self->bytes_hashed = 0; self->buffer_offset = 0; } static void nn_sha1_add (struct nn_sha1 *self, uint8_t data) { uint8_t i; uint32_t a, b, c, d, e, t; uint8_t * const buf = (uint8_t*) self->buffer; if (self->is_little_endian) buf [self->buffer_offset ^ 3] = data; else buf [self->buffer_offset] = data; self->buffer_offset++; if (self->buffer_offset == SHA1_BLOCK_LEN) { a = self->state [0]; b = self->state [1]; c = self->state [2]; d = self->state [3]; e = self->state [4]; for (i = 0; i < 80; i++) { if (i >= 16) { t = self->buffer [(i + 13) & 15] ^ self->buffer [(i + 8) & 15] ^ self->buffer [(i + 2) & 15] ^ self->buffer [i & 15]; self->buffer [i & 15] = sha1_rol32 (t, 1); } if (i < 20) t = (d ^ (b & (c ^ d))) + 0x5A827999; else if (i < 40) t = (b ^ c ^ d) + 0x6ED9EBA1; else if (i < 60) t = ((b & c) | (d & (b | c))) + 0x8F1BBCDC; else t = (b ^ c ^ d) + 0xCA62C1D6; t += sha1_rol32 (a, 5) + e + self->buffer [i & 15]; e = d; d = c; c = sha1_rol32 (b, 30); b = a; a = t; } self->state [0] += a; self->state [1] += b; self->state [2] += c; self->state [3] += d; self->state [4] += e; self->buffer_offset = 0; } } void nn_sha1_hashbyte (struct nn_sha1 *self, uint8_t data) { ++self->bytes_hashed; nn_sha1_add (self, data); } uint8_t* nn_sha1_result (struct nn_sha1 *self) { int i; /* Pad to complete the last block. */ nn_sha1_add (self, 0x80); while (self->buffer_offset != 56) nn_sha1_add (self, 0x00); /* Append length in the last 8 bytes. SHA-1 supports 64-bit hashes, so zero-pad the top bits. Shifting to multiply by 8 as SHA-1 supports bit- as well as byte-streams. */ nn_sha1_add (self, 0); nn_sha1_add (self, 0); nn_sha1_add (self, 0); nn_sha1_add (self, self->bytes_hashed >> 29); nn_sha1_add (self, self->bytes_hashed >> 21); nn_sha1_add (self, self->bytes_hashed >> 13); nn_sha1_add (self, self->bytes_hashed >> 5); nn_sha1_add (self, self->bytes_hashed << 3); /* Correct byte order for little-endian systems. */ if (self->is_little_endian) { for (i = 0; i < 5; i++) { self->state [i] = (((self->state [i]) << 24) & 0xFF000000) | (((self->state [i]) << 8) & 0x00FF0000) | (((self->state [i]) >> 8) & 0x0000FF00) | (((self->state [i]) >> 24) & 0x000000FF); } } /* 20-octet pointer to hash. */ return (uint8_t*) self->state; } nanomsg-1.1.5/src/transports/ws/sha1.h000066400000000000000000000050721336111550300176260ustar00rootroot00000000000000/* Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. 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. */ #ifndef NN_SHA1_INCLUDED #define NN_SHA1_INCLUDED #include /*****************************************************************************/ /* SHA-1 SECURITY NOTICE: */ /* The algorithm as designed below is not intended for general purpose use. */ /* As-designed, it is a single-purpose function for this WebSocket */ /* Opening Handshake. As per RFC 6455 10.8, SHA-1 usage "doesn't depend on */ /* any security properties of SHA-1, such as collision resistance or */ /* resistance to the second pre-image attack (as described in [RFC4270])". */ /* Caveat emptor for uses of this function elsewhere. */ /* */ /* Based on sha1.c (Public Domain) by Steve Reid, these functions calculate */ /* the SHA1 hash of arbitrary byte locations byte-by-byte. */ /*****************************************************************************/ #define SHA1_HASH_LEN 20 #define SHA1_BLOCK_LEN 64 struct nn_sha1 { uint32_t buffer [SHA1_BLOCK_LEN / sizeof (uint32_t)]; uint32_t state [SHA1_HASH_LEN / sizeof (uint32_t)]; uint32_t bytes_hashed; uint8_t buffer_offset; uint8_t is_little_endian; }; void nn_sha1_init (struct nn_sha1 *self); void nn_sha1_hashbyte (struct nn_sha1 *self, uint8_t data); uint8_t* nn_sha1_result (struct nn_sha1 *self); #endif nanomsg-1.1.5/src/transports/ws/sws.c000066400000000000000000001652651336111550300176140ustar00rootroot00000000000000/* Copyright (c) 2013 250bpm s.r.o. All rights reserved. Copyright (c) 2014-2016 Jack R. Dunaway. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "sws.h" #include "../../ws.h" #include "../../nn.h" #include "../../utils/alloc.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/wire.h" #include "../../utils/attr.h" #include "../../utils/random.h" /* States of the object as a whole. */ #define NN_SWS_STATE_IDLE 1 #define NN_SWS_STATE_HANDSHAKE 2 #define NN_SWS_STATE_STOPPING_HANDSHAKE 3 #define NN_SWS_STATE_ACTIVE 4 #define NN_SWS_STATE_CLOSING_CONNECTION 5 #define NN_SWS_STATE_BROKEN_CONNECTION 6 #define NN_SWS_STATE_DONE 7 #define NN_SWS_STATE_STOPPING 8 /* Possible states of the inbound part of the object. */ #define NN_SWS_INSTATE_RECV_HDR 1 #define NN_SWS_INSTATE_RECV_HDREXT 2 #define NN_SWS_INSTATE_RECV_PAYLOAD 3 #define NN_SWS_INSTATE_RECVD_CHUNKED 4 #define NN_SWS_INSTATE_RECVD_CONTROL 5 #define NN_SWS_INSTATE_FAILING 6 #define NN_SWS_INSTATE_CLOSED 7 /* Possible states of the outbound part of the object. */ #define NN_SWS_OUTSTATE_IDLE 1 #define NN_SWS_OUTSTATE_SENDING 2 /* Subordinate srcptr objects. */ #define NN_SWS_SRC_USOCK 1 #define NN_SWS_SRC_HANDSHAKE 2 /* WebSocket opcode constants as per RFC 6455 5.2. */ #define NN_WS_OPCODE_FRAGMENT 0x00 #define NN_WS_OPCODE_TEXT NN_WS_MSG_TYPE_TEXT #define NN_WS_OPCODE_BINARY NN_WS_MSG_TYPE_BINARY #define NN_WS_OPCODE_UNUSED3 0x03 #define NN_WS_OPCODE_UNUSED4 0x04 #define NN_WS_OPCODE_UNUSED5 0x05 #define NN_WS_OPCODE_UNUSED6 0x06 #define NN_WS_OPCODE_UNUSED7 0x07 #define NN_WS_OPCODE_CLOSE 0x08 #define NN_WS_OPCODE_PING 0x09 #define NN_WS_OPCODE_PONG 0x0A #define NN_WS_OPCODE_UNUSEDB 0x0B #define NN_WS_OPCODE_UNUSEDC 0x0C #define NN_WS_OPCODE_UNUSEDD 0x0D #define NN_WS_OPCODE_UNUSEDE 0x0E #define NN_WS_OPCODE_UNUSEDF 0x0F /* WebSocket protocol header bit masks as per RFC 6455. */ #define NN_SWS_FRAME_BITMASK_MASKED 0x80 #define NN_SWS_FRAME_BITMASK_NOT_MASKED 0x00 #define NN_SWS_FRAME_BITMASK_LENGTH 0x7F /* WebSocket Close Status Codes (1004-1006 and 1015 are reserved). */ #define NN_SWS_CLOSE_NORMAL 1000 #define NN_SWS_CLOSE_GOING_AWAY 1001 #define NN_SWS_CLOSE_ERR_PROTO 1002 #define NN_SWS_CLOSE_ERR_WUT 1003 #define NN_SWS_CLOSE_ERR_INVALID_FRAME 1007 #define NN_SWS_CLOSE_ERR_POLICY 1008 #define NN_SWS_CLOSE_ERR_TOOBIG 1009 #define NN_SWS_CLOSE_ERR_EXTENSION 1010 #define NN_SWS_CLOSE_ERR_SERVER 1011 /* UTF-8 validation. */ #define NN_SWS_UTF8_INVALID -2 #define NN_SWS_UTF8_FRAGMENT -1 /* Stream is a special type of pipe. Implementation of the virtual pipe API. */ static int nn_sws_send (struct nn_pipebase *self, struct nn_msg *msg); static int nn_sws_recv (struct nn_pipebase *self, struct nn_msg *msg); const struct nn_pipebase_vfptr nn_sws_pipebase_vfptr = { nn_sws_send, nn_sws_recv }; /* Private functions. */ static void nn_sws_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_sws_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); /* Ceases further I/O on the underlying socket and prepares to send a close handshake on the next receive. */ static void nn_sws_fail_conn (struct nn_sws *self, int code, char *reason); /* Start receiving new message chunk. */ static int nn_sws_recv_hdr (struct nn_sws *self); /* Mask or unmask message payload. */ static void nn_sws_mask_payload (uint8_t *payload, size_t payload_len, const uint8_t *mask, size_t mask_len, int *mask_start_pos); /* Validates incoming text chunks for UTF-8 compliance as per RFC 3629. */ static void nn_sws_validate_utf8_chunk (struct nn_sws *self); /* Ensures that Close frames received from peer conform to RFC 6455 section 7. */ static void nn_sws_acknowledge_close_handshake (struct nn_sws *self); void nn_sws_init (struct nn_sws *self, int src, struct nn_ep *ep, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_sws_handler, nn_sws_shutdown, src, self, owner); self->state = NN_SWS_STATE_IDLE; nn_ws_handshake_init (&self->handshaker, NN_SWS_SRC_HANDSHAKE, &self->fsm); self->usock = NULL; self->usock_owner.src = -1; self->usock_owner.fsm = NULL; nn_pipebase_init (&self->pipebase, &nn_sws_pipebase_vfptr, ep); self->instate = -1; nn_list_init (&self->inmsg_array); self->outstate = -1; nn_msg_init (&self->outmsg, 0); self->continuing = 0; memset (self->utf8_code_pt_fragment, 0, NN_SWS_UTF8_MAX_CODEPOINT_LEN); self->utf8_code_pt_fragment_len = 0; self->pings_sent = 0; self->pongs_sent = 0; self->pings_received = 0; self->pongs_received = 0; nn_fsm_event_init (&self->done); } void nn_sws_term (struct nn_sws *self) { nn_assert_state (self, NN_SWS_STATE_IDLE); nn_fsm_event_term (&self->done); nn_msg_term (&self->outmsg); nn_msg_array_term (&self->inmsg_array); nn_pipebase_term (&self->pipebase); nn_ws_handshake_term (&self->handshaker); nn_fsm_term (&self->fsm); } int nn_sws_isidle (struct nn_sws *self) { return nn_fsm_isidle (&self->fsm); } void nn_sws_start (struct nn_sws *self, struct nn_usock *usock, int mode, const char *resource, const char *host, uint8_t msg_type) { /* Take ownership of the underlying socket. */ nn_assert (self->usock == NULL && self->usock_owner.fsm == NULL); self->usock_owner.src = NN_SWS_SRC_USOCK; self->usock_owner.fsm = &self->fsm; nn_usock_swap_owner (usock, &self->usock_owner); self->usock = usock; self->mode = mode; self->resource = resource; self->remote_host = host; self->msg_type = msg_type; /* Launch the state machine. */ nn_fsm_start (&self->fsm); } void nn_sws_stop (struct nn_sws *self) { nn_fsm_stop (&self->fsm); } void *nn_msg_chunk_new (size_t size, struct nn_list *msg_array) { struct msg_chunk *self; self = nn_alloc (sizeof (struct msg_chunk), "msg_chunk"); alloc_assert (self); nn_chunkref_init (&self->chunk, size); nn_list_item_init (&self->item); nn_list_insert (msg_array, &self->item, nn_list_end (msg_array)); return nn_chunkref_data (&self->chunk); } void nn_msg_chunk_term (struct msg_chunk *it, struct nn_list *msg_array) { nn_chunkref_term (&it->chunk); nn_list_erase (msg_array, &it->item); nn_list_item_term (&it->item); nn_free (it); } void nn_msg_array_term (struct nn_list *msg_array) { struct nn_list_item *it; struct msg_chunk *ch; while (!nn_list_empty (msg_array)) { it = nn_list_begin (msg_array); ch = nn_cont (it, struct msg_chunk, item); nn_msg_chunk_term (ch, msg_array); } nn_list_term (msg_array); } /* Given a buffer location, this function determines whether the leading octets form a valid UTF-8 code point. */ static int nn_utf8_code_point (const uint8_t *buffer, size_t len) { /* The lack of information is considered neither valid nor invalid. */ if (!buffer || !len) return NN_SWS_UTF8_FRAGMENT; /* RFC 3629 section 4 UTF8-1. */ if (buffer [0] <= 0x7F) return 1; /* 0xC2, or 11000001, is the smallest conceivable multi-octet code point that is not an illegal overlong encoding. */ if (buffer [0] < 0xC2) return NN_SWS_UTF8_INVALID; /* Largest 2-octet code point starts with 0xDF (11011111). */ if (buffer [0] <= 0xDF) { if (len < 2) return NN_SWS_UTF8_FRAGMENT; /* Ensure continuation byte in form of 10xxxxxx */ else if ((buffer [1] & 0xC0) != 0x80) return NN_SWS_UTF8_INVALID; else return 2; } /* RFC 3629 section 4 UTF8-3, where 0xEF is 11101111. */ if (buffer [0] <= 0xEF) { /* Fragment. */ if (len < 2) return NN_SWS_UTF8_FRAGMENT; /* Illegal overlong sequence detection. */ else if (buffer [0] == 0xE0 && (buffer [1] < 0xA0 || buffer [1] == 0x80)) return NN_SWS_UTF8_INVALID; /* Illegal UTF-16 surrogate pair half U+D800 through U+DFFF. */ else if (buffer [0] == 0xED && buffer [1] >= 0xA0) return NN_SWS_UTF8_INVALID; /* Fragment. */ else if (len < 3) return NN_SWS_UTF8_FRAGMENT; /* Ensure continuation bytes 2 and 3 in form of 10xxxxxx */ else if ((buffer [1] & 0xC0) != 0x80 || (buffer [2] & 0xC0) != 0x80) return NN_SWS_UTF8_INVALID; else return 3; } /* RFC 3629 section 4 UTF8-4, where 0xF4 is 11110100. Why not 11110111 to follow the pattern? Because UTF-8 encoding stops at 0x10FFFF as per RFC 3629. */ if (buffer [0] <= 0xF4) { /* Fragment. */ if (len < 2) return NN_SWS_UTF8_FRAGMENT; /* Illegal overlong sequence detection. */ else if (buffer [0] == 0xF0 && buffer [1] < 0x90) return NN_SWS_UTF8_INVALID; /* Illegal code point greater than U+10FFFF. */ else if (buffer [0] == 0xF4 && buffer [1] >= 0x90) return NN_SWS_UTF8_INVALID; /* Fragment. */ else if (len < 4) return NN_SWS_UTF8_FRAGMENT; /* Ensure continuation bytes 2, 3, and 4 in form of 10xxxxxx */ else if ((buffer [1] & 0xC0) != 0x80 || (buffer [2] & 0xC0) != 0x80 || (buffer [3] & 0xC0) != 0x80) return NN_SWS_UTF8_INVALID; else return 4; } /* UTF-8 encoding stops at U+10FFFF and only defines up to 4-octet code point sequences. */ if (buffer [0] >= 0xF5) return NN_SWS_UTF8_INVALID; /* Algorithm error; a case above should have been satisfied. */ nn_assert (0); } static void nn_sws_mask_payload (uint8_t *payload, size_t payload_len, const uint8_t *mask, size_t mask_len, int *mask_start_pos) { unsigned i; if (mask_start_pos) { for (i = 0; i < payload_len; i++) { payload [i] ^= mask [(i + *mask_start_pos) % mask_len]; } *mask_start_pos = (i + *mask_start_pos) % mask_len; return; } else { for (i = 0; i < payload_len; i++) { payload [i] ^= mask [i % mask_len]; } return; } } static int nn_sws_recv_hdr (struct nn_sws *self) { if (!self->continuing) { nn_assert (nn_list_empty (&self->inmsg_array)); self->inmsg_current_chunk_buf = NULL; self->inmsg_chunks = 0; self->inmsg_current_chunk_len = 0; self->inmsg_total_size = 0; } memset (self->inmsg_control, 0, NN_SWS_PAYLOAD_MAX_LENGTH); memset (self->inhdr, 0, NN_SWS_FRAME_MAX_HDR_LEN); self->instate = NN_SWS_INSTATE_RECV_HDR; nn_usock_recv (self->usock, self->inhdr, NN_SWS_FRAME_SIZE_INITIAL, NULL); return 0; } static int nn_sws_send (struct nn_pipebase *self, struct nn_msg *msg) { struct nn_sws *sws; struct nn_iovec iov [3]; int mask_pos; size_t nn_msg_size; size_t hdr_len; struct nn_cmsghdr *cmsg; struct nn_msghdr msghdr; uint8_t rand_mask [NN_SWS_FRAME_SIZE_MASK]; sws = nn_cont (self, struct nn_sws, pipebase); nn_assert_state (sws, NN_SWS_STATE_ACTIVE); nn_assert (sws->outstate == NN_SWS_OUTSTATE_IDLE); /* Move the message to the local storage. */ nn_msg_term (&sws->outmsg); nn_msg_mv (&sws->outmsg, msg); memset (sws->outhdr, 0, sizeof (sws->outhdr)); hdr_len = NN_SWS_FRAME_SIZE_INITIAL; cmsg = NULL; msghdr.msg_iov = NULL; msghdr.msg_iovlen = 0; msghdr.msg_controllen = nn_chunkref_size (&sws->outmsg.hdrs); /* If the outgoing message has specified an opcode and control framing in its header, properly frame it as per RFC 6455 5.2. */ if (msghdr.msg_controllen > 0) { msghdr.msg_control = nn_chunkref_data (&sws->outmsg.hdrs); cmsg = NN_CMSG_FIRSTHDR (&msghdr); while (cmsg) { if (cmsg->cmsg_level == NN_WS && cmsg->cmsg_type == NN_WS_MSG_TYPE) break; cmsg = NN_CMSG_NXTHDR (&msghdr, cmsg); } } /* If the header does not specify an opcode, take default from option. */ if (cmsg) sws->outhdr [0] = *(uint8_t *) NN_CMSG_DATA (cmsg); else sws->outhdr [0] = sws->msg_type; /* For now, enforce that outgoing messages are the final frame. */ sws->outhdr [0] |= NN_SWS_FRAME_BITMASK_FIN; nn_msg_size = nn_chunkref_size (&sws->outmsg.sphdr) + nn_chunkref_size (&sws->outmsg.body); /* Framing WebSocket payload size in network byte order (big endian). */ if (nn_msg_size <= NN_SWS_PAYLOAD_MAX_LENGTH) { sws->outhdr [1] |= (uint8_t) nn_msg_size; hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_0; } else if (nn_msg_size <= NN_SWS_PAYLOAD_MAX_LENGTH_16) { sws->outhdr [1] |= NN_SWS_PAYLOAD_FRAME_16; nn_puts (&sws->outhdr [hdr_len], (uint16_t) nn_msg_size); hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_16; } else { sws->outhdr [1] |= NN_SWS_PAYLOAD_FRAME_63; nn_putll (&sws->outhdr [hdr_len], (uint64_t) nn_msg_size); hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_63; } if (sws->mode == NN_WS_CLIENT) { sws->outhdr [1] |= NN_SWS_FRAME_BITMASK_MASKED; /* Generate 32-bit mask as per RFC 6455 5.3. */ nn_random_generate (rand_mask, NN_SWS_FRAME_SIZE_MASK); memcpy (&sws->outhdr [hdr_len], rand_mask, NN_SWS_FRAME_SIZE_MASK); hdr_len += NN_SWS_FRAME_SIZE_MASK; /* Mask payload, beginning with header and moving to body. */ mask_pos = 0; nn_sws_mask_payload (nn_chunkref_data (&sws->outmsg.sphdr), nn_chunkref_size (&sws->outmsg.sphdr), rand_mask, NN_SWS_FRAME_SIZE_MASK, &mask_pos); nn_sws_mask_payload (nn_chunkref_data (&sws->outmsg.body), nn_chunkref_size (&sws->outmsg.body), rand_mask, NN_SWS_FRAME_SIZE_MASK, &mask_pos); } else if (sws->mode == NN_WS_SERVER) { sws->outhdr [1] |= NN_SWS_FRAME_BITMASK_NOT_MASKED; } else { /* Developer error; sws object was not constructed properly. */ nn_assert (0); } /* Start async sending. */ iov [0].iov_base = sws->outhdr; iov [0].iov_len = hdr_len; iov [1].iov_base = nn_chunkref_data (&sws->outmsg.sphdr); iov [1].iov_len = nn_chunkref_size (&sws->outmsg.sphdr); iov [2].iov_base = nn_chunkref_data (&sws->outmsg.body); iov [2].iov_len = nn_chunkref_size (&sws->outmsg.body); nn_usock_send (sws->usock, iov, 3); sws->outstate = NN_SWS_OUTSTATE_SENDING; return 0; } static int nn_sws_recv (struct nn_pipebase *self, struct nn_msg *msg) { struct nn_sws *sws; struct nn_list_item *it; struct msg_chunk *ch; struct nn_cmsghdr *cmsg; uint8_t opcode_hdr; uint8_t opcode; size_t cmsgsz; size_t pos; sws = nn_cont (self, struct nn_sws, pipebase); nn_assert_state (sws, NN_SWS_STATE_ACTIVE); switch (sws->instate) { case NN_SWS_INSTATE_RECVD_CHUNKED: /* Relay opcode to the user in order to interpret payload. */ opcode_hdr = sws->inmsg_hdr; /* This library should not deliver fragmented messages to the application, so it's expected that this is the final frame. */ nn_assert (sws->is_final_frame); nn_assert (opcode_hdr & NN_SWS_FRAME_BITMASK_FIN); opcode_hdr &= ~NN_SWS_FRAME_BITMASK_FIN; /* The library is expected to have failed any connections with other opcodes; these are the only two opcodes that can be chunked. */ opcode = opcode_hdr & NN_SWS_FRAME_BITMASK_OPCODE; nn_assert (opcode == NN_WS_OPCODE_BINARY || opcode == NN_WS_OPCODE_TEXT); nn_msg_init (msg, sws->inmsg_total_size); pos = 0; /* Reassemble incoming message scatter array. */ while (!nn_list_empty (&sws->inmsg_array)) { it = nn_list_begin (&sws->inmsg_array); ch = nn_cont (it, struct msg_chunk, item); memcpy (((uint8_t*) nn_chunkref_data (&msg->body)) + pos, nn_chunkref_data (&ch->chunk), nn_chunkref_size (&ch->chunk)); pos += nn_chunkref_size (&ch->chunk); nn_msg_chunk_term (ch, &sws->inmsg_array); } nn_assert (pos == sws->inmsg_total_size); nn_assert (nn_list_empty (&sws->inmsg_array)); /* No longer collecting scatter array of incoming msg chunks. */ sws->continuing = 0; nn_sws_recv_hdr (sws); break; case NN_SWS_INSTATE_RECVD_CONTROL: /* Relay opcode to the user in order to interpret payload. */ opcode_hdr = sws->inhdr [0]; /* This library should not deliver fragmented messages to the application, so it's expected that this is the final frame. */ nn_assert (sws->is_final_frame); nn_assert (opcode_hdr & NN_SWS_FRAME_BITMASK_FIN); opcode_hdr &= ~NN_SWS_FRAME_BITMASK_FIN; /* The library is expected to have failed any connections with other opcodes; these are the only two control opcodes delivered. */ opcode = opcode_hdr & NN_SWS_FRAME_BITMASK_OPCODE; nn_assert (opcode == NN_WS_OPCODE_PING || opcode == NN_WS_OPCODE_PONG); nn_msg_init (msg, sws->inmsg_current_chunk_len); memcpy (((uint8_t*) nn_chunkref_data (&msg->body)), sws->inmsg_control, sws->inmsg_current_chunk_len); nn_sws_recv_hdr (sws); break; default: /* Unexpected state. */ nn_assert (0); break; } /* Allocate and populate WebSocket-specific control headers. */ cmsgsz = NN_CMSG_SPACE (sizeof (opcode_hdr)); nn_chunkref_init (&msg->hdrs, cmsgsz); cmsg = nn_chunkref_data (&msg->hdrs); cmsg->cmsg_level = NN_WS; cmsg->cmsg_type = NN_WS_MSG_TYPE; cmsg->cmsg_len = cmsgsz; memcpy (NN_CMSG_DATA (cmsg), &opcode_hdr, sizeof (opcode_hdr)); return 0; } static void nn_sws_validate_utf8_chunk (struct nn_sws *self) { uint8_t *pos; int code_point_len; size_t len; len = self->inmsg_current_chunk_len; pos = self->inmsg_current_chunk_buf; /* For chunked transfers, it's possible that a previous chunk was cut intra-code point. That partially-validated code point is reassembled with the beginning of the current chunk and checked. */ if (self->utf8_code_pt_fragment_len) { nn_assert (self->utf8_code_pt_fragment_len < NN_SWS_UTF8_MAX_CODEPOINT_LEN); /* Keep adding octets from fresh buffer to previous code point fragment to check for validity. */ while (len > 0) { self->utf8_code_pt_fragment [self->utf8_code_pt_fragment_len] = *pos; self->utf8_code_pt_fragment_len++; pos++; len--; code_point_len = nn_utf8_code_point (self->utf8_code_pt_fragment, self->utf8_code_pt_fragment_len); if (code_point_len > 0) { /* Valid code point found; continue validating. */ break; } else if (code_point_len == NN_SWS_UTF8_INVALID) { nn_sws_fail_conn (self, NN_SWS_CLOSE_ERR_INVALID_FRAME, "Invalid UTF-8 code point split on previous frame."); return; } else if (code_point_len == NN_SWS_UTF8_FRAGMENT) { if (self->is_final_frame) { nn_sws_fail_conn (self, NN_SWS_CLOSE_ERR_INVALID_FRAME, "Truncated UTF-8 payload with invalid code point."); return; } else { /* This chunk is well-formed; now recv the next chunk. */ nn_sws_recv_hdr (self); return; } } } } if (self->utf8_code_pt_fragment_len >= NN_SWS_UTF8_MAX_CODEPOINT_LEN) nn_assert (0); while (len > 0) { code_point_len = nn_utf8_code_point (pos, len); if (code_point_len > 0) { /* Valid code point found; continue validating. */ nn_assert (len >= (size_t) code_point_len); len -= code_point_len; pos += code_point_len; continue; } else if (code_point_len == NN_SWS_UTF8_INVALID) { self->utf8_code_pt_fragment_len = 0; memset (self->utf8_code_pt_fragment, 0, NN_SWS_UTF8_MAX_CODEPOINT_LEN); nn_sws_fail_conn (self, NN_SWS_CLOSE_ERR_INVALID_FRAME, "Invalid UTF-8 code point in payload."); return; } else if (code_point_len == NN_SWS_UTF8_FRAGMENT) { nn_assert (len < NN_SWS_UTF8_MAX_CODEPOINT_LEN); self->utf8_code_pt_fragment_len = len; memcpy (self->utf8_code_pt_fragment, pos, len); if (self->is_final_frame) { nn_sws_fail_conn (self, NN_SWS_CLOSE_ERR_INVALID_FRAME, "Truncated UTF-8 payload with invalid code point."); } else { /* Previous frame ended in the middle of a code point; receive more. */ nn_sws_recv_hdr (self); } return; } } /* Entire buffer is well-formed. */ nn_assert (len == 0); self->utf8_code_pt_fragment_len = 0; memset (self->utf8_code_pt_fragment, 0, NN_SWS_UTF8_MAX_CODEPOINT_LEN); if (self->is_final_frame) { self->instate = NN_SWS_INSTATE_RECVD_CHUNKED; nn_pipebase_received (&self->pipebase); } else { nn_sws_recv_hdr (self); } return; } static void nn_sws_acknowledge_close_handshake (struct nn_sws *self) { uint8_t *pos; uint16_t close_code; int code_point_len; size_t len; len = self->inmsg_current_chunk_len; pos = self->inmsg_current_chunk_buf; /* Peer did not provide a Close Code, so choose our own here. */ if (len == 0) { nn_sws_fail_conn (self, NN_SWS_CLOSE_NORMAL, ""); return; } /* If the payload is not even long enough for the required 2-octet Close Code, the connection should have already been failed. */ nn_assert (len >= NN_SWS_CLOSE_CODE_LEN); len -= NN_SWS_CLOSE_CODE_LEN; pos += NN_SWS_CLOSE_CODE_LEN; /* As per RFC 6455 7.1.6, the Close Reason following the Close Code must be well-formed UTF-8. */ while (len > 0) { code_point_len = nn_utf8_code_point (pos, len); if (code_point_len > 0) { /* Valid code point found; continue validating. */ nn_assert (len >= (size_t) code_point_len); len -= code_point_len; pos += code_point_len; continue; } else { /* RFC 6455 7.1.6 */ nn_sws_fail_conn (self, NN_SWS_CLOSE_ERR_PROTO, "Invalid UTF-8 sent as Close Reason."); return; } } /* Entire Close Reason is well-formed UTF-8 (or empty) */ nn_assert (len == 0); close_code = nn_gets (self->inmsg_current_chunk_buf); if (close_code == NN_SWS_CLOSE_NORMAL || close_code == NN_SWS_CLOSE_GOING_AWAY || close_code == NN_SWS_CLOSE_ERR_PROTO || close_code == NN_SWS_CLOSE_ERR_WUT || close_code == NN_SWS_CLOSE_ERR_INVALID_FRAME || close_code == NN_SWS_CLOSE_ERR_POLICY || close_code == NN_SWS_CLOSE_ERR_TOOBIG || close_code == NN_SWS_CLOSE_ERR_EXTENSION || close_code == NN_SWS_CLOSE_ERR_SERVER || (close_code >= 3000 && close_code <= 3999) || (close_code >= 4000 && close_code <= 4999)) { /* Repeat close code, per RFC 6455 7.4.1 and 7.4.2 */ nn_sws_fail_conn (self, (int) close_code, ""); } else { nn_sws_fail_conn (self, NN_SWS_CLOSE_ERR_PROTO, "Unrecognized close code."); } return; } static void nn_sws_fail_conn (struct nn_sws *self, int code, char *reason) { size_t reason_len; size_t payload_len; uint8_t rand_mask [NN_SWS_FRAME_SIZE_MASK]; uint8_t *payload_pos; struct nn_iovec iov; nn_assert_state (self, NN_SWS_STATE_ACTIVE); /* Stop user send/recv actions. */ self->instate = NN_SWS_INSTATE_CLOSED; nn_pipebase_stop (&self->pipebase); /* Destroy any remnant incoming message fragments. */ nn_msg_array_term (&self->inmsg_array); reason_len = strlen (reason); payload_len = reason_len + NN_SWS_CLOSE_CODE_LEN; /* Ensure text is short enough to also include code and framing. */ nn_assert (payload_len <= NN_SWS_PAYLOAD_MAX_LENGTH); /* RFC 6455 section 5.5.1. */ self->fail_msg [0] = (char)(NN_SWS_FRAME_BITMASK_FIN | NN_WS_OPCODE_CLOSE); /* Size of the payload, which is the status code plus the reason. */ self->fail_msg [1] = (char)payload_len; self->fail_msg_len = NN_SWS_FRAME_SIZE_INITIAL; switch (self->mode) { case NN_WS_SERVER: self->fail_msg [1] |= NN_SWS_FRAME_BITMASK_NOT_MASKED; break; case NN_WS_CLIENT: self->fail_msg [1] |= NN_SWS_FRAME_BITMASK_MASKED; /* Generate 32-bit mask as per RFC 6455 5.3. */ nn_random_generate (rand_mask, NN_SWS_FRAME_SIZE_MASK); memcpy (&self->fail_msg [NN_SWS_FRAME_SIZE_INITIAL], rand_mask, NN_SWS_FRAME_SIZE_MASK); self->fail_msg_len += NN_SWS_FRAME_SIZE_MASK; break; default: /* Developer error. */ nn_assert (0); } payload_pos = (uint8_t*) (&self->fail_msg [self->fail_msg_len]); /* Copy Status Code in network order (big-endian). */ nn_puts (payload_pos, (uint16_t) code); self->fail_msg_len += NN_SWS_CLOSE_CODE_LEN; /* Copy Close Reason immediately following the code. */ memcpy (payload_pos + NN_SWS_CLOSE_CODE_LEN, reason, reason_len); self->fail_msg_len += reason_len; /* If this is a client, apply mask. */ if (self->mode == NN_WS_CLIENT) { nn_sws_mask_payload (payload_pos, payload_len, rand_mask, NN_SWS_FRAME_SIZE_MASK, NULL); } if (self->outstate == NN_SWS_OUTSTATE_IDLE) { iov.iov_base = self->fail_msg; iov.iov_len = self->fail_msg_len; nn_usock_send (self->usock, &iov, 1); self->outstate = NN_SWS_OUTSTATE_SENDING; self->state = NN_SWS_STATE_CLOSING_CONNECTION; } else { self->state = NN_SWS_STATE_DONE; nn_fsm_raise (&self->fsm, &self->done, NN_SWS_RETURN_CLOSE_HANDSHAKE); } return; } static void nn_sws_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_sws *sws; sws = nn_cont (self, struct nn_sws, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { /* TODO: Consider sending a close code here? */ nn_pipebase_stop (&sws->pipebase); nn_ws_handshake_stop (&sws->handshaker); sws->state = NN_SWS_STATE_STOPPING; } if (nn_slow (sws->state == NN_SWS_STATE_STOPPING)) { if (nn_ws_handshake_isidle (&sws->handshaker)) { nn_usock_swap_owner (sws->usock, &sws->usock_owner); sws->usock = NULL; sws->usock_owner.src = -1; sws->usock_owner.fsm = NULL; sws->state = NN_SWS_STATE_IDLE; nn_fsm_stopped (&sws->fsm, NN_SWS_RETURN_STOPPED); return; } return; } nn_fsm_bad_state (sws->state, src, type); } static void nn_sws_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_sws *sws; int rc; int opt; size_t opt_sz = sizeof (opt); sws = nn_cont (self, struct nn_sws, fsm); switch (sws->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_SWS_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_ws_handshake_start (&sws->handshaker, sws->usock, &sws->pipebase, sws->mode, sws->resource, sws->remote_host); sws->state = NN_SWS_STATE_HANDSHAKE; return; default: nn_fsm_bad_action (sws->state, src, type); } default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* HANDSHAKE state. */ /******************************************************************************/ case NN_SWS_STATE_HANDSHAKE: switch (src) { case NN_SWS_SRC_HANDSHAKE: switch (type) { case NN_WS_HANDSHAKE_OK: /* Before moving to the active state stop the handshake state machine. */ nn_ws_handshake_stop (&sws->handshaker); sws->state = NN_SWS_STATE_STOPPING_HANDSHAKE; return; case NN_WS_HANDSHAKE_ERROR: /* Raise the error and move directly to the DONE state. ws_handshake object will be stopped later on. */ sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_CLOSE_HANDSHAKE); return; default: nn_fsm_bad_action (sws->state, src, type); } default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* STOPPING_HANDSHAKE state. */ /******************************************************************************/ case NN_SWS_STATE_STOPPING_HANDSHAKE: switch (src) { case NN_SWS_SRC_HANDSHAKE: switch (type) { case NN_WS_HANDSHAKE_STOPPED: /* Start the pipe. */ rc = nn_pipebase_start (&sws->pipebase); if (nn_slow (rc < 0)) { sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR); return; } /* Start receiving a message in asynchronous manner. */ nn_sws_recv_hdr (sws); /* Mark the pipe as available for sending. */ sws->outstate = NN_SWS_OUTSTATE_IDLE; sws->state = NN_SWS_STATE_ACTIVE; return; default: nn_fsm_bad_action (sws->state, src, type); } default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_SWS_STATE_ACTIVE: switch (src) { case NN_SWS_SRC_USOCK: switch (type) { case NN_USOCK_SENT: /* The message is now fully sent. */ nn_assert (sws->outstate == NN_SWS_OUTSTATE_SENDING); sws->outstate = NN_SWS_OUTSTATE_IDLE; nn_msg_term (&sws->outmsg); nn_msg_init (&sws->outmsg, 0); nn_pipebase_sent (&sws->pipebase); return; case NN_USOCK_RECEIVED: switch (sws->instate) { case NN_SWS_INSTATE_RECV_HDR: /* Require RSV1, RSV2, and RSV3 bits to be unset for x-nanomsg protocol as per RFC 6455 section 5.2. */ if (sws->inhdr [0] & NN_SWS_FRAME_BITMASK_RSV1 || sws->inhdr [0] & NN_SWS_FRAME_BITMASK_RSV2 || sws->inhdr [0] & NN_SWS_FRAME_BITMASK_RSV3) { nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "RSV1, RSV2, and RSV3 must be unset."); return; } sws->is_final_frame = sws->inhdr [0] & NN_SWS_FRAME_BITMASK_FIN; sws->masked = sws->inhdr [1] & NN_SWS_FRAME_BITMASK_MASKED; switch (sws->mode) { case NN_WS_SERVER: /* Require mask bit to be set from client. */ if (sws->masked) { /* Continue receiving header for this frame. */ sws->ext_hdr_len = NN_SWS_FRAME_SIZE_MASK; break; } else { nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Server expects MASK bit to be set."); return; } case NN_WS_CLIENT: /* Require mask bit to be unset from server. */ if (sws->masked) { nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Client expects MASK bit to be unset."); return; } else { /* Continue receiving header for this frame. */ sws->ext_hdr_len = 0; break; } default: /* Only two modes of this endpoint are expected. */ nn_assert (0); return; } sws->opcode = sws->inhdr [0] & NN_SWS_FRAME_BITMASK_OPCODE; sws->payload_ctl = sws->inhdr [1] & NN_SWS_FRAME_BITMASK_LENGTH; /* Prevent unexpected continuation frame. */ if (!sws->continuing && sws->opcode == NN_WS_OPCODE_FRAGMENT) { nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "No message to continue."); return; } /* Preserve initial message opcode and RSV bits in case this is a fragmented message. */ if (!sws->continuing) sws->inmsg_hdr = sws->inhdr [0] | NN_SWS_FRAME_BITMASK_FIN; if (sws->payload_ctl <= NN_SWS_PAYLOAD_MAX_LENGTH) { sws->ext_hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_0; } else if (sws->payload_ctl == NN_SWS_PAYLOAD_FRAME_16) { sws->ext_hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_16; } else if (sws->payload_ctl == NN_SWS_PAYLOAD_FRAME_63) { sws->ext_hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_63; } else { /* Developer error parsing/handling length. */ nn_assert (0); return; } switch (sws->opcode) { case NN_WS_OPCODE_TEXT: /* Fall thru; TEXT and BINARY handled alike. */ case NN_WS_OPCODE_BINARY: sws->is_control_frame = 0; if (sws->continuing) { nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Expected continuation frame opcode."); return; } if (!sws->is_final_frame) sws->continuing = 1; if (sws->ext_hdr_len == 0 && sws->payload_ctl == 0) { /* Only a remote server could send a 2-byte msg; sanity-check that this endpoint is a client. */ nn_assert (sws->mode == NN_WS_CLIENT); sws->inmsg_current_chunk_len = 0; if (sws->continuing) { /* This frame was empty, but continue next frame in fragmented sequence. */ nn_sws_recv_hdr (sws); return; } else { /* Special case when there is no payload, mask, or additional frames. */ sws->instate = NN_SWS_INSTATE_RECVD_CHUNKED; nn_pipebase_received (&sws->pipebase); return; } } /* Continue to receive extended header+payload. */ break; case NN_WS_OPCODE_FRAGMENT: sws->is_control_frame = 0; sws->continuing = !sws->is_final_frame; if (sws->ext_hdr_len == 0 && sws->payload_ctl == 0) { /* Only a remote server could send a 2-byte msg; sanity-check that this endpoint is a client. */ nn_assert (sws->mode == NN_WS_CLIENT); sws->inmsg_current_chunk_len = 0; if (sws->continuing) { /* This frame was empty, but continue next frame in fragmented sequence. */ nn_sws_recv_hdr (sws); return; } else { /* Special case when there is no payload, mask, or additional frames. */ sws->instate = NN_SWS_INSTATE_RECVD_CHUNKED; nn_pipebase_received (&sws->pipebase); return; } } /* Continue to receive extended header+payload. */ break; case NN_WS_OPCODE_PING: sws->is_control_frame = 1; sws->pings_received++; if (sws->payload_ctl > NN_SWS_PAYLOAD_MAX_LENGTH) { /* As per RFC 6455 section 5.4, large payloads on control frames is not allowed, and on receipt the endpoint MUST close connection immediately. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Control frame payload exceeds allowable length."); return; } if (!sws->is_final_frame) { /* As per RFC 6455 section 5.4, fragmentation of control frames is not allowed; on receipt the endpoint MUST close connection immediately. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Cannot fragment control message (FIN=0)."); return; } if (sws->ext_hdr_len == 0 && sws->payload_ctl == 0) { /* Special case when there is no payload, mask, or additional frames. */ sws->inmsg_current_chunk_len = 0; sws->instate = NN_SWS_INSTATE_RECVD_CONTROL; nn_pipebase_received (&sws->pipebase); return; } /* Continue to receive extended header+payload. */ break; case NN_WS_OPCODE_PONG: sws->is_control_frame = 1; sws->pongs_received++; if (sws->payload_ctl > NN_SWS_PAYLOAD_MAX_LENGTH) { /* As per RFC 6455 section 5.4, large payloads on control frames is not allowed, and on receipt the endpoint MUST close connection immediately. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Control frame payload exceeds allowable length."); return; } if (!sws->is_final_frame) { /* As per RFC 6455 section 5.4, fragmentation of control frames is not allowed; on receipt the endpoint MUST close connection immediately. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Cannot fragment control message (FIN=0)."); return; } if (sws->ext_hdr_len == 0 && sws->payload_ctl == 0) { /* Special case when there is no payload, mask, or additional frames. */ sws->inmsg_current_chunk_len = 0; sws->instate = NN_SWS_INSTATE_RECVD_CONTROL; nn_pipebase_received (&sws->pipebase); return; } /* Continue to receive extended header+payload. */ break; case NN_WS_OPCODE_CLOSE: /* RFC 6455 section 5.5.1. */ sws->is_control_frame = 1; if (!sws->is_final_frame) { /* As per RFC 6455 section 5.4, fragmentation of control frames is not allowed; on receipt the endpoint MUST close connection immediately. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Cannot fragment control message (FIN=0)."); return; } if (sws->payload_ctl > NN_SWS_PAYLOAD_MAX_LENGTH) { /* As per RFC 6455 section 5.4, large payloads on control frames is not allowed, and on receipt the endpoint MUST close connection immediately. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Control frame payload exceeds allowable length."); return; } if (sws->payload_ctl == 1) { /* As per RFC 6455 section 5.5.1, if a payload is to accompany a close frame, the first two bytes MUST be the close code. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Expected 2byte close code."); return; } if (sws->ext_hdr_len == 0 && sws->payload_ctl == 0) { /* Special case when there is no payload, mask, or additional frames. */ sws->inmsg_current_chunk_len = 0; nn_sws_acknowledge_close_handshake (sws); return; } /* Continue to receive extended header+payload. */ break; default: /* Client sent an invalid opcode; as per RFC 6455 section 10.7, close connection with code. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Invalid opcode."); return; } if (sws->ext_hdr_len == 0) { /* Only a remote server could send a 2-byte msg; sanity-check that this endpoint is a client. */ nn_assert (sws->mode == NN_WS_CLIENT); /* In the case of no additional header, the payload is known to be within these bounds. */ nn_assert (0 < sws->payload_ctl && sws->payload_ctl <= NN_SWS_PAYLOAD_MAX_LENGTH); sws->inmsg_current_chunk_len = sws->payload_ctl; /* Use scatter/gather array for application messages, and a fixed-width buffer for control messages. This is convenient since control messages can be interspersed between chunked application msgs. */ if (sws->is_control_frame) { sws->inmsg_current_chunk_buf = sws->inmsg_control; } else { sws->inmsg_total_size += sws->inmsg_current_chunk_len; /* Protect non-control messages against the NN_RCVMAXSIZE threshold; control messages already have a small pre-allocated buffer, and therefore are not subject to this limit. */ nn_pipebase_getopt (&sws->pipebase, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, &opt_sz); if (opt >= 0 && sws->inmsg_total_size > (size_t) opt) { nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_TOOBIG, "Message larger than application allows."); return; } sws->inmsg_chunks++; sws->inmsg_current_chunk_buf = nn_msg_chunk_new (sws->inmsg_current_chunk_len, &sws->inmsg_array); } sws->instate = NN_SWS_INSTATE_RECV_PAYLOAD; nn_usock_recv (sws->usock, sws->inmsg_current_chunk_buf, sws->inmsg_current_chunk_len, NULL); return; } else { /* Continue receiving the rest of the header frame. */ sws->instate = NN_SWS_INSTATE_RECV_HDREXT; nn_usock_recv (sws->usock, sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL, sws->ext_hdr_len, NULL); return; } case NN_SWS_INSTATE_RECV_HDREXT: nn_assert (sws->ext_hdr_len > 0); if (sws->payload_ctl <= NN_SWS_PAYLOAD_MAX_LENGTH) { sws->inmsg_current_chunk_len = sws->payload_ctl; if (sws->masked) { sws->mask = sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL; } else { sws->mask = NULL; } } else if (sws->payload_ctl == NN_SWS_PAYLOAD_FRAME_16) { sws->inmsg_current_chunk_len = nn_gets (sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL); if (sws->masked) { sws->mask = sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL + NN_SWS_FRAME_SIZE_PAYLOAD_16; } else { sws->mask = NULL; } } else if (sws->payload_ctl == NN_SWS_PAYLOAD_FRAME_63) { sws->inmsg_current_chunk_len = (size_t) nn_getll (sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL); if (sws->masked) { sws->mask = sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL + NN_SWS_FRAME_SIZE_PAYLOAD_63; } else { sws->mask = NULL; } } else { /* Client sent invalid data; as per RFC 6455, server closes the connection immediately. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Invalid payload length."); return; } /* Handle zero-length message bodies. */ if (sws->inmsg_current_chunk_len == 0) { if (sws->is_final_frame) { if (sws->opcode == NN_WS_OPCODE_CLOSE) { nn_sws_acknowledge_close_handshake (sws); } else { sws->instate = (sws->is_control_frame ? NN_SWS_INSTATE_RECVD_CONTROL : NN_SWS_INSTATE_RECVD_CHUNKED); nn_pipebase_received (&sws->pipebase); } } else { nn_sws_recv_hdr (sws); } return; } nn_assert (sws->inmsg_current_chunk_len > 0); /* Use scatter/gather array for application messages, and a fixed-width buffer for control messages. This is convenient since control messages can be interspersed between chunked application msgs. */ if (sws->is_control_frame) { sws->inmsg_current_chunk_buf = sws->inmsg_control; } else { sws->inmsg_total_size += sws->inmsg_current_chunk_len; /* Protect non-control messages against the NN_RCVMAXSIZE threshold; control messages already have a small pre-allocated buffer, and therefore are not subject to this limit. */ nn_pipebase_getopt (&sws->pipebase, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, &opt_sz); if (opt >= 0 && sws->inmsg_total_size > (size_t) opt) { nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_TOOBIG, "Message size exceeds limit."); return; } sws->inmsg_chunks++; sws->inmsg_current_chunk_buf = nn_msg_chunk_new (sws->inmsg_current_chunk_len, &sws->inmsg_array); } sws->instate = NN_SWS_INSTATE_RECV_PAYLOAD; nn_usock_recv (sws->usock, sws->inmsg_current_chunk_buf, sws->inmsg_current_chunk_len, NULL); return; case NN_SWS_INSTATE_RECV_PAYLOAD: /* Unmask if necessary. */ if (sws->masked) { nn_sws_mask_payload (sws->inmsg_current_chunk_buf, sws->inmsg_current_chunk_len, sws->mask, NN_SWS_FRAME_SIZE_MASK, NULL); } switch (sws->opcode) { case NN_WS_OPCODE_TEXT: nn_sws_validate_utf8_chunk (sws); return; case NN_WS_OPCODE_BINARY: if (sws->is_final_frame) { sws->instate = NN_SWS_INSTATE_RECVD_CHUNKED; nn_pipebase_received (&sws->pipebase); } else { nn_sws_recv_hdr (sws); } return; case NN_WS_OPCODE_FRAGMENT: /* Must check original opcode to see if this fragment needs UTF-8 validation. */ if ((sws->inmsg_hdr & NN_SWS_FRAME_BITMASK_OPCODE) == NN_WS_OPCODE_TEXT) { nn_sws_validate_utf8_chunk (sws); } else if (sws->is_final_frame) { sws->instate = NN_SWS_INSTATE_RECVD_CHUNKED; nn_pipebase_received (&sws->pipebase); } else { nn_sws_recv_hdr (sws); } return; case NN_WS_OPCODE_PING: sws->instate = NN_SWS_INSTATE_RECVD_CONTROL; nn_pipebase_received (&sws->pipebase); return; case NN_WS_OPCODE_PONG: sws->instate = NN_SWS_INSTATE_RECVD_CONTROL; nn_pipebase_received (&sws->pipebase); return; case NN_WS_OPCODE_CLOSE: nn_sws_acknowledge_close_handshake (sws); return; default: /* This should have been prevented upstream. */ nn_assert (0); return; } default: nn_fsm_error ("Unexpected socket instate", sws->state, src, type); } case NN_USOCK_SHUTDOWN: nn_pipebase_stop (&sws->pipebase); sws->state = NN_SWS_STATE_BROKEN_CONNECTION; return; case NN_USOCK_ERROR: nn_pipebase_stop (&sws->pipebase); sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR); return; default: nn_fsm_bad_action (sws->state, src, type); } break; default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* CLOSING_CONNECTION state. */ /* Wait for acknowledgement closing handshake was successfully sent. */ /******************************************************************************/ case NN_SWS_STATE_CLOSING_CONNECTION: switch (src) { case NN_SWS_SRC_USOCK: switch (type) { case NN_USOCK_SENT: /* Wait for acknowledgement closing handshake was sent to peer. */ nn_assert (sws->outstate == NN_SWS_OUTSTATE_SENDING); sws->outstate = NN_SWS_OUTSTATE_IDLE; sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_CLOSE_HANDSHAKE); return; case NN_USOCK_SHUTDOWN: return; case NN_USOCK_ERROR: sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR); return; default: nn_fsm_bad_action (sws->state, src, type); } default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* SHUTTING_DOWN state. */ /* The underlying connection is closed. We are just waiting that underlying */ /* usock being closed */ /******************************************************************************/ case NN_SWS_STATE_BROKEN_CONNECTION: switch (src) { case NN_SWS_SRC_USOCK: switch (type) { case NN_USOCK_ERROR: sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR); return; default: nn_fsm_bad_action (sws->state, src, type); } default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* DONE state. */ /* The underlying connection is closed. There's nothing that can be done in */ /* this state except stopping the object. */ /******************************************************************************/ case NN_SWS_STATE_DONE: nn_fsm_bad_source (sws->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (sws->state, src, type); } } nanomsg-1.1.5/src/transports/ws/sws.h000066400000000000000000000154601336111550300176100ustar00rootroot00000000000000/* Copyright (c) 2013 250bpm s.r.o. All rights reserved. Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_SWS_INCLUDED #define NN_SWS_INCLUDED #include "../../transport.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "ws_handshake.h" #include "../../utils/msg.h" #include "../../utils/list.h" /* This state machine handles WebSocket connection from the point where it is established to the point when it is broken. */ /* Return codes of this state machine. */ #define NN_SWS_RETURN_ERROR 1 #define NN_SWS_RETURN_CLOSE_HANDSHAKE 2 #define NN_SWS_RETURN_STOPPED 3 /* WebSocket protocol header frame sizes. */ #define NN_SWS_FRAME_SIZE_INITIAL 2 #define NN_SWS_FRAME_SIZE_PAYLOAD_0 0 #define NN_SWS_FRAME_SIZE_PAYLOAD_16 2 #define NN_SWS_FRAME_SIZE_PAYLOAD_63 8 #define NN_SWS_FRAME_SIZE_MASK 4 /* WebSocket control bitmasks as per RFC 6455 5.2. */ #define NN_SWS_FRAME_BITMASK_FIN 0x80 #define NN_SWS_FRAME_BITMASK_RSV1 0x40 #define NN_SWS_FRAME_BITMASK_RSV2 0x20 #define NN_SWS_FRAME_BITMASK_RSV3 0x10 #define NN_SWS_FRAME_BITMASK_OPCODE 0x0F /* UTF-8 validation. */ #define NN_SWS_UTF8_MAX_CODEPOINT_LEN 4 /* The longest possible header frame length. As per RFC 6455 5.2: first 2 bytes of initial framing + up to 8 bytes of additional extended payload length header + 4 byte mask = 14bytes Not all messages will use the maximum amount allocated, but statically allocating this buffer for convenience. */ #define NN_SWS_FRAME_MAX_HDR_LEN 14 /* WebSocket protocol payload length framing RFC 6455 section 5.2. */ #define NN_SWS_PAYLOAD_MAX_LENGTH 125 #define NN_SWS_PAYLOAD_MAX_LENGTH_16 65535 #define NN_SWS_PAYLOAD_MAX_LENGTH_63 9223372036854775807 #define NN_SWS_PAYLOAD_FRAME_16 0x7E #define NN_SWS_PAYLOAD_FRAME_63 0x7F /* WebSocket Close Status Code length. */ #define NN_SWS_CLOSE_CODE_LEN 2 struct nn_sws { /* The state machine. */ struct nn_fsm fsm; int state; /* Default message type set on outbound frames. */ uint8_t msg_type; /* Controls Tx/Rx framing based on whether this peer is acting as a Client or a Server. */ int mode; /* The underlying socket. */ struct nn_usock *usock; /* Child state machine to do protocol header exchange. */ struct nn_ws_handshake handshaker; /* The original owner of the underlying socket. */ struct nn_fsm_owner usock_owner; /* Pipe connecting this WebSocket connection to the nanomsg core. */ struct nn_pipebase pipebase; /* Requested resource when acting as client. */ const char* resource; /* Remote Host in header request when acting as client. */ const char* remote_host; /* State of inbound state machine. */ int instate; /* Buffer used to store the framing of incoming message. */ uint8_t inhdr [NN_SWS_FRAME_MAX_HDR_LEN]; /* Parsed header frames. */ uint8_t opcode; uint8_t payload_ctl; uint8_t masked; uint8_t *mask; size_t ext_hdr_len; int is_final_frame; int is_control_frame; /* As valid fragments are being received, this flag stays true until the FIN bit is received. This state is also used to determine peer sequencing anamolies that trigger this endpoint to fail the connection. */ int continuing; /* When validating continuation frames of UTF-8, it may be necessary to buffer tail-end of the previous frame in order to continue validation in the case that frames are chopped on intra-code point boundaries. */ uint8_t utf8_code_pt_fragment [NN_SWS_UTF8_MAX_CODEPOINT_LEN]; size_t utf8_code_pt_fragment_len; /* Statistics on control frames. */ int pings_sent; int pongs_sent; int pings_received; int pongs_received; /* Fragments of message being received at the moment. */ struct nn_list inmsg_array; uint8_t *inmsg_current_chunk_buf; size_t inmsg_current_chunk_len; size_t inmsg_total_size; int inmsg_chunks; uint8_t inmsg_hdr; /* Control message being received at the moment. Because these can be interspersed between fragmented TEXT and BINARY messages, they are stored in this buffer so as not to interrupt the message array. */ uint8_t inmsg_control [NN_SWS_PAYLOAD_MAX_LENGTH]; /* Reason this connection is closing to send as closing handshake. */ char fail_msg [NN_SWS_PAYLOAD_MAX_LENGTH]; size_t fail_msg_len; /* State of the outbound state machine. */ int outstate; /* Buffer used to store the header of outgoing message. */ uint8_t outhdr [NN_SWS_FRAME_MAX_HDR_LEN]; /* Message being sent at the moment. */ struct nn_msg outmsg; /* Event raised when the state machine ends. */ struct nn_fsm_event done; }; /* Scatter/gather array element type forincoming message chunks. Fragmented message frames are reassembled prior to notifying the user. */ struct msg_chunk { struct nn_list_item item; struct nn_chunkref chunk; }; /* Allocate a new message chunk, append it to message array, and return pointer to its buffer. */ void *nn_msg_chunk_new (size_t size, struct nn_list *msg_array); /* Deallocate a message chunk and remove it from array. */ void nn_msg_chunk_term (struct msg_chunk *it, struct nn_list *msg_array); /* Deallocate an entire message array. */ void nn_msg_array_term (struct nn_list *msg_array); void nn_sws_init (struct nn_sws *self, int src, struct nn_ep *ep, struct nn_fsm *owner); void nn_sws_term (struct nn_sws *self); int nn_sws_isidle (struct nn_sws *self); void nn_sws_start (struct nn_sws *self, struct nn_usock *usock, int mode, const char *resource, const char *host, uint8_t msg_type); void nn_sws_stop (struct nn_sws *self); #endif nanomsg-1.1.5/src/transports/ws/ws.c000066400000000000000000000102451336111550300174140ustar00rootroot00000000000000/* Copyright (c) 2012-2013 250bpm s.r.o. All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "bws.h" #include "cws.h" #include "sws.h" #include "../../ws.h" #include "../utils/port.h" #include "../utils/iface.h" #include "../../utils/err.h" #include "../../utils/alloc.h" #include "../../utils/fast.h" #include "../../utils/cont.h" #include #if defined NN_HAVE_WINDOWS #include "../../utils/win.h" #else #include #endif /* WebSocket-specific socket options. */ struct nn_ws_optset { struct nn_optset base; int msg_type; }; static void nn_ws_optset_destroy (struct nn_optset *self); static int nn_ws_optset_setopt (struct nn_optset *self, int option, const void *optval, size_t optvallen); static int nn_ws_optset_getopt (struct nn_optset *self, int option, void *optval, size_t *optvallen); static const struct nn_optset_vfptr nn_ws_optset_vfptr = { nn_ws_optset_destroy, nn_ws_optset_setopt, nn_ws_optset_getopt }; /* nn_transport interface. */ static int nn_ws_bind (struct nn_ep *); static int nn_ws_connect (struct nn_ep *); static struct nn_optset *nn_ws_optset (void); struct nn_transport nn_ws = { "ws", NN_WS, NULL, NULL, nn_ws_bind, nn_ws_connect, nn_ws_optset, }; static int nn_ws_bind (struct nn_ep *ep) { return nn_bws_create (ep); } static int nn_ws_connect (struct nn_ep *ep) { return nn_cws_create (ep); } static struct nn_optset *nn_ws_optset () { struct nn_ws_optset *optset; optset = nn_alloc (sizeof (struct nn_ws_optset), "optset (ws)"); alloc_assert (optset); optset->base.vfptr = &nn_ws_optset_vfptr; /* Default values for WebSocket options. */ optset->msg_type = NN_WS_MSG_TYPE_BINARY; return &optset->base; } static void nn_ws_optset_destroy (struct nn_optset *self) { struct nn_ws_optset *optset; optset = nn_cont (self, struct nn_ws_optset, base); nn_free (optset); } static int nn_ws_optset_setopt (struct nn_optset *self, int option, const void *optval, size_t optvallen) { struct nn_ws_optset *optset; int val; optset = nn_cont (self, struct nn_ws_optset, base); if (optvallen != sizeof (int)) { return -EINVAL; } val = *(int *)optval; switch (option) { case NN_WS_MSG_TYPE: switch (val) { case NN_WS_MSG_TYPE_TEXT: case NN_WS_MSG_TYPE_BINARY: optset->msg_type = val; return 0; default: return -EINVAL; } default: return -ENOPROTOOPT; } } static int nn_ws_optset_getopt (struct nn_optset *self, int option, void *optval, size_t *optvallen) { struct nn_ws_optset *optset; optset = nn_cont (self, struct nn_ws_optset, base); switch (option) { case NN_WS_MSG_TYPE: memcpy (optval, &optset->msg_type, *optvallen < sizeof (int) ? *optvallen : sizeof (int)); *optvallen = sizeof (int); return 0; default: return -ENOPROTOOPT; } } nanomsg-1.1.5/src/transports/ws/ws_handshake.c000066400000000000000000001474331336111550300214340ustar00rootroot00000000000000/* Copyright (c) 2013 250bpm s.r.o. All rights reserved. Copyright (c) 2014-2016 Jack R. Dunaway. All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #include "ws_handshake.h" #include "sha1.h" #include "../../aio/timer.h" #include "../../core/sock.h" #include "../utils/base64.h" #include "../../utils/alloc.h" #include "../../utils/err.h" #include "../../utils/cont.h" #include "../../utils/fast.h" #include "../../utils/wire.h" #include "../../utils/attr.h" #include "../../utils/random.h" #include "../../utils/strcasestr.h" #include #include #include #define CRLF "\r\n" /*****************************************************************************/ /*** BEGIN undesirable dependency *******************************************/ /*****************************************************************************/ /* TODO: A transport should be SP agnostic; alas, these includes are */ /* required for the map. Ideally, this map would live in another */ /* abstraction layer; perhaps a "registry" of Scalability Protocols? */ /*****************************************************************************/ #include "../../pair.h" #include "../../reqrep.h" #include "../../pubsub.h" #include "../../survey.h" #include "../../pipeline.h" #include "../../bus.h" static const struct nn_ws_sp_map NN_WS_HANDSHAKE_SP_MAP[] = { { NN_PAIR, NN_PAIR, "pair.sp.nanomsg.org" }, { NN_REQ, NN_REP, "req.sp.nanomsg.org" }, { NN_REP, NN_REQ, "rep.sp.nanomsg.org" }, { NN_PUB, NN_SUB, "pub.sp.nanomsg.org" }, { NN_SUB, NN_PUB, "sub.sp.nanomsg.org" }, { NN_SURVEYOR, NN_RESPONDENT, "surveyor.sp.nanomsg.org" }, { NN_RESPONDENT, NN_SURVEYOR, "respondent.sp.nanomsg.org" }, { NN_PUSH, NN_PULL, "push.sp.nanomsg.org" }, { NN_PULL, NN_PUSH, "pull.sp.nanomsg.org" }, { NN_BUS, NN_BUS, "bus.sp.nanomsg.org" } }; const size_t NN_WS_HANDSHAKE_SP_MAP_LEN = sizeof (NN_WS_HANDSHAKE_SP_MAP) / sizeof (NN_WS_HANDSHAKE_SP_MAP [0]); /*****************************************************************************/ /*** END undesirable dependency *********************************************/ /*****************************************************************************/ /* State machine finite states. */ #define NN_WS_HANDSHAKE_STATE_IDLE 1 #define NN_WS_HANDSHAKE_STATE_SERVER_RECV 2 #define NN_WS_HANDSHAKE_STATE_SERVER_REPLY 3 #define NN_WS_HANDSHAKE_STATE_CLIENT_SEND 4 #define NN_WS_HANDSHAKE_STATE_CLIENT_RECV 5 #define NN_WS_HANDSHAKE_STATE_HANDSHAKE_SENT 6 #define NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR 7 #define NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_DONE 8 #define NN_WS_HANDSHAKE_STATE_DONE 9 #define NN_WS_HANDSHAKE_STATE_STOPPING 10 /* Subordinate srcptr objects. */ #define NN_WS_HANDSHAKE_SRC_USOCK 1 #define NN_WS_HANDSHAKE_SRC_TIMER 2 /* Time allowed to complete handshake. */ #define NN_WS_HANDSHAKE_TIMEOUT 5000 /* Possible return codes internal to the parsing operations. */ #define NN_WS_HANDSHAKE_NOMATCH 0 #define NN_WS_HANDSHAKE_MATCH 1 /* Possible return codes from parsing opening handshake from peer. */ #define NN_WS_HANDSHAKE_VALID 0 #define NN_WS_HANDSHAKE_RECV_MORE 1 #define NN_WS_HANDSHAKE_INVALID -1 /* Possible handshake responses to send to client when acting as server. */ #define NN_WS_HANDSHAKE_RESPONSE_NULL -1 #define NN_WS_HANDSHAKE_RESPONSE_OK 0 #define NN_WS_HANDSHAKE_RESPONSE_TOO_BIG 1 #define NN_WS_HANDSHAKE_RESPONSE_UNUSED2 2 #define NN_WS_HANDSHAKE_RESPONSE_WSPROTO 3 #define NN_WS_HANDSHAKE_RESPONSE_WSVERSION 4 #define NN_WS_HANDSHAKE_RESPONSE_NNPROTO 5 #define NN_WS_HANDSHAKE_RESPONSE_NOTPEER 6 #define NN_WS_HANDSHAKE_RESPONSE_UNKNOWNTYPE 7 /* Private functions. */ static void nn_ws_handshake_handler (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_ws_handshake_shutdown (struct nn_fsm *self, int src, int type, void *srcptr); static void nn_ws_handshake_leave (struct nn_ws_handshake *self, int rc); /* WebSocket protocol support functions. */ static int nn_ws_handshake_parse_client_opening (struct nn_ws_handshake *self); static void nn_ws_handshake_server_reply (struct nn_ws_handshake *self); static void nn_ws_handshake_client_request (struct nn_ws_handshake *self); static int nn_ws_handshake_parse_server_response (struct nn_ws_handshake *self); static int nn_ws_handshake_hash_key (const char *key, size_t key_len, char *hashed, size_t hashed_len); /* String parsing support functions. */ /* Scans for reference token against subject string, optionally ignoring case sensitivity and/or leading spaces in subject. On match, advances the subject pointer to the next non-ignored character past match. Both strings must be NULL terminated to avoid undefined behavior. Returns NN_WS_HANDSHAKE_MATCH on match; else, NN_WS_HANDSHAKE_NOMATCH. */ static int nn_ws_match_token (const char* token, const char **subj, int case_insensitive, int ignore_leading_sp); /* Scans subject string for termination sequence, optionally ignoring leading and/or trailing spaces in subject. On match, advances the subject pointer to the next character past match. Both strings must be NULL terminated to avoid undefined behavior. If the match succeeds, values are stored into *addr and *len. */ static int nn_ws_match_value (const char* termseq, const char **subj, int ignore_leading_sp, int ignore_trailing_sp, const char **addr, size_t* const len); /* Compares subject octet stream to expected value, optionally ignoring case sensitivity. Returns non-zero on success, zero on failure. */ static int nn_ws_validate_value (const char* expected, const char *subj, size_t subj_len, int case_insensitive); void nn_ws_handshake_init (struct nn_ws_handshake *self, int src, struct nn_fsm *owner) { nn_fsm_init (&self->fsm, nn_ws_handshake_handler, nn_ws_handshake_shutdown, src, self, owner); self->state = NN_WS_HANDSHAKE_STATE_IDLE; nn_timer_init (&self->timer, NN_WS_HANDSHAKE_SRC_TIMER, &self->fsm); nn_fsm_event_init (&self->done); self->timeout = NN_WS_HANDSHAKE_TIMEOUT; self->usock = NULL; self->usock_owner.src = -1; self->usock_owner.fsm = NULL; self->pipebase = NULL; } void nn_ws_handshake_term (struct nn_ws_handshake *self) { nn_assert_state (self, NN_WS_HANDSHAKE_STATE_IDLE); nn_fsm_event_term (&self->done); nn_timer_term (&self->timer); nn_fsm_term (&self->fsm); } int nn_ws_handshake_isidle (struct nn_ws_handshake *self) { return nn_fsm_isidle (&self->fsm); } void nn_ws_handshake_start (struct nn_ws_handshake *self, struct nn_usock *usock, struct nn_pipebase *pipebase, int mode, const char *resource, const char *host) { /* It's expected this resource has been allocated during intial connect. */ if (mode == NN_WS_CLIENT) nn_assert (strlen (resource) >= 1); /* Take ownership of the underlying socket. */ nn_assert (self->usock == NULL && self->usock_owner.fsm == NULL); self->usock_owner.src = NN_WS_HANDSHAKE_SRC_USOCK; self->usock_owner.fsm = &self->fsm; nn_usock_swap_owner (usock, &self->usock_owner); self->usock = usock; self->pipebase = pipebase; self->mode = mode; self->resource = resource; self->remote_host = host; memset (self->opening_hs, 0, sizeof (self->opening_hs)); memset (self->response, 0, sizeof (self->response)); self->recv_pos = 0; self->retries = 0; /* Calculate the absolute minimum length possible for a valid opening handshake. This is an optimization since we must poll for the remainder of the opening handshake in small byte chunks. */ switch (self->mode) { case NN_WS_SERVER: self->recv_len = strlen ( "GET x HTTP/1.1\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Host: x\r\n" "Origin: x\r\n" "Sec-WebSocket-Key: xxxxxxxxxxxxxxxxxxxxxxxx\r\n" "Sec-WebSocket-Version: xx\r\n\r\n"); break; case NN_WS_CLIENT: /* Shortest conceiveable response from server is a terse status. */ self->recv_len = strlen ("HTTP/1.1 xxx\r\n\r\n"); break; default: /* Developer error; unexpected mode. */ nn_assert (0); break; } /* Launch the state machine. */ nn_fsm_start (&self->fsm); } void nn_ws_handshake_stop (struct nn_ws_handshake *self) { nn_fsm_stop (&self->fsm); } static void nn_ws_handshake_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_ws_handshake *handshaker; handshaker = nn_cont (self, struct nn_ws_handshake, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING; } if (nn_slow (handshaker->state == NN_WS_HANDSHAKE_STATE_STOPPING)) { if (!nn_timer_isidle (&handshaker->timer)) return; handshaker->state = NN_WS_HANDSHAKE_STATE_IDLE; nn_fsm_stopped (&handshaker->fsm, NN_WS_HANDSHAKE_STOPPED); return; } nn_fsm_bad_state (handshaker->state, src, type); } static int nn_ws_match_token (const char* token, const char **subj, int case_insensitive, int ignore_leading_sp) { const char *pos; nn_assert (token && *subj); pos = *subj; if (ignore_leading_sp) { while (*pos == '\x20' && *pos) { pos++; } } if (case_insensitive) { while (*token && *pos) { if (tolower (*token) != tolower (*pos)) return NN_WS_HANDSHAKE_NOMATCH; token++; pos++; } } else { while (*token && *pos) { if (*token != *pos) return NN_WS_HANDSHAKE_NOMATCH; token++; pos++; } } /* Encountered end of subject before matching completed. */ if (!*pos && *token) return NN_WS_HANDSHAKE_NOMATCH; /* Entire token has been matched. */ nn_assert (!*token); /* On success, advance subject position. */ *subj = pos; return NN_WS_HANDSHAKE_MATCH; } static int nn_ws_match_value (const char* termseq, const char **subj, int ignore_leading_sp, int ignore_trailing_sp, const char **addr, size_t* const len) { const char *start; const char *end; nn_assert (termseq && *subj); start = *subj; if (addr) *addr = NULL; if (len) *len = 0; /* Find first occurence of termination sequence. */ end = strstr (start, termseq); /* Was a termination sequence found? */ if (end) { *subj = end + strlen (termseq); } else { return NN_WS_HANDSHAKE_NOMATCH; } if (ignore_leading_sp) { while (*start == '\x20' && start < end) { start++; } } if (addr) *addr = start; /* In this special case, the value was "found", but is just empty or ignored space. */ if (start == end) return NN_WS_HANDSHAKE_MATCH; if (ignore_trailing_sp) { while (*(end - 1) == '\x20' && start < end) { end--; } } if (len) *len = end - start; return NN_WS_HANDSHAKE_MATCH; } static int nn_ws_validate_value (const char* expected, const char *subj, size_t subj_len, int case_insensitive) { if (strlen (expected) != subj_len) return NN_WS_HANDSHAKE_NOMATCH; if (case_insensitive) { while (*expected && *subj) { if (tolower (*expected) != tolower (*subj)) return NN_WS_HANDSHAKE_NOMATCH; expected++; subj++; } } else { while (*expected && *subj) { if (*expected != *subj) return NN_WS_HANDSHAKE_NOMATCH; expected++; subj++; } } return NN_WS_HANDSHAKE_MATCH; } static void nn_ws_handshake_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_ws_handshake *handshaker; size_t i; handshaker = nn_cont (self, struct nn_ws_handshake, fsm); switch (handshaker->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_WS_HANDSHAKE_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_assert (handshaker->recv_pos == 0); nn_assert (handshaker->recv_len >= NN_WS_HANDSHAKE_TERMSEQ_LEN); nn_timer_start (&handshaker->timer, handshaker->timeout); switch (handshaker->mode) { case NN_WS_CLIENT: /* Send opening handshake to server. */ nn_assert (handshaker->recv_len <= sizeof (handshaker->response)); handshaker->state = NN_WS_HANDSHAKE_STATE_CLIENT_SEND; nn_ws_handshake_client_request (handshaker); return; case NN_WS_SERVER: /* Begin receiving opening handshake from client. */ nn_assert (handshaker->recv_len <= sizeof (handshaker->opening_hs)); handshaker->state = NN_WS_HANDSHAKE_STATE_SERVER_RECV; nn_usock_recv (handshaker->usock, handshaker->opening_hs, handshaker->recv_len, NULL); return; default: /* Unexpected mode. */ nn_assert (0); return; } default: nn_fsm_bad_action (handshaker->state, src, type); } default: nn_fsm_bad_source (handshaker->state, src, type); } /******************************************************************************/ /* SERVER_RECV state. */ /******************************************************************************/ case NN_WS_HANDSHAKE_STATE_SERVER_RECV: switch (src) { case NN_WS_HANDSHAKE_SRC_USOCK: switch (type) { case NN_USOCK_RECEIVED: /* Parse bytes received thus far. */ switch (nn_ws_handshake_parse_client_opening (handshaker)) { case NN_WS_HANDSHAKE_INVALID: /* Opening handshake parsed successfully but does not contain valid values. Respond failure to client. */ handshaker->state = NN_WS_HANDSHAKE_STATE_SERVER_REPLY; nn_ws_handshake_server_reply (handshaker); return; case NN_WS_HANDSHAKE_VALID: /* Opening handshake parsed successfully, and is valid. Respond success to client. */ handshaker->state = NN_WS_HANDSHAKE_STATE_SERVER_REPLY; nn_ws_handshake_server_reply (handshaker); return; case NN_WS_HANDSHAKE_RECV_MORE: /* Not enough bytes have been received to determine validity; remain in the receive state, and retrieve more bytes from client. */ handshaker->recv_pos += handshaker->recv_len; /* Validate the previous recv operation. */ nn_assert (handshaker->recv_pos < sizeof (handshaker->opening_hs)); /* Ensure we can back-track at least the length of the termination sequence to determine how many bytes to receive on the next retry. This is an assertion, not a conditional, since under no condition is it necessary to initially receive so few bytes. */ nn_assert (handshaker->recv_pos >= (int) NN_WS_HANDSHAKE_TERMSEQ_LEN); /* We only compare if we have at least one byte to compare against. When i drops to zero, it means we don't have any bytes to match against, and it is automatically true. */ for (i = NN_WS_HANDSHAKE_TERMSEQ_LEN; i > 0; i--) { if (memcmp (NN_WS_HANDSHAKE_TERMSEQ, handshaker->opening_hs + handshaker->recv_pos - i, i) == 0) { break; } } nn_assert (i < NN_WS_HANDSHAKE_TERMSEQ_LEN); handshaker->recv_len = NN_WS_HANDSHAKE_TERMSEQ_LEN - i; /* In the unlikely case the client would overflow what we assumed was a sufficiently-large buffer to receive the handshake, we fail the client. */ if (handshaker->recv_len + handshaker->recv_pos > sizeof (handshaker->opening_hs)) { handshaker->response_code = NN_WS_HANDSHAKE_RESPONSE_TOO_BIG; handshaker->state = NN_WS_HANDSHAKE_STATE_SERVER_REPLY; nn_ws_handshake_server_reply (handshaker); } else { handshaker->retries++; nn_usock_recv (handshaker->usock, handshaker->opening_hs + handshaker->recv_pos, handshaker->recv_len, NULL); } return; default: nn_fsm_error ("Unexpected handshake result", handshaker->state, src, type); } return; case NN_USOCK_SHUTDOWN: /* Ignore it and wait for ERROR event. */ return; case NN_USOCK_ERROR: nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (handshaker->state, src, type); } case NN_WS_HANDSHAKE_SRC_TIMER: switch (type) { case NN_TIMER_TIMEOUT: nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (handshaker->state, src, type); } default: nn_fsm_bad_source (handshaker->state, src, type); } /******************************************************************************/ /* SERVER_REPLY state. */ /******************************************************************************/ case NN_WS_HANDSHAKE_STATE_SERVER_REPLY: switch (src) { case NN_WS_HANDSHAKE_SRC_USOCK: switch (type) { case NN_USOCK_SENT: /* As per RFC 6455 4.2.2, the handshake is now complete and the connection is immediately ready for send/recv. */ nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_DONE; case NN_USOCK_SHUTDOWN: /* Ignore it and wait for ERROR event. */ return; case NN_USOCK_ERROR: nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (handshaker->state, src, type); } case NN_WS_HANDSHAKE_SRC_TIMER: switch (type) { case NN_TIMER_TIMEOUT: nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (handshaker->state, src, type); } default: nn_fsm_bad_source (handshaker->state, src, type); } /******************************************************************************/ /* CLIENT_SEND state. */ /******************************************************************************/ case NN_WS_HANDSHAKE_STATE_CLIENT_SEND: switch (src) { case NN_WS_HANDSHAKE_SRC_USOCK: switch (type) { case NN_USOCK_SENT: handshaker->state = NN_WS_HANDSHAKE_STATE_CLIENT_RECV; nn_usock_recv (handshaker->usock, handshaker->response, handshaker->recv_len, NULL); return; case NN_USOCK_SHUTDOWN: /* Ignore it and wait for ERROR event. */ return; case NN_USOCK_ERROR: nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (handshaker->state, src, type); } case NN_WS_HANDSHAKE_SRC_TIMER: switch (type) { case NN_TIMER_TIMEOUT: nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (handshaker->state, src, type); } default: nn_fsm_bad_source (handshaker->state, src, type); } /******************************************************************************/ /* CLIENT_RECV state. */ /******************************************************************************/ case NN_WS_HANDSHAKE_STATE_CLIENT_RECV: switch (src) { case NN_WS_HANDSHAKE_SRC_USOCK: switch (type) { case NN_USOCK_RECEIVED: /* Parse bytes received thus far. */ switch (nn_ws_handshake_parse_server_response (handshaker)) { case NN_WS_HANDSHAKE_INVALID: /* Opening handshake parsed successfully but does not contain valid values. Fail connection. */ nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; return; case NN_WS_HANDSHAKE_VALID: /* As per RFC 6455 4.2.2, the handshake is now complete and the connection is immediately ready for send/recv. */ nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_DONE; return; case NN_WS_HANDSHAKE_RECV_MORE: /* Not enough bytes have been received to determine validity; remain in the receive state, and retrieve more bytes from client. */ handshaker->recv_pos += handshaker->recv_len; /* Validate the previous recv operation. */ nn_assert (handshaker->recv_pos < sizeof (handshaker->response)); /* Ensure we can back-track at least the length of the termination sequence to determine how many bytes to receive on the next retry. This is an assertion, not a conditional, since under no condition is it necessary to initially receive so few bytes. */ nn_assert (handshaker->recv_pos >= (int) NN_WS_HANDSHAKE_TERMSEQ_LEN); /* If i goes to 0, it no need to compare. */ for (i = NN_WS_HANDSHAKE_TERMSEQ_LEN; i > 0; i--) { if (memcmp (NN_WS_HANDSHAKE_TERMSEQ, handshaker->response + handshaker->recv_pos - i, i) == 0) { break; } } nn_assert (i < NN_WS_HANDSHAKE_TERMSEQ_LEN); handshaker->recv_len = NN_WS_HANDSHAKE_TERMSEQ_LEN - i; /* In the unlikely case the client would overflow what we assumed was a sufficiently-large buffer to receive the handshake, we fail the connection. */ if (handshaker->recv_len + handshaker->recv_pos > sizeof (handshaker->response)) { nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; } else { handshaker->retries++; nn_usock_recv (handshaker->usock, handshaker->response + handshaker->recv_pos, handshaker->recv_len, NULL); } return; default: nn_fsm_error ("Unexpected handshake result", handshaker->state, src, type); } return; case NN_USOCK_SHUTDOWN: /* Ignore it and wait for ERROR event. */ return; case NN_USOCK_ERROR: nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (handshaker->state, src, type); } case NN_WS_HANDSHAKE_SRC_TIMER: switch (type) { case NN_TIMER_TIMEOUT: nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (handshaker->state, src, type); } default: nn_fsm_bad_source (handshaker->state, src, type); } /******************************************************************************/ /* HANDSHAKE_SENT state. */ /******************************************************************************/ case NN_WS_HANDSHAKE_STATE_HANDSHAKE_SENT: switch (src) { case NN_WS_HANDSHAKE_SRC_USOCK: switch (type) { case NN_USOCK_SENT: /* As per RFC 6455 4.2.2, the handshake is now complete and the connection is immediately ready for send/recv. */ nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_DONE; return; case NN_USOCK_SHUTDOWN: /* Ignore it and wait for ERROR event. */ return; case NN_USOCK_ERROR: nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (handshaker->state, src, type); } case NN_WS_HANDSHAKE_SRC_TIMER: switch (type) { case NN_TIMER_TIMEOUT: nn_timer_stop (&handshaker->timer); handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR; return; default: nn_fsm_bad_action (handshaker->state, src, type); } default: nn_fsm_bad_source (handshaker->state, src, type); } /******************************************************************************/ /* STOPPING_TIMER_ERROR state. */ /******************************************************************************/ case NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR: switch (src) { case NN_WS_HANDSHAKE_SRC_USOCK: /* Ignore. The only circumstance the client would send bytes is to notify the server it is closing the connection. Wait for the socket to eventually error. */ return; case NN_WS_HANDSHAKE_SRC_TIMER: switch (type) { case NN_TIMER_STOPPED: nn_ws_handshake_leave (handshaker, NN_WS_HANDSHAKE_ERROR); return; default: nn_fsm_bad_action (handshaker->state, src, type); } default: nn_fsm_bad_source (handshaker->state, src, type); } /******************************************************************************/ /* STOPPING_TIMER_DONE state. */ /******************************************************************************/ case NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_DONE: switch (src) { case NN_WS_HANDSHAKE_SRC_USOCK: /* Ignore. The only circumstance the client would send bytes is to notify the server it is closing the connection. Wait for the socket to eventually error. */ return; case NN_WS_HANDSHAKE_SRC_TIMER: switch (type) { case NN_TIMER_STOPPED: nn_ws_handshake_leave (handshaker, NN_WS_HANDSHAKE_OK); return; default: nn_fsm_bad_action (handshaker->state, src, type); } default: nn_fsm_bad_source (handshaker->state, src, type); } /******************************************************************************/ /* DONE state. */ /* The header exchange was either done successfully of failed. There's */ /* nothing that can be done in this state except stopping the object. */ /******************************************************************************/ case NN_WS_HANDSHAKE_STATE_DONE: nn_fsm_bad_source (handshaker->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (handshaker->state, src, type); } } /******************************************************************************/ /* State machine actions. */ /******************************************************************************/ static void nn_ws_handshake_leave (struct nn_ws_handshake *self, int rc) { nn_usock_swap_owner (self->usock, &self->usock_owner); self->usock = NULL; self->usock_owner.src = -1; self->usock_owner.fsm = NULL; self->state = NN_WS_HANDSHAKE_STATE_DONE; nn_fsm_raise (&self->fsm, &self->done, rc); } static int nn_ws_handshake_parse_client_opening (struct nn_ws_handshake *self) { /* As per RFC 6455 section 1.7, this parser is not intended to be a general-purpose parser for arbitrary HTTP headers. As with the design philosophy of nanomsg, application-specific exchanges are better reserved for accepted connections, not as fields within these headers. */ int rc; const char *pos; unsigned i; /* Guarantee that a NULL terminator exists to enable treating this recv buffer like a string. */ nn_assert (memchr (self->opening_hs, '\0', sizeof (self->opening_hs))); /* Having found the NULL terminator, from this point forward string functions may be used. */ nn_assert (strlen (self->opening_hs) < sizeof (self->opening_hs)); pos = self->opening_hs; /* Is the opening handshake from the client fully received? */ if (!strstr (pos, NN_WS_HANDSHAKE_TERMSEQ)) return NN_WS_HANDSHAKE_RECV_MORE; self->host = NULL; self->origin = NULL; self->key = NULL; self->upgrade = NULL; self->conn = NULL; self->version = NULL; self->protocol = NULL; self->uri = NULL; self->host_len = 0; self->origin_len = 0; self->key_len = 0; self->upgrade_len = 0; self->conn_len = 0; self->version_len = 0; self->protocol_len = 0; self->uri_len = 0; /* NB: If we got here, we already have a fully received set of HTTP headers. So there is no point in asking for more if the headers lack what we need. */ /* This function, if generating a return value that triggers a response to the client, should replace this sentinel value with a proper response code. */ self->response_code = NN_WS_HANDSHAKE_RESPONSE_NULL; /* RFC 7230 3.1.1 Request Line: HTTP Method Note requirement of one space and case sensitivity. */ if (!nn_ws_match_token ("GET\x20", &pos, 0, 0)) return NN_WS_HANDSHAKE_INVALID; /* RFC 7230 3.1.1 Request Line: Requested Resource. */ if (!nn_ws_match_value ("\x20", &pos, 0, 0, &self->uri, &self->uri_len)) return NN_WS_HANDSHAKE_INVALID; /* RFC 7230 3.1.1 Request Line: HTTP version. Note case sensitivity. */ if (!nn_ws_match_token ("HTTP/1.1", &pos, 0, 0)) return NN_WS_HANDSHAKE_INVALID; if (!nn_ws_match_token (CRLF, &pos, 0, 0)) return NN_WS_HANDSHAKE_INVALID; /* It's expected the current position is now at the first header field. Match them one by one. */ while (strlen (pos)) { const char *conn = NULL; size_t conn_len = 0; if (nn_ws_match_token ("Host:", &pos, 1, 0)) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->host, &self->host_len); } else if (nn_ws_match_token ("Origin:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->origin, &self->origin_len); } else if (nn_ws_match_token ("Sec-WebSocket-Key:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->key, &self->key_len); } else if (nn_ws_match_token ("Upgrade:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->upgrade, &self->upgrade_len); } else if (nn_ws_match_token ("Connection:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &conn, &conn_len); /* The values here can be comma delimited, or they can be listed as separate Connection headers. We only care about the presence of the Upgrade header, and we're willing to assume well-formedness. This crummy parse may let clients send us a malformed header that we ought to reject, but we'll just cite Postel's law here if anyone asks. */ self->conn = nn_strcasestr (conn, "upgrade"); if (self->conn != NULL) { self->conn_len = strlen ("upgrade"); } } else if (nn_ws_match_token ("Sec-WebSocket-Version:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->version, &self->version_len); } else if (nn_ws_match_token ("Sec-WebSocket-Protocol:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->protocol, &self->protocol_len); } else if (nn_ws_match_token ("Sec-WebSocket-Extensions:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->extensions, &self->extensions_len); } else if (nn_ws_match_token (CRLF, &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { /* Exit loop since all headers are parsed. */ break; } else { /* Skip unknown headers. */ rc = nn_ws_match_value (CRLF, &pos, 1, 1, NULL, NULL); } if (rc != NN_WS_HANDSHAKE_MATCH) return NN_WS_HANDSHAKE_INVALID; } /* Validate the opening handshake is now fully parsed. Additionally, as per RFC 6455 section 4.1, the client should not send additional data after the opening handshake, so this assertion validates upstream recv logic prevented this case. */ nn_assert (strlen (pos) == 0); /* TODO: protocol expectations below this point are hard-coded here as an initial design decision. Perhaps in the future these values should be settable via compile time (or run-time socket) options? */ /* These header fields are required as per RFC 6455 section 4.1. */ if (!self->host || !self->upgrade || !self->conn || !self->key || !self->version) { self->response_code = NN_WS_HANDSHAKE_RESPONSE_WSPROTO; return NN_WS_HANDSHAKE_INVALID; } /* RFC 6455 section 4.2.1.6 (version December 2011). */ if (nn_ws_validate_value ("13", self->version, self->version_len, 1) != NN_WS_HANDSHAKE_MATCH) { self->response_code = NN_WS_HANDSHAKE_RESPONSE_WSVERSION; return NN_WS_HANDSHAKE_INVALID; } /* RFC 6455 section 4.2.1.3 (version December 2011). */ if (nn_ws_validate_value ("websocket", self->upgrade, self->upgrade_len, 1) != NN_WS_HANDSHAKE_MATCH) { self->response_code = NN_WS_HANDSHAKE_RESPONSE_WSPROTO; return NN_WS_HANDSHAKE_INVALID; } /* RFC 6455 section 4.2.1.4 (version December 2011). */ if (nn_ws_validate_value ("Upgrade", self->conn, self->conn_len, 1) != NN_WS_HANDSHAKE_MATCH) { self->response_code = NN_WS_HANDSHAKE_RESPONSE_WSPROTO; return NN_WS_HANDSHAKE_INVALID; } /* At this point, client meets RFC 6455 compliance for opening handshake. Now it's time to check nanomsg-imposed required handshake values. */ if (self->protocol) { /* Ensure the client SP is a compatible socket type. */ for (i = 0; i < NN_WS_HANDSHAKE_SP_MAP_LEN; i++) { if (nn_ws_validate_value (NN_WS_HANDSHAKE_SP_MAP [i].ws_sp, self->protocol, self->protocol_len, 1)) { if (self->pipebase->sock->socktype->protocol == NN_WS_HANDSHAKE_SP_MAP [i].server) { self->response_code = NN_WS_HANDSHAKE_RESPONSE_OK; return NN_WS_HANDSHAKE_VALID; } else { self->response_code = NN_WS_HANDSHAKE_RESPONSE_NOTPEER; return NN_WS_HANDSHAKE_INVALID; } break; } } self->response_code = NN_WS_HANDSHAKE_RESPONSE_UNKNOWNTYPE; return NN_WS_HANDSHAKE_INVALID; } else { /* Be permissive and generous here, assuming that if a protocol is not explicitly declared, PAIR is presumed. This enables interoperability with non-nanomsg remote peers, nominally by making the local socket PAIR type. For any other local socket type, we expect connection to be rejected as incompatible if the header is not specified. */ if (nn_pipebase_ispeer (self->pipebase, NN_PAIR)) { self->response_code = NN_WS_HANDSHAKE_RESPONSE_OK; return NN_WS_HANDSHAKE_VALID; } else { self->response_code = NN_WS_HANDSHAKE_RESPONSE_NOTPEER; return NN_WS_HANDSHAKE_INVALID; } } } static int nn_ws_handshake_parse_server_response (struct nn_ws_handshake *self) { /* As per RFC 6455 section 1.7, this parser is not intended to be a general-purpose parser for arbitrary HTTP headers. As with the design philosophy of nanomsg, application-specific exchanges are better reserved for accepted connections, not as fields within these headers. */ int rc; const char *pos; /* Guarantee that a NULL terminator exists to enable treating this recv buffer like a string. The lack of such would indicate a failure upstream to catch a buffer overflow. */ nn_assert (memchr (self->response, '\0', sizeof (self->response))); /* Having found the NULL terminator, from this point forward string functions may be used. */ nn_assert (strlen (self->response) < sizeof (self->response)); pos = self->response; /* Is the response from the server fully received? */ if (!strstr (pos, NN_WS_HANDSHAKE_TERMSEQ)) return NN_WS_HANDSHAKE_RECV_MORE; self->status_code = NULL; self->reason_phrase = NULL; self->server = NULL; self->accept_key = NULL; self->upgrade = NULL; self->conn = NULL; self->version = NULL; self->protocol = NULL; self->status_code_len = 0; self->reason_phrase_len = 0; self->server_len = 0; self->accept_key_len = 0; self->upgrade_len = 0; self->conn_len = 0; self->version_len = 0; self->protocol_len = 0; /* RFC 7230 3.1.2 Status Line: HTTP Version. */ if (!nn_ws_match_token ("HTTP/1.1\x20", &pos, 0, 0)) return NN_WS_HANDSHAKE_RECV_MORE; /* RFC 7230 3.1.2 Status Line: Status Code. */ if (!nn_ws_match_value ("\x20", &pos, 0, 0, &self->status_code, &self->status_code_len)) return NN_WS_HANDSHAKE_RECV_MORE; /* RFC 7230 3.1.2 Status Line: Reason Phrase. */ if (!nn_ws_match_value (CRLF, &pos, 0, 0, &self->reason_phrase, &self->reason_phrase_len)) return NN_WS_HANDSHAKE_RECV_MORE; /* It's expected the current position is now at the first header field. Match them one by one. */ while (strlen (pos)) { if (nn_ws_match_token ("Server:", &pos, 1, 0)) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->server, &self->server_len); } else if (nn_ws_match_token ("Sec-WebSocket-Accept:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->accept_key, &self->accept_key_len); } else if (nn_ws_match_token ("Upgrade:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->upgrade, &self->upgrade_len); } else if (nn_ws_match_token ("Connection:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->conn, &self->conn_len); } else if (nn_ws_match_token ("Sec-WebSocket-Version-Server:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->version, &self->version_len); } else if (nn_ws_match_token ("Sec-WebSocket-Protocol-Server:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->protocol, &self->protocol_len); } else if (nn_ws_match_token ("Sec-WebSocket-Extensions:", &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { rc = nn_ws_match_value (CRLF, &pos, 1, 1, &self->extensions, &self->extensions_len); } else if (nn_ws_match_token (CRLF, &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) { /* Exit loop since all headers are parsed. */ break; } else { /* Skip unknown headers. */ rc = nn_ws_match_value (CRLF, &pos, 1, 1, NULL, NULL); } if (rc != NN_WS_HANDSHAKE_MATCH) return NN_WS_HANDSHAKE_RECV_MORE; } /* Validate the opening handshake is now fully parsed. Additionally, as per RFC 6455 section 4.1, the client should not send additional data after the opening handshake, so this assertion validates upstream recv logic prevented this case. */ nn_assert (strlen (pos) == 0); /* TODO: protocol expectations below this point are hard-coded here as an initial design decision. Perhaps in the future these values should be settable via compile time (or run-time socket) options? */ /* These header fields are required as per RFC 6455 4.2.2. */ if (!self->status_code || !self->upgrade || !self->conn || !self->accept_key) return NN_WS_HANDSHAKE_INVALID; /* TODO: Currently, we only handle a successful connection upgrade. Anything else is treated as a failed connection. Consider handling other scenarios like 3xx redirects. */ if (nn_ws_validate_value ("101", self->status_code, self->status_code_len, 1) != NN_WS_HANDSHAKE_MATCH) return NN_WS_HANDSHAKE_INVALID; /* RFC 6455 section 4.2.2.5.2 (version December 2011). */ if (nn_ws_validate_value ("websocket", self->upgrade, self->upgrade_len, 1) != NN_WS_HANDSHAKE_MATCH) return NN_WS_HANDSHAKE_INVALID; /* RFC 6455 section 4.2.2.5.3 (version December 2011). */ if (nn_ws_validate_value ("Upgrade", self->conn, self->conn_len, 1) != NN_WS_HANDSHAKE_MATCH) return NN_WS_HANDSHAKE_INVALID; /* RFC 6455 section 4.2.2.5.4 (version December 2011). */ if (nn_ws_validate_value (self->expected_accept_key, self->accept_key, self->accept_key_len, 1) != NN_WS_HANDSHAKE_MATCH) return NN_WS_HANDSHAKE_INVALID; /* Server response meets RFC 6455 compliance for opening handshake. */ return NN_WS_HANDSHAKE_VALID; } static void nn_ws_handshake_client_request (struct nn_ws_handshake *self) { struct nn_iovec open_request; size_t encoded_key_len; int rc; unsigned i; /* Generate random 16-byte key as per RFC 6455 4.1 */ uint8_t rand_key [16]; /* Known length required to base64 encode above random key plus string NULL terminator. */ char encoded_key [24 + 1]; nn_random_generate (rand_key, sizeof (rand_key)); rc = nn_base64_encode (rand_key, sizeof (rand_key), encoded_key, sizeof (encoded_key)); nn_assert (rc >=0); encoded_key_len = strlen (encoded_key); nn_assert (encoded_key_len == sizeof (encoded_key) - 1); /* Pre-calculated expected Accept Key value as per RFC 6455 section 4.2.2.5.4 (version December 2011). */ rc = nn_ws_handshake_hash_key (encoded_key, encoded_key_len, self->expected_accept_key, sizeof (self->expected_accept_key)); nn_assert (rc == NN_WS_HANDSHAKE_ACCEPT_KEY_LEN); /* Lookup SP header value. */ for (i = 0; i < NN_WS_HANDSHAKE_SP_MAP_LEN; i++) { if (NN_WS_HANDSHAKE_SP_MAP [i].client == self->pipebase->sock->socktype->protocol) { break; } } /* Guarantee that the socket type was found in the map. */ nn_assert (i < NN_WS_HANDSHAKE_SP_MAP_LEN); sprintf (self->opening_hs, "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Key: %s\r\n" "Sec-WebSocket-Version: 13\r\n" "Sec-WebSocket-Protocol: %s\r\n\r\n", self->resource, self->remote_host, encoded_key, NN_WS_HANDSHAKE_SP_MAP[i].ws_sp); open_request.iov_len = strlen (self->opening_hs); open_request.iov_base = self->opening_hs; nn_usock_send (self->usock, &open_request, 1); } static void nn_ws_handshake_server_reply (struct nn_ws_handshake *self) { struct nn_iovec response; char *code; char *version; char *protocol; int rc; /* Allow room for NULL terminator. */ char accept_key [NN_WS_HANDSHAKE_ACCEPT_KEY_LEN + 1]; memset (self->response, 0, sizeof (self->response)); if (self->response_code == NN_WS_HANDSHAKE_RESPONSE_OK) { /* Upgrade connection as per RFC 6455 section 4.2.2. */ rc = nn_ws_handshake_hash_key (self->key, self->key_len, accept_key, sizeof (accept_key)); nn_assert (rc >= 0); nn_assert (strlen (accept_key) == NN_WS_HANDSHAKE_ACCEPT_KEY_LEN); protocol = nn_alloc (self->protocol_len + 1, "WebSocket protocol"); alloc_assert (protocol); strncpy (protocol, self->protocol, self->protocol_len); protocol [self->protocol_len] = '\0'; sprintf (self->response, "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Accept: %s\r\n" "Sec-WebSocket-Protocol: %s\r\n\r\n", accept_key, protocol); nn_free (protocol); } else { /* Fail the connection with a helpful hint. */ switch (self->response_code) { case NN_WS_HANDSHAKE_RESPONSE_TOO_BIG: code = "400 Opening Handshake Too Long"; break; case NN_WS_HANDSHAKE_RESPONSE_WSPROTO: code = "400 Cannot Have Body"; break; case NN_WS_HANDSHAKE_RESPONSE_WSVERSION: code = "400 Unsupported WebSocket Version"; break; case NN_WS_HANDSHAKE_RESPONSE_NNPROTO: code = "400 Missing nanomsg Required Headers"; break; case NN_WS_HANDSHAKE_RESPONSE_NOTPEER: code = "400 Incompatible Socket Type"; break; case NN_WS_HANDSHAKE_RESPONSE_UNKNOWNTYPE: code = "400 Unrecognized Socket Type"; break; default: /* Unexpected failure response. */ nn_assert (0); break; } version = nn_alloc (self->version_len + 1, "WebSocket version"); alloc_assert (version); strncpy (version, self->version, self->version_len); version [self->version_len] = '\0'; /* Fail connection as per RFC 6455 4.4. */ sprintf (self->response, "HTTP/1.1 %s\r\n" "Sec-WebSocket-Version: %s\r\n", code, version); nn_free (version); } response.iov_len = strlen (self->response); response.iov_base = &self->response; nn_usock_send (self->usock, &response, 1); return; } static int nn_ws_handshake_hash_key (const char *key, size_t key_len, char *hashed, size_t hashed_len) { int rc; unsigned i; struct nn_sha1 hash; nn_sha1_init (&hash); for (i = 0; i < key_len; i++) nn_sha1_hashbyte (&hash, key [i]); for (i = 0; i < strlen (NN_WS_HANDSHAKE_MAGIC_GUID); i++) nn_sha1_hashbyte (&hash, NN_WS_HANDSHAKE_MAGIC_GUID [i]); rc = nn_base64_encode (nn_sha1_result (&hash), sizeof (hash.state), hashed, hashed_len); return rc; } nanomsg-1.1.5/src/transports/ws/ws_handshake.h000066400000000000000000000124211336111550300214250ustar00rootroot00000000000000/* Copyright (c) 2013 250bpm s.r.o. All rights reserved. Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_WS_HANDSHAKE_INCLUDED #define NN_WS_HANDSHAKE_INCLUDED #include "../../transport.h" #include "../../aio/fsm.h" #include "../../aio/usock.h" #include "../../aio/timer.h" /* This state machine exchanges a handshake with a WebSocket client. */ /* Return codes of this state machine. */ #define NN_WS_HANDSHAKE_OK 1 #define NN_WS_HANDSHAKE_ERROR 2 #define NN_WS_HANDSHAKE_STOPPED 3 /* WebSocket endpoint modes that determine framing of Tx/Rx and Opening Handshake HTTP headers. */ #define NN_WS_CLIENT 1 #define NN_WS_SERVER 2 /* A ws:// buffer for nanomsg is intentionally smaller than recommendation of RFC 7230 3.1.1 since it neither requires nor accepts arbitrarily large headers. */ #define NN_WS_HANDSHAKE_MAX_SIZE 4096 /* WebSocket protocol tokens as per RFC 6455. */ #define NN_WS_HANDSHAKE_MAGIC_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" #define NN_WS_HANDSHAKE_TERMSEQ "\r\n\r\n" #define NN_WS_HANDSHAKE_TERMSEQ_LEN strlen (NN_WS_HANDSHAKE_TERMSEQ) /* Expected Accept Key length based on RFC 6455 4.2.2.5.4. */ #define NN_WS_HANDSHAKE_ACCEPT_KEY_LEN 28 struct nn_ws_handshake { /* The state machine. */ struct nn_fsm fsm; int state; /* Controls HTTP headers and behavior based on whether this peer is acting as a Client or a Server. */ int mode; /* Used to timeout opening handshake. */ struct nn_timer timer; int timeout; /* The underlying socket. */ struct nn_usock *usock; /* The original owner of the underlying socket. */ struct nn_fsm_owner usock_owner; /* Handle to the pipe. */ struct nn_pipebase *pipebase; /* Requested resource when acting as client. */ const char* resource; /* Remote Host in header request when acting as client. */ const char* remote_host; /* Opening handshake verbatim from client as per RFC 6455 1.3. */ char opening_hs [NN_WS_HANDSHAKE_MAX_SIZE]; /* Monitor/control the opening recv poll. */ int retries; size_t recv_pos; size_t recv_len; /* Expected handshake fields from client as per RFC 6455 4.1, where these pointers reference the opening_hs. */ const char *host; size_t host_len; const char *origin; size_t origin_len; const char *key; size_t key_len; const char *upgrade; size_t upgrade_len; const char *conn; size_t conn_len; const char *version; size_t version_len; /* Expected handshake fields from client required by nanomsg. */ const char *protocol; size_t protocol_len; /* Expected handshake fields from server as per RFC 6455 4.2.2. */ const char *server; size_t server_len; const char *accept_key; size_t accept_key_len; char expected_accept_key [NN_WS_HANDSHAKE_ACCEPT_KEY_LEN + 1]; const char *status_code; size_t status_code_len; const char *reason_phrase; size_t reason_phrase_len; /* Unused, optional handshake fields. */ const char *uri; size_t uri_len; const char *extensions; size_t extensions_len; /* Identifies the response to be sent to client's opening handshake. */ int response_code; /* Response to send back to client. */ char response [512]; /* Event fired when the state machine ends. */ struct nn_fsm_event done; }; /* Structure that maps scalability protocol to corresponding WebSocket header values. */ struct nn_ws_sp_map { /* Scalability Protocol ID for server... */ int server; /* ... and corresponding client Protocol ID */ int client; /* ... and corresponding WebSocket header field value. */ const char* ws_sp; }; void nn_ws_handshake_init (struct nn_ws_handshake *self, int src, struct nn_fsm *owner); void nn_ws_handshake_term (struct nn_ws_handshake *self); int nn_ws_handshake_isidle (struct nn_ws_handshake *self); void nn_ws_handshake_start (struct nn_ws_handshake *self, struct nn_usock *usock, struct nn_pipebase *pipebase, int mode, const char *resource, const char *host); void nn_ws_handshake_stop (struct nn_ws_handshake *self); #endif nanomsg-1.1.5/src/utils/000077500000000000000000000000001336111550300151055ustar00rootroot00000000000000nanomsg-1.1.5/src/utils/README000066400000000000000000000002641336111550300157670ustar00rootroot00000000000000This directory contains the utilities. Utilities are general-purpose components that may be used by the core library as well as by individual transports and scalability protocols. nanomsg-1.1.5/src/utils/alloc.c000066400000000000000000000072531336111550300163520ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "alloc.h" #if defined NN_ALLOC_MONITOR #include "mutex.h" #include #include #include #include struct nn_alloc_hdr { size_t size; const char *name; }; static struct nn_mutex nn_alloc_sync; static size_t nn_alloc_bytes; static size_t nn_alloc_blocks; void nn_alloc_init (void) { nn_mutex_init (&nn_alloc_sync); nn_alloc_bytes = 0; nn_alloc_blocks = 0; } void nn_alloc_term (void) { nn_mutex_term (&nn_alloc_sync); } void *nn_alloc_ (size_t size, const char *name) { uint8_t *chunk; chunk = malloc (sizeof (struct nn_alloc_hdr) + size); if (!chunk) return NULL; nn_mutex_lock (&nn_alloc_sync); ((struct nn_alloc_hdr*) chunk)->size = size; ((struct nn_alloc_hdr*) chunk)->name = name; nn_alloc_bytes += size; ++nn_alloc_blocks; printf ("Allocating %s (%zu bytes)\n", name, size); printf ("Current memory usage: %zu bytes in %zu blocks\n", nn_alloc_bytes, nn_alloc_blocks); nn_mutex_unlock (&nn_alloc_sync); return chunk + sizeof (struct nn_alloc_hdr); } void *nn_realloc (void *ptr, size_t size) { struct nn_alloc_hdr *oldchunk; struct nn_alloc_hdr *newchunk; size_t oldsize; oldchunk = ((struct nn_alloc_hdr*) ptr) - 1; oldsize = oldchunk->size; newchunk = realloc (oldchunk, sizeof (struct nn_alloc_hdr) + size); if (!newchunk) return NULL; newchunk->size = size; nn_mutex_lock (&nn_alloc_sync); nn_alloc_bytes -= oldsize; nn_alloc_bytes += size; printf ("Reallocating %s (%zu bytes to %zu bytes)\n", newchunk->name, oldsize, size); printf ("Current memory usage: %zu bytes in %zu blocks\n", nn_alloc_bytes, nn_alloc_blocks); nn_mutex_unlock (&nn_alloc_sync); return newchunk + sizeof (struct nn_alloc_hdr); } void nn_free (void *ptr) { struct nn_alloc_hdr *chunk; if (!ptr) return; chunk = ((struct nn_alloc_hdr*) ptr) - 1; nn_mutex_lock (&nn_alloc_sync); nn_alloc_bytes -= chunk->size; --nn_alloc_blocks; printf ("Deallocating %s (%zu bytes)\n", chunk->name, chunk->size); printf ("Current memory usage: %zu bytes in %zu blocks\n", nn_alloc_bytes, nn_alloc_blocks); nn_mutex_unlock (&nn_alloc_sync); free (chunk); } #else #include void nn_alloc_init (void) { } void nn_alloc_term (void) { } void *nn_alloc_ (size_t size) { return malloc (size); } void *nn_realloc (void *ptr, size_t size) { return realloc (ptr, size); } void nn_free (void *ptr) { free (ptr); } #endif nanomsg-1.1.5/src/utils/alloc.h000066400000000000000000000032101336111550300163440ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef NN_ALLOC_INCLUDED #define NN_ALLOC_INCLUDED #include /* These functions allow for interception of memory allocation-related functionality. */ void nn_alloc_init (void); void nn_alloc_term (void); void *nn_realloc (void *ptr, size_t size); void nn_free (void *ptr); #if defined NN_ALLOC_MONITOR #define nn_alloc(size, name) nn_alloc_ (size, name) void *nn_alloc_ (size_t size, const char *name); #else #define nn_alloc(size, name) nn_alloc_(size) void *nn_alloc_ (size_t size); #endif #endif nanomsg-1.1.5/src/utils/atomic.c000066400000000000000000000050621336111550300165300ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "atomic.h" #include "err.h" #include "attr.h" void nn_atomic_init (struct nn_atomic *self, uint32_t n) { self->n = n; #if defined NN_ATOMIC_MUTEX nn_mutex_init (&self->sync); #endif } #if defined NN_ATOMIC_MUTEX void nn_atomic_term (struct nn_atomic *self) { nn_mutex_term (&self->sync); } #else void nn_atomic_term (NN_UNUSED struct nn_atomic *self) { } #endif uint32_t nn_atomic_inc (struct nn_atomic *self, uint32_t n) { #if defined NN_ATOMIC_WINAPI return (uint32_t) InterlockedExchangeAdd ((LONG*) &self->n, n); #elif defined NN_ATOMIC_SOLARIS return atomic_add_32_nv (&self->n, n) - n; #elif defined NN_ATOMIC_GCC_BUILTINS return (uint32_t) __sync_fetch_and_add (&self->n, n); #elif defined NN_ATOMIC_MUTEX uint32_t res; nn_mutex_lock (&self->sync); res = self->n; self->n += n; nn_mutex_unlock (&self->sync); return res; #else #error #endif } uint32_t nn_atomic_dec (struct nn_atomic *self, uint32_t n) { #if defined NN_ATOMIC_WINAPI return (uint32_t) InterlockedExchangeAdd ((LONG*) &self->n, -((LONG) n)); #elif defined NN_ATOMIC_SOLARIS return atomic_add_32_nv (&self->n, -((int32_t) n)) + n; #elif defined NN_ATOMIC_GCC_BUILTINS return (uint32_t) __sync_fetch_and_sub (&self->n, n); #elif defined NN_ATOMIC_MUTEX uint32_t res; nn_mutex_lock (&self->sync); res = self->n; self->n -= n; nn_mutex_unlock (&self->sync); return res; #else #error #endif } nanomsg-1.1.5/src/utils/atomic.h000066400000000000000000000040341336111550300165330ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_ATOMIC_INCLUDED #define NN_ATOMIC_INCLUDED #if defined NN_HAVE_WINDOWS #include "win.h" #define NN_ATOMIC_WINAPI #elif NN_HAVE_ATOMIC_SOLARIS #include #define NN_ATOMIC_SOLARIS #elif defined NN_HAVE_GCC_ATOMIC_BUILTINS #define NN_ATOMIC_GCC_BUILTINS #else #include "mutex.h" #define NN_ATOMIC_MUTEX #endif #include struct nn_atomic { #if defined NN_ATOMIC_MUTEX struct nn_mutex sync; #endif volatile uint32_t n; }; /* Initialise the object. Set it to value 'n'. */ void nn_atomic_init (struct nn_atomic *self, uint32_t n); /* Destroy the object. */ void nn_atomic_term (struct nn_atomic *self); /* Atomically add n to the object, return old value of the object. */ uint32_t nn_atomic_inc (struct nn_atomic *self, uint32_t n); /* Atomically subtract n from the object, return old value of the object. */ uint32_t nn_atomic_dec (struct nn_atomic *self, uint32_t n); #endif nanomsg-1.1.5/src/utils/attr.h000066400000000000000000000024711336111550300162340ustar00rootroot00000000000000/* Copyright (c) 2013 Insollo Entertainment, LLC. All rights reserved. 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. */ #ifndef NN_ATTR_INCLUDED #define NN_ATTR_INCLUDED #if defined __GNUC__ || defined __llvm__ #define NN_UNUSED __attribute__ ((unused)) #else #define NN_UNUSED #endif #endif nanomsg-1.1.5/src/utils/chunk.c000066400000000000000000000161271336111550300163700ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright (c) 2014 Achille Roussel All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #include "chunk.h" #include "atomic.h" #include "alloc.h" #include "fast.h" #include "wire.h" #include "err.h" #include #define NN_CHUNK_TAG 0xdeadcafe #define NN_CHUNK_TAG_DEALLOCATED 0xbeadfeed typedef void (*nn_chunk_free_fn) (void *p); struct nn_chunk { /* Number of places the chunk is referenced from. */ struct nn_atomic refcount; /* Size of the message in bytes. */ size_t size; /* Deallocation function. */ nn_chunk_free_fn ffn; /* The structure if followed by optional empty space, a 32 bit unsigned integer specifying the size of said empty space, a 32 bit tag and the message data itself. */ }; /* Private functions. */ static struct nn_chunk *nn_chunk_getptr (void *p); static void *nn_chunk_getdata (struct nn_chunk *c); static void nn_chunk_default_free (void *p); static size_t nn_chunk_hdrsize (); int nn_chunk_alloc (size_t size, int type, void **result) { size_t sz; struct nn_chunk *self; const size_t hdrsz = nn_chunk_hdrsize (); /* Compute total size to be allocated. Check for overflow. */ sz = hdrsz + size; if (nn_slow (sz < hdrsz)) return -ENOMEM; /* Allocate the actual memory depending on the type. */ switch (type) { case 0: self = nn_alloc (sz, "message chunk"); break; default: return -EINVAL; } if (nn_slow (!self)) return -ENOMEM; /* Fill in the chunk header. */ nn_atomic_init (&self->refcount, 1); self->size = size; self->ffn = nn_chunk_default_free; /* Fill in the size of the empty space between the chunk header and the message. */ nn_putl ((uint8_t*) ((uint32_t*) (self + 1)), 0); /* Fill in the tag. */ nn_putl ((uint8_t*) ((((uint32_t*) (self + 1))) + 1), NN_CHUNK_TAG); *result = nn_chunk_getdata (self); return 0; } int nn_chunk_realloc (size_t size, void **chunk) { struct nn_chunk *self; void *new_ptr; size_t hdr_size; int rc; void *p = *chunk; self = nn_chunk_getptr (p); /* Check if we only have one reference to this object, in that case we can reallocate the memory chunk. */ if (self->refcount.n == 1) { size_t grow; size_t empty; /* If the new size is smaller than the old size, we can just keep it. Avoid an allocation. We'll have wasted & lost data at the end, but who cares. This is basically "chop". */ if (size <= self->size) { self->size = size; return (0); } hdr_size = nn_chunk_hdrsize (); empty = (uint8_t*) p - (uint8_t*) self - hdr_size; grow = size - self->size; /* Check for overflow. */ if (hdr_size + size < size) { return -ENOMEM; } /* Can we grow into empty space? */ if (grow <= empty) { new_ptr = (uint8_t *)p - grow; memmove (new_ptr, p, self->size); self->size = size; /* Recalculate the size of empty space, and reconstruct the tag and prefix. */ empty = (uint8_t *)new_ptr - (uint8_t *)self - hdr_size; nn_putl ((uint8_t*) (((uint32_t*) new_ptr) - 1), NN_CHUNK_TAG); nn_putl ((uint8_t*) (((uint32_t*) new_ptr) - 2), (uint32_t) empty); *chunk = p; return (0); } } /* There are either multiple references to this memory chunk, or we cannot reuse the existing space. We create a new one copy the data. (This is no worse than nn_realloc, btw.) */ new_ptr = NULL; rc = nn_chunk_alloc (size, 0, &new_ptr); if (nn_slow (rc != 0)) { return rc; } memcpy (new_ptr, nn_chunk_getdata (self), self->size); *chunk = new_ptr; nn_chunk_free (p); return 0; } void nn_chunk_free (void *p) { struct nn_chunk *self; self = nn_chunk_getptr (p); /* Decrement the reference count. Actual deallocation happens only if it drops to zero. */ if (nn_atomic_dec (&self->refcount, 1) <= 1) { /* Mark chunk as deallocated. */ nn_putl ((uint8_t*) (((uint32_t*) p) - 1), NN_CHUNK_TAG_DEALLOCATED); /* Deallocate the resources held by the chunk. */ nn_atomic_term (&self->refcount); /* Deallocate the memory block according to the allocation mechanism specified. */ self->ffn (self); } } void nn_chunk_addref (void *p, uint32_t n) { struct nn_chunk *self; self = nn_chunk_getptr (p); nn_atomic_inc (&self->refcount, n); } size_t nn_chunk_size (void *p) { return nn_chunk_getptr (p)->size; } void *nn_chunk_trim (void *p, size_t n) { struct nn_chunk *self; const size_t hdrsz = sizeof (struct nn_chunk) + 2 * sizeof (uint32_t); size_t empty_space; self = nn_chunk_getptr (p); /* Sanity check. We cannot trim more bytes than there are in the chunk. */ nn_assert (n <= self->size); /* Adjust the chunk header. */ p = ((uint8_t*) p) + n; nn_putl ((uint8_t*) (((uint32_t*) p) - 1), NN_CHUNK_TAG); empty_space = (uint8_t*) p - (uint8_t*) self - hdrsz; nn_assert(empty_space < UINT32_MAX); nn_putl ((uint8_t*) (((uint32_t*) p) - 2), (uint32_t) empty_space); /* Adjust the size of the message. */ self->size -= n; return p; } static struct nn_chunk *nn_chunk_getptr (void *p) { uint32_t off; nn_assert (nn_getl ((uint8_t*) p - sizeof (uint32_t)) == NN_CHUNK_TAG); off = nn_getl ((uint8_t*) p - 2 * sizeof (uint32_t)); return (struct nn_chunk*) ((uint8_t*) p - 2 *sizeof (uint32_t) - off - sizeof (struct nn_chunk)); } static void *nn_chunk_getdata (struct nn_chunk *self) { return ((uint8_t*) (self + 1)) + 2 * sizeof (uint32_t); } static void nn_chunk_default_free (void *p) { nn_free (p); } static size_t nn_chunk_hdrsize () { return sizeof (struct nn_chunk) + 2 * sizeof (uint32_t); } nanomsg-1.1.5/src/utils/chunk.h000066400000000000000000000036601336111550300163730ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_CHUNK_INCLUDED #define NN_CHUNK_INCLUDED #include #include /* Allocates the chunk using the allocation mechanism specified by 'type'. */ int nn_chunk_alloc (size_t size, int type, void **result); /* Resizes a chunk previously allocated with nn_chunk_alloc. */ int nn_chunk_realloc (size_t size, void **chunk); /* Releases a reference to the chunk and once the reference count had dropped to zero, deallocates the chunk. */ void nn_chunk_free (void *p); /* Increases the reference count of the chunk by 'n'. */ void nn_chunk_addref (void *p, uint32_t n); /* Returns size of the chunk buffer. */ size_t nn_chunk_size (void *p); /* Trims n bytes from the beginning of the chunk. Returns pointer to the new chunk. */ void *nn_chunk_trim (void *p, size_t n); #endif nanomsg-1.1.5/src/utils/chunkref.c000066400000000000000000000106121336111550300170560ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "chunkref.h" #include "err.h" #include /* nn_chunkref should be reinterpreted as this structure in case the first byte ('tag') is 0xff. */ struct nn_chunkref_chunk { uint8_t tag; void *chunk; }; /* Check whether VSM are small enough for size to fit into the first byte of the structure. */ CT_ASSERT (NN_CHUNKREF_MAX < 255); /* Check whether nn_chunkref_chunk fits into nn_chunkref. */ CT_ASSERT (sizeof (struct nn_chunkref) >= sizeof (struct nn_chunkref_chunk)); void nn_chunkref_init (struct nn_chunkref *self, size_t size) { int rc; struct nn_chunkref_chunk *ch; if (size < NN_CHUNKREF_MAX) { self->u.ref [0] = (uint8_t) size; return; } ch = (struct nn_chunkref_chunk*) self; ch->tag = 0xff; rc = nn_chunk_alloc (size, 0, &ch->chunk); errno_assert (rc == 0); } void nn_chunkref_init_chunk (struct nn_chunkref *self, void *chunk) { struct nn_chunkref_chunk *ch; ch = (struct nn_chunkref_chunk*) self; ch->tag = 0xff; ch->chunk = chunk; } void nn_chunkref_term (struct nn_chunkref *self) { struct nn_chunkref_chunk *ch; if (self->u.ref [0] == 0xff) { ch = (struct nn_chunkref_chunk*) self; nn_chunk_free (ch->chunk); } } void *nn_chunkref_getchunk (struct nn_chunkref *self) { int rc; struct nn_chunkref_chunk *ch; void *chunk; if (self->u.ref [0] == 0xff) { ch = (struct nn_chunkref_chunk*) self; self->u.ref [0] = 0; return ch->chunk; } rc = nn_chunk_alloc (self->u.ref [0], 0, &chunk); errno_assert (rc == 0); memcpy (chunk, &self->u.ref [1], self->u.ref [0]); self->u.ref [0] = 0; return chunk; } void nn_chunkref_mv (struct nn_chunkref *dst, struct nn_chunkref *src) { memcpy (dst, src, src->u.ref [0] == 0xff ? (int)sizeof (struct nn_chunkref_chunk) : src->u.ref [0] + 1); } void nn_chunkref_cp (struct nn_chunkref *dst, struct nn_chunkref *src) { struct nn_chunkref_chunk *ch; if (src->u.ref [0] == 0xff) { ch = (struct nn_chunkref_chunk*) src; nn_chunk_addref (ch->chunk, 1); } memcpy (dst, src, sizeof (struct nn_chunkref)); } void *nn_chunkref_data (struct nn_chunkref *self) { return self->u.ref [0] == 0xff ? ((struct nn_chunkref_chunk*) self)->chunk : &self->u.ref [1]; } size_t nn_chunkref_size (struct nn_chunkref *self) { return self->u.ref [0] == 0xff ? nn_chunk_size (((struct nn_chunkref_chunk*) self)->chunk) : self->u.ref [0]; } void nn_chunkref_trim (struct nn_chunkref *self, size_t n) { struct nn_chunkref_chunk *ch; if (self->u.ref [0] == 0xff) { ch = (struct nn_chunkref_chunk*) self; ch->chunk = nn_chunk_trim (ch->chunk, n); return; } nn_assert (self->u.ref [0] >= n); memmove (&self->u.ref [1], &self->u.ref [1 + n], self->u.ref [0] - n); self->u.ref [0] -= (uint8_t) n; } void nn_chunkref_bulkcopy_start (struct nn_chunkref *self, uint32_t copies) { struct nn_chunkref_chunk *ch; if (self->u.ref [0] == 0xff) { ch = (struct nn_chunkref_chunk*) self; nn_chunk_addref (ch->chunk, copies); } } void nn_chunkref_bulkcopy_cp (struct nn_chunkref *dst, struct nn_chunkref *src) { memcpy (dst, src, sizeof (struct nn_chunkref)); } nanomsg-1.1.5/src/utils/chunkref.h000066400000000000000000000073371336111550300170750ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_CHUNKREF_INCLUDED #define NN_CHUNKREF_INCLUDED #define NN_CHUNKREF_MAX 32 #include "chunk.h" #include #include /* This class represents a reference to a data chunk. It's either an actual reference to data allocated on the heap, or if short enough, it may store the data in itself. While user messages are not often short enough to store them inside the chunkref itself, SP protocol headers mostly are and thus we can avoid additional memory allocation per message. */ struct nn_chunkref { union { uint8_t ref [NN_CHUNKREF_MAX]; /* This option is present only to force alignemt of nn_chunkref to the word boudnary. */ void *unused; } u; }; /* Initialise the chunkref. The actual storage will be either on stack (for small messages, or will be allocated via nn_chunk object. */ void nn_chunkref_init (struct nn_chunkref *self, size_t size); /* Create a chunkref from an existing chunk object. */ void nn_chunkref_init_chunk (struct nn_chunkref *self, void *chunk); /* Deallocate the chunk. */ void nn_chunkref_term (struct nn_chunkref *self); /* Get the underlying chunk. If it doesn't exist (small messages) it allocates one. Chunkref points to empty chunk after the call. */ void *nn_chunkref_getchunk (struct nn_chunkref *self); /* Moves chunk content from src to dst. dst should not be initialised before calling this function. After the call, dst becomes initialised and src becomes uninitialised. */ void nn_chunkref_mv (struct nn_chunkref *dst, struct nn_chunkref *src); /* Copies chunk content from src to dst. dst should not be initialised before calling this function. */ void nn_chunkref_cp (struct nn_chunkref *dst, struct nn_chunkref *src); /* Returns the pointer to the binary data stored in the chunk. */ void *nn_chunkref_data (struct nn_chunkref *self); /* Returns the size of the binary data stored in the chunk. */ size_t nn_chunkref_size (struct nn_chunkref *self); /* Trims n bytes from the beginning of the chunk. */ void nn_chunkref_trim (struct nn_chunkref *self, size_t n); /* Bulk copying is done by first invoking nn_chunkref_bulkcopy_start on the source chunk and specifying how many copies of the chunk will be made. Then, nn_chunkref_bulkcopy_cp should be used 'copies' of times to make individual copies of the source chunk. Note: Using bulk copying is more efficient than making each copy separately. */ void nn_chunkref_bulkcopy_start (struct nn_chunkref *self, uint32_t copies); void nn_chunkref_bulkcopy_cp (struct nn_chunkref *dst, struct nn_chunkref *src); #endif nanomsg-1.1.5/src/utils/clock.c000066400000000000000000000054401336111550300163470ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2012 Julien Ammous Copyright 2016 Garrett D'Amore 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. */ #if defined NN_HAVE_WINDOWS #include "win.h" #elif defined NN_HAVE_OSX #include #elif defined NN_HAVE_CLOCK_MONOTONIC || defined NN_HAVE_GETHRTIME #include #else #include #endif #include "clock.h" #include "fast.h" #include "err.h" #include "attr.h" uint64_t nn_clock_ms (void) { #if defined NN_HAVE_WINDOWS LARGE_INTEGER tps; LARGE_INTEGER time; double tpms; QueryPerformanceFrequency (&tps); QueryPerformanceCounter (&time); tpms = (double) (tps.QuadPart / 1000); return (uint64_t) (time.QuadPart / tpms); #elif defined NN_HAVE_OSX static mach_timebase_info_data_t nn_clock_timebase_info; uint64_t ticks; /* If the global timebase info is not initialised yet, init it. */ if (nn_slow (!nn_clock_timebase_info.denom)) mach_timebase_info (&nn_clock_timebase_info); ticks = mach_absolute_time (); return ticks * nn_clock_timebase_info.numer / nn_clock_timebase_info.denom / 1000000; #elif defined NN_HAVE_GETHRTIME return gethrtime () / 1000000; #elif defined NN_HAVE_CLOCK_MONOTONIC int rc; struct timespec tv; rc = clock_gettime (CLOCK_MONOTONIC, &tv); errno_assert (rc == 0); return tv.tv_sec * (uint64_t) 1000 + tv.tv_nsec / 1000000; #else int rc; struct timeval tv; /* Gettimeofday is slow on some systems. Moreover, it's not necessarily monotonic. Thus, it's used as a last resort mechanism. */ rc = gettimeofday (&tv, NULL); errno_assert (rc == 0); return tv.tv_sec * (uint64_t) 1000 + tv.tv_usec / 1000; #endif } nanomsg-1.1.5/src/utils/clock.h000066400000000000000000000024341336111550300163540ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef NN_CLOCK_INCLUDED #define NN_CLOCK_INCLUDED #include /* Returns current time in milliseconds. */ uint64_t nn_clock_ms (void); #endif nanomsg-1.1.5/src/utils/closefd.c000066400000000000000000000031201336111550300166640ustar00rootroot00000000000000/* Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2015 Garrett D'Amore 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. */ #if !defined NN_HAVE_WINDOWS #include "closefd.h" #include "fast.h" #include "err.h" #include void nn_closefd (int fd) { int rc; if (nn_slow (fd < 0)) { return; } rc = close (fd); if (nn_fast (rc == 0)) return; errno_assert (errno == EINTR || errno == ETIMEDOUT || errno == EWOULDBLOCK || errno == EINPROGRESS || errno == ECONNRESET); } #endif nanomsg-1.1.5/src/utils/closefd.h000066400000000000000000000024021336111550300166730ustar00rootroot00000000000000/* Copyright (c) 2013 GoPivotal, Inc. All rights reserved. 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. */ #ifndef NN_CLOSEFD_INCLUDED #define NN_CLOSEFD_INCLUDED #if !defined NN_HAVE_WINDOWS void nn_closefd (int fd); #endif #endif nanomsg-1.1.5/src/utils/condvar.c000066400000000000000000000107471336111550300167160ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. */ #include "mutex.h" #include "condvar.h" #include "err.h" #if NN_HAVE_WINDOWS int nn_condvar_init (nn_condvar_t *cond) { InitializeConditionVariable (&cond->cv); return (0); } void nn_condvar_term (nn_condvar_t *cond) { } int nn_condvar_wait (nn_condvar_t *cond, nn_mutex_t *lock, int timeout) { BOOL brc; DWORD expire; /* Likely this is redundant, but for API correctness be explicit. */ expire = (timeout < 0) ? INFINITE : (DWORD) timeout; /* We must own the lock if we are going to call this. */ nn_assert (lock->owner == GetCurrentThreadId()); /* Clear ownership as SleepConditionVariableCS will drop it. */ lock->owner = 0; brc = SleepConditionVariableCS (&cond->cv, &lock->cs, expire); /* We have reacquired the lock, so nobody should own it right now. */ nn_assert (lock->owner == 0); /* Note we own it now. */ lock->owner = GetCurrentThreadId(); if (!brc && GetLastError () == ERROR_TIMEOUT) { return (-ETIMEDOUT); } return (0); } void nn_condvar_signal (nn_condvar_t *cond) { WakeConditionVariable (&cond->cv); } void nn_condvar_broadcast (nn_condvar_t *cond) { WakeAllConditionVariable (&cond->cv); } #else /* !NN_HAVE_WINDOWS */ #include int nn_condvar_init (nn_condvar_t *cond) { int rc; /* This should really never fail, but the system may do so for ENOMEM or EAGAIN due to resource exhaustion, or EBUSY if reusing a condition variable with no intervening destroy call. */ rc = pthread_cond_init (&cond->cv, NULL); return (-rc); } void nn_condvar_term (nn_condvar_t *cond) { int rc; /* This should never fail, the system is allowed to return EBUSY if there are outstanding waiters (a serious bug!), or EINVAL if the cv is somehow invalid or illegal. Either of these cases would represent a serious programming defect in our caller. */ rc = pthread_cond_destroy (&cond->cv); errnum_assert (rc == 0, rc); } int nn_condvar_wait (nn_condvar_t *cond, nn_mutex_t *lock, int timeout) { int rc; struct timeval tv; struct timespec ts; if (timeout < 0) { /* This is an infinite sleep. We don't care about return values, as any error we can treat as just a premature wakeup. */ (void) pthread_cond_wait (&cond->cv, &lock->mutex); return (0); } rc = gettimeofday(&tv, NULL); errnum_assert (rc == 0, rc); /* There are extra operations performed here, but they are done to avoid wrap of the tv_usec and ts_nsec members on 32-bit systems. */ tv.tv_sec += timeout / 1000; tv.tv_usec += (timeout % 1000) * 1000; ts.tv_sec = tv.tv_sec + (tv.tv_usec / 1000000); ts.tv_nsec = (tv.tv_usec % 1000000) * 1000; rc = pthread_cond_timedwait (&cond->cv, &lock->mutex, &ts); if (rc == ETIMEDOUT) return (-ETIMEDOUT); /* Treat all other cases (including errors) as normal wakeup. */ return (0); } void nn_condvar_signal (nn_condvar_t *cond) { /* The only legal failure mode here is EINVAL if we passed a bad condition variable. We don't check that. */ (void) pthread_cond_signal (&cond->cv); } void nn_condvar_broadcast (nn_condvar_t *cond) { /* The only legal failure mode here is EINVAL if we passed a bad condition variable. We don't check that. */ (void) pthread_cond_broadcast (&cond->cv); } #endif nanomsg-1.1.5/src/utils/condvar.h000066400000000000000000000045561336111550300167240ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_CONDVAR_INCLUDED #define NN_CONDVAR_INCLUDED #include "mutex.h" #ifdef NN_HAVE_WINDOWS #include "win.h" struct nn_condvar { CONDITION_VARIABLE cv; }; #else /* !NN_HAVE_WINDOWS */ #include struct nn_condvar { pthread_cond_t cv; }; #endif /* NN_HAVE_WINDOWS */ typedef struct nn_condvar nn_condvar_t; /* Initialise the condvar. */ int nn_condvar_init (nn_condvar_t *cond); /* Terminate the condvar. */ void nn_condvar_term (nn_condvar_t *cond); /* Sleep on a condition variable, with a possible timeout. The mutex should be held when calling, and will be dropped on entry and reacquired atomically on return. The caller will wake when signaled, or when the timeout expires, but may be woken spuriously as well. If the timeout expires without a signal, -ETIMEDOUT will be returned, otherwise 0 will be returned. If expire is < 0, then no timeout will be used, representing a potentially infinite wait. */ int nn_condvar_wait (nn_condvar_t *cond, nn_mutex_t *lock, int timeout); /* Signal (wake) one condition variable waiter. */ void nn_condvar_signal (nn_condvar_t *cond); /* Signal all condition variable waiters, waking all of them. */ void nn_condvar_broadcast (nn_condvar_t *cond); #endif nanomsg-1.1.5/src/utils/cont.h000066400000000000000000000027231336111550300162250ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef NN_CONT_INCLUDED #define NN_CONT_INCLUDED #include /* Takes a pointer to a member variable and computes pointer to the structure that contains it. 'type' is type of the structure, not the member. */ #define nn_cont(ptr, type, member) \ (ptr ? ((type*) (((char*) ptr) - offsetof(type, member))) : NULL) #endif nanomsg-1.1.5/src/utils/efd.c000066400000000000000000000054111336111550300160100ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved. Copyright 2017 Garrett D'Amore Copyright 2017 Capitar IT Group BV 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. */ #include "efd.h" #include "clock.h" #if defined NN_USE_EVENTFD #include "efd_eventfd.inc" #elif defined NN_USE_PIPE #include "efd_pipe.inc" #elif defined NN_USE_SOCKETPAIR #include "efd_socketpair.inc" #elif defined NN_USE_WINSOCK #include "efd_win.inc" #else #error #endif #if defined NN_HAVE_POLL #include int nn_efd_wait (struct nn_efd *self, int timeout) { int rc; struct pollfd pfd; pfd.fd = nn_efd_getfd (self); pfd.events = POLLIN; if (pfd.fd < 0) return -EBADF; rc = poll (&pfd, 1, timeout); switch (rc) { case 0: return -ETIMEDOUT; case -1: return (-errno); } return 0; } #elif defined NN_HAVE_WINDOWS int nn_efd_wait (struct nn_efd *self, int timeout) { int rc; WSAPOLLFD pfd; pfd.fd = self->r; if (nn_slow (pfd.fd == INVALID_SOCKET)) { return -EBADF; } pfd.events = POLLIN; rc = WSAPoll(&pfd, 1, timeout); switch (rc) { case 0: return -ETIMEDOUT; case SOCKET_ERROR: rc = nn_err_wsa_to_posix (WSAGetLastError ()); errno = rc; /* Treat these as a non-fatal errors, typically occuring when the socket is being closed from a separate thread during a blocking I/O operation. */ if (rc == EINTR || rc == ENOTSOCK) { return self->r == INVALID_SOCKET ? -EBADF : -EINTR; } return (-rc); } return (0); } #else #error #endif nanomsg-1.1.5/src/utils/efd.h000066400000000000000000000050241336111550300160150ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2015 Garrett D'Amore Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved. 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. */ #ifndef NN_EFD_INCLUDED #define NN_EFD_INCLUDED /* Provides a way to send signals via file descriptors. The important part is that nn_efd_getfd() returns an actual OS-level file descriptor that you can poll on to wait for the event. */ #include "fd.h" #if defined NN_USE_EVENTFD #include "efd_eventfd.h" #elif defined NN_USE_PIPE #include "efd_pipe.h" #elif defined NN_USE_SOCKETPAIR #include "efd_socketpair.h" #elif defined NN_USE_WINSOCK #include "efd_win.h" #else #error #endif /* Initialise the efd object. */ int nn_efd_init (struct nn_efd *self); /* Uninitialise the efd object. */ void nn_efd_term (struct nn_efd *self); /* Get the OS file descriptor that is readable when the efd object is signaled. */ nn_fd nn_efd_getfd (struct nn_efd *self); /* Stop the efd object. */ void nn_efd_stop (struct nn_efd *self); /* Switch the object into signaled state. */ void nn_efd_signal (struct nn_efd *self); /* Switch the object into unsignaled state. */ void nn_efd_unsignal (struct nn_efd *self); /* Wait till efd object becomes signaled or when timeout (in milliseconds, nagative value meaning 'infinite') expires. In the former case 0 is returened. In the latter, -ETIMEDOUT. */ int nn_efd_wait (struct nn_efd *self, int timeout); #endif nanomsg-1.1.5/src/utils/efd_eventfd.h000066400000000000000000000022451336111550300175320ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ struct nn_efd { int efd; }; nanomsg-1.1.5/src/utils/efd_eventfd.inc000066400000000000000000000050021336111550300200460ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2015 Garrett D'Amore 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. */ #include "err.h" #include "closefd.h" #include #include #include #include int nn_efd_init (struct nn_efd *self) { int rc; int flags; self->efd = eventfd (0, EFD_CLOEXEC); if (self->efd == -1 && (errno == EMFILE || errno == ENFILE)) return -EMFILE; errno_assert (self->efd != -1); flags = fcntl (self->efd, F_GETFL, 0); if (flags == -1) flags = 0; rc = fcntl (self->efd, F_SETFL, flags | O_NONBLOCK); errno_assert (rc != -1); return 0; } void nn_efd_term (struct nn_efd *self) { int fd = self->efd; self->efd = -1; nn_closefd (fd); } void nn_efd_stop (struct nn_efd *self) { nn_efd_signal (self); } nn_fd nn_efd_getfd (struct nn_efd *self) { return self->efd; } void nn_efd_signal (struct nn_efd *self) { const uint64_t one = 1; ssize_t nbytes; int fd = self->efd; if (nn_slow (fd < 0)) return; nbytes = write (fd, &one, sizeof (one)); errno_assert (nbytes == sizeof (one)); } void nn_efd_unsignal (struct nn_efd *self) { uint64_t count; int fd = self->efd; if (nn_slow (fd < 0)) return; /* Extract all the signals from the eventfd. */ ssize_t sz = read (fd, &count, sizeof (count)); errno_assert (sz >= 0); nn_assert (sz == sizeof (count)); } nanomsg-1.1.5/src/utils/efd_pipe.h000066400000000000000000000022561336111550300170360ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ struct nn_efd { int r; int w; }; nanomsg-1.1.5/src/utils/efd_pipe.inc000066400000000000000000000064511336111550300173610ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2015 Garrett D'Amore 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. */ #include "err.h" #include "fast.h" #include "closefd.h" #include #include #include #include int nn_efd_init (struct nn_efd *self) { int rc; int flags; int p [2]; #if defined NN_HAVE_PIPE2 rc = pipe2 (p, O_NONBLOCK | O_CLOEXEC); if ((rc == -1) && (errno == ENOTSUP)) { /* Deal with unimplemented system call/libc mismatch (Linux). */ rc = pipe (p); } #else rc = pipe (p); #endif if (rc != 0 && (errno == EMFILE || errno == ENFILE)) return -EMFILE; errno_assert (rc == 0); self->r = p [0]; self->w = p [1]; #if !defined NN_HAVE_PIPE2 && defined FD_CLOEXEC rc = fcntl (self->r, F_SETFD, FD_CLOEXEC); errno_assert (rc != -1); rc = fcntl (self->w, F_SETFD, FD_CLOEXEC); errno_assert (rc != -1); #endif #if !defined NN_HAVE_PIPE2 flags = fcntl (self->r, F_GETFL, 0); if (flags == -1) flags = 0; rc = fcntl (self->r, F_SETFL, flags | O_NONBLOCK); errno_assert (rc != -1); #endif return 0; } void nn_efd_term (struct nn_efd *self) { /* Close the read side first. */ int fd = self->r; self->r = -1; nn_closefd (fd); fd = self->w; self->w = -1; nn_closefd (fd); } void nn_efd_stop (struct nn_efd *self) { /* Close the write side, which wakes up pollers with POLLHUP. */ int fd = self->w; self->w = -1; nn_closefd (fd); } nn_fd nn_efd_getfd (struct nn_efd *self) { return self->r; } void nn_efd_signal (struct nn_efd *self) { ssize_t nbytes; char c = 101; int fd = self->w; if (nn_slow (fd < 0)) return; nbytes = write (self->w, &c, 1); errno_assert (nbytes != -1); nn_assert (nbytes == 1); } void nn_efd_unsignal (struct nn_efd *self) { ssize_t nbytes; uint8_t buf [16]; while (1) { int fd = self->r; if (nn_slow (fd < 0)) return; nbytes = read (fd, buf, sizeof (buf)); if (nbytes < 0 && errno == EAGAIN) nbytes = 0; errno_assert (nbytes >= 0); if (nn_fast ((size_t) nbytes < sizeof (buf))) break; } } nanomsg-1.1.5/src/utils/efd_socketpair.h000066400000000000000000000023021336111550300202350ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ typedef int nn_fd; struct nn_efd { int r; int w; }; nanomsg-1.1.5/src/utils/efd_socketpair.inc000066400000000000000000000062371336111550300205720ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2015 Garrett D'Amore 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. */ #include "err.h" #include "fast.h" #include "closefd.h" #include #include #include #include #include int nn_efd_init (struct nn_efd *self) { int rc; int flags; int sp [2]; #if defined SOCK_CLOEXEC rc = socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sp); #else rc = socketpair (AF_UNIX, SOCK_STREAM, 0, sp); #endif if (rc != 0 && (errno == EMFILE || errno == ENFILE)) return -EMFILE; errno_assert (rc == 0); self->r = sp [0]; self->w = sp [1]; #if !defined SOCK_CLOEXEC && defined FD_CLOEXEC rc = fcntl (self->r, F_SETFD, FD_CLOEXEC); errno_assert (rc != -1); rc = fcntl (self->w, F_SETFD, FD_CLOEXEC); errno_assert (rc != -1); #endif flags = fcntl (self->r, F_GETFL, 0); if (flags == -1) flags = 0; rc = fcntl (self->r, F_SETFL, flags | O_NONBLOCK); errno_assert (rc != -1); return 0; } void nn_efd_stop (struct nn_efd *self) { int fd = self->w; self->w = -1; nn_closefd (fd); } void nn_efd_term (struct nn_efd *self) { int fd = self->r; self->r = -1; nn_closefd (fd); fd = self->w; self->w = -1; nn_closefd (fd); } nn_fd nn_efd_getfd (struct nn_efd *self) { return self->r; } void nn_efd_signal (struct nn_efd *self) { ssize_t nbytes; char c = 101; int fd = self->w; if (nn_slow (fd < 0)) return; #if defined MSG_NOSIGNAL nbytes = send (fd, &c, 1, MSG_NOSIGNAL); #else nbytes = send (fd, &c, 1, 0); #endif errno_assert (nbytes != -1); nn_assert (nbytes == 1); } void nn_efd_unsignal (struct nn_efd *self) { ssize_t nbytes; uint8_t buf [16]; while (1) { int fd = self->r; if (nn_slow (fd < 0)) return; nbytes = recv (self->r, buf, sizeof (buf), 0); if (nbytes < 0 && errno == EAGAIN) nbytes = 0; errno_assert (nbytes >= 0); if (nn_fast (nbytes < sizeof (buf))) break; } } nanomsg-1.1.5/src/utils/efd_win.h000066400000000000000000000024701336111550300166740ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2017 Garrett D'Amore Copyright 2017 Capitar IT Group BV 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. */ #include "win.h" struct nn_efd { SOCKET r; SOCKET w; }; nanomsg-1.1.5/src/utils/efd_win.inc000066400000000000000000000132441336111550300172170ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright 2017 Garrett D'Amore Copyright 2018 Staysail Systems, Inc. Copyright 2018 Capitar IT Group BV 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. */ #include "err.h" #include "fast.h" #include #include int nn_efd_init (struct nn_efd *self) { SOCKET listener; int rc; struct sockaddr_in addr; socklen_t addrlen; int one; BOOL nodelay; u_long nonblock; /* Unfortunately, on Windows the only way to send signal to a file descriptor (SOCKET) is to create a full-blown TCP connecting on top of the loopback interface. */ self->w = INVALID_SOCKET; self->r = INVALID_SOCKET; /* Create listening socket. */ listener = socket (AF_INET, SOCK_STREAM, 0); if (listener == SOCKET_ERROR) goto wsafail; one = 1; rc = setsockopt (listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char*) &one, sizeof (one)); if (rc == SOCKET_ERROR) goto wsafail; /* Bind the listening socket to the local port. */ memset (&addr, 0, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); addr.sin_port = 0; rc = bind (listener, (const struct sockaddr*) &addr, sizeof (addr)); if (rc == SOCKET_ERROR) goto wsafail; /* Get the port we bound to (will be ephemeral.) */ addrlen = sizeof (addr); rc = getsockname (listener, (struct sockaddr *) &addr, &addrlen); if (rc == SOCKET_ERROR) goto wsafail; /* Start listening for the incomming connections. In normal case we are going to accept just a single connection, so backlog buffer of size 1 is sufficient. */ rc = listen (listener, 1); if (rc == SOCKET_ERROR) goto wsafail; /* The following code is in the loop, because windows sometimes delays WSAEADDRINUSE error to the `connect` call. But retrying the connection works like a charm. Still we want to limit number of retries */ /* Create the writer socket. */ self->w = socket (AF_INET, SOCK_STREAM, 0); if (listener == SOCKET_ERROR) goto wsafail; /* Set TCP_NODELAY on the writer socket to make efd as fast as possible. There's only one byte going to be written, so batching would not make sense anyway. */ nodelay = 1; rc = setsockopt (self->w, IPPROTO_TCP, TCP_NODELAY, (char*) &nodelay, sizeof (nodelay)); if (nn_slow (rc == SOCKET_ERROR)) goto wsafail; /* Connect the writer socket to the listener socket. */ rc = connect (self->w, (struct sockaddr*) &addr, sizeof (addr)); if (rc == SOCKET_ERROR) goto wsafail; /* Accept new incoming connection. */ addrlen = sizeof (addr); self->r = accept (listener, (struct sockaddr*) &addr, &addrlen); if (self->r == INVALID_SOCKET) goto wsafail; /* Close the listener, we don't need it anymore. */ (void) closesocket (listener); /* Make the receiving socket non-blocking. */ nonblock = 1; rc = ioctlsocket (self->r, FIONBIO, &nonblock); wsa_assert (rc != SOCKET_ERROR); return 0; wsafail: rc = nn_err_wsa_to_posix (WSAGetLastError ()); return -rc; } void nn_efd_stop (struct nn_efd *self) { int rc; SOCKET s = self->w; self->w = INVALID_SOCKET; if (s != INVALID_SOCKET) { rc = closesocket (s); wsa_assert (rc != INVALID_SOCKET); } } void nn_efd_term (struct nn_efd *self) { int rc; SOCKET s; s = self->r; self->r = INVALID_SOCKET; if (s != INVALID_SOCKET) { rc = closesocket (s); wsa_assert (rc != INVALID_SOCKET); } s = self->w; self->w = INVALID_SOCKET; if (s != INVALID_SOCKET) { rc = closesocket (s); wsa_assert (rc != INVALID_SOCKET); } } nn_fd nn_efd_getfd (struct nn_efd *self) { return self->r; } void nn_efd_signal (struct nn_efd *self) { int rc; unsigned char c = 0xec; SOCKET s = self->w; if (nn_fast (s != INVALID_SOCKET)) { rc = send (s, (char*) &c, 1, 0); wsa_assert (rc != SOCKET_ERROR); nn_assert (rc == 1); } } void nn_efd_unsignal (struct nn_efd *self) { int rc; uint8_t buf [16]; while (1) { SOCKET s = self->r; if (nn_slow (s == INVALID_SOCKET)) break; rc = recv (s, (char*) buf, sizeof (buf), 0); if (rc == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK) rc = 0; wsa_assert (rc != SOCKET_ERROR); if ((rc == SOCKET_ERROR) || (rc < sizeof (buf))) break; } } nanomsg-1.1.5/src/utils/err.c000066400000000000000000000127351336111550300160510ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "err.h" #ifdef NN_HAVE_WINDOWS #include "win.h" #endif #ifdef NN_HAVE_BACKTRACE #include void nn_backtrace_print (void) { void *frames[50]; int size; size = backtrace (frames, sizeof (frames) / sizeof (frames[0])); if (size > 1) { /* Don't include the frame nn_backtrace_print itself. */ backtrace_symbols_fd (&frames[1], size-1, fileno (stderr)); } } /* XXX: Add Windows backtraces */ #else void nn_backtrace_print (void) { } #endif #include void nn_err_abort (void) { abort (); } int nn_err_errno (void) { return errno; } const char *nn_err_strerror (int errnum) { switch (errnum) { #if defined NN_HAVE_WINDOWS case ENOTSUP: return "Not supported"; case EPROTONOSUPPORT: return "Protocol not supported"; case ENOBUFS: return "No buffer space available"; case ENETDOWN: return "Network is down"; case EADDRINUSE: return "Address in use"; case EADDRNOTAVAIL: return "Address not available"; case ECONNREFUSED: return "Connection refused"; case EINPROGRESS: return "Operation in progress"; case ENOTSOCK: return "Not a socket"; case EAFNOSUPPORT: return "Address family not supported"; case EPROTO: return "Protocol error"; case EAGAIN: return "Resource unavailable, try again"; case EBADF: return "Bad file descriptor"; case EINVAL: return "Invalid argument"; case EMFILE: return "Too many open files"; case EFAULT: return "Bad address"; case EACCES: return "Permission denied"; case ENETRESET: return "Connection aborted by network"; case ENETUNREACH: return "Network unreachable"; case EHOSTUNREACH: return "Host is unreachable"; case ENOTCONN: return "The socket is not connected"; case EMSGSIZE: return "Message too large"; case ETIMEDOUT: return "Timed out"; case ECONNABORTED: return "Connection aborted"; case ECONNRESET: return "Connection reset"; case ENOPROTOOPT: return "Protocol not available"; case EISCONN: return "Socket is connected"; #endif case ETERM: return "Nanomsg library was terminated"; case EFSM: return "Operation cannot be performed in this state"; default: #if defined _MSC_VER #pragma warning (push) #pragma warning (disable:4996) #endif return strerror (errnum); #if defined _MSC_VER #pragma warning (pop) #endif } } #ifdef NN_HAVE_WINDOWS int nn_err_wsa_to_posix (int wsaerr) { switch (wsaerr) { case WSAEINPROGRESS: return EAGAIN; case WSAEBADF: return EBADF; case WSAEINVAL: return EINVAL; case WSAEMFILE: return EMFILE; case WSAEFAULT: return EFAULT; case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT; case WSAENOBUFS: return ENOBUFS; case WSAENETDOWN: return ENETDOWN; case WSAEADDRINUSE: return EADDRINUSE; case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL; case WSAEAFNOSUPPORT: return EAFNOSUPPORT; case WSAEACCES: return EACCES; case WSAENETRESET: return ENETRESET; case WSAENETUNREACH: return ENETUNREACH; case WSAEHOSTUNREACH: return EHOSTUNREACH; case WSAENOTCONN: return ENOTCONN; case WSAEMSGSIZE: return EMSGSIZE; case WSAETIMEDOUT: return ETIMEDOUT; case WSAECONNREFUSED: return ECONNREFUSED; case WSAECONNABORTED: return ECONNABORTED; case WSAECONNRESET: return ECONNRESET; case WSAENOTSOCK: return ENOTSOCK; case ERROR_BROKEN_PIPE: return ECONNRESET; case WSAESOCKTNOSUPPORT: return ESOCKTNOSUPPORT; case ERROR_NOT_CONNECTED: return ENOTCONN; case ERROR_PIPE_NOT_CONNECTED: return ENOTCONN; case ERROR_NO_DATA: return EPIPE; default: nn_assert (0); } } void nn_win_error (int err, char *buf, size_t bufsize) { DWORD rc = FormatMessageA ( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD) err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (DWORD) bufsize, NULL ); nn_assert (rc); } #endif nanomsg-1.1.5/src/utils/err.h000066400000000000000000000132631336111550300160530ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_ERR_INCLUDED #define NN_ERR_INCLUDED #include #include #include /* Include nn.h header to define nanomsg-specific error codes. */ #include "../nn.h" #include "fast.h" #if defined _MSC_VER #define NN_NORETURN __declspec(noreturn) #elif defined __GNUC__ #define NN_NORETURN __attribute__ ((noreturn)) #else #define NN_NORETURN #endif /* Same as system assert(). However, under Win32 assert has some deficiencies. Thus this macro. */ #define nn_assert(x) \ do {\ if (nn_slow (!(x))) {\ nn_backtrace_print (); \ fprintf (stderr, "Assertion failed: %s (%s:%d)\n", #x, \ __FILE__, __LINE__);\ fflush (stderr);\ nn_err_abort ();\ }\ } while (0) #define nn_assert_state(obj, state_name) \ do {\ if (nn_slow ((obj)->state != state_name)) {\ nn_backtrace_print (); \ fprintf (stderr, \ "Assertion failed: %d == %s (%s:%d)\n", \ (obj)->state, #state_name, \ __FILE__, __LINE__);\ fflush (stderr);\ nn_err_abort ();\ }\ } while (0) /* Checks whether memory allocation was successful. */ #define alloc_assert(x) \ do {\ if (nn_slow (!x)) {\ nn_backtrace_print (); \ fprintf (stderr, "Out of memory (%s:%d)\n",\ __FILE__, __LINE__);\ fflush (stderr);\ nn_err_abort ();\ }\ } while (0) /* Check the condition. If false prints out the errno. */ #define errno_assert(x) \ do {\ if (nn_slow (!(x))) {\ nn_backtrace_print (); \ fprintf (stderr, "%s [%d] (%s:%d)\n", nn_err_strerror (errno),\ (int) errno, __FILE__, __LINE__);\ fflush (stderr);\ nn_err_abort ();\ }\ } while (0) /* Checks whether supplied errno number is an error. */ #define errnum_assert(cond, err) \ do {\ if (nn_slow (!(cond))) {\ nn_backtrace_print (); \ fprintf (stderr, "%s [%d] (%s:%d)\n", nn_err_strerror (err),\ (int) (err), __FILE__, __LINE__);\ fflush (stderr);\ nn_err_abort ();\ }\ } while (0) /* Checks the condition. If false prints out the GetLastError info. */ #define win_assert(x) \ do {\ if (nn_slow (!(x))) {\ char errstr [256];\ DWORD errnum = WSAGetLastError ();\ nn_backtrace_print (); \ nn_win_error ((int) errnum, errstr, 256);\ fprintf (stderr, "%s [%d] (%s:%d)\n",\ errstr, (int) errnum, __FILE__, __LINE__);\ fflush (stderr);\ nn_err_abort ();\ }\ } while (0) /* Checks the condition. If false prints out the WSAGetLastError info. */ #define wsa_assert(x) \ do {\ if (nn_slow (!(x))) {\ char errstr [256];\ DWORD errnum = WSAGetLastError ();\ nn_backtrace_print (); \ nn_win_error (errnum, errstr, 256);\ fprintf (stderr, "%s [%d] (%s:%d)\n",\ errstr, (int) errnum, __FILE__, __LINE__);\ fflush (stderr);\ nn_err_abort ();\ }\ } while (0) /* Assertion-like macros for easier fsm debugging. */ #define nn_fsm_error(message, state, src, type) \ do {\ nn_backtrace_print(); \ fprintf (stderr, "%s: state=%d source=%d action=%d (%s:%d)\n", \ message, state, src, type, __FILE__, __LINE__);\ fflush (stderr);\ nn_err_abort ();\ } while (0) #define nn_fsm_bad_action(state, src, type) nn_fsm_error(\ "Unexpected action", state, src, type) #define nn_fsm_bad_state(state, src, type) nn_fsm_error(\ "Unexpected state", state, src, type) #define nn_fsm_bad_source(state, src, type) nn_fsm_error(\ "Unexpected source", state, src, type) /* Compile-time assert. */ #define CT_ASSERT_HELPER2(prefix, line) prefix##line #define CT_ASSERT_HELPER1(prefix, line) CT_ASSERT_HELPER2(prefix, line) #if defined __COUNTER__ #define CT_ASSERT(x) \ typedef int CT_ASSERT_HELPER1(ct_assert_,__COUNTER__) [(x) ? 1 : -1] #else #define CT_ASSERT(x) \ typedef int CT_ASSERT_HELPER1(ct_assert_,__LINE__) [(x) ? 1 : -1] #endif NN_NORETURN void nn_err_abort (void); int nn_err_errno (void); const char *nn_err_strerror (int errnum); void nn_backtrace_print (void); #ifdef NN_HAVE_WINDOWS int nn_err_wsa_to_posix (int wsaerr); void nn_win_error (int err, char *buf, size_t bufsize); #endif #endif nanomsg-1.1.5/src/utils/fast.h000066400000000000000000000025671336111550300162250ustar00rootroot00000000000000/* Copyright (c) 2012Martin Sustrik All rights reserved. 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. */ #ifndef NN_FAST_INCLUDED #define NN_FAST_INCLUDED #if defined __GNUC__ || defined __llvm__ #define nn_fast(x) __builtin_expect ((x), 1) #define nn_slow(x) __builtin_expect ((x), 0) #else #define nn_fast(x) (x) #define nn_slow(x) (x) #endif #endif nanomsg-1.1.5/src/utils/fd.h000066400000000000000000000024521336111550300156520ustar00rootroot00000000000000/* Copyright (c) 2013 Immanuel Weber, Fraunhofer FHR/AMLS All rights reserved. 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. */ #ifndef NN_FD_INCLUDED #define NN_FD_INCLUDED #ifdef NN_HAVE_WINDOWS #include "win.h" typedef SOCKET nn_fd; #else typedef int nn_fd; #endif #endif nanomsg-1.1.5/src/utils/hash.c000066400000000000000000000114761336111550300162050ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "hash.h" #include "fast.h" #include "alloc.h" #include "cont.h" #include "err.h" #define NN_HASH_INITIAL_SLOTS 32 static uint32_t nn_hash_key (uint32_t key); void nn_hash_init (struct nn_hash *self) { uint32_t i; self->slots = NN_HASH_INITIAL_SLOTS; self->items = 0; self->array = nn_alloc (sizeof (struct nn_list) * NN_HASH_INITIAL_SLOTS, "hash map"); alloc_assert (self->array); for (i = 0; i != NN_HASH_INITIAL_SLOTS; ++i) nn_list_init (&self->array [i]); } void nn_hash_term (struct nn_hash *self) { uint32_t i; for (i = 0; i != self->slots; ++i) nn_list_term (&self->array [i]); nn_free (self->array); } static void nn_hash_rehash (struct nn_hash *self) { uint32_t i; uint32_t oldslots; struct nn_list *oldarray; struct nn_hash_item *hitm; uint32_t newslot; /* Allocate new double-sized array of slots. */ oldslots = self->slots; oldarray = self->array; self->slots *= 2; self->array = nn_alloc (sizeof (struct nn_list) * self->slots, "hash map"); alloc_assert (self->array); for (i = 0; i != self->slots; ++i) nn_list_init (&self->array [i]); /* Move the items from old slot array to new slot array. */ for (i = 0; i != oldslots; ++i) { while (!nn_list_empty (&oldarray [i])) { hitm = nn_cont (nn_list_begin (&oldarray [i]), struct nn_hash_item, list); nn_list_erase (&oldarray [i], &hitm->list); newslot = nn_hash_key (hitm->key) % self->slots; nn_list_insert (&self->array [newslot], &hitm->list, nn_list_end (&self->array [newslot])); } nn_list_term (&oldarray [i]); } /* Deallocate the old array of slots. */ nn_free (oldarray); } void nn_hash_insert (struct nn_hash *self, uint32_t key, struct nn_hash_item *item) { struct nn_list_item *it; uint32_t i; i = nn_hash_key (key) % self->slots; for (it = nn_list_begin (&self->array [i]); it != nn_list_end (&self->array [i]); it = nn_list_next (&self->array [i], it)) nn_assert (nn_cont (it, struct nn_hash_item, list)->key != key); item->key = key; nn_list_insert (&self->array [i], &item->list, nn_list_end (&self->array [i])); ++self->items; /* If the hash is getting full, double the amount of slots and re-hash all the items. */ if (nn_slow (self->items * 2 > self->slots && self->slots < 0x80000000)) nn_hash_rehash(self); } void nn_hash_erase (struct nn_hash *self, struct nn_hash_item *item) { uint32_t slot; slot = nn_hash_key (item->key) % self->slots; nn_list_erase (&self->array [slot], &item->list); --self->items; } struct nn_hash_item *nn_hash_get (struct nn_hash *self, uint32_t key) { uint32_t slot; struct nn_list_item *it; struct nn_hash_item *item; slot = nn_hash_key (key) % self->slots; for (it = nn_list_begin (&self->array [slot]); it != nn_list_end (&self->array [slot]); it = nn_list_next (&self->array [slot], it)) { item = nn_cont (it, struct nn_hash_item, list); if (item->key == key) return item; } return NULL; } uint32_t nn_hash_key (uint32_t key) { /* TODO: This is a randomly chosen hashing function. Give some thought to picking a more fitting one. */ key = (key ^ 61) ^ (key >> 16); key += key << 3; key = key ^ (key >> 4); key = key * 0x27d4eb2d; key = key ^ (key >> 15); return key; } void nn_hash_item_init (struct nn_hash_item *self) { nn_list_item_init (&self->list); } void nn_hash_item_term (struct nn_hash_item *self) { nn_list_item_term (&self->list); } nanomsg-1.1.5/src/utils/hash.h000066400000000000000000000047021336111550300162040ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_HASH_INCLUDED #define NN_HASH_INCLUDED #include "list.h" #include #include /* Use for initialising a hash item statically. */ #define NN_HASH_ITEM_INITIALIZER {0xffff, NN_LIST_ITEM_INITILIZER} struct nn_hash_item { uint32_t key; struct nn_list_item list; }; struct nn_hash { uint32_t slots; uint32_t items; struct nn_list *array; }; /* Initialise the hash table. */ void nn_hash_init (struct nn_hash *self); /* Terminate the hash. Note that hash must be manually emptied before the termination. */ void nn_hash_term (struct nn_hash *self); /* Adds an item to the hash. */ void nn_hash_insert (struct nn_hash *self, uint32_t key, struct nn_hash_item *item); /* Removes the element from the hash it is in at the moment. */ void nn_hash_erase (struct nn_hash *self, struct nn_hash_item *item); /* Gets an item in the hash based on the key. Returns NULL if there's no corresponing item in the hash table. */ struct nn_hash_item *nn_hash_get (struct nn_hash *self, uint32_t key); /* Initialise a hash item. At this point it is not a part of any hash table. */ void nn_hash_item_init (struct nn_hash_item *self); /* Terminate a hash item. The item must not be in a hash table prior to this call. */ void nn_hash_item_term (struct nn_hash_item *self); #endif nanomsg-1.1.5/src/utils/list.c000066400000000000000000000063771336111550300162410ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include #include "list.h" #include "err.h" #include "attr.h" void nn_list_init (struct nn_list *self) { self->first = NULL; self->last = NULL; } void nn_list_term (struct nn_list *self) { nn_assert (self->first == NULL); nn_assert (self->last == NULL); } int nn_list_empty (struct nn_list *self) { return self->first ? 0 : 1; } struct nn_list_item *nn_list_begin (struct nn_list *self) { return self->first; } struct nn_list_item *nn_list_end (NN_UNUSED struct nn_list *self) { return NULL; } struct nn_list_item *nn_list_prev (struct nn_list *self, struct nn_list_item *it) { if (!it) return self->last; nn_assert (it->prev != NN_LIST_NOTINLIST); return it->prev; } struct nn_list_item *nn_list_next (NN_UNUSED struct nn_list *self, struct nn_list_item *it) { nn_assert (it->next != NN_LIST_NOTINLIST); return it->next; } void nn_list_insert (struct nn_list *self, struct nn_list_item *item, struct nn_list_item *it) { nn_assert (!nn_list_item_isinlist (item)); item->prev = it ? it->prev : self->last; item->next = it; if (item->prev) item->prev->next = item; if (item->next) item->next->prev = item; if (!self->first || self->first == it) self->first = item; if (!it) self->last = item; } struct nn_list_item *nn_list_erase (struct nn_list *self, struct nn_list_item *item) { struct nn_list_item *next; nn_assert (nn_list_item_isinlist (item)); if (item->prev) item->prev->next = item->next; else self->first = item->next; if (item->next) item->next->prev = item->prev; else self->last = item->prev; next = item->next; item->prev = NN_LIST_NOTINLIST; item->next = NN_LIST_NOTINLIST; return next; } void nn_list_item_init (struct nn_list_item *self) { self->prev = NN_LIST_NOTINLIST; self->next = NN_LIST_NOTINLIST; } void nn_list_item_term (struct nn_list_item *self) { nn_assert (!nn_list_item_isinlist (self)); } int nn_list_item_isinlist (struct nn_list_item *self) { return self->prev == NN_LIST_NOTINLIST ? 0 : 1; } nanomsg-1.1.5/src/utils/list.h000066400000000000000000000063771336111550300162460ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef NN_LIST_INCLUDED #define NN_LIST_INCLUDED struct nn_list_item { struct nn_list_item *next; struct nn_list_item *prev; }; struct nn_list { struct nn_list_item *first; struct nn_list_item *last; }; /* Undefined value for initializing a list item which is not part of a list. */ #define NN_LIST_NOTINLIST ((struct nn_list_item*) -1) /* Use for initializing a list item statically. */ #define NN_LIST_ITEM_INITIALIZER {NN_LIST_NOTINLIST, NN_LIST_NOTINLIST} /* Initialise the list. */ void nn_list_init (struct nn_list *self); /* Terminates the list. Note that all items must be removed before the termination. */ void nn_list_term (struct nn_list *self); /* Returns 1 is list has zero items, 0 otherwise. */ int nn_list_empty (struct nn_list *self); /* Returns iterator to the first item in the list. */ struct nn_list_item *nn_list_begin (struct nn_list *self); /* Returns iterator to one past the last item in the list. */ struct nn_list_item *nn_list_end (struct nn_list *self); /* Returns iterator to an item prior to the one pointed to by 'it'. */ struct nn_list_item *nn_list_prev (struct nn_list *self, struct nn_list_item *it); /* Returns iterator to one past the item pointed to by 'it'. */ struct nn_list_item *nn_list_next (struct nn_list *self, struct nn_list_item *it); /* Adds the item to the list before the item pointed to by 'it'. Priot to insertion item should not be part of any list. */ void nn_list_insert (struct nn_list *self, struct nn_list_item *item, struct nn_list_item *it); /* Removes the item from the list and returns pointer to the next item in the list. Item must be part of the list. */ struct nn_list_item *nn_list_erase (struct nn_list *self, struct nn_list_item *item); /* Initialize a list item. At this point it is not part of any list. */ void nn_list_item_init (struct nn_list_item *self); /* Terminates a list item. Item must not be part of any list before it's terminated. */ void nn_list_item_term (struct nn_list_item *self); /* Returns 1 is the item is part of a list, 0 otherwise. */ int nn_list_item_isinlist (struct nn_list_item *self); #endif nanomsg-1.1.5/src/utils/msg.c000066400000000000000000000052461336111550300160460ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "msg.h" #include void nn_msg_init (struct nn_msg *self, size_t size) { nn_chunkref_init (&self->sphdr, 0); nn_chunkref_init (&self->hdrs, 0); nn_chunkref_init (&self->body, size); } void nn_msg_init_chunk (struct nn_msg *self, void *chunk) { nn_chunkref_init (&self->sphdr, 0); nn_chunkref_init (&self->hdrs, 0); nn_chunkref_init_chunk (&self->body, chunk); } void nn_msg_term (struct nn_msg *self) { nn_chunkref_term (&self->sphdr); nn_chunkref_term (&self->hdrs); nn_chunkref_term (&self->body); } void nn_msg_mv (struct nn_msg *dst, struct nn_msg *src) { nn_chunkref_mv (&dst->sphdr, &src->sphdr); nn_chunkref_mv (&dst->hdrs, &src->hdrs); nn_chunkref_mv (&dst->body, &src->body); } void nn_msg_cp (struct nn_msg *dst, struct nn_msg *src) { nn_chunkref_cp (&dst->sphdr, &src->sphdr); nn_chunkref_cp (&dst->hdrs, &src->hdrs); nn_chunkref_cp (&dst->body, &src->body); } void nn_msg_bulkcopy_start (struct nn_msg *self, uint32_t copies) { nn_chunkref_bulkcopy_start (&self->sphdr, copies); nn_chunkref_bulkcopy_start (&self->hdrs, copies); nn_chunkref_bulkcopy_start (&self->body, copies); } void nn_msg_bulkcopy_cp (struct nn_msg *dst, struct nn_msg *src) { nn_chunkref_bulkcopy_cp (&dst->sphdr, &src->sphdr); nn_chunkref_bulkcopy_cp (&dst->hdrs, &src->hdrs); nn_chunkref_bulkcopy_cp (&dst->body, &src->body); } void nn_msg_replace_body (struct nn_msg *self, struct nn_chunkref new_body) { nn_chunkref_term (&self->body); self->body = new_body; } nanomsg-1.1.5/src/utils/msg.h000066400000000000000000000062161336111550300160510ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_MSG_INCLUDED #define NN_MSG_INCLUDED #include "chunkref.h" #include struct nn_msg { /* Contains SP message header. This field directly corresponds to SP message header as defined in SP RFCs. There's no leading cmsghdr or trailing padding. */ struct nn_chunkref sphdr; /* Contains any additional transport-level message headers. Format of this buffer is a list of cmsgs as defined by POSIX (see "ancillary data"). */ struct nn_chunkref hdrs; /* Contains application level message payload. */ struct nn_chunkref body; }; /* Initialises a message with body 'size' bytes long and empty header. */ void nn_msg_init (struct nn_msg *self, size_t size); /* Initialise message with body provided in the form of chunk pointer. */ void nn_msg_init_chunk (struct nn_msg *self, void *chunk); /* Frees resources allocate with the message. */ void nn_msg_term (struct nn_msg *self); /* Moves the content of the message from src to dst. dst should not be initialised prior to the operation. src will be uninitialised after the operation. */ void nn_msg_mv (struct nn_msg *dst, struct nn_msg *src); /* Copies a message from src to dst. dst should not be initialised prior to the operation. */ void nn_msg_cp (struct nn_msg *dst, struct nn_msg *src); /* Bulk copying is done by first invoking nn_msg_bulkcopy_start on the source message and specifying how many copies of the message will be made. Then, nn_msg_bulkcopy_cp should be used 'copies' of times to make individual copies of the source message. Note: Bulk copying is more efficient than making each copy separately. */ void nn_msg_bulkcopy_start (struct nn_msg *self, uint32_t copies); void nn_msg_bulkcopy_cp (struct nn_msg *dst, struct nn_msg *src); /** Replaces the message body with entirely new data. This allows protocols that substantially rewrite or preprocess the userland message to be written. */ void nn_msg_replace_body(struct nn_msg *self, struct nn_chunkref newBody); #endif nanomsg-1.1.5/src/utils/mutex.c000066400000000000000000000053031336111550300164140ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "mutex.h" #include "err.h" #include #ifdef NN_HAVE_WINDOWS void nn_mutex_init (nn_mutex_t *self) { InitializeCriticalSection (&self->cs); self->owner = 0; } void nn_mutex_term (nn_mutex_t *self) { /* Make sure we don't free a locked mutex. */ nn_assert(self->owner == 0); DeleteCriticalSection (&self->cs); } void nn_mutex_lock (nn_mutex_t *self) { EnterCriticalSection (&self->cs); /* Make sure we don't recursively enter mutexes. */ nn_assert(self->owner == 0); self->owner = GetCurrentThreadId(); } void nn_mutex_unlock (nn_mutex_t *self) { /* Make sure that we own the mutex we are releasing. */ nn_assert(self->owner == GetCurrentThreadId()); self->owner = 0; LeaveCriticalSection (&self->cs); } #else void nn_mutex_init (nn_mutex_t *self) { int rc; pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); errnum_assert (rc == 0, rc); rc = pthread_mutex_init (&self->mutex, NULL); errnum_assert (rc == 0, rc); pthread_mutexattr_destroy(&attr); } void nn_mutex_term (nn_mutex_t *self) { int rc; rc = pthread_mutex_destroy (&self->mutex); errnum_assert (rc == 0, rc); } void nn_mutex_lock (nn_mutex_t *self) { int rc; rc = pthread_mutex_lock (&self->mutex); errnum_assert (rc == 0, rc); } void nn_mutex_unlock (nn_mutex_t *self) { int rc; rc = pthread_mutex_unlock (&self->mutex); errnum_assert (rc == 0, rc); } #endif nanomsg-1.1.5/src/utils/mutex.h000066400000000000000000000036321336111550300164240ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef NN_MUTEX_INCLUDED #define NN_MUTEX_INCLUDED #ifdef NN_HAVE_WINDOWS #include "win.h" #else #include #endif struct nn_mutex { /* NB: The fields of this structure are private to the mutex implementation. */ #ifdef NN_HAVE_WINDOWS CRITICAL_SECTION cs; DWORD owner; int debug; #else pthread_mutex_t mutex; #endif }; typedef struct nn_mutex nn_mutex_t; /* Initialise the mutex. */ void nn_mutex_init (nn_mutex_t *self); /* Terminate the mutex. */ void nn_mutex_term (nn_mutex_t *self); /* Lock the mutex. Behaviour of multiple locks from the same thread is undefined. */ void nn_mutex_lock (nn_mutex_t *self); /* Unlock the mutex. Behaviour of unlocking an unlocked mutex is undefined */ void nn_mutex_unlock (nn_mutex_t *self); #endif nanomsg-1.1.5/src/utils/once.c000066400000000000000000000033101336111550300161720ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. */ #include "once.h" #if NN_HAVE_WINDOWS /* This craziness is required because Windows doesn't have the notion of static initializers for CriticalSections. */ BOOL CALLBACK nn_do_once_cb (PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) { void (*func)(void) = Parameter; func(); return (TRUE); } void nn_do_once (nn_once_t *once, void (*func)(void)) { (void) InitOnceExecuteOnce(&once->once, nn_do_once_cb, func, NULL); } #else /* !NN_HAVE_WINDOWS */ void nn_do_once (nn_once_t *once, void (*func)(void)) { pthread_once (&once->once, func); } #endif nanomsg-1.1.5/src/utils/once.h000066400000000000000000000031371336111550300162060ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_ONCE_INCLUDED #define NN_ONCE_INCLUDED #ifdef NN_HAVE_WINDOWS #include "win.h" struct nn_once { INIT_ONCE once; }; #define NN_ONCE_INITIALIZER { INIT_ONCE_STATIC_INIT } #else /* !NN_HAVE_WINDOWS */ #include struct nn_once { pthread_once_t once; }; #define NN_ONCE_INITIALIZER { PTHREAD_ONCE_INIT } #endif /* NN_HAVE_WINDOWS */ typedef struct nn_once nn_once_t; void nn_do_once (nn_once_t *once, void (*func)(void)); #endif /* NN_ONCE_INCLUDED */ nanomsg-1.1.5/src/utils/queue.c000066400000000000000000000056431336111550300164050ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include #include "queue.h" #include "err.h" void nn_queue_init (struct nn_queue *self) { self->head = NULL; self->tail = NULL; } void nn_queue_term (struct nn_queue *self) { self->head = NULL; self->tail = NULL; } int nn_queue_empty (struct nn_queue *self) { return self->head ? 0 : 1; } void nn_queue_push (struct nn_queue *self, struct nn_queue_item *item) { nn_assert (item->next == NN_QUEUE_NOTINQUEUE); item->next = NULL; if (!self->head) self->head = item; if (self->tail) self->tail->next = item; self->tail = item; } void nn_queue_remove (struct nn_queue *self, struct nn_queue_item *item) { struct nn_queue_item *it; struct nn_queue_item *prev; if (item->next == NN_QUEUE_NOTINQUEUE) return; prev = NULL; for (it = self->head; it != NULL; it = it->next) { if (it == item) { if (self->head == it) self->head = it->next; if (self->tail == it) self->tail = prev; if (prev) prev->next = it->next; item->next = NN_QUEUE_NOTINQUEUE; return; } prev = it; } } struct nn_queue_item *nn_queue_pop (struct nn_queue *self) { struct nn_queue_item *result; if (!self->head) return NULL; result = self->head; self->head = result->next; if (!self->head) self->tail = NULL; result->next = NN_QUEUE_NOTINQUEUE; return result; } void nn_queue_item_init (struct nn_queue_item *self) { self->next = NN_QUEUE_NOTINQUEUE; } void nn_queue_item_term (struct nn_queue_item *self) { nn_assert (self->next == NN_QUEUE_NOTINQUEUE); } int nn_queue_item_isinqueue (struct nn_queue_item *self) { return self->next == NN_QUEUE_NOTINQUEUE ? 0 : 1; } nanomsg-1.1.5/src/utils/queue.h000066400000000000000000000053151336111550300164060ustar00rootroot00000000000000/* Copyright (c) 2012-2014 Martin Sustrik All rights reserved. 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. */ #ifndef NN_QUEUE_INCLUDED #define NN_QUEUE_INCLUDED /* Undefined value for initialising a queue item which is not part of a queue. */ #define NN_QUEUE_NOTINQUEUE ((struct nn_queue_item*) -1) /* Use for initialising a queue item statically. */ #define NN_QUEUE_ITEM_INITIALIZER {NN_LIST_NOTINQUEUE} struct nn_queue_item { struct nn_queue_item *next; }; struct nn_queue { struct nn_queue_item *head; struct nn_queue_item *tail; }; /* Initialise the queue. */ void nn_queue_init (struct nn_queue *self); /* Terminate the queue. Note that queue must be manually emptied before the termination. */ void nn_queue_term (struct nn_queue *self); /* Returns 1 if there are no items in the queue, 0 otherwise. */ int nn_queue_empty (struct nn_queue *self); /* Inserts one element into the queue. */ void nn_queue_push (struct nn_queue *self, struct nn_queue_item *item); /* Remove the item if it is present in the queue. */ void nn_queue_remove (struct nn_queue *self, struct nn_queue_item *item); /* Retrieves one element from the queue. The element is removed from the queue. Returns NULL if the queue is empty. */ struct nn_queue_item *nn_queue_pop (struct nn_queue *self); /* Initialise a queue item. At this point it is not a part of any queue. */ void nn_queue_item_init (struct nn_queue_item *self); /* Terminate a queue item. The item must not be in a queue prior to this call. */ void nn_queue_item_term (struct nn_queue_item *self); /* Returns 1 if item is a part of a queue. 0 otherwise. */ int nn_queue_item_isinqueue (struct nn_queue_item *self); #endif nanomsg-1.1.5/src/utils/random.c000066400000000000000000000042241336111550300165330ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "random.h" #include "clock.h" #include "fast.h" #ifdef NN_HAVE_WINDOWS #include "win.h" #else #include #include #endif #include static uint64_t nn_random_state; void nn_random_seed () { uint64_t pid; #ifdef NN_HAVE_WINDOWS pid = (uint64_t) GetCurrentProcessId (); #else pid = (uint64_t) getpid (); #endif /* The initial state for pseudo-random number generator is computed from the exact timestamp and process ID. */ memcpy (&nn_random_state, "\xfa\x9b\x23\xe3\x07\xcc\x61\x1f", 8); nn_random_state ^= pid + nn_clock_ms(); } void nn_random_generate (void *buf, size_t len) { uint8_t *pos; pos = (uint8_t*) buf; while (1) { /* Generate a pseudo-random integer. */ nn_random_state = nn_random_state * 1103515245 + 12345; /* Move the bytes to the output buffer. */ memcpy (pos, &nn_random_state, len > 8 ? 8 : len); if (nn_fast (len <= 8)) return; len -= 8; pos += 8; } } nanomsg-1.1.5/src/utils/random.h000066400000000000000000000025731336111550300165450ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef NN_RANDOM_INCLUDED #define NN_RANDOM_INCLUDED #include /* Seeds the pseudorandom number generator. */ void nn_random_seed (); /* Generate a pseudorandom byte sequence. */ void nn_random_generate (void *buf, size_t len); #endif nanomsg-1.1.5/src/utils/sem.c000066400000000000000000000102261336111550300160360ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "sem.h" #include "err.h" #include "fast.h" #if defined NN_HAVE_WINDOWS void nn_sem_init (struct nn_sem *self) { self->h = CreateEvent (NULL, FALSE, FALSE, NULL); win_assert (self->h); } void nn_sem_term (struct nn_sem *self) { BOOL brc; brc = CloseHandle (self->h); win_assert (brc); } void nn_sem_post (struct nn_sem *self) { BOOL brc; brc = SetEvent (self->h); win_assert (brc); } int nn_sem_wait (struct nn_sem *self) { DWORD rc; rc = WaitForSingleObject (self->h, INFINITE); win_assert (rc != WAIT_FAILED); nn_assert (rc == WAIT_OBJECT_0); return 0; } #elif defined NN_HAVE_SEMAPHORE void nn_sem_init (struct nn_sem *self) { int rc; rc = sem_init (&self->sem, 0, 0); errno_assert (rc == 0); } void nn_sem_term (struct nn_sem *self) { int rc; rc = sem_destroy (&self->sem); errno_assert (rc == 0); } void nn_sem_post (struct nn_sem *self) { int rc; rc = sem_post (&self->sem); errno_assert (rc == 0); } int nn_sem_wait (struct nn_sem *self) { int rc; rc = sem_wait (&self->sem); if (nn_slow (rc < 0 && errno == EINTR)) return -EINTR; errno_assert (rc == 0); return 0; } #else /* Simulate semaphores with condition variables. */ void nn_sem_init (struct nn_sem *self) { int rc; rc = pthread_mutex_init (&self->mutex, NULL); errnum_assert (rc == 0, rc); rc = pthread_cond_init (&self->cond, NULL); errnum_assert (rc == 0, rc); self->signaled = 0; } void nn_sem_term (struct nn_sem *self) { int rc; rc = pthread_cond_destroy (&self->cond); errnum_assert (rc == 0, rc); rc = pthread_mutex_destroy (&self->mutex); errnum_assert (rc == 0, rc); } void nn_sem_post (struct nn_sem *self) { int rc; rc = pthread_mutex_lock (&self->mutex); errnum_assert (rc == 0, rc); nn_assert (self->signaled == 0); self->signaled = 1; rc = pthread_cond_signal (&self->cond); errnum_assert (rc == 0, rc); rc = pthread_mutex_unlock (&self->mutex); errnum_assert (rc == 0, rc); } int nn_sem_wait (struct nn_sem *self) { int rc; /* With OSX, semaphores are global named objects. They are not useful for our use case. To get a similar object we exploit the implementation detail of pthread_cond_wait() in Darwin kernel: It exits if signal is caught. Note that this behaviour is not mandated by POSIX and may break with future versions of Darwin. */ rc = pthread_mutex_lock (&self->mutex); errnum_assert (rc == 0, rc); if (nn_fast (self->signaled)) { rc = pthread_mutex_unlock (&self->mutex); errnum_assert (rc == 0, rc); return 0; } rc = pthread_cond_wait (&self->cond, &self->mutex); errnum_assert (rc == 0, rc); if (nn_slow (!self->signaled)) { rc = pthread_mutex_unlock (&self->mutex); errnum_assert (rc == 0, rc); return -EINTR; } self->signaled = 0; rc = pthread_mutex_unlock (&self->mutex); errnum_assert (rc == 0, rc); return 0; } #endif nanomsg-1.1.5/src/utils/sem.h000066400000000000000000000037321336111550300160470ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_SEM_INCLUDED #define NN_SEM_INCLUDED /* Simple semaphore. It can have only two values (0/1 i.e. locked/unlocked). */ struct nn_sem; /* Initialise the sem object. It is created in locked state. */ void nn_sem_init (struct nn_sem *self); /* Uninitialise the sem object. */ void nn_sem_term (struct nn_sem *self); /* Unlock the semaphore. */ void nn_sem_post (struct nn_sem *self); /* Waits till sem object becomes unlocked and locks it. */ int nn_sem_wait (struct nn_sem *self); #if defined NN_HAVE_WINDOWS #include "win.h" struct nn_sem { HANDLE h; }; #elif defined NN_HAVE_SEMAPHORE #include struct nn_sem { sem_t sem; }; #else /* Simulate semaphore with condition variable. */ #include struct nn_sem { pthread_mutex_t mutex; pthread_cond_t cond; int signaled; }; #endif #endif nanomsg-1.1.5/src/utils/sleep.c000066400000000000000000000030171336111550300163620ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "sleep.h" #include "err.h" #ifdef NN_HAVE_WINDOWS #include "win.h" void nn_sleep (int milliseconds) { Sleep (milliseconds); } #else #include void nn_sleep (int milliseconds) { int rc; struct timespec ts; ts.tv_sec = milliseconds / 1000; ts.tv_nsec = milliseconds % 1000 * 1000000; rc = nanosleep (&ts, NULL); errno_assert (rc == 0); } #endif nanomsg-1.1.5/src/utils/sleep.h000066400000000000000000000024271336111550300163730ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef NN_SLEEP_INCLUDED #define NN_SLEEP_INCLUDED /* Platform independent implementation of sleeping. */ void nn_sleep (int milliseconds); #endif nanomsg-1.1.5/src/utils/stopwatch.c000066400000000000000000000042601336111550300172670ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "stopwatch.h" #if defined NN_HAVE_WINDOWS #include "win.h" void nn_stopwatch_init (struct nn_stopwatch *self) { LARGE_INTEGER time; QueryPerformanceCounter (&time); self->start = (uint64_t) (time.QuadPart); } uint64_t nn_stopwatch_term (struct nn_stopwatch *self) { LARGE_INTEGER tps; LARGE_INTEGER time; QueryPerformanceFrequency (&tps); QueryPerformanceCounter (&time); return (uint64_t) ((time.QuadPart - self->start) * 1000000 / tps.QuadPart); } #else #include #include #include void nn_stopwatch_init (struct nn_stopwatch *self) { int rc; struct timeval tv; rc = gettimeofday (&tv, NULL); assert (rc == 0); self->start = (uint64_t) (((uint64_t) tv.tv_sec) * 1000000 + tv.tv_usec); } uint64_t nn_stopwatch_term (struct nn_stopwatch *self) { int rc; struct timeval tv; uint64_t end; rc = gettimeofday (&tv, NULL); assert (rc == 0); end = (uint64_t) (((uint64_t) tv.tv_sec) * 1000000 + tv.tv_usec); return end - self->start; } #endif nanomsg-1.1.5/src/utils/stopwatch.h000066400000000000000000000041141336111550300172720ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2015 Garrett D'Amore 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. */ #ifndef NN_STOPWATCH_INCLUDED #define NN_STOPWATCH_INCLUDED #include #include "err.h" /* Check whether measured time is the expected time (in microseconds). The upper tolerance is 50ms so that the test doesn't fail even on very slow or very loaded systems. Likewise on some systems we can wind up firing up to a single tick early (Windows), so the lower bound is pretty low. The consequence of this is that programs which specify a timeout should be a little more pessimistic (at least 10ms) then they might otherwise think they need to be. */ #define time_assert(actual,expected) \ nn_assert (actual > ((expected) - 10000) && actual < ((expected) + 50000)); /* Measures time interval in microseconds. */ struct nn_stopwatch { uint64_t start; }; void nn_stopwatch_init (struct nn_stopwatch *self); uint64_t nn_stopwatch_term (struct nn_stopwatch *self); #endif nanomsg-1.1.5/src/utils/strcasecmp.c000066400000000000000000000026071336111550300174220ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. */ #include #include "strcasecmp.h" int nn_strcasecmp(const char *a, const char *b) { int rv; for (;;) { if ((*a == 0) && (*b == 0)) { return (0); } if ((rv = (tolower(*a) - tolower(*b))) != 0) { return (rv); } a++; b++; } return (0); } nanomsg-1.1.5/src/utils/strcasecmp.h000066400000000000000000000024251336111550300174250ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_STRCASECMP_INCLUDED #define NN_STRCASECMP_INCLUDED extern int nn_strcasecmp(const char *, const char *); #endif /* NN_STRCASECMP_INCLUDED */ nanomsg-1.1.5/src/utils/strcasestr.c000066400000000000000000000026151336111550300174520ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. */ #include #include #include "strncasecmp.h" const char * nn_strcasestr(const char *str, const char *key) { size_t len = strlen(key); while (*str != '\0') { if (nn_strncasecmp(str, key, len) == 0) { return str; } str++; } return (NULL); } nanomsg-1.1.5/src/utils/strcasestr.h000066400000000000000000000024241336111550300174550ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. */ #ifndef NN_STRCASESTR_INCLUDED #define NN_STRCASESTR_INCLUDED extern const char *nn_strcasestr(const char *, const char *); #endif /* NN_STRCASESTR */ nanomsg-1.1.5/src/utils/strncasecmp.c000066400000000000000000000026761336111550300176060ustar00rootroot00000000000000/* Copyright 2017 Garrett D'Amore 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. */ #include #include "strncasecmp.h" int nn_strncasecmp(const char *a, const char *b, size_t len) { int rv; size_t count; for (count = 0; count < len; count++) { if ((*a == 0) && (*b == 0)) { return (0); } if ((rv = tolower(*a) - tolower(*b)) != 0) { return (rv); } a++; b++; } return (0); } nanomsg-1.1.5/src/utils/strncasecmp.h000066400000000000000000000024661336111550300176100ustar00rootroot00000000000000/* Copyright 2017 Garrett D'Amore 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. */ #ifndef NN_STRNCASECMP_INCLUDED #define NN_STRNCASECMP_INCLUDED #include extern int nn_strncasecmp(const char *, const char *, size_t); #endif /* NN_STRNCASECMP_INCLUDED */ nanomsg-1.1.5/src/utils/thread.c000066400000000000000000000023631336111550300165240ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "thread.h" #ifdef NN_HAVE_WINDOWS #include "thread_win.inc" #else #include "thread_posix.inc" #endif nanomsg-1.1.5/src/utils/thread.h000066400000000000000000000030141336111550300165230ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_THREAD_INCLUDED #define NN_THREAD_INCLUDED /* Platform independent implementation of threading. */ typedef void (nn_thread_routine) (void*); #if defined NN_HAVE_WINDOWS #include "thread_win.h" #else #include "thread_posix.h" #endif void nn_thread_init (struct nn_thread *self, nn_thread_routine *routine, void *arg); void nn_thread_term (struct nn_thread *self); #endif nanomsg-1.1.5/src/utils/thread_posix.h000066400000000000000000000023601336111550300177500ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include struct nn_thread { nn_thread_routine *routine; void *arg; pthread_t handle; }; nanomsg-1.1.5/src/utils/thread_posix.inc000066400000000000000000000046101336111550300202720ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. Copyright (c) 2014 Achille Roussel All rights reserved. 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. */ #include "err.h" #include static void *nn_thread_main_routine (void *arg) { struct nn_thread *self; self = (struct nn_thread*) arg; /* Run the thread routine. */ self->routine (self->arg); return NULL; } void nn_thread_init (struct nn_thread *self, nn_thread_routine *routine, void *arg) { int rc; sigset_t new_sigmask; sigset_t old_sigmask; /* No signals should be processed by this thread. The library doesn't use signals and thus all the signals should be delivered to application threads, not to worker threads. */ rc = sigfillset (&new_sigmask); errno_assert (rc == 0); rc = pthread_sigmask (SIG_BLOCK, &new_sigmask, &old_sigmask); errnum_assert (rc == 0, rc); self->routine = routine; self->arg = arg; rc = pthread_create (&self->handle, NULL, nn_thread_main_routine, (void*) self); errnum_assert (rc == 0, rc); /* Restore signal set to what it was before. */ rc = pthread_sigmask (SIG_SETMASK, &old_sigmask, NULL); errnum_assert (rc == 0, rc); } void nn_thread_term (struct nn_thread *self) { int rc; rc = pthread_join (self->handle, NULL); errnum_assert (rc == 0, rc); } nanomsg-1.1.5/src/utils/thread_win.h000066400000000000000000000023511336111550300174030ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "win.h" struct nn_thread { nn_thread_routine *routine; void *arg; HANDLE handle; }; nanomsg-1.1.5/src/utils/thread_win.inc000066400000000000000000000035231336111550300177270ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "err.h" static unsigned int __stdcall nn_thread_main_routine (void *arg) { struct nn_thread *self; self = (struct nn_thread*) arg; self->routine (self->arg); return 0; } void nn_thread_init (struct nn_thread *self, nn_thread_routine *routine, void *arg) { self->routine = routine; self->arg = arg; self->handle = (HANDLE) _beginthreadex (NULL, 0, nn_thread_main_routine, (void*) self, 0 , NULL); win_assert (self->handle != NULL); } void nn_thread_term (struct nn_thread *self) { DWORD rc; BOOL brc; rc = WaitForSingleObject (self->handle, INFINITE); win_assert (rc != WAIT_FAILED); brc = CloseHandle (self->handle); win_assert (brc != 0); } nanomsg-1.1.5/src/utils/win.h000066400000000000000000000030761336111550300160610ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #ifndef NN_WIN_INCLUDED #define NN_WIN_INCLUDED #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include #include #include #include /* This structure does not exist on Windows platform. Let's fake it. */ struct sockaddr_un { short sun_family; char sun_path [sizeof (struct sockaddr_storage) - sizeof (short)]; }; #define ssize_t int #endif nanomsg-1.1.5/src/utils/wire.c000066400000000000000000000052371336111550300162260ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #include "wire.h" #if defined NN_HAVE_WINDOWS #include "win.h" #else #include #endif uint16_t nn_gets (const uint8_t *buf) { return (((uint16_t) buf [0]) << 8) | ((uint16_t) buf [1]); } void nn_puts (uint8_t *buf, uint16_t val) { buf [0] = (uint8_t) (((val) >> 8) & 0xff); buf [1] = (uint8_t) (val & 0xff); } uint32_t nn_getl (const uint8_t *buf) { return (((uint32_t) buf [0]) << 24) | (((uint32_t) buf [1]) << 16) | (((uint32_t) buf [2]) << 8) | ((uint32_t) buf [3]); } void nn_putl (uint8_t *buf, uint32_t val) { buf [0] = (uint8_t) (((val) >> 24) & 0xff); buf [1] = (uint8_t) (((val) >> 16) & 0xff); buf [2] = (uint8_t) (((val) >> 8) & 0xff); buf [3] = (uint8_t) (val & 0xff); } uint64_t nn_getll (const uint8_t *buf) { return (((uint64_t) buf [0]) << 56) | (((uint64_t) buf [1]) << 48) | (((uint64_t) buf [2]) << 40) | (((uint64_t) buf [3]) << 32) | (((uint64_t) buf [4]) << 24) | (((uint64_t) buf [5]) << 16) | (((uint64_t) buf [6]) << 8) | (((uint64_t) buf [7] << 0)); } void nn_putll (uint8_t *buf, uint64_t val) { buf [0] = (uint8_t) ((val >> 56) & 0xff); buf [1] = (uint8_t) ((val >> 48) & 0xff); buf [2] = (uint8_t) ((val >> 40) & 0xff); buf [3] = (uint8_t) ((val >> 32) & 0xff); buf [4] = (uint8_t) ((val >> 24) & 0xff); buf [5] = (uint8_t) ((val >> 16) & 0xff); buf [6] = (uint8_t) ((val >> 8) & 0xff); buf [7] = (uint8_t) (val & 0xff); } nanomsg-1.1.5/src/utils/wire.h000066400000000000000000000027151336111550300162310ustar00rootroot00000000000000/* Copyright (c) 2012-2013 Martin Sustrik All rights reserved. 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. */ #ifndef NN_WIRE_INCLUDED #define NN_WIRE_INCLUDED #include uint16_t nn_gets (const uint8_t *buf); void nn_puts (uint8_t *buf, uint16_t val); uint32_t nn_getl (const uint8_t *buf); void nn_putl (uint8_t *buf, uint32_t val); uint64_t nn_getll (const uint8_t *buf); void nn_putll (uint8_t *buf, uint64_t val); #endif nanomsg-1.1.5/src/ws.h000066400000000000000000000033761336111550300145600ustar00rootroot00000000000000/* Copyright (c) 2012 250bpm s.r.o. All rights reserved. Copyright (c) 2014 Wirebird Labs LLC. All rights reserved. Copyright 2015 Garrett D'Amore 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. */ #ifndef WS_H_INCLUDED #define WS_H_INCLUDED #include "nn.h" #ifdef __cplusplus extern "C" { #endif #define NN_WS -4 /* NN_WS level socket/cmsg options. Note that only NN_WSMG_TYPE_TEXT and NN_WS_MSG_TYPE_BINARY messages are supported fully by this implementation. Attempting to set other message types is undefined. */ #define NN_WS_MSG_TYPE 1 /* WebSocket opcode constants as per RFC 6455 5.2 */ #define NN_WS_MSG_TYPE_TEXT 0x01 #define NN_WS_MSG_TYPE_BINARY 0x02 #ifdef __cplusplus } #endif #endif nanomsg-1.1.5/tests/000077500000000000000000000000001336111550300143205ustar00rootroot00000000000000nanomsg-1.1.5/tests/README000066400000000000000000000007021336111550300151770ustar00rootroot00000000000000This directory contains automatic tests for nanomsg library. To run the tests do "make test" in the build directory, or alternatively run ctest. Note that the code here is probably ill-suited for demonstration purposes, as it is primarily oriented towards testing the library, rather than serving as any sort of example. Instead, we recommend looking in ../demo for some example programs that demonstrate the API as we feel it is meant to be used. nanomsg-1.1.5/tests/async_shutdown.c000066400000000000000000000047451336111550300175460ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2015 Jack R. Dunaway. All rights reserved. Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/pubsub.h" #include "../src/pipeline.h" #include "../src/tcp.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" #include "../src/utils/atomic.c" /* Test condition of closing sockets that are blocking in another thread. */ #define TEST_LOOPS 10 struct nn_atomic active; static void routine (NN_UNUSED void *arg) { int s; int rc; int msg; nn_assert (arg); s = *((int *) arg); /* We don't expect to actually receive a message here; therefore, the datatype of 'msg' is irrelevant. */ rc = nn_recv (s, &msg, sizeof(msg), 0); errno_assert (rc == -1 && nn_errno () == EBADF); } int main (int argc, const char *argv[]) { int sb; int i; struct nn_thread thread; char socket_address[128]; test_addr_from(socket_address, "tcp", "127.0.0.1", get_test_port(argc, argv)); for (i = 0; i != TEST_LOOPS; ++i) { sb = test_socket (AF_SP, NN_PULL); test_bind (sb, socket_address); nn_sleep (100); nn_thread_init (&thread, routine, &sb); nn_sleep (100); test_close (sb); nn_thread_term (&thread); } return 0; } nanomsg-1.1.5/tests/block.c000066400000000000000000000040641336111550300155620ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" /* This test checks whether blocking on send/recv works as expected. */ #define SOCKET_ADDRESS "inproc://a" int sc; int sb; void worker (NN_UNUSED void *arg) { /* Wait 0.1 sec for the main thread to block. */ nn_sleep (100); test_send (sc, "ABC"); /* Wait 0.1 sec for the main thread to process the previous message and block once again. */ nn_sleep (100); test_send (sc, "ABC"); } int main () { struct nn_thread thread; sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); nn_thread_init (&thread, worker, NULL); test_recv (sb, "ABC"); test_recv (sb, "ABC"); nn_thread_term (&thread); test_close (sc); test_close (sb); return 0; } nanomsg-1.1.5/tests/bug328.c000066400000000000000000000037151336111550300155040ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2016 Franklin "Snaipe" Mathieu Copyright 2016 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "testutil.h" int main (int argc, const char *argv[]) { int sb; int sc; char socket_address[128]; test_addr_from(socket_address, "tcp", "127.0.0.1", get_test_port(argc, argv)); sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, socket_address); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, socket_address); nn_sleep(100); test_send (sc, "ABC"); test_recv (sb, "ABC"); nn_assert (nn_get_statistic (sc, NN_STAT_CURRENT_CONNECTIONS) == 1); test_close (sb); nn_sleep(300); nn_assert (nn_get_statistic (sc, NN_STAT_CURRENT_CONNECTIONS) == 0); test_close (sc); return 0; } nanomsg-1.1.5/tests/bug777.c000066400000000000000000000032371336111550300155130ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "testutil.h" int main (NN_UNUSED int argc, const NN_UNUSED char *argv[]) { int sb; int sc1; int sc2; sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, "inproc://pair"); sc1 = test_socket (AF_SP, NN_PAIR); test_connect (sc1, "inproc://pair"); sc2 = test_socket (AF_SP, NN_PAIR); test_connect (sc2, "inproc://pair"); test_send (sb, "HELLO"); test_recv (sc1, "HELLO"); test_send (sc1, "THERE"); test_recv (sb, "THERE"); return 0; } nanomsg-1.1.5/tests/bus.c000066400000000000000000000052451336111550300152630ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/bus.h" #include "testutil.h" #define SOCKET_ADDRESS_A "inproc://a" #define SOCKET_ADDRESS_B "inproc://b" int main () { int rc; int bus1; int bus2; int bus3; char buf [3]; /* Create a simple bus topology consisting of 3 nodes. */ bus1 = test_socket (AF_SP, NN_BUS); test_bind (bus1, SOCKET_ADDRESS_A); bus2 = test_socket (AF_SP, NN_BUS); test_bind (bus2, SOCKET_ADDRESS_B); test_connect (bus2, SOCKET_ADDRESS_A); bus3 = test_socket (AF_SP, NN_BUS); test_connect (bus3, SOCKET_ADDRESS_A); test_connect (bus3, SOCKET_ADDRESS_B); /* Send a message from each node. */ test_send (bus1, "A"); test_send (bus2, "AB"); test_send (bus3, "ABC"); /* Check that two messages arrived at each node. */ rc = nn_recv (bus1, buf, 3, 0); errno_assert (rc >= 0); nn_assert (rc == 2 || rc == 3); rc = nn_recv (bus1, buf, 3, 0); errno_assert (rc >= 0); nn_assert (rc == 2 || rc == 3); rc = nn_recv (bus2, buf, 3, 0); errno_assert (rc >= 0); nn_assert (rc == 1 || rc == 3); rc = nn_recv (bus2, buf, 3, 0); errno_assert (rc >= 0); nn_assert (rc == 1 || rc == 3); rc = nn_recv (bus3, buf, 3, 0); errno_assert (rc >= 0); nn_assert (rc == 1 || rc == 2); rc = nn_recv (bus3, buf, 3, 0); errno_assert (rc >= 0); nn_assert (rc == 1 || rc == 2); /* Wait till both connections are established. */ nn_sleep (10); test_close (bus3); test_close (bus2); test_close (bus1); return 0; } nanomsg-1.1.5/tests/cmsg.c000066400000000000000000000071301336111550300154160ustar00rootroot00000000000000/* Copyright (c) 2014 Martin Sustrik All rights reserved. Copyright 2015 Garrett D'Amore Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/tcp.h" #include "../src/reqrep.h" #include "testutil.h" int main (int argc, const char *argv[]) { int rc; int rep; int req; struct nn_msghdr hdr; struct nn_iovec iovec; unsigned char body [3]; unsigned char ctrl [256]; struct nn_cmsghdr *cmsg; unsigned char *data; void *buf; char socket_address[128]; test_addr_from(socket_address, "tcp", "127.0.0.1", get_test_port(argc, argv)); rep = test_socket (AF_SP_RAW, NN_REP); test_bind (rep, socket_address); req = test_socket (AF_SP, NN_REQ); test_connect (req, socket_address); /* Test ancillary data in static buffer. */ test_send (req, "ABC"); iovec.iov_base = body; iovec.iov_len = sizeof (body); hdr.msg_iov = &iovec; hdr.msg_iovlen = 1; hdr.msg_control = ctrl; hdr.msg_controllen = sizeof (ctrl); rc = nn_recvmsg (rep, &hdr, 0); errno_assert (rc == 3); cmsg = NN_CMSG_FIRSTHDR (&hdr); while (1) { nn_assert (cmsg); if (cmsg->cmsg_level == PROTO_SP && cmsg->cmsg_type == SP_HDR) break; cmsg = NN_CMSG_NXTHDR (&hdr, cmsg); } nn_assert (cmsg->cmsg_len == NN_CMSG_SPACE (8+sizeof (size_t))); data = NN_CMSG_DATA (cmsg); nn_assert (!(data[0+sizeof (size_t)] & 0x80)); nn_assert (data[4+sizeof (size_t)] & 0x80); rc = nn_sendmsg (rep, &hdr, 0); nn_assert (rc == 3); test_recv (req, "ABC"); /* Test ancillary data in dynamically allocated buffer (NN_MSG). */ test_send (req, "ABC"); iovec.iov_base = body; iovec.iov_len = sizeof (body); hdr.msg_iov = &iovec; hdr.msg_iovlen = 1; hdr.msg_control = &buf; hdr.msg_controllen = NN_MSG; rc = nn_recvmsg (rep, &hdr, 0); errno_assert (rc == 3); cmsg = NN_CMSG_FIRSTHDR (&hdr); while (1) { nn_assert (cmsg); if (cmsg->cmsg_level == PROTO_SP && cmsg->cmsg_type == SP_HDR) break; cmsg = NN_CMSG_NXTHDR (&hdr, cmsg); } nn_assert (cmsg->cmsg_len == NN_CMSG_SPACE (8+sizeof (size_t))); data = NN_CMSG_DATA (cmsg); nn_assert (!(data[0+sizeof (size_t)] & 0x80)); nn_assert (data[4+sizeof (size_t)] & 0x80); rc = nn_sendmsg (rep, &hdr, 0); nn_assert (rc == 3); test_recv (req, "ABC"); test_close (req); test_close (rep); return 0; } nanomsg-1.1.5/tests/device.c000066400000000000000000000121461336111550300157270ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. 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. */ #include "../src/nn.h" #include "../src/bus.h" #include "../src/pair.h" #include "../src/pipeline.h" #include "../src/inproc.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" #define SOCKET_ADDRESS_A "inproc://a" #define SOCKET_ADDRESS_B "inproc://b" #define SOCKET_ADDRESS_C "inproc://c" #define SOCKET_ADDRESS_D "inproc://d" #define SOCKET_ADDRESS_E "inproc://e" void device1 (NN_UNUSED void *arg) { int rc; int deva; int devb; /* Intialise the device sockets. */ deva = test_socket (AF_SP_RAW, NN_PAIR); test_bind (deva, SOCKET_ADDRESS_A); devb = test_socket (AF_SP_RAW, NN_PAIR); test_bind (devb, SOCKET_ADDRESS_B); /* Run the device. */ rc = nn_device (deva, devb); nn_assert (rc < 0 && (nn_errno () == EBADF)); /* Clean up. */ test_close (devb); test_close (deva); } void device2 (NN_UNUSED void *arg) { int rc; int devc; int devd; /* Intialise the device sockets. */ devc = test_socket (AF_SP_RAW, NN_PULL); test_bind (devc, SOCKET_ADDRESS_C); devd = test_socket (AF_SP_RAW, NN_PUSH); test_bind (devd, SOCKET_ADDRESS_D); /* Run the device. */ rc = nn_device (devc, devd); nn_assert (rc < 0 && nn_errno () == EBADF); /* Clean up. */ test_close (devd); test_close (devc); } void device3 (NN_UNUSED void *arg) { int rc; int deve; /* Intialise the device socket. */ deve = test_socket (AF_SP_RAW, NN_BUS); test_bind (deve, SOCKET_ADDRESS_E); /* Run the device. */ rc = nn_device (deve, -1); nn_assert (rc < 0 && nn_errno () == EBADF); /* Clean up. */ test_close (deve); } int main () { int enda; int endb; int endc; int endd; int ende1; int ende2; struct nn_thread thread1; struct nn_thread thread2; struct nn_thread thread3; int timeo; /* Test the bi-directional device. */ /* Start the device. */ nn_thread_init (&thread1, device1, NULL); /* Create two sockets to connect to the device. */ enda = test_socket (AF_SP, NN_PAIR); test_connect (enda, SOCKET_ADDRESS_A); endb = test_socket (AF_SP, NN_PAIR); test_connect (endb, SOCKET_ADDRESS_B); /* Pass a pair of messages between endpoints. */ test_send (enda, "ABC"); test_recv (endb, "ABC"); test_send (endb, "ABC"); test_recv (enda, "ABC"); /* Clean up. */ test_close (endb); test_close (enda); /* Test the uni-directional device. */ /* Start the device. */ nn_thread_init (&thread2, device2, NULL); /* Create two sockets to connect to the device. */ endc = test_socket (AF_SP, NN_PUSH); test_connect (endc, SOCKET_ADDRESS_C); endd = test_socket (AF_SP, NN_PULL); test_connect (endd, SOCKET_ADDRESS_D); /* Pass a message between endpoints. */ test_send (endc, "XYZ"); test_recv (endd, "XYZ"); /* Clean up. */ test_close (endd); test_close (endc); /* Test the loopback device. */ /* Start the device. */ nn_thread_init (&thread3, device3, NULL); /* Create two sockets to connect to the device. */ ende1 = test_socket (AF_SP, NN_BUS); test_connect (ende1, SOCKET_ADDRESS_E); ende2 = test_socket (AF_SP, NN_BUS); test_connect (ende2, SOCKET_ADDRESS_E); /* BUS is unreliable so wait a bit for connections to be established. */ nn_sleep (100); /* Pass a message to the bus. */ test_send (ende1, "KLM"); test_recv (ende2, "KLM"); /* Make sure that the message doesn't arrive at the socket it was originally sent to. */ timeo = 100; test_setsockopt (ende1, NN_SOL_SOCKET, NN_RCVTIMEO, &timeo, sizeof (timeo)); test_drop (ende1, ETIMEDOUT); /* Clean up. */ test_close (ende2); test_close (ende1); /* Shut down the devices. */ nn_term (); nn_thread_term (&thread1); nn_thread_term (&thread2); nn_thread_term (&thread3); return 0; } nanomsg-1.1.5/tests/device4.c000066400000000000000000000060361336111550300160140ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2015 Garrett D'Amore Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/reqrep.h" #include "../src/tcp.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" static char socket_address_f[128], socket_address_g[128]; void device4 (NN_UNUSED void *arg) { int rc; int devf; int devg; /* Intialise the device sockets. */ devf = test_socket (AF_SP_RAW, NN_REP); test_bind (devf, socket_address_f); devg = test_socket (AF_SP_RAW, NN_REQ); test_bind (devg, socket_address_g); /* Run the device. */ rc = nn_device (devf, devg); nn_assert (rc < 0 && (nn_errno () == EBADF)); /* Clean up. */ test_close (devg); test_close (devf); } int main (int argc, const char *argv[]) { int endf; int endg; struct nn_thread thread4; int port = get_test_port(argc, argv); test_addr_from(socket_address_f, "tcp", "127.0.0.1", port); test_addr_from(socket_address_g, "tcp", "127.0.0.1", port + 1); /* Test the bi-directional device with REQ/REP (headers). */ /* Start the device. */ nn_thread_init (&thread4, device4, NULL); /* Create two sockets to connect to the device. */ endf = test_socket (AF_SP, NN_REQ); test_connect (endf, socket_address_f); endg = test_socket (AF_SP, NN_REP); test_connect (endg, socket_address_g); /* Wait for TCP to establish. */ nn_sleep (100); /* Pass a message between endpoints. */ test_send (endf, "XYZ"); test_recv (endg, "XYZ"); /* Now send a reply. */ test_send (endg, "REPLYXYZ"); test_recv (endf, "REPLYXYZ"); /* Clean up. */ test_close (endg); test_close (endf); /* Shut down the devices. */ nn_term (); nn_thread_term (&thread4); return 0; } nanomsg-1.1.5/tests/device5.c000066400000000000000000000072201336111550300160110ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2015 Garrett D'Amore Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/reqrep.h" #include "../src/tcp.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" static char socket_address_h[128], socket_address_i[128], socket_address_j[128]; void device5 (NN_UNUSED void *arg) { int rc; int dev0; int dev1; /* Intialise the device sockets. */ dev0 = test_socket (AF_SP_RAW, NN_REP); test_bind (dev0, socket_address_h); dev1 = test_socket (AF_SP_RAW, NN_REQ); test_bind (dev1, socket_address_i); /* Run the device. */ rc = nn_device (dev0, dev1); nn_assert (rc < 0 && nn_errno () == EBADF); /* Clean up. */ test_close (dev0); test_close (dev1); } void device6 (NN_UNUSED void *arg) { int rc; int dev2; int dev3; dev2 = test_socket (AF_SP_RAW, NN_REP); test_connect (dev2, socket_address_i); dev3 = test_socket (AF_SP_RAW, NN_REQ); test_bind (dev3, socket_address_j); /* Run the device. */ rc = nn_device (dev2, dev3); nn_assert (rc < 0 && nn_errno () == EBADF); /* Clean up. */ test_close (dev2); test_close (dev3); } int main (int argc, const char *argv[]) { int end0; int end1; struct nn_thread thread5; struct nn_thread thread6; int port = get_test_port(argc, argv); test_addr_from(socket_address_h, "tcp", "127.0.0.1", port); test_addr_from(socket_address_i, "tcp", "127.0.0.1", port + 1); test_addr_from(socket_address_j, "tcp", "127.0.0.1", port + 2); /* Test the bi-directional device with REQ/REP (headers). */ /* Start the devices. */ nn_thread_init (&thread5, device5, NULL); nn_thread_init (&thread6, device6, NULL); /* Create two sockets to connect to the device. */ end0 = test_socket (AF_SP, NN_REQ); test_connect (end0, socket_address_h); end1 = test_socket (AF_SP, NN_REP); test_connect (end1, socket_address_j); /* Wait for TCP to establish. */ nn_sleep (100); /* Pass a message between endpoints. */ test_send (end0, "XYZ"); test_recv (end1, "XYZ"); /* Now send a reply. */ test_send (end1, "REPLYXYZ"); test_recv (end0, "REPLYXYZ"); /* Clean up. */ test_close (end0); test_close (end1); /* Shut down the devices. */ nn_term (); nn_thread_term (&thread5); nn_thread_term (&thread6); return 0; } nanomsg-1.1.5/tests/device6.c000066400000000000000000000073041336111550300160150ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2015 Garrett D'Amore Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/survey.h" #include "../src/tcp.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" static char socket_address_h[128], socket_address_i[128], socket_address_j[128]; void device5 (NN_UNUSED void *arg) { int rc; int dev0; int dev1; /* Intialise the device sockets. */ dev0 = test_socket (AF_SP_RAW, NN_RESPONDENT); test_bind (dev0, socket_address_h); dev1 = test_socket (AF_SP_RAW, NN_SURVEYOR); test_bind (dev1, socket_address_i); /* Run the device. */ rc = nn_device (dev0, dev1); nn_assert (rc < 0 && nn_errno () == EBADF); /* Clean up. */ test_close (dev0); test_close (dev1); } void device6 (NN_UNUSED void *arg) { int rc; int dev2; int dev3; dev2 = test_socket (AF_SP_RAW, NN_RESPONDENT); test_connect (dev2, socket_address_i); dev3 = test_socket (AF_SP_RAW, NN_SURVEYOR); test_bind (dev3, socket_address_j); /* Run the device. */ rc = nn_device (dev2, dev3); nn_assert (rc < 0 && nn_errno () == EBADF); /* Clean up. */ test_close (dev2); test_close (dev3); } int main (int argc, const char *argv[]) { int end0; int end1; struct nn_thread thread5; struct nn_thread thread6; int port = get_test_port(argc, argv); test_addr_from(socket_address_h, "tcp", "127.0.0.1", port); test_addr_from(socket_address_i, "tcp", "127.0.0.1", port + 1); test_addr_from(socket_address_j, "tcp", "127.0.0.1", port + 2); /* Test the bi-directional device with SURVEYOR(headers). */ /* Start the devices. */ nn_thread_init (&thread5, device5, NULL); nn_thread_init (&thread6, device6, NULL); /* Create two sockets to connect to the device. */ end0 = test_socket (AF_SP, NN_SURVEYOR); test_connect (end0, socket_address_h); end1 = test_socket (AF_SP, NN_RESPONDENT); test_connect (end1, socket_address_j); /* Wait up to a second for TCP to establish. */ nn_sleep (1000); /* Pass a message between endpoints. */ test_send (end0, "XYZ"); test_recv (end1, "XYZ"); /* Now send a reply. */ test_send (end1, "REPLYXYZ"); test_recv (end0, "REPLYXYZ"); /* Clean up. */ test_close (end0); test_close (end1); /* Shut down the devices. */ nn_term (); nn_thread_term (&thread5); nn_thread_term (&thread6); return 0; } nanomsg-1.1.5/tests/device7.c000066400000000000000000000071751336111550300160240ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2015 Garrett D'Amore Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/reqrep.h" #include "../src/tcp.h" #include "../src/inproc.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" #define SOCKET_ADDRESS_I "inproc://nobody" static char socket_address_h[128], socket_address_j[128]; void device5 (NN_UNUSED void *arg) { int rc; int dev0; int dev1; /* Intialise the device sockets. */ dev0 = test_socket (AF_SP_RAW, NN_REP); test_bind (dev0, socket_address_h); dev1 = test_socket (AF_SP_RAW, NN_REQ); test_bind (dev1, SOCKET_ADDRESS_I); /* Run the device. */ rc = nn_device (dev0, dev1); nn_assert (rc < 0 && nn_errno () == EBADF); /* Clean up. */ test_close (dev0); test_close (dev1); } void device6 (NN_UNUSED void *arg) { int rc; int dev2; int dev3; dev2 = test_socket (AF_SP_RAW, NN_REP); test_connect (dev2, SOCKET_ADDRESS_I); dev3 = test_socket (AF_SP_RAW, NN_REQ); test_bind (dev3, socket_address_j); /* Run the device. */ rc = nn_device (dev2, dev3); nn_assert (rc < 0 && nn_errno () == EBADF); /* Clean up. */ test_close (dev2); test_close (dev3); } int main (int argc, const char *argv[]) { int end0; int end1; struct nn_thread thread5; struct nn_thread thread6; int port = get_test_port(argc, argv); test_addr_from(socket_address_h, "tcp", "127.0.0.1", port); test_addr_from(socket_address_j, "tcp", "127.0.0.1", port + 1); /* Test the bi-directional device with REQ/REP (headers). */ /* Start the devices. */ nn_thread_init (&thread5, device5, NULL); nn_thread_init (&thread6, device6, NULL); /* Create two sockets to connect to the device. */ end0 = test_socket (AF_SP, NN_REQ); test_connect (end0, socket_address_h); end1 = test_socket (AF_SP, NN_REP); test_connect (end1, socket_address_j); /* Wait for TCP to establish. */ nn_sleep (1000); /* Pass a message between endpoints. */ test_send (end0, "XYZ"); test_recv (end1, "XYZ"); /* Now send a reply. */ test_send (end1, "REPLYXYZ"); test_recv (end0, "REPLYXYZ"); /* Clean up. */ test_close (end0); test_close (end1); /* Shut down the devices. */ nn_term (); nn_thread_term (&thread5); nn_thread_term (&thread6); return 0; } nanomsg-1.1.5/tests/domain.c000066400000000000000000000034071336111550300157370ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "testutil.h" /* Test the NN_DOMAIN and NN_PROTOCOL socket options. */ int main () { int rc; int s; int op; size_t opsz; s = test_socket (AF_SP, NN_PAIR); opsz = sizeof (op); rc = nn_getsockopt (s, NN_SOL_SOCKET, NN_DOMAIN, &op, &opsz); errno_assert (rc == 0); nn_assert (opsz == sizeof (op)); nn_assert (op == AF_SP); opsz = sizeof (op); rc = nn_getsockopt (s, NN_SOL_SOCKET, NN_PROTOCOL, &op, &opsz); errno_assert (rc == 0); nn_assert (opsz == sizeof (op)); nn_assert (op == NN_PAIR); test_close (s); return 0; } nanomsg-1.1.5/tests/emfile.c000066400000000000000000000033541336111550300157320ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/tcp.h" #include "../src/utils/err.c" #define MAX_SOCKETS 1000 int main () { int rc; int i; int socks [MAX_SOCKETS]; /* First, just create as much SP sockets as possible. */ for (i = 0; i != MAX_SOCKETS; ++i) { socks [i] = nn_socket (AF_SP, NN_PAIR); if (socks [i] < 0) { errno_assert (nn_errno () == EMFILE); break; } } while (1) { --i; if (i == -1) break; rc = nn_close (socks [i]); errno_assert (rc == 0); } return 0; } nanomsg-1.1.5/tests/hash.c000066400000000000000000000041201336111550300154040ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "../src/utils/err.c" #include "../src/utils/list.c" #include "../src/utils/hash.c" #include "../src/utils/alloc.c" int main () { struct nn_hash hash; uint32_t k; struct nn_hash_item *item; struct nn_hash_item *item5000 = NULL; nn_hash_init (&hash); /* Insert 10000 elements into the hash table. */ for (k = 0; k != 10000; ++k) { item = nn_alloc (sizeof (struct nn_hash_item), "item"); nn_assert (item); if (k == 5000) item5000 = item; nn_hash_item_init (item); nn_hash_insert (&hash, k, item); } /* Find one element and check whether it is the correct one. */ nn_assert (nn_hash_get (&hash, 5000) == item5000); /* Remove all the elements from the hash table and terminate it. */ for (k = 0; k != 10000; ++k) { item = nn_hash_get (&hash, k); nn_hash_erase (&hash, item); nn_free (item); } nn_hash_term (&hash); return 0; } nanomsg-1.1.5/tests/inproc.c000066400000000000000000000141271336111550300157630ustar00rootroot00000000000000 /* Copyright (c) 2012 Martin Sustrik All rights reserved. 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 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. */ #include "../src/nn.h" #include "../src/bus.h" #include "../src/pair.h" #include "../src/pubsub.h" #include "../src/reqrep.h" #include "../src/inproc.h" #include "testutil.h" /* Tests inproc transport. */ #define SOCKET_ADDRESS "inproc://test" int main () { int rc; int sb; int sc; int s1, s2; int i; char buf [256]; int val; struct nn_msghdr hdr; struct nn_iovec iovec; unsigned char body [3]; void *control; struct nn_cmsghdr *cmsg; unsigned char *data; /* Create a simple topology. */ sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); /* Try a duplicate bind. It should fail. */ rc = nn_bind (sc, SOCKET_ADDRESS); nn_assert (rc < 0 && errno == EADDRINUSE); /* Ping-pong test. */ for (i = 0; i != 100; ++i) { test_send (sc, "ABC"); test_recv (sb, "ABC"); test_send (sb, "DEFG"); test_recv (sc, "DEFG"); } /* Batch transfer test. */ for (i = 0; i != 100; ++i) { test_send (sc, "XYZ"); } for (i = 0; i != 100; ++i) { test_recv (sb, "XYZ"); } test_close (sc); test_close (sb); /* Test whether queue limits are observed. */ sb = test_socket (AF_SP, NN_PAIR); val = 200; test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVBUF, &val, sizeof (val)); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); val = 200; test_setsockopt (sc, NN_SOL_SOCKET, NN_SNDTIMEO, &val, sizeof (val)); i = 0; while (1) { rc = nn_send (sc, "0123456789", 10, 0); if (rc < 0 && nn_errno () == ETIMEDOUT) break; errno_assert (rc >= 0); nn_assert (rc == 10); ++i; } nn_assert (i == 20); test_recv (sb, "0123456789"); test_send (sc, "0123456789"); rc = nn_send (sc, "0123456789", 10, 0); nn_assert (rc < 0 && nn_errno () == ETIMEDOUT); for (i = 0; i != 20; ++i) { test_recv (sb, "0123456789"); } /* Make sure that even a message that doesn't fit into the buffers gets across. */ for (i = 0; i != sizeof (buf); ++i) buf [i] = 'A'; rc = nn_send (sc, buf, 256, 0); errno_assert (rc >= 0); nn_assert (rc == 256); rc = nn_recv (sb, buf, sizeof (buf), 0); errno_assert (rc >= 0); nn_assert (rc == 256); test_close (sc); test_close (sb); #if 0 /* Test whether connection rejection is handled decently. */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); s1 = test_socket (AF_SP, NN_PAIR); test_connect (s1, SOCKET_ADDRESS); s2 = test_socket (AF_SP, NN_PAIR); test_connect (s2, SOCKET_ADDRESS); nn_sleep (100); test_close (s2); test_close (s1); test_close (sb); #endif /* Check whether SP message header is transferred correctly. */ sb = test_socket (AF_SP_RAW, NN_REP); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_REQ); test_connect (sc, SOCKET_ADDRESS); test_send (sc, "ABC"); iovec.iov_base = body; iovec.iov_len = sizeof (body); hdr.msg_iov = &iovec; hdr.msg_iovlen = 1; hdr.msg_control = &control; hdr.msg_controllen = NN_MSG; rc = nn_recvmsg (sb, &hdr, 0); errno_assert (rc == 3); cmsg = NN_CMSG_FIRSTHDR (&hdr); while (1) { nn_assert (cmsg); if (cmsg->cmsg_level == PROTO_SP && cmsg->cmsg_type == SP_HDR) break; cmsg = NN_CMSG_NXTHDR (&hdr, cmsg); } nn_assert (cmsg->cmsg_len == NN_CMSG_SPACE (8+sizeof (size_t))); data = NN_CMSG_DATA (cmsg); nn_assert (!(data[0+sizeof (size_t)] & 0x80)); nn_assert (data[4+sizeof (size_t)] & 0x80); nn_freemsg (control); test_close (sc); test_close (sb); /* Test binding a new socket after originally bound socket shuts down. */ sb = test_socket (AF_SP, NN_BUS); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_BUS); test_connect (sc, SOCKET_ADDRESS); s1 = test_socket (AF_SP, NN_BUS); test_connect (s1, SOCKET_ADDRESS); /* Close bound socket, leaving connected sockets connect. */ test_close (sb); nn_sleep (100); /* Rebind a new socket to the address to which our connected sockets are listening. */ s2 = test_socket (AF_SP, NN_BUS); test_bind (s2, SOCKET_ADDRESS); /* Ping-pong test. */ for (i = 0; i != 100; ++i) { test_send (sc, "ABC"); test_send (s1, "QRS"); test_recv (s2, "ABC"); test_recv (s2, "QRS"); test_send (s2, "DEFG"); test_recv (sc, "DEFG"); test_recv (s1, "DEFG"); } /* Batch transfer test. */ for (i = 0; i != 100; ++i) { test_send (sc, "XYZ"); } for (i = 0; i != 100; ++i) { test_recv (s2, "XYZ"); } for (i = 0; i != 100; ++i) { test_send (s1, "MNO"); } for (i = 0; i != 100; ++i) { test_recv (s2, "MNO"); } test_close (s1); test_close (sc); test_close (s2); return 0; } nanomsg-1.1.5/tests/inproc_shutdown.c000066400000000000000000000041621336111550300177140ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/pubsub.h" #include "../src/inproc.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" /* Stress test the inproc transport. */ #define THREAD_COUNT 100 #define SOCKET_ADDRESS "inproc://test" static void routine (NN_UNUSED void *arg) { int s; s = nn_socket (AF_SP, NN_SUB); if (s < 0 && nn_errno () == EMFILE) return; errno_assert (s >= 0); test_connect (s, SOCKET_ADDRESS); test_close (s); } int main () { int sb; int i; int j; struct nn_thread threads [THREAD_COUNT]; /* Stress the shutdown algorithm. */ sb = test_socket (AF_SP, NN_PUB); test_bind (sb, SOCKET_ADDRESS); for (j = 0; j != 10; ++j) { for (i = 0; i != THREAD_COUNT; ++i) nn_thread_init (&threads [i], routine, NULL); for (i = 0; i != THREAD_COUNT; ++i) nn_thread_term (&threads [i]); } test_close (sb); return 0; } nanomsg-1.1.5/tests/iovec.c000066400000000000000000000042671336111550300156020ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "testutil.h" #include #define SOCKET_ADDRESS "inproc://a" int main () { int rc; int sb; int sc; struct nn_iovec iov [2]; struct nn_msghdr hdr; char buf [6]; sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); iov [0].iov_base = "AB"; iov [0].iov_len = 2; iov [1].iov_base = "CDEF"; iov [1].iov_len = 4; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = iov; hdr.msg_iovlen = 2; rc = nn_sendmsg (sc, &hdr, 0); errno_assert (rc >= 0); nn_assert (rc == 6); iov [0].iov_base = buf; iov [0].iov_len = 4; iov [1].iov_base = buf + 4; iov [1].iov_len = 2; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = iov; hdr.msg_iovlen = 2; rc = nn_recvmsg (sb, &hdr, 0); errno_assert (rc >= 0); nn_assert (rc == 6); nn_assert (memcmp (buf, "ABCDEF", 6) == 0); test_close (sc); test_close (sb); return 0; } nanomsg-1.1.5/tests/ipc.c000066400000000000000000000123051336111550300152400ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/pubsub.h" #include "../src/ipc.h" #include "testutil.h" /* Tests IPC transport. */ #define SOCKET_ADDRESS "ipc://test.ipc" int main () { #ifndef NN_HAVE_WSL int sb; int sc; int i; int s1, s2; void * dummy_buf; int rc; int opt; size_t opt_sz = sizeof (opt); int size; char * buf; /* Try closing a IPC socket while it not connected. */ sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); test_close (sc); /* Open the socket anew. */ sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); /* Leave enough time for at least one re-connect attempt. */ nn_sleep (200); sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); /* Ping-pong test. */ for (i = 0; i != 1; ++i) { test_send (sc, "0123456789012345678901234567890123456789"); test_recv (sb, "0123456789012345678901234567890123456789"); test_send (sb, "0123456789012345678901234567890123456789"); test_recv (sc, "0123456789012345678901234567890123456789"); } /* Batch transfer test. */ for (i = 0; i != 100; ++i) { test_send (sc, "XYZ"); } for (i = 0; i != 100; ++i) { test_recv (sb, "XYZ"); } /* Send something large enough to trigger overlapped I/O on Windows. */ size = 10000; buf = malloc (size); for (i = 0; i < size; ++i) { buf[i] = 48 + i % 10; } buf[size-1] = '\0'; test_send (sc, buf); test_recv (sb, buf); free (buf); test_close (sc); test_close (sb); /* Test whether connection rejection is handled decently. */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); s1 = test_socket (AF_SP, NN_PAIR); test_connect (s1, SOCKET_ADDRESS); s2 = test_socket (AF_SP, NN_PAIR); test_connect (s2, SOCKET_ADDRESS); nn_sleep (100); test_close (s2); test_close (s1); test_close (sb); /* On Windows, CreateNamedPipeA does not run exclusively. We should look at fixing this, but it will require changing the usock code for Windows. In the meantime just disable this test on Windows. */ #if !defined(NN_HAVE_WINDOWS) /* Test two sockets binding to the same address. */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); s1 = test_socket (AF_SP, NN_PAIR); rc = nn_bind (s1, SOCKET_ADDRESS); nn_assert (rc < 0); errno_assert (nn_errno () == EADDRINUSE); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); nn_sleep (100); test_send (sb, "ABC"); test_recv (sc, "ABC"); test_close (sb); test_close (sc); test_close (s1); #endif /* Test NN_RCVMAXSIZE limit */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); s1 = test_socket (AF_SP, NN_PAIR); test_connect (s1, SOCKET_ADDRESS); opt = 4; rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, opt_sz); nn_assert (rc == 0); nn_sleep (100); test_send (s1, "ABCD"); test_recv (sb, "ABCD"); test_send (s1, "ABCDE"); /* Without sleep nn_recv returns EAGAIN even for string of acceptable size, so false positives are possible. */ nn_sleep (100); rc = nn_recv (sb, &dummy_buf, NN_MSG, NN_DONTWAIT); nn_assert (rc < 0); errno_assert (nn_errno () == EAGAIN); test_close (sb); test_close (s1); /* Test that NN_RCVMAXSIZE can be -1, but not lower */ sb = test_socket (AF_SP, NN_PAIR); opt = -1; rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, opt_sz); nn_assert (rc >= 0); opt = -2; rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, opt_sz); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); test_close (sb); /* Test closing a socket that is waiting to connect. */ sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); nn_sleep (100); test_close (sc); #endif /* NN_HAVE_WSL */ return 0; } nanomsg-1.1.5/tests/ipc_shutdown.c000066400000000000000000000065071336111550300172020ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/pubsub.h" #include "../src/pipeline.h" #include "../src/ipc.h" #include "testutil.h" #include "../src/utils/thread.c" #ifndef NN_HAVE_WSL /* Stress test the IPC transport. */ #define THREAD_COUNT 100 #define TEST2_THREAD_COUNT 10 #define MESSAGES_PER_THREAD 10 #define TEST_LOOPS 10 #define SOCKET_ADDRESS "ipc://test-shutdown.ipc" volatile int active; static void routine (NN_UNUSED void *arg) { int s; s = nn_socket (AF_SP, NN_SUB); if (s < 0 && nn_errno () == EMFILE) return; errno_assert (s >= 0); test_connect (s, SOCKET_ADDRESS); test_close (s); } static void routine2 (NN_UNUSED void *arg) { int s; int i; s = test_socket (AF_SP, NN_PULL); for (i = 0; i < 10; ++i) { test_connect (s, SOCKET_ADDRESS); } for (i = 0; i < MESSAGES_PER_THREAD; ++i) { test_recv (s, "hello"); } test_close (s); active --; } #endif /* NN_HAVE_WSL */ int main () { #ifndef NN_HAVE_WSL int sb; int i; int j; struct nn_thread threads [THREAD_COUNT]; /* Stress the shutdown algorithm. */ #if defined(SIGPIPE) && defined(SIG_IGN) signal (SIGPIPE, SIG_IGN); #endif sb = test_socket (AF_SP, NN_PUB); test_bind (sb, SOCKET_ADDRESS); for (j = 0; j != TEST_LOOPS; ++j) { for (i = 0; i != THREAD_COUNT; ++i) nn_thread_init (&threads [i], routine, NULL); for (i = 0; i != THREAD_COUNT; ++i) nn_thread_term (&threads [i]); } test_close (sb); /* Test race condition of sending message while socket shutting down */ sb = test_socket (AF_SP, NN_PUSH); test_bind (sb, SOCKET_ADDRESS); for (j = 0; j != TEST_LOOPS; ++j) { for (i = 0; i != TEST2_THREAD_COUNT; ++i) nn_thread_init (&threads [i], routine2, NULL); active = TEST2_THREAD_COUNT; while (active) { (void) nn_send (sb, "hello", 5, NN_DONTWAIT); nn_sleep (0); } for (i = 0; i != TEST2_THREAD_COUNT; ++i) nn_thread_term (&threads [i]); } test_close (sb); #endif /* NN_HAVE_WSL */ return 0; } nanomsg-1.1.5/tests/ipc_stress.c000066400000000000000000000070751336111550300166530ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2017 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/pubsub.h" #include "../src/pipeline.h" #include "../src/ipc.h" #include "testutil.h" #include "../src/utils/thread.c" #include "../src/utils/atomic.h" #include "../src/utils/atomic.c" /* Stress test the IPC transport. */ #ifndef NN_HAVE_WSL #define THREAD_COUNT 10 #define TEST_LOOPS 10 #define SOCKET_ADDRESS "ipc://test-stress.ipc" static void server(NN_UNUSED void *arg) { int bytes; int count; int sock = nn_socket(AF_SP, NN_PULL); int res[TEST_LOOPS]; nn_assert(sock >= 0); nn_assert(nn_bind(sock, SOCKET_ADDRESS) >= 0); count = THREAD_COUNT * TEST_LOOPS; memset(res, 0, sizeof (res)); while (count > 0) { char *buf = NULL; int tid; int num; bytes = nn_recv(sock, &buf, NN_MSG, 0); nn_assert(bytes >= 0); nn_assert(bytes >= 2); nn_assert(buf[0] >= 'A' && buf[0] <= 'Z'); nn_assert(buf[1] >= 'a' && buf[0] <= 'z'); tid = buf[0]-'A'; num = buf[1]-'a'; nn_assert(tid < THREAD_COUNT); nn_assert(res[tid] == num); res[tid]=num+1; nn_freemsg(buf); count--; } nn_close(sock); } static void client(void *arg) { intptr_t id = (intptr_t)arg; int bytes; char msg[3]; size_t sz_msg; int i; msg[0] = 'A' + id%26; msg[1] = 'a'; msg[2] = '\0'; /* '\0' too */ sz_msg = strlen (msg) + 1; for (i = 0; i < TEST_LOOPS; i++) { int cli_sock = nn_socket (AF_SP, NN_PUSH); msg[1] = 'a' + i%26; nn_assert (cli_sock >= 0); nn_assert (nn_connect (cli_sock, SOCKET_ADDRESS) >= 0); /* Give time to allow for connect to establish. */ nn_sleep (50); bytes = nn_send (cli_sock, msg, sz_msg, 0); /* This would better be handled via semaphore or condvar. */ nn_sleep (100); nn_assert ((size_t)bytes == sz_msg); nn_close (cli_sock); } } int main() { int i; struct nn_thread srv_thread; struct nn_thread cli_threads[THREAD_COUNT]; /* Stress the shutdown algorithm. */ nn_thread_init(&srv_thread, server, NULL); for (i = 0; i != THREAD_COUNT; ++i) nn_thread_init(&cli_threads[i], client, (void *)(intptr_t)i); for (i = 0; i != THREAD_COUNT; ++i) nn_thread_term(&cli_threads[i]); return 0; } #else int main() { return (0); } #endif nanomsg-1.1.5/tests/list.c000066400000000000000000000131301336111550300154350ustar00rootroot00000000000000/* Copyright (c) 2013 Nir Soffer 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. */ #include "../src/utils/cont.h" #include "../src/utils/err.c" #include "../src/utils/list.c" static struct nn_list_item sentinel; /* Typical object that can be added to a list. */ struct item { int value; struct nn_list_item item; }; /* Initializing list items statically so they can be inserted into a list. */ static struct item that = {1, NN_LIST_ITEM_INITIALIZER}; static struct item other = {2, NN_LIST_ITEM_INITIALIZER}; int main () { int rc; struct nn_list list; struct nn_list_item *list_item; struct item *item; /* List item life cycle. */ /* Initialize the item. Make sure it's not part of any list. */ nn_list_item_init (&that.item); nn_assert (!nn_list_item_isinlist (&that.item)); /* That may be part of some list, or uninitialized memory. */ that.item.prev = &sentinel; that.item.next = &sentinel; nn_assert (nn_list_item_isinlist (&that.item)); that.item.prev = NULL; that.item.next = NULL; nn_assert (nn_list_item_isinlist (&that.item)); /* Before termination, item must be removed from the list. */ nn_list_item_init (&that.item); nn_list_item_term (&that.item); /* Initializing a list. */ /* Uninitialized list has random content. */ list.first = &sentinel; list.last = &sentinel; nn_list_init (&list); nn_assert (list.first == NULL); nn_assert (list.last == NULL); nn_list_term (&list); /* Empty list. */ nn_list_init (&list); rc = nn_list_empty (&list); nn_assert (rc == 1); list_item = nn_list_begin (&list); nn_assert (list_item == NULL); list_item = nn_list_end (&list); nn_assert (list_item == NULL); nn_list_term (&list); /* Inserting and erasing items. */ nn_list_init (&list); nn_list_item_init (&that.item); /* Item doesn'tt belong to list yet. */ nn_assert (!nn_list_item_isinlist (&that.item)); nn_list_insert (&list, &that.item, nn_list_end (&list)); /* Item is now part of a list. */ nn_assert (nn_list_item_isinlist (&that.item)); /* Single item does not have prev or next item. */ nn_assert (that.item.prev == NULL); nn_assert (that.item.next == NULL); /* Item is both first and list item. */ nn_assert (list.first == &that.item); nn_assert (list.last == &that.item); /* Removing an item. */ nn_list_erase (&list, &that.item); nn_assert (!nn_list_item_isinlist (&that.item)); nn_assert (list.first == NULL); nn_assert (list.last == NULL); nn_list_item_term (&that.item); nn_list_term (&list); /* Iterating items. */ nn_list_init (&list); nn_list_item_init (&that.item); nn_list_insert (&list, &that.item, nn_list_end (&list)); list_item = nn_list_begin (&list); nn_assert (list_item == &that.item); item = nn_cont (list_item, struct item, item); nn_assert (item == &that); list_item = nn_list_end (&list); nn_assert (list_item == NULL); list_item = nn_list_prev (&list, &that.item); nn_assert (list_item == NULL); list_item = nn_list_next (&list, &that.item); nn_assert (list_item == NULL); rc = nn_list_empty (&list); nn_assert (rc == 0); nn_list_erase (&list, &that.item); nn_list_item_term (&that.item); nn_list_term (&list); /* Appending items. */ nn_list_init (&list); nn_list_item_init (&that.item); nn_list_item_init (&other.item); nn_list_insert (&list, &that.item, nn_list_end (&list)); nn_list_insert (&list, &other.item, nn_list_end (&list)); list_item = nn_list_begin (&list); nn_assert (list_item == &that.item); list_item = nn_list_next (&list, list_item); nn_assert (list_item == &other.item); nn_list_erase (&list, &that.item); nn_list_erase (&list, &other.item); nn_list_item_term (&that.item); nn_list_item_term (&other.item); nn_list_term (&list); /* Prepending items. */ nn_list_init (&list); nn_list_item_init (&that.item); nn_list_item_init (&other.item); nn_list_insert (&list, &that.item, nn_list_begin (&list)); nn_list_insert (&list, &other.item, nn_list_begin (&list)); list_item = nn_list_begin (&list); nn_assert (list_item == &other.item); list_item = nn_list_next (&list, list_item); nn_assert (list_item == &that.item); nn_list_erase (&list, &that.item); nn_list_erase (&list, &other.item); nn_list_item_term (&that.item); nn_list_item_term (&other.item); nn_list_term (&list); return 0; } nanomsg-1.1.5/tests/msg.c000066400000000000000000000101361336111550300152530ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright 2016 Franklin "Snaipe" Mathieu Copyright 2017 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "testutil.h" #include #define SOCKET_ADDRESS "inproc://a" char longdata[1 << 20]; int main (int argc, const char *argv[]) { int rc; int sb; int sc; unsigned char *buf1, *buf2; int i; struct nn_iovec iov; struct nn_msghdr hdr; char socket_address_tcp[128]; test_addr_from(socket_address_tcp, "tcp", "127.0.0.1", get_test_port(argc, argv)); sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); buf1 = nn_allocmsg (256, 0); alloc_assert (buf1); for (i = 0; i != 256; ++i) buf1 [i] = (unsigned char) i; rc = nn_send (sc, &buf1, NN_MSG, 0); errno_assert (rc >= 0); nn_assert (rc == 256); buf2 = NULL; rc = nn_recv (sb, &buf2, NN_MSG, 0); errno_assert (rc >= 0); nn_assert (rc == 256); nn_assert (buf2); for (i = 0; i != 256; ++i) nn_assert (buf2 [i] == (unsigned char) i); rc = nn_freemsg (buf2); errno_assert (rc == 0); buf1 = nn_allocmsg (256, 0); alloc_assert (buf1); for (i = 0; i != 256; ++i) buf1 [i] = (unsigned char) i; iov.iov_base = &buf1; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; rc = nn_sendmsg (sc, &hdr, 0); errno_assert (rc >= 0); nn_assert (rc == 256); buf2 = NULL; iov.iov_base = &buf2; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; rc = nn_recvmsg (sb, &hdr, 0); errno_assert (rc >= 0); nn_assert (rc == 256); nn_assert (buf2); for (i = 0; i != 256; ++i) nn_assert (buf2 [i] == (unsigned char) i); rc = nn_freemsg (buf2); errno_assert (rc == 0); test_close (sc); test_close (sb); /* Test receiving of large message */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, socket_address_tcp); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, socket_address_tcp); for (i = 0; i < (int) sizeof (longdata); ++i) longdata[i] = '0' + (i % 10); longdata [sizeof (longdata) - 1] = 0; test_send (sb, longdata); rc = nn_recv (sc, &buf2, NN_MSG, 0); errno_assert (rc >= 0); nn_assert (rc == sizeof (longdata) - 1); nn_assert (buf2); for (i = 0; i < (int) sizeof (longdata) - 1; ++i) nn_assert (buf2 [i] == longdata [i]); rc = nn_freemsg (buf2); errno_assert (rc == 0); test_close (sc); test_close (sb); /* Test reallocmsg */ buf1 = nn_allocmsg (8, 0); alloc_assert (buf1); buf2 = nn_reallocmsg (buf1, 1); nn_assert (buf2 == buf1); buf1 = nn_reallocmsg (buf2, 100); nn_assert (buf1 != buf2); nn_assert (buf1 != 0); nn_freemsg (buf1); return 0; } nanomsg-1.1.5/tests/pair.c000066400000000000000000000031261336111550300154210ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "testutil.h" #define SOCKET_ADDRESS "inproc://a" int main () { int sb; int sc; sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); test_send (sc, "ABC"); test_recv (sb, "ABC"); test_send (sb, "DEF"); test_recv (sc, "DEF"); test_close (sc); test_close (sb); return 0; } nanomsg-1.1.5/tests/pipeline.c000066400000000000000000000047031336111550300162750ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pipeline.h" #include "testutil.h" #define SOCKET_ADDRESS "inproc://a" int main () { int push1; int push2; int pull1; int pull2; /* Test fan-out. */ push1 = test_socket (AF_SP, NN_PUSH); test_bind (push1, SOCKET_ADDRESS); pull1 = test_socket (AF_SP, NN_PULL); test_connect (pull1, SOCKET_ADDRESS); pull2 = test_socket (AF_SP, NN_PULL); test_connect (pull2, SOCKET_ADDRESS); /* Wait till both connections are established to get messages spread evenly between the two pull sockets. */ nn_sleep (10); test_send (push1, "ABC"); test_send (push1, "DEF"); test_recv (pull1, "ABC"); test_recv (pull2, "DEF"); test_close (push1); test_close (pull1); test_close (pull2); /* Test fan-in. */ pull1 = test_socket (AF_SP, NN_PULL); test_bind (pull1, SOCKET_ADDRESS); push1 = test_socket (AF_SP, NN_PUSH); test_connect (push1, SOCKET_ADDRESS); push2 = test_socket (AF_SP, NN_PUSH); test_connect (push2, SOCKET_ADDRESS); test_send (push1, "ABC"); test_send (push2, "DEF"); test_recv (pull1, "ABC"); test_recv (pull1, "DEF"); test_close (pull1); test_close (push1); test_close (push2); return 0; } nanomsg-1.1.5/tests/poll.c000066400000000000000000000124261336111550300154370ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/inproc.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" #if defined NN_HAVE_WINDOWS #include "../src/utils/win.h" #else #include #endif /* Test of polling via NN_SNDFD/NN_RCVFD mechanism. */ #define SOCKET_ADDRESS "inproc://a" int sc; void routine1 (NN_UNUSED void *arg) { nn_sleep (10); test_send (sc, "ABC"); } void routine2 (NN_UNUSED void *arg) { nn_sleep (10); nn_term (); } #define NN_IN 1 #define NN_OUT 2 int getevents (int s, int events, int timeout) { int rc; fd_set pollset; #if defined NN_HAVE_WINDOWS SOCKET rcvfd; SOCKET sndfd; #else int rcvfd; int sndfd; int maxfd; #endif size_t fdsz; struct timeval tv; int revents; #if !defined NN_HAVE_WINDOWS maxfd = 0; #endif FD_ZERO (&pollset); if (events & NN_IN) { fdsz = sizeof (rcvfd); rc = nn_getsockopt (s, NN_SOL_SOCKET, NN_RCVFD, (char*) &rcvfd, &fdsz); errno_assert (rc == 0); nn_assert (fdsz == sizeof (rcvfd)); FD_SET (rcvfd, &pollset); #if !defined NN_HAVE_WINDOWS if (rcvfd + 1 > maxfd) maxfd = rcvfd + 1; #endif } if (events & NN_OUT) { fdsz = sizeof (sndfd); rc = nn_getsockopt (s, NN_SOL_SOCKET, NN_SNDFD, (char*) &sndfd, &fdsz); errno_assert (rc == 0); nn_assert (fdsz == sizeof (sndfd)); FD_SET (sndfd, &pollset); #if !defined NN_HAVE_WINDOWS if (sndfd + 1 > maxfd) maxfd = sndfd + 1; #endif } if (timeout >= 0) { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; } #if defined NN_HAVE_WINDOWS rc = select (0, &pollset, NULL, NULL, timeout < 0 ? NULL : &tv); wsa_assert (rc != SOCKET_ERROR); #else rc = select (maxfd, &pollset, NULL, NULL, timeout < 0 ? NULL : &tv); errno_assert (rc >= 0); #endif revents = 0; if ((events & NN_IN) && FD_ISSET (rcvfd, &pollset)) revents |= NN_IN; if ((events & NN_OUT) && FD_ISSET (sndfd, &pollset)) revents |= NN_OUT; return revents; } int main () { int rc; int sb; char buf [3]; struct nn_thread thread; struct nn_pollfd pfd [2]; /* Test nn_poll() function. */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); test_send (sc, "ABC"); nn_sleep (100); pfd [0].fd = sb; pfd [0].events = NN_POLLIN | NN_POLLOUT; pfd [1].fd = sc; pfd [1].events = NN_POLLIN | NN_POLLOUT; rc = nn_poll (pfd, 2, -1); errno_assert (rc >= 0); nn_assert (rc == 2); nn_assert (pfd [0].revents == (NN_POLLIN | NN_POLLOUT)); nn_assert (pfd [1].revents == NN_POLLOUT); test_close (sc); test_close (sb); /* Create a simple topology. */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, SOCKET_ADDRESS); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); /* Check the initial state of the socket. */ rc = getevents (sb, NN_IN | NN_OUT, 1000); nn_assert (rc == NN_OUT); /* Poll for IN when there's no message available. The call should time out. */ rc = getevents (sb, NN_IN, 10); nn_assert (rc == 0); /* Send a message and start polling. This time IN event should be signaled. */ test_send (sc, "ABC"); rc = getevents (sb, NN_IN, 1000); nn_assert (rc == NN_IN); /* Receive the message and make sure that IN is no longer signaled. */ test_recv (sb, "ABC"); rc = getevents (sb, NN_IN, 10); nn_assert (rc == 0); /* Check signalling from a different thread. */ nn_thread_init (&thread, routine1, NULL); rc = getevents (sb, NN_IN, 1000); nn_assert (rc == NN_IN); test_recv (sb, "ABC"); nn_thread_term (&thread); /* Check terminating the library from a different thread. */ nn_thread_init (&thread, routine2, NULL); rc = nn_recv (sb, buf, sizeof (buf), 0); nn_assert (rc < 0 && nn_errno () == EBADF); nn_thread_term (&thread); /* Clean up. */ test_close (sc); test_close (sb); return 0; } nanomsg-1.1.5/tests/prio.c000066400000000000000000000072341336111550300154430ustar00rootroot00000000000000/* Copyright (c) 2013-2014 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pipeline.h" #include "testutil.h" #define SOCKET_ADDRESS_A "inproc://a" #define SOCKET_ADDRESS_B "inproc://b" int main () { int rc; int push1; int push2; int pull1; int pull2; int sndprio; int rcvprio; /* Test send priorities. */ pull1 = test_socket (AF_SP, NN_PULL); test_bind (pull1, SOCKET_ADDRESS_A); pull2 = test_socket (AF_SP, NN_PULL); test_bind (pull2, SOCKET_ADDRESS_B); push1 = test_socket (AF_SP, NN_PUSH); sndprio = 1; rc = nn_setsockopt (push1, NN_SOL_SOCKET, NN_SNDPRIO, &sndprio, sizeof (sndprio)); errno_assert (rc == 0); test_connect (push1, SOCKET_ADDRESS_A); sndprio = 2; rc = nn_setsockopt (push1, NN_SOL_SOCKET, NN_SNDPRIO, &sndprio, sizeof (sndprio)); errno_assert (rc == 0); test_connect (push1, SOCKET_ADDRESS_B); test_send (push1, "ABC"); test_send (push1, "DEF"); test_recv (pull1, "ABC"); test_recv (pull1, "DEF"); test_close (pull1); test_close (push1); test_close (pull2); /* Test receive priorities. */ push1 = test_socket (AF_SP, NN_PUSH); test_bind (push1, SOCKET_ADDRESS_A); push2 = test_socket (AF_SP, NN_PUSH); test_bind (push2, SOCKET_ADDRESS_B); pull1 = test_socket (AF_SP, NN_PULL); rcvprio = 2; rc = nn_setsockopt (pull1, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, sizeof (rcvprio)); errno_assert (rc == 0); test_connect (pull1, SOCKET_ADDRESS_A); rcvprio = 1; rc = nn_setsockopt (pull1, NN_SOL_SOCKET, NN_RCVPRIO, &rcvprio, sizeof (rcvprio)); errno_assert (rc == 0); test_connect (pull1, SOCKET_ADDRESS_B); test_send (push1, "ABC"); test_send (push2, "DEF"); nn_sleep (100); test_recv (pull1, "DEF"); test_recv (pull1, "ABC"); test_close (pull1); test_close (push2); test_close (push1); /* Test removing a pipe from the list. */ push1 = test_socket (AF_SP, NN_PUSH); test_bind (push1, SOCKET_ADDRESS_A); pull1 = test_socket (AF_SP, NN_PULL); test_connect (pull1, SOCKET_ADDRESS_A); test_send (push1, "ABC"); test_recv (pull1, "ABC"); test_close (pull1); rc = nn_send (push1, "ABC", 3, NN_DONTWAIT); nn_assert (rc == -1 && nn_errno() == EAGAIN); pull1 = test_socket (AF_SP, NN_PULL); test_connect (pull1, SOCKET_ADDRESS_A); test_send (push1, "ABC"); test_recv (pull1, "ABC"); test_close (pull1); test_close (push1); return 0; } nanomsg-1.1.5/tests/pubsub.c000066400000000000000000000060031336111550300157630ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pubsub.h" #include "testutil.h" #define SOCKET_ADDRESS "inproc://a" int main () { int rc; int pub1; int pub2; int sub1; int sub2; char buf [8]; size_t sz; pub1 = test_socket (AF_SP, NN_PUB); test_bind (pub1, SOCKET_ADDRESS); sub1 = test_socket (AF_SP, NN_SUB); rc = nn_setsockopt (sub1, NN_SUB, NN_SUB_SUBSCRIBE, "", 0); errno_assert (rc == 0); sz = sizeof (buf); rc = nn_getsockopt (sub1, NN_SUB, NN_SUB_SUBSCRIBE, buf, &sz); nn_assert (rc == -1 && nn_errno () == ENOPROTOOPT); test_connect (sub1, SOCKET_ADDRESS); sub2 = test_socket (AF_SP, NN_SUB); rc = nn_setsockopt (sub2, NN_SUB, NN_SUB_SUBSCRIBE, "", 0); errno_assert (rc == 0); test_connect (sub2, SOCKET_ADDRESS); /* Wait till connections are established to prevent message loss. */ nn_sleep (10); test_send (pub1, "0123456789012345678901234567890123456789"); test_recv (sub1, "0123456789012345678901234567890123456789"); test_recv (sub2, "0123456789012345678901234567890123456789"); test_close (pub1); test_close (sub1); test_close (sub2); /* Check receiving messages from two publishers. */ sub1 = test_socket (AF_SP, NN_SUB); rc = nn_setsockopt (sub1, NN_SUB, NN_SUB_SUBSCRIBE, "", 0); errno_assert (rc == 0); test_bind (sub1, SOCKET_ADDRESS); pub1 = test_socket (AF_SP, NN_PUB); test_connect (pub1, SOCKET_ADDRESS); pub2 = test_socket (AF_SP, NN_PUB); test_connect (pub2, SOCKET_ADDRESS); nn_sleep (100); test_send (pub1, "0123456789012345678901234567890123456789"); test_send (pub2, "0123456789012345678901234567890123456789"); test_recv (sub1, "0123456789012345678901234567890123456789"); test_recv (sub1, "0123456789012345678901234567890123456789"); test_close (pub2); test_close (pub1); test_close (sub1); return 0; } nanomsg-1.1.5/tests/reqrep.c000066400000000000000000000124721336111550300157700ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/reqrep.h" #include "testutil.h" #define SOCKET_ADDRESS "inproc://test" int main () { int rc; int rep1; int rep2; int req1; int req2; int resend_ivl; char buf [7]; int timeo; /* Test req/rep with full socket types. */ rep1 = test_socket (AF_SP, NN_REP); test_bind (rep1, SOCKET_ADDRESS); req1 = test_socket (AF_SP, NN_REQ); test_connect (req1, SOCKET_ADDRESS); req2 = test_socket (AF_SP, NN_REQ); test_connect (req2, SOCKET_ADDRESS); /* Check invalid sequence of sends and recvs. */ rc = nn_send (rep1, "ABC", 3, 0); nn_assert (rc == -1 && nn_errno () == EFSM); rc = nn_recv (req1, buf, sizeof (buf), 0); nn_assert (rc == -1 && nn_errno () == EFSM); /* Check fair queueing the requests. */ test_send (req2, "ABC"); test_recv (rep1, "ABC"); test_send (rep1, "ABC"); test_recv (req2, "ABC"); test_send (req1, "ABC"); test_recv (rep1, "ABC"); test_send (rep1, "ABC"); test_recv (req1, "ABC"); test_close (rep1); test_close (req1); test_close (req2); /* Check load-balancing of requests. */ req1 = test_socket (AF_SP, NN_REQ); test_bind (req1, SOCKET_ADDRESS); rep1 = test_socket (AF_SP, NN_REP); test_connect (rep1, SOCKET_ADDRESS); rep2 = test_socket (AF_SP, NN_REP); test_connect (rep2, SOCKET_ADDRESS); test_send (req1, "ABC"); test_recv (rep1, "ABC"); test_send (rep1, "ABC"); test_recv (req1, "ABC"); test_send (req1, "ABC"); test_recv (rep2, "ABC"); test_send (rep2, "ABC"); test_recv (req1, "ABC"); test_close (rep2); test_close (rep1); test_close (req1); /* Test re-sending of the request. */ rep1 = test_socket (AF_SP, NN_REP); test_bind (rep1, SOCKET_ADDRESS); req1 = test_socket (AF_SP, NN_REQ); test_connect (req1, SOCKET_ADDRESS); resend_ivl = 100; rc = nn_setsockopt (req1, NN_REQ, NN_REQ_RESEND_IVL, &resend_ivl, sizeof (resend_ivl)); errno_assert (rc == 0); test_send (req1, "ABC"); test_recv (rep1, "ABC"); /* The following waits for request to be resent */ test_recv (rep1, "ABC"); test_close (req1); test_close (rep1); /* Check sending a request when the peer is not available. (It should be sent immediatelly when the peer comes online rather than relying on the resend algorithm. */ req1 = test_socket (AF_SP, NN_REQ); test_connect (req1, SOCKET_ADDRESS); test_send (req1, "ABC"); rep1 = test_socket (AF_SP, NN_REP); test_bind (rep1, SOCKET_ADDRESS); timeo = 200; rc = nn_setsockopt (rep1, NN_SOL_SOCKET, NN_RCVTIMEO, &timeo, sizeof (timeo)); errno_assert (rc == 0); test_recv (rep1, "ABC"); test_close (req1); test_close (rep1); /* Check removing socket request sent to (It should be sent immediatelly to other peer rather than relying on the resend algorithm). */ req1 = test_socket (AF_SP, NN_REQ); test_bind (req1, SOCKET_ADDRESS); rep1 = test_socket (AF_SP, NN_REP); test_connect (rep1, SOCKET_ADDRESS); rep2 = test_socket (AF_SP, NN_REP); test_connect (rep2, SOCKET_ADDRESS); timeo = 200; rc = nn_setsockopt (rep1, NN_SOL_SOCKET, NN_RCVTIMEO, &timeo, sizeof (timeo)); errno_assert (rc == 0); rc = nn_setsockopt (rep2, NN_SOL_SOCKET, NN_RCVTIMEO, &timeo, sizeof (timeo)); errno_assert (rc == 0); test_send (req1, "ABC"); /* We got request through rep1 */ test_recv (rep1, "ABC"); /* But instead replying we simulate crash */ test_close (rep1); /* The rep2 should get request immediately */ test_recv (rep2, "ABC"); /* Let's check it's delivered well */ test_send (rep2, "REPLY"); test_recv (req1, "REPLY"); test_close (req1); test_close (rep2); /* Test cancelling delayed request */ req1 = test_socket (AF_SP, NN_REQ); test_connect (req1, SOCKET_ADDRESS); test_send (req1, "ABC"); test_send (req1, "DEF"); rep1 = test_socket (AF_SP, NN_REP); test_bind (rep1, SOCKET_ADDRESS); timeo = 100; test_recv (rep1, "DEF"); test_close (req1); test_close (rep1); return 0; } nanomsg-1.1.5/tests/reqttl.c000066400000000000000000000113061336111550300160000ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/reqrep.h" #include "../src/tcp.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" static char socket_address_a[128]; static char socket_address_b[128]; int dev0; int dev1; void device (NN_UNUSED void *arg) { int rc; /* Run the device. */ rc = nn_device (dev0, dev1); nn_assert (rc < 0 && nn_errno () == EBADF); /* Clean up. */ test_close (dev0); test_close (dev1); } int main (int argc, const char *argv[]) { int end0; int end1; struct nn_thread thread1; int timeo; int maxttl; size_t sz; int rc; int port = get_test_port(argc, argv); test_addr_from(socket_address_a, "tcp", "127.0.0.1", port); test_addr_from(socket_address_b, "tcp", "127.0.0.1", port + 1); /* Intialise the device sockets. */ dev0 = test_socket (AF_SP_RAW, NN_REP); dev1 = test_socket (AF_SP_RAW, NN_REQ); test_bind (dev0, socket_address_a); test_bind (dev1, socket_address_b); /* Start the device. */ nn_thread_init (&thread1, device, NULL); end0 = test_socket (AF_SP, NN_REQ); end1 = test_socket (AF_SP, NN_REP); /* Test the bi-directional device TTL */ test_connect (end0, socket_address_a); test_connect (end1, socket_address_b); /* Wait for TCP to establish. */ nn_sleep (100); /* Pass a message between endpoints. */ /* Set up max receive timeout. */ timeo = 100; test_setsockopt (end0, NN_SOL_SOCKET, NN_RCVTIMEO, &timeo, sizeof (timeo)); timeo = 100; test_setsockopt (end1, NN_SOL_SOCKET, NN_RCVTIMEO, &timeo, sizeof (timeo)); /* Test default TTL is 8. */ sz = sizeof (maxttl); maxttl = -1; rc = nn_getsockopt(end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, &sz); nn_assert (rc == 0); nn_assert (sz == sizeof (maxttl)); nn_assert (maxttl == 8); /* Test to make sure option TTL cannot be set below 1. */ maxttl = -1; rc = nn_setsockopt(end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); nn_assert (rc < 0 && nn_errno () == EINVAL); nn_assert (maxttl == -1); maxttl = 0; rc = nn_setsockopt(end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); nn_assert (rc < 0 && nn_errno () == EINVAL); nn_assert (maxttl == 0); /* Test to set non-integer size */ maxttl = 8; rc = nn_setsockopt(end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, 1); nn_assert (rc < 0 && nn_errno () == EINVAL); nn_assert (maxttl == 8); test_send (end0, "XYZ"); test_recv (end1, "XYZ"); /* Now send a reply. */ test_send (end1, "REPLYXYZ\n"); test_recv (end0, "REPLYXYZ\n"); /* Now set the max TTL. */ maxttl = 1; test_setsockopt (end0, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); test_setsockopt (end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); test_send (end0, "DROPTHIS"); test_drop (end1, ETIMEDOUT); /* Now set the max TTL up. */ maxttl = 2; test_setsockopt (end0, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); test_setsockopt (end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); test_send (end0, "DONTDROP"); test_recv (end1, "DONTDROP"); test_send (end1, "GOTIT"); test_recv (end0, "GOTIT"); /* Clean up. */ test_close (end0); test_close (end1); /* Shut down the devices. */ nn_term (); nn_thread_term (&thread1); return 0; } nanomsg-1.1.5/tests/separation.c000066400000000000000000000074041336111550300166360ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Franklin "Snaipe" Mathieu Copyright 2017 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/pipeline.h" #include "../src/inproc.h" #include "../src/ipc.h" #include "../src/tcp.h" #include "testutil.h" #define SOCKET_ADDRESS_INPROC "inproc://a" #define SOCKET_ADDRESS_IPC "ipc://test-separation.ipc" /* This test checks whether the library prevents interconnecting sockets between different non-compatible protocols. */ int main (int argc, const char *argv[]) { int rc; int pair; int pull; int timeo; char socket_address_tcp[128]; test_addr_from(socket_address_tcp, "tcp", "127.0.0.1", get_test_port(argc, argv)); /* Inproc: Bind first, connect second. */ pair = test_socket (AF_SP, NN_PAIR); test_bind (pair, SOCKET_ADDRESS_INPROC); pull = test_socket (AF_SP, NN_PULL); test_connect (pull, SOCKET_ADDRESS_INPROC); timeo = 100; test_setsockopt (pair, NN_SOL_SOCKET, NN_SNDTIMEO, &timeo, sizeof (timeo)); rc = nn_send (pair, "ABC", 3, 0); errno_assert (rc < 0 && nn_errno () == ETIMEDOUT); test_close (pull); test_close (pair); /* Inproc: Connect first, bind second. */ pull = test_socket (AF_SP, NN_PULL); test_connect (pull, SOCKET_ADDRESS_INPROC); pair = test_socket (AF_SP, NN_PAIR); test_bind (pair, SOCKET_ADDRESS_INPROC); timeo = 100; test_setsockopt (pair, NN_SOL_SOCKET, NN_SNDTIMEO, &timeo, sizeof (timeo)); rc = nn_send (pair, "ABC", 3, 0); errno_assert (rc < 0 && nn_errno () == ETIMEDOUT); test_close (pull); test_close (pair); #if !defined NN_HAVE_WINDOWS && !defined NN_HAVE_WSL /* IPC */ pair = test_socket (AF_SP, NN_PAIR); test_bind (pair, SOCKET_ADDRESS_IPC); pull = test_socket (AF_SP, NN_PULL); test_connect (pull, SOCKET_ADDRESS_IPC); timeo = 100; test_setsockopt (pair, NN_SOL_SOCKET, NN_SNDTIMEO, &timeo, sizeof (timeo)); rc = nn_send (pair, "ABC", 3, 0); errno_assert (rc < 0 && nn_errno () == ETIMEDOUT); test_close (pull); test_close (pair); #endif /* TCP */ pair = test_socket (AF_SP, NN_PAIR); test_bind (pair, socket_address_tcp); pull = test_socket (AF_SP, NN_PULL); test_connect (pull, socket_address_tcp); timeo = 100; test_setsockopt (pair, NN_SOL_SOCKET, NN_SNDTIMEO, &timeo, sizeof (timeo)); rc = nn_send (pair, "ABC", 3, 0); errno_assert (rc < 0 && nn_errno () == ETIMEDOUT); test_close (pull); test_close (pair); return 0; } nanomsg-1.1.5/tests/shutdown.c000066400000000000000000000033541336111550300163440ustar00rootroot00000000000000/* Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/tcp.h" #include "../src/reqrep.h" #include "testutil.h" int main (int argc, const char *argv[]) { int s; int rc; int eid; char socket_address[128]; test_addr_from(socket_address, "tcp", "127.0.0.1", get_test_port(argc, argv)); /* Run endpoint shutdown and socket shutdown in parallel. */ s = test_socket (AF_SP, NN_REQ); eid = test_connect (s, socket_address); rc = nn_shutdown (s, eid); errno_assert (rc == 0); test_close (s); return 0; } nanomsg-1.1.5/tests/stats.c000066400000000000000000000076721336111550300156360ustar00rootroot00000000000000/* Copyright 2016 Garrett D'Amore Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/reqrep.h" #include "testutil.h" int main (int argc, const char *argv[]) { int rep1; int req1; char socket_address[128]; test_addr_from(socket_address, "tcp", "127.0.0.1", get_test_port(argc, argv)); /* Test req/rep with full socket types. */ rep1 = test_socket (AF_SP, NN_REP); test_bind (rep1, socket_address); nn_sleep (100); req1 = test_socket (AF_SP, NN_REQ); test_connect (req1, socket_address); nn_sleep (200); nn_assert (nn_get_statistic(rep1, NN_STAT_ACCEPTED_CONNECTIONS) == 1); nn_assert (nn_get_statistic(rep1, NN_STAT_ESTABLISHED_CONNECTIONS) == 0); nn_assert (nn_get_statistic(rep1, NN_STAT_CURRENT_CONNECTIONS) == 1); nn_assert (nn_get_statistic(rep1, NN_STAT_MESSAGES_SENT) == 0); nn_assert (nn_get_statistic(rep1, NN_STAT_MESSAGES_RECEIVED) == 0); nn_assert (nn_get_statistic(req1, NN_STAT_ACCEPTED_CONNECTIONS) == 0); nn_assert (nn_get_statistic(req1, NN_STAT_ESTABLISHED_CONNECTIONS) == 1); nn_assert (nn_get_statistic(req1, NN_STAT_CURRENT_CONNECTIONS) == 1); nn_assert (nn_get_statistic(req1, NN_STAT_MESSAGES_SENT) == 0); nn_assert (nn_get_statistic(req1, NN_STAT_MESSAGES_RECEIVED) == 0); test_send (req1, "ABC"); nn_sleep (100); nn_assert (nn_get_statistic(req1, NN_STAT_MESSAGES_SENT) == 1); nn_assert (nn_get_statistic(req1, NN_STAT_BYTES_SENT) == 3); nn_assert (nn_get_statistic(req1, NN_STAT_MESSAGES_RECEIVED) == 0); nn_assert (nn_get_statistic(req1, NN_STAT_BYTES_RECEIVED) == 0); test_recv(rep1, "ABC"); nn_assert (nn_get_statistic(rep1, NN_STAT_MESSAGES_SENT) == 0); nn_assert (nn_get_statistic(rep1, NN_STAT_BYTES_SENT) == 0); nn_assert (nn_get_statistic(rep1, NN_STAT_MESSAGES_RECEIVED) == 1); nn_assert (nn_get_statistic(rep1, NN_STAT_BYTES_RECEIVED) == 3); test_send (rep1, "OK"); test_recv (req1, "OK"); nn_assert (nn_get_statistic(req1, NN_STAT_MESSAGES_SENT) == 1); nn_assert (nn_get_statistic(req1, NN_STAT_BYTES_SENT) == 3); nn_assert (nn_get_statistic(req1, NN_STAT_MESSAGES_RECEIVED) == 1); nn_assert (nn_get_statistic(req1, NN_STAT_BYTES_RECEIVED) == 2); nn_assert (nn_get_statistic(rep1, NN_STAT_MESSAGES_SENT) == 1); nn_assert (nn_get_statistic(rep1, NN_STAT_BYTES_SENT) == 2); nn_assert (nn_get_statistic(rep1, NN_STAT_MESSAGES_RECEIVED) == 1); nn_assert (nn_get_statistic(rep1, NN_STAT_BYTES_RECEIVED) == 3); test_close (req1); nn_sleep (100); nn_assert (nn_get_statistic(rep1, NN_STAT_ACCEPTED_CONNECTIONS) == 1); nn_assert (nn_get_statistic(rep1, NN_STAT_ESTABLISHED_CONNECTIONS) == 0); nn_assert (nn_get_statistic(rep1, NN_STAT_CURRENT_CONNECTIONS) == 0); test_close (rep1); return 0; } nanomsg-1.1.5/tests/survey.c000066400000000000000000000067031336111550300160270ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2015 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/survey.h" #include "testutil.h" #define SOCKET_ADDRESS "inproc://test" int main () { int rc; int surveyor; int respondent1; int respondent2; int respondent3; int deadline; char buf [7]; /* Test a simple survey with three respondents. */ surveyor = test_socket (AF_SP, NN_SURVEYOR); deadline = 500; rc = nn_setsockopt (surveyor, NN_SURVEYOR, NN_SURVEYOR_DEADLINE, &deadline, sizeof (deadline)); errno_assert (rc == 0); test_bind (surveyor, SOCKET_ADDRESS); respondent1 = test_socket (AF_SP, NN_RESPONDENT); test_connect (respondent1, SOCKET_ADDRESS); respondent2 = test_socket (AF_SP, NN_RESPONDENT); test_connect (respondent2, SOCKET_ADDRESS); respondent3 = test_socket (AF_SP, NN_RESPONDENT); test_connect (respondent3, SOCKET_ADDRESS); /* Check that attempt to recv with no survey pending is EFSM. */ rc = nn_recv (surveyor, buf, sizeof (buf), 0); errno_assert (rc == -1 && nn_errno () == EFSM); /* Send the survey. */ test_send (surveyor, "ABC"); /* First respondent answers. */ test_recv (respondent1, "ABC"); test_send (respondent1, "DEF"); /* Second respondent answers. */ test_recv (respondent2, "ABC"); test_send (respondent2, "DEF"); /* Surveyor gets the responses. */ test_recv (surveyor, "DEF"); test_recv (surveyor, "DEF"); /* There are no more responses. Surveyor hits the deadline. */ rc = nn_recv (surveyor, buf, sizeof (buf), 0); errno_assert (rc == -1 && nn_errno () == ETIMEDOUT); /* Third respondent answers (it have already missed the deadline). */ test_recv (respondent3, "ABC"); test_send (respondent3, "GHI"); /* Surveyor initiates new survey. */ test_send (surveyor, "ABC"); /* Check that stale response from third respondent is not delivered. */ rc = nn_recv (surveyor, buf, sizeof (buf), 0); errno_assert (rc == -1 && nn_errno () == ETIMEDOUT); /* Check that subsequent attempt to recv with no survey pending is EFSM. */ rc = nn_recv (surveyor, buf, sizeof (buf), 0); errno_assert (rc == -1 && nn_errno () == EFSM); test_close (surveyor); test_close (respondent1); test_close (respondent2); test_close (respondent3); return 0; } nanomsg-1.1.5/tests/surveyttl.c000066400000000000000000000111751336111550300165520ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright 2016 Garrett D'Amore Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/survey.h" #include "../src/tcp.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" static char socket_address_a[128]; static char socket_address_b[128]; int dev0; int dev1; void device (NN_UNUSED void *arg) { int rc; /* Run the device. */ rc = nn_device (dev0, dev1); nn_assert (rc < 0 && nn_errno () == EBADF); /* Clean up. */ test_close (dev0); test_close (dev1); } int main (int argc, const char *argv[]) { int end0; int end1; struct nn_thread thread1; int timeo; int maxttl; size_t sz; int rc; int port = get_test_port(argc, argv); test_addr_from(socket_address_a, "tcp", "127.0.0.1", port); test_addr_from(socket_address_b, "tcp", "127.0.0.1", port + 1); /* Intialise the device sockets. */ dev0 = test_socket (AF_SP_RAW, NN_RESPONDENT); dev1 = test_socket (AF_SP_RAW, NN_SURVEYOR); test_bind (dev0, socket_address_a); test_bind (dev1, socket_address_b); /* Start the device. */ nn_thread_init (&thread1, device, NULL); end0 = test_socket (AF_SP, NN_SURVEYOR); end1 = test_socket (AF_SP, NN_RESPONDENT); /* Test the bi-directional device TTL */ test_connect (end0, socket_address_a); test_connect (end1, socket_address_b); /* Wait for TCP to establish. */ nn_sleep (100); /* Set up max receive timeout. */ timeo = 100; test_setsockopt (end0, NN_SOL_SOCKET, NN_RCVTIMEO, &timeo, sizeof (timeo)); timeo = 100; test_setsockopt (end1, NN_SOL_SOCKET, NN_RCVTIMEO, &timeo, sizeof (timeo)); /* Test default TTL is 8. */ sz = sizeof (maxttl); maxttl = -1; rc = nn_getsockopt(end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, &sz); nn_assert (rc == 0); nn_assert (sz == sizeof (maxttl)); nn_assert (maxttl == 8); /* Test to make sure option TTL cannot be set below 1. */ maxttl = -1; rc = nn_setsockopt(end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); nn_assert (rc < 0 && nn_errno () == EINVAL); nn_assert (maxttl == -1); maxttl = 0; rc = nn_setsockopt(end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); nn_assert (rc < 0 && nn_errno () == EINVAL); nn_assert (maxttl == 0); /* Test to set non-integer size */ maxttl = 8; rc = nn_setsockopt(end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, 1); nn_assert (rc < 0 && nn_errno () == EINVAL); nn_assert (maxttl == 8); /* Pass a message between endpoints. */ test_send (end0, "SURVEY"); test_recv (end1, "SURVEY"); /* Now send a reply. */ test_send (end1, "REPLYXYZ"); test_recv (end0, "REPLYXYZ"); /* Now set the max TTL. */ maxttl = 1; test_setsockopt (end0, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); test_setsockopt (end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); test_send (end0, "DROPTHIS"); test_drop (end1, ETIMEDOUT); maxttl = 2; test_setsockopt (end0, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); test_setsockopt (end1, NN_SOL_SOCKET, NN_MAXTTL, &maxttl, sizeof (maxttl)); test_send (end0, "DONTDROP"); test_recv (end1, "DONTDROP"); /* Clean up. */ test_close (end0); test_close (end1); /* Shut down the devices. */ nn_term (); nn_thread_term (&thread1); return 0; } nanomsg-1.1.5/tests/symbol.c000066400000000000000000000037571336111550300160050ustar00rootroot00000000000000/* Copyright (c) 2013 Evan Wies 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. */ #include "../src/utils/err.c" int main () { int i; struct nn_symbol_properties sym; int value; nn_assert (nn_symbol (-1, NULL) == NULL); nn_assert (nn_errno () == EINVAL); nn_assert (nn_symbol_info (-1, &sym, (int) sizeof (sym)) == 0); nn_assert (nn_symbol (2000, NULL) == NULL); nn_assert (nn_errno () == EINVAL); nn_assert (nn_symbol_info (2000, &sym, (int) sizeof (sym)) == 0); nn_assert (nn_symbol (6, &value) != NULL); nn_assert (value != 0); nn_assert (nn_symbol_info (6, &sym, (int) sizeof (sym)) == sizeof (sym)); for (i = 0; ; ++i) { const char* name = nn_symbol (i, &value); if (name == NULL) { nn_assert (nn_errno () == EINVAL); break; } } for (i = 0; ; ++i) { if (nn_symbol_info (i, &sym, sizeof (sym)) == 0) break; } return 0; } nanomsg-1.1.5/tests/tcp.c000066400000000000000000000162331336111550300152570ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2015 Garrett D'Amore Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/pubsub.h" #include "../src/tcp.h" #include "testutil.h" /* Tests TCP transport. */ int sc; int main (int argc, const char *argv[]) { int rc; int sb; int i; int opt; size_t sz; int s1, s2; void * dummy_buf; char addr[128]; char socket_address[128]; int port = get_test_port(argc, argv); test_addr_from(socket_address, "tcp", "127.0.0.1", port); /* Try closing bound but unconnected socket. */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, socket_address); test_close (sb); /* Try closing a TCP socket while it not connected. At the same time test specifying the local address for the connection. */ sc = test_socket (AF_SP, NN_PAIR); test_addr_from(addr, "tcp", "127.0.0.1;127.0.0.1", port); test_connect (sc, addr); test_close (sc); /* Open the socket anew. */ sc = test_socket (AF_SP, NN_PAIR); /* Check NODELAY socket option. */ sz = sizeof (opt); rc = nn_getsockopt (sc, NN_TCP, NN_TCP_NODELAY, &opt, &sz); errno_assert (rc == 0); nn_assert (sz == sizeof (opt)); nn_assert (opt == 0); opt = 2; rc = nn_setsockopt (sc, NN_TCP, NN_TCP_NODELAY, &opt, sizeof (opt)); nn_assert (rc < 0 && nn_errno () == EINVAL); opt = 1; rc = nn_setsockopt (sc, NN_TCP, NN_TCP_NODELAY, &opt, sizeof (opt)); errno_assert (rc == 0); sz = sizeof (opt); rc = nn_getsockopt (sc, NN_TCP, NN_TCP_NODELAY, &opt, &sz); errno_assert (rc == 0); nn_assert (sz == sizeof (opt)); nn_assert (opt == 1); /* Try using invalid address strings. */ rc = nn_connect (sc, "tcp://*:"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "tcp://*:1000000"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "tcp://*:some_port"); nn_assert (rc < 0); rc = nn_connect (sc, "tcp://eth10000;127.0.0.1:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == ENODEV); rc = nn_connect (sc, "tcp://127.0.0.1"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_bind (sc, "tcp://127.0.0.1:"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_bind (sc, "tcp://127.0.0.1:1000000"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_bind (sc, "tcp://eth10000:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == ENODEV); rc = nn_connect (sc, "tcp://:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "tcp://-hostname:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "tcp://abc.123.---.#:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "tcp://[::1]:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "tcp://abc...123:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "tcp://.123:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); /* Connect correctly. Do so before binding the peer socket. */ test_connect (sc, socket_address); /* Leave enough time for at least on re-connect attempt. */ nn_sleep (200); sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, socket_address); /* Ping-pong test. */ for (i = 0; i != 100; ++i) { test_send (sc, "ABC"); test_recv (sb, "ABC"); test_send (sb, "DEF"); test_recv (sc, "DEF"); } /* Batch transfer test. */ for (i = 0; i != 100; ++i) { test_send (sc, "0123456789012345678901234567890123456789"); } for (i = 0; i != 100; ++i) { test_recv (sb, "0123456789012345678901234567890123456789"); } test_close (sc); test_close (sb); /* Test whether connection rejection is handled decently. */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, socket_address); s1 = test_socket (AF_SP, NN_PAIR); test_connect (s1, socket_address); s2 = test_socket (AF_SP, NN_PAIR); test_connect (s2, socket_address); nn_sleep (100); test_close (s2); test_close (s1); test_close (sb); /* Test two sockets binding to the same address. */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, socket_address); s1 = test_socket (AF_SP, NN_PAIR); rc = nn_bind (s1, socket_address); nn_assert (rc < 0); errno_assert (nn_errno () == EADDRINUSE); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, socket_address); nn_sleep (100); test_send (sb, "ABC"); test_recv (sc, "ABC"); test_close (sb); test_close (sc); test_close (s1); /* Test NN_RCVMAXSIZE limit */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, socket_address); s1 = test_socket (AF_SP, NN_PAIR); test_connect (s1, socket_address); opt = 4; rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); nn_assert (rc == 0); nn_sleep (100); test_send (s1, "ABC"); test_recv (sb, "ABC"); test_send (s1, "0123456789012345678901234567890123456789"); rc = nn_recv (sb, &dummy_buf, NN_MSG, NN_DONTWAIT); nn_assert (rc < 0); errno_assert (nn_errno () == EAGAIN); test_close (sb); test_close (s1); /* Test that NN_RCVMAXSIZE can be -1, but not lower */ sb = test_socket (AF_SP, NN_PAIR); opt = -1; rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); nn_assert (rc >= 0); opt = -2; rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); test_close (sb); /* Test closing a socket that is waiting to connect. */ sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, socket_address); nn_sleep (100); test_close (sc); return 0; } nanomsg-1.1.5/tests/tcp_shutdown.c000066400000000000000000000073551336111550300172170ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright 2016 Franklin "Snaipe" Mathieu Copyright 2017 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/pubsub.h" #include "../src/pipeline.h" #include "../src/tcp.h" #include "testutil.h" #include "../src/utils/attr.h" #include "../src/utils/thread.c" #include "../src/utils/atomic.c" /* Stress test the TCP transport. */ #ifdef NN_HAVE_WSL #define THREAD_COUNT 10 #else #define THREAD_COUNT 100 #endif #define TEST2_THREAD_COUNT 10 #define MESSAGES_PER_THREAD 10 #define TEST_LOOPS 10 struct nn_atomic active; static char socket_address[128]; static void routine (NN_UNUSED void *arg) { int s; s = nn_socket (AF_SP, NN_SUB); if (s < 0 && nn_errno () == EMFILE) return; errno_assert (s >= 0); test_connect (s, socket_address); test_close (s); } static void routine2 (NN_UNUSED void *arg) { int s; int i; int ms; s = test_socket (AF_SP, NN_PULL); test_connect (s, socket_address); ms = 2000; test_setsockopt (s, NN_SOL_SOCKET, NN_RCVTIMEO, &ms, sizeof (ms)); for (i = 0; i < MESSAGES_PER_THREAD; ++i) { test_recv (s, "hello"); } test_close (s); nn_atomic_dec(&active, 1); } int main (int argc, const char *argv[]) { int sb; int i; int j; struct nn_thread threads [THREAD_COUNT]; test_addr_from(socket_address, "tcp", "127.0.0.1", get_test_port(argc, argv)); /* Stress the shutdown algorithm. */ #if defined(SIGPIPE) && defined(SIG_IGN) signal (SIGPIPE, SIG_IGN); #endif sb = test_socket (AF_SP, NN_PUB); test_bind (sb, socket_address); for (j = 0; j != TEST_LOOPS; ++j) { for (i = 0; i != THREAD_COUNT; ++i) nn_thread_init (&threads [i], routine, NULL); for (i = 0; i != THREAD_COUNT; ++i) { nn_thread_term (&threads [i]); } } test_close (sb); /* Test race condition of sending message while socket shutting down */ sb = test_socket (AF_SP, NN_PUSH); test_bind (sb, socket_address); for (j = 0; j != TEST_LOOPS; ++j) { int ms; nn_atomic_init(&active, TEST2_THREAD_COUNT); for (i = 0; i != TEST2_THREAD_COUNT; ++i) nn_thread_init (&threads [i], routine2, &threads[i]); nn_sleep(100); ms = 200; test_setsockopt (sb, NN_SOL_SOCKET, NN_SNDTIMEO, &ms, sizeof (ms)); while (active.n) { (void) nn_send (sb, "hello", 5, 0); } for (i = 0; i != TEST2_THREAD_COUNT; ++i) nn_thread_term (&threads [i]); nn_atomic_term(&active); } test_close (sb); return 0; } nanomsg-1.1.5/tests/term.c000066400000000000000000000045471336111550300154450ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/utils/thread.c" #include "testutil.h" static void worker (NN_UNUSED void *arg) { int rc; int s; char buf [3]; /* Test socket. */ s = test_socket (AF_SP, NN_PAIR); /* Launch blocking function to check that it will be unblocked once nn_term() is called from the main thread. */ rc = nn_recv (s, buf, sizeof (buf), 0); nn_assert (rc == -1 && nn_errno () == EBADF); /* Check that all subsequent operations fail in synchronous manner. */ rc = nn_recv (s, buf, sizeof (buf), 0); nn_assert (rc == -1 && nn_errno () == EBADF); test_close (s); } int main () { int rc; int s; struct nn_thread thread; /* Close the socket with no associated endpoints. */ s = test_socket (AF_SP, NN_PAIR); test_close (s); /* Test nn_term() before nn_close(). */ nn_thread_init (&thread, worker, NULL); nn_sleep (100); nn_term (); /* Check that it's not possible to create new sockets after nn_term(). */ rc = nn_socket (AF_SP, NN_PAIR); nn_assert (rc == -1); errno_assert (nn_errno () == ETERM); /* Wait till worker thread terminates. */ nn_thread_term (&thread); return 0; } nanomsg-1.1.5/tests/testutil.h000066400000000000000000000155341336111550300163560ustar00rootroot00000000000000/* Copyright (c) 2013 Insollo Entertainment, LLC. All rights reserved. Copyright 2015 Garrett D'Amore Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #ifndef TESTUTIL_H_INCLUDED #define TESTUTIL_H_INCLUDED #include "../src/utils/attr.h" #include "../src/utils/err.c" #include "../src/utils/sleep.c" static int test_socket_impl (char *file, int line, int family, int protocol); static int test_connect_impl (char *file, int line, int sock, char *address); static int test_bind_impl (char *file, int line, int sock, char *address); static void test_close_impl (char *file, int line, int sock); static void test_send_impl (char *file, int line, int sock, char *data); static void test_recv_impl (char *file, int line, int sock, char *data); static void test_drop_impl (char *file, int line, int sock, int err); static int test_setsockopt_impl (char *file, int line, int sock, int level, int option, const void *optval, size_t optlen); #define test_socket(f, p) test_socket_impl (__FILE__, __LINE__, (f), (p)) #define test_connect(s, a) test_connect_impl (__FILE__, __LINE__, (s), (a)) #define test_bind(s, a) test_bind_impl (__FILE__, __LINE__, (s), (a)) #define test_send(s, d) test_send_impl (__FILE__, __LINE__, (s), (d)) #define test_recv(s, d) test_recv_impl (__FILE__, __LINE__, (s), (d)) #define test_drop(s, e) test_drop_impl (__FILE__, __LINE__, (s), (e)) #define test_close(s) test_close_impl (__FILE__, __LINE__, (s)) #define test_setsockopt(s, l, o, v, z) test_setsockopt_impl (__FILE__, \ __LINE__, (s), (l), (o), (v), (z)) static int NN_UNUSED test_socket_impl (char *file, int line, int family, int protocol) { int sock; sock = nn_socket (family, protocol); if (sock == -1) { fprintf (stderr, "Failed create socket: %s [%d] (%s:%d)\n", nn_err_strerror (errno), (int) errno, file, line); nn_err_abort (); } return sock; } static int NN_UNUSED test_connect_impl (char *file, int line, int sock, char *address) { int rc; rc = nn_connect (sock, address); if(rc < 0) { fprintf (stderr, "Failed connect to \"%s\": %s [%d] (%s:%d)\n", address, nn_err_strerror (errno), (int) errno, file, line); nn_err_abort (); } return rc; } static int NN_UNUSED test_bind_impl (char *file, int line, int sock, char *address) { int rc; rc = nn_bind (sock, address); if(rc < 0) { fprintf (stderr, "Failed bind to \"%s\": %s [%d] (%s:%d)\n", address, nn_err_strerror (errno), (int) errno, file, line); nn_err_abort (); } return rc; } static int NN_UNUSED test_setsockopt_impl (char *file, int line, int sock, int level, int option, const void *optval, size_t optlen) { int rc; rc = nn_setsockopt (sock, level, option, optval, optlen); if(rc < 0) { fprintf (stderr, "Failed set option \"%d\": %s [%d] (%s:%d)\n", option, nn_err_strerror (errno), (int) errno, file, line); nn_err_abort (); } return rc; } static void NN_UNUSED test_close_impl (char *file, int line, int sock) { int rc; rc = nn_close (sock); if ((rc != 0) && (errno != EBADF && errno != ETERM)) { fprintf (stderr, "Failed to close socket: %s [%d] (%s:%d)\n", nn_err_strerror (errno), (int) errno, file, line); nn_err_abort (); } } static void NN_UNUSED test_send_impl (char *file, int line, int sock, char *data) { size_t data_len; int rc; data_len = strlen (data); rc = nn_send (sock, data, data_len, 0); if (rc < 0) { fprintf (stderr, "Failed to send: %s [%d] (%s:%d)\n", nn_err_strerror (errno), (int) errno, file, line); nn_err_abort (); } if (rc != (int)data_len) { fprintf (stderr, "Data to send is truncated: %d != %d (%s:%d)\n", rc, (int) data_len, file, line); nn_err_abort (); } } static void NN_UNUSED test_recv_impl (char *file, int line, int sock, char *data) { size_t data_len; int rc; char *buf; data_len = strlen (data); /* We allocate plus one byte so that we are sure that message received has correct length and not truncated */ buf = malloc (data_len+1); alloc_assert (buf); rc = nn_recv (sock, buf, data_len+1, 0); if (rc < 0) { fprintf (stderr, "Failed to recv: %s [%d] (%s:%d)\n", nn_err_strerror (errno), (int) errno, file, line); nn_err_abort (); } if (rc != (int)data_len) { fprintf (stderr, "Received data has wrong length: %d != %d (%s:%d)\n", rc, (int) data_len, file, line); nn_err_abort (); } if (memcmp (data, buf, data_len) != 0) { /* We don't print the data as it may have binary garbage */ fprintf (stderr, "Received data is wrong (%s:%d)\n", file, line); nn_err_abort (); } free (buf); } static void NN_UNUSED test_drop_impl (char *file, int line, int sock, int err) { int rc; char buf[1024]; rc = nn_recv (sock, buf, sizeof (buf), 0); if (rc < 0 && err != errno) { fprintf (stderr, "Got wrong err to recv: %s [%d != %d] (%s:%d)\n", nn_err_strerror (errno), (int) errno, err, file, line); nn_err_abort (); } else if (rc >= 0) { fprintf (stderr, "Did not drop message: [%d bytes] (%s:%d)\n", rc, file, line); nn_err_abort (); } } static int NN_UNUSED get_test_port (int argc, const char *argv[]) { return atoi(argc < 2 ? "5555" : argv[1]); } static void NN_UNUSED test_addr_from (char *out, const char *proto, const char *ip, int port) { sprintf(out, "%s://%s:%d", proto, ip, port); } #endif nanomsg-1.1.5/tests/timeo.c000066400000000000000000000041331336111550300156020ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "testutil.h" #include "../src/utils/stopwatch.c" int main () { int rc; int s; int timeo; char buf [3]; struct nn_stopwatch stopwatch; uint64_t elapsed; s = test_socket (AF_SP, NN_PAIR); timeo = 100; rc = nn_setsockopt (s, NN_SOL_SOCKET, NN_RCVTIMEO, &timeo, sizeof (timeo)); errno_assert (rc == 0); nn_stopwatch_init (&stopwatch); rc = nn_recv (s, buf, sizeof (buf), 0); elapsed = nn_stopwatch_term (&stopwatch); errno_assert (rc < 0 && nn_errno () == ETIMEDOUT); time_assert (elapsed, 100000); timeo = 100; rc = nn_setsockopt (s, NN_SOL_SOCKET, NN_SNDTIMEO, &timeo, sizeof (timeo)); errno_assert (rc == 0); nn_stopwatch_init (&stopwatch); rc = nn_send (s, "ABC", 3, 0); elapsed = nn_stopwatch_term (&stopwatch); errno_assert (rc < 0 && nn_errno () == ETIMEDOUT); time_assert (elapsed, 100000); test_close (s); return 0; } nanomsg-1.1.5/tests/trie.c000066400000000000000000000200341336111550300154260ustar00rootroot00000000000000/* Copyright (c) 2013 Martin Sustrik All rights reserved. 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. */ #include "../src/protocols/pubsub/trie.c" #include "../src/utils/alloc.c" #include "../src/utils/err.c" #include int main () { int rc; struct nn_trie trie; /* Try matching with an empty trie. */ nn_trie_init (&trie); rc = nn_trie_match (&trie, (const uint8_t*) "", 0); nn_assert (rc == 0); rc = nn_trie_match (&trie, (const uint8_t*) "ABC", 3); nn_assert (rc == 0); nn_trie_term (&trie); /* Try matching with "all" subscription. */ nn_trie_init (&trie); rc = nn_trie_subscribe (&trie, (const uint8_t*) "", 0); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "", 0); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "ABC", 3); nn_assert (rc == 1); nn_trie_term (&trie); /* Try some simple matching. */ nn_trie_init (&trie); rc = nn_trie_subscribe (&trie, (const uint8_t*) "ABC", 3); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "DEF", 3); nn_assert (rc == 0); rc = nn_trie_match (&trie, (const uint8_t*) "AB", 2); nn_assert (rc == 0); rc = nn_trie_match (&trie, (const uint8_t*) "ABC", 3); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "ABCDE", 5); nn_assert (rc == 1); nn_trie_term (&trie); /* Try a long subcsription. */ nn_trie_init (&trie); rc = nn_trie_subscribe (&trie, (const uint8_t*) "01234567890123456789012345678901234", 35); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "", 0); nn_assert (rc == 0); rc = nn_trie_match (&trie, (const uint8_t*) "012456789", 10); nn_assert (rc == 0); rc = nn_trie_match (&trie, (const uint8_t*) "012345678901234567", 18); nn_assert (rc == 0); rc = nn_trie_match (&trie, (const uint8_t*) "01234567890123456789012345678901234", 35); nn_assert (rc == 1); nn_trie_term (&trie); /* Try matching with a sparse node involved. */ nn_trie_init (&trie); rc = nn_trie_subscribe (&trie, (const uint8_t*) "ABC", 3); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "ADE", 3); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "A", 1); nn_assert (rc == 0); rc = nn_trie_match (&trie, (const uint8_t*) "AD", 2); nn_assert (rc == 0); nn_trie_term (&trie); /* Try matching with a dense node involved. */ nn_trie_init (&trie); rc = nn_trie_subscribe (&trie, (const uint8_t*) "A", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "B", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "C", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "0", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "E", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "F", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "1", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "@", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "b", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "f", 1); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "0", 1); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "A", 1); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "f", 1); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "000", 3); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "a", 1); nn_assert (rc == 0); rc = nn_trie_match (&trie, (const uint8_t*) "c", 1); nn_assert (rc == 0); nn_trie_term (&trie); /* Check prefix splitting and compaction. */ nn_trie_init (&trie); rc = nn_trie_subscribe (&trie, (const uint8_t*) "ABCD", 4); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "AB", 2); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "AB", 2); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "AB", 2); nn_assert (rc == 0); rc = nn_trie_match (&trie, (const uint8_t*) "ABCDEF", 6); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "ABEF", 4); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "ABCD", 4); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "ABCD", 4); nn_assert (rc == 0); rc = nn_trie_match (&trie, (const uint8_t*) "ABEF", 4); nn_assert (rc == 1); nn_trie_term (&trie); /* Check whether there's no problem with removing all subscriptions. */ nn_trie_init (&trie); rc = nn_trie_subscribe (&trie, (const uint8_t*) "A", 1); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "A", 1); nn_assert (rc == 1); rc = nn_trie_match (&trie, (const uint8_t*) "", 0); nn_assert (rc == 0); rc = nn_trie_match (&trie, (const uint8_t*) "A", 1); nn_assert (rc == 0); nn_trie_term (&trie); /* Check converting from sparse node to dense node and vice versa. */ nn_trie_init (&trie); rc = nn_trie_subscribe (&trie, (const uint8_t*) "A", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "B", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "C", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "0", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "E", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "F", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "1", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "@", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "b", 1); nn_assert (rc == 1); rc = nn_trie_subscribe (&trie, (const uint8_t*) "f", 1); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "0", 1); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "f", 1); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "E", 1); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "B", 1); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "A", 1); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "1", 1); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "@", 1); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "F", 1); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "C", 1); nn_assert (rc == 1); rc = nn_trie_unsubscribe (&trie, (const uint8_t*) "b", 1); nn_assert (rc == 1); nn_trie_term (&trie); return 0; } nanomsg-1.1.5/tests/win_sec_attr.c000066400000000000000000000107401336111550300171470ustar00rootroot00000000000000/* Copyright (c) 2015 Timothee "TTimo" Besset All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/pubsub.h" #include "../src/ipc.h" #include "testutil.h" #include #include #include /* Windows only. Custom SECURITY_ATTRIBUTES on a socket. */ #define PIPE_NAME "win_sec_attr.ipc" #define SOCKET_ADDRESS "ipc://" PIPE_NAME int main () { int sb; int sc; SECURITY_ATTRIBUTES sec; BOOL ret; SID SIDAuthUsers; DWORD SIDSize; EXPLICIT_ACCESS xa; PACL pACL; DWORD ret2; int ret3; void *void_ret_value = NULL; size_t void_ret_size = sizeof (void_ret_value); HANDLE pipeHandle = NULL; PSID pSidOwner = NULL; BOOL equal = FALSE; BOOL bret = FALSE; PACL dacl = NULL; PACE_HEADER ace = NULL; PACCESS_ALLOWED_ACE allowed_ace = NULL; PSID the_sid = NULL; PSECURITY_DESCRIPTOR sd = NULL; sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, SOCKET_ADDRESS); sb = test_socket (AF_SP, NN_PAIR); memset (&sec, 0, sizeof (sec)); sec.lpSecurityDescriptor = malloc (SECURITY_DESCRIPTOR_MIN_LENGTH); ret = InitializeSecurityDescriptor (sec.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); nn_assert (ret); SIDSize = sizeof (SIDAuthUsers); ret = CreateWellKnownSid (WinAuthenticatedUserSid, NULL, &SIDAuthUsers, &SIDSize); nn_assert (ret); xa.grfAccessPermissions = GENERIC_READ | GENERIC_WRITE; xa.grfAccessMode = SET_ACCESS; xa.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; xa.Trustee.TrusteeForm = TRUSTEE_IS_SID; xa.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; xa.Trustee.ptstrName = (LPSTR) &SIDAuthUsers; ret2 = SetEntriesInAcl (1, &xa, NULL, &pACL); nn_assert (ret2 == ERROR_SUCCESS); ret = SetSecurityDescriptorDacl (sec.lpSecurityDescriptor, TRUE, pACL, FALSE); nn_assert (ret); sec.nLength = sizeof (sec); sec.bInheritHandle = TRUE; ret3 = nn_setsockopt (sb, NN_IPC, NN_IPC_SEC_ATTR, &sec, sizeof (sec)); nn_assert (ret3 == 0); test_bind (sb, SOCKET_ADDRESS); nn_sleep (200); test_send (sc, "0123456789012345678901234567890123456789"); test_recv (sb, "0123456789012345678901234567890123456789"); ret3 = nn_getsockopt (sb, NN_IPC, NN_IPC_SEC_ATTR, &void_ret_value, &void_ret_size); nn_assert (ret3 == 0); nn_assert (void_ret_value == &sec); /* Verify that the pipe has the same security descriptor that we set by comparing the ace of the kernel object to the one we created it with. */ pipeHandle = CreateFileA ("\\\\.\\\\pipe\\" PIPE_NAME, READ_CONTROL, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); nn_assert (pipeHandle != INVALID_HANDLE_VALUE); ret2 = GetSecurityInfo (pipeHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &dacl, NULL, &sd); nn_assert (ret2 == ERROR_SUCCESS); nn_assert (1 == dacl->AceCount); bret = GetAce (dacl, 0, &ace); nn_assert (bret == TRUE); nn_assert (ace->AceType == ACCESS_ALLOWED_ACE_TYPE); allowed_ace = (PACCESS_ALLOWED_ACE) ace; the_sid = (PSID) &(allowed_ace->SidStart); nn_assert (IsValidSid (the_sid)); equal = EqualSid ((PSID) &(allowed_ace->SidStart), &SIDAuthUsers); nn_assert (equal); LocalFree (sd); test_close (sc); test_close (sb); LocalFree (pACL); free (sec.lpSecurityDescriptor); return 0; } nanomsg-1.1.5/tests/ws.c000066400000000000000000000173641336111550300151300ustar00rootroot00000000000000/* Copyright (c) 2012 250bpm s.r.o. All rights reserved. Copyright (c) 2014-2016 Jack R. Dunaway. All rights reserved. Copyright 2015 Garrett D'Amore Copyright 2016 Franklin "Snaipe" Mathieu 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. */ #include "../src/nn.h" #include "../src/pair.h" #include "../src/ws.h" #include "testutil.h" static char socket_address[128]; /* Basic tests for WebSocket transport. */ /* test_text() verifies that we drop messages properly when sending invalid UTF-8, but not when we send valid data. */ void test_text () { int sb; int sc; int opt; uint8_t bad[20]; /* Negative testing... bad UTF-8 data for text. */ sb = test_socket (AF_SP, NN_PAIR); sc = test_socket (AF_SP, NN_PAIR); opt = NN_WS_MSG_TYPE_TEXT; test_setsockopt (sb, NN_WS, NN_WS_MSG_TYPE, &opt, sizeof (opt)); opt = NN_WS_MSG_TYPE_TEXT; test_setsockopt (sc, NN_WS, NN_WS_MSG_TYPE, &opt, sizeof (opt)); opt = 500; test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVTIMEO, &opt, sizeof (opt)); test_bind (sb, socket_address); test_connect (sc, socket_address); test_send (sc, "GOOD"); test_recv (sb, "GOOD"); /* and the bad ... */ strcpy ((char *)bad, "BAD."); bad[2] = (char)0xDD; test_send (sc, (char *)bad); /* Make sure we dropped the frame. */ test_drop (sb, ETIMEDOUT); test_close (sb); test_close (sc); return; } int main (int argc, const char *argv[]) { int rc; int sb; int sc; int sb2; int opt; size_t sz; int i; char any_address[128]; test_addr_from (socket_address, "ws", "127.0.0.1", get_test_port (argc, argv)); test_addr_from (any_address, "ws", "*", get_test_port (argc, argv)); /* Try closing bound but unconnected socket. */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, any_address); test_close (sb); /* Try closing a TCP socket while it not connected. At the same time test specifying the local address for the connection. */ sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, socket_address); test_close (sc); /* Open the socket anew. */ sc = test_socket (AF_SP, NN_PAIR); /* Check socket options. */ sz = sizeof (opt); rc = nn_getsockopt (sc, NN_WS, NN_WS_MSG_TYPE, &opt, &sz); errno_assert (rc == 0); nn_assert (sz == sizeof (opt)); nn_assert (opt == NN_WS_MSG_TYPE_BINARY); /* Default port 80 should be assumed if not explicitly declared. */ rc = nn_connect (sc, "ws://127.0.0.1"); errno_assert (rc >= 0); /* Try using invalid address strings. */ rc = nn_connect (sc, "ws://*:"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "ws://*:1000000"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "ws://*:some_port"); nn_assert (rc < 0); rc = nn_connect (sc, "ws://eth10000;127.0.0.1:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == ENODEV); rc = nn_bind (sc, "ws://127.0.0.1:"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_bind (sc, "ws://127.0.0.1:1000000"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_bind (sc, "ws://eth10000:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == ENODEV); rc = nn_connect (sc, "ws://:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "ws://-hostname:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "ws://abc.123.---.#:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "ws://[::1]:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "ws://abc...123:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); rc = nn_connect (sc, "ws://.123:5555"); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); test_close (sc); sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, socket_address); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, socket_address); /* Ping-pong test. */ for (i = 0; i != 100; ++i) { test_send (sc, "ABC"); test_recv (sb, "ABC"); test_send (sb, "DEF"); test_recv (sc, "DEF"); } /* Batch transfer test. */ for (i = 0; i != 100; ++i) { test_send (sc, "0123456789012345678901234567890123456789"); } for (i = 0; i != 100; ++i) { test_recv (sb, "0123456789012345678901234567890123456789"); } test_close (sc); test_close (sb); /* Test two sockets binding to the same address. */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, socket_address); sb2 = test_socket (AF_SP, NN_PAIR); rc = nn_bind (sb2, socket_address); nn_assert (rc < 0); errno_assert (nn_errno () == EADDRINUSE); test_close(sb); test_close(sb2); /* Test that NN_RCVMAXSIZE can be -1, but not lower */ sb = test_socket (AF_SP, NN_PAIR); opt = -1; rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); nn_assert (rc >= 0); opt = -2; rc = nn_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); nn_assert (rc < 0); errno_assert (nn_errno () == EINVAL); test_close (sb); /* Test NN_RCVMAXSIZE limit */ sb = test_socket (AF_SP, NN_PAIR); test_bind (sb, socket_address); sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, socket_address); opt = 1000; test_setsockopt (sc, NN_SOL_SOCKET, NN_SNDTIMEO, &opt, sizeof (opt)); nn_assert (opt == 1000); opt = 1000; test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVTIMEO, &opt, sizeof (opt)); nn_assert (opt == 1000); opt = 4; test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); test_send (sc, "ABC"); test_recv (sb, "ABC"); test_send (sc, "ABCD"); test_recv (sb, "ABCD"); test_send (sc, "ABCDE"); test_drop (sb, ETIMEDOUT); /* Increase the size limit, reconnect, then try sending again. The reason a reconnect is necessary is because after a protocol violation, the connecting socket will not continue automatic reconnection attempts. */ opt = 5; test_setsockopt (sb, NN_SOL_SOCKET, NN_RCVMAXSIZE, &opt, sizeof (opt)); test_connect (sc, socket_address); test_send (sc, "ABCDE"); test_recv (sb, "ABCDE"); test_close (sb); test_close (sc); test_text (); /* Test closing a socket that is waiting to connect. */ sc = test_socket (AF_SP, NN_PAIR); test_connect (sc, socket_address); nn_sleep (100); test_close (sc); return 0; } nanomsg-1.1.5/tests/ws_async_shutdown.c000066400000000000000000000062631336111550300202540ustar00rootroot00000000000000/* Copyright (c) 2012 Martin Sustrik All rights reserved. Copyright (c) 2015-2016 Jack R. Dunaway. All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pubsub.h" #include "testutil.h" #include "../src/utils/thread.c" static char socket_address [128]; /* Test condition of closing sockets that are blocking in another thread. */ #define TEST_LOOPS 10 #define TEST_THREADS 10 static void routine (NN_UNUSED void *arg) { int s; int rc; char msg[1]; nn_assert (arg); s = *(int *)arg; while (1) { rc = nn_recv (s, &msg, sizeof(msg), 0); if (rc == 0) { continue; } nn_assert (rc == -1); /* A timeout is OK since PUB/SUB is lossy. */ if (nn_errno () == ETIMEDOUT) { continue; } break; } /* Socket is expected to be closed by caller. */ errno_assert (nn_errno () == EBADF); } int main (int argc, const char *argv[]) { int i; int j; int s; int sb; int rcvtimeo = 10; int sndtimeo = 0; int sockets [TEST_THREADS]; struct nn_thread threads [TEST_THREADS]; test_addr_from (socket_address, "ws", "127.0.0.1", get_test_port (argc, argv)); for (i = 0; i != TEST_LOOPS; ++i) { sb = test_socket (AF_SP, NN_PUB); test_bind (sb, socket_address); test_setsockopt (sb, NN_SOL_SOCKET, NN_SNDTIMEO, &sndtimeo, sizeof (sndtimeo)); for (j = 0; j < TEST_THREADS; j++){ s = test_socket (AF_SP, NN_SUB); test_setsockopt (s, NN_SOL_SOCKET, NN_RCVTIMEO, &rcvtimeo, sizeof (rcvtimeo)); test_setsockopt (s, NN_SUB, NN_SUB_SUBSCRIBE, "", 0); test_connect (s, socket_address); sockets [j] = s; nn_thread_init (&threads [j], routine, &sockets [j]); } /* Allow all threads a bit of time to connect. */ nn_sleep (100); test_send (sb, ""); for (j = 0; j < TEST_THREADS; j++) { test_close (sockets [j]); nn_thread_term (&threads [j]); } test_close (sb); } return 0; } nanomsg-1.1.5/tests/zerocopy.c000066400000000000000000000141111336111550300163340ustar00rootroot00000000000000/* Copyright (c) 2013 GoPivotal, Inc. All rights reserved. Copyright (c) 2014 Achille Roussel. All rights reserved. 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. */ #include "../src/nn.h" #include "../src/pubsub.h" #include "../src/reqrep.h" #include "testutil.h" /* * Nanomsg never zero copies anymore - it used to be an attribute of * the inproc transport, but frankly its a mistake for anyone to depend * on that. The implementation must be free to copy, move data, etc. * The only thing that should be guaranteed is that the "ownership" of the * message on send is passed to libnanomsg. libnanomsg may give that message * to an inproc receiver, or it can do something else (like copy the data) * with it. */ #if 0 #include void test_allocmsg_reqrep () { int rc; int req; void *p; struct nn_iovec iov; struct nn_msghdr hdr; /* Try to create an oversized message. */ p = nn_allocmsg (-1, 0); nn_assert (!p && nn_errno () == ENOMEM); p = nn_allocmsg (-3, 0); nn_assert (!p && nn_errno () == ENOMEM); /* Try to create a message of unknown type. */ p = nn_allocmsg (100, 333); nn_assert (!p && nn_errno () == EINVAL); /* Create a socket. */ req = test_socket (AF_SP_RAW, NN_REQ); /* Make send fail and check whether the zero-copy buffer is left alone rather than deallocated. */ p = nn_allocmsg (100, 0); nn_assert (p); rc = nn_send (req, &p, NN_MSG, NN_DONTWAIT); nn_assert (rc < 0); errno_assert (nn_errno () == EAGAIN); memset (p, 0, 100); rc = nn_freemsg (p); errno_assert (rc == 0); /* Same thing with nn_sendmsg(). */ p = nn_allocmsg (100, 0); nn_assert (p); iov.iov_base = &p; iov.iov_len = NN_MSG; memset (&hdr, 0, sizeof (hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; nn_sendmsg (req, &hdr, NN_DONTWAIT); errno_assert (nn_errno () == EAGAIN); memset (p, 0, 100); rc = nn_freemsg (p); errno_assert (rc == 0); /* Clean up. */ test_close (req); } void test_reallocmsg_reqrep () { int rc; int req; int rep; void *p; void *p2; /* Create sockets. */ req = nn_socket (AF_SP, NN_REQ); rep = nn_socket (AF_SP, NN_REP); rc = nn_bind (rep, "inproc://test"); errno_assert (rc >= 0); rc = nn_connect (req, "inproc://test"); errno_assert (rc >= 0); /* Create message, make sure we handle overflow. */ p = nn_allocmsg (100, 0); nn_assert (p); p2 = nn_reallocmsg (p, (size_t)-3); errno_assert (nn_errno () == ENOMEM); nn_assert (p2 == NULL); /* Realloc to fit data size. */ memcpy (p, "Hello World!", 12); p = nn_reallocmsg (p, 12); nn_assert (p); rc = nn_send (req, &p, NN_MSG, 0); errno_assert (rc == 12); /* Receive request and send response. */ rc = nn_recv (rep, &p, NN_MSG, 0); errno_assert (rc == 12); rc = nn_send (rep, &p, NN_MSG, 0); errno_assert (rc == 12); /* Receive response and free message. */ rc = nn_recv (req, &p, NN_MSG, 0); errno_assert (rc == 12); rc = memcmp (p, "Hello World!", 12); nn_assert (rc == 0); rc = nn_freemsg (p); errno_assert (rc == 0); /* Clean up. */ nn_close (req); nn_close (rep); } void test_reallocmsg_pubsub () { int rc; int pub; int sub1; int sub2; void *p; void *p1; void *p2; /* Create sockets. */ pub = nn_socket (AF_SP, NN_PUB); sub1 = nn_socket (AF_SP, NN_SUB); sub2 = nn_socket (AF_SP, NN_SUB); rc = nn_bind (pub, "inproc://test"); errno_assert (rc >= 0); rc = nn_connect (sub1, "inproc://test"); errno_assert (rc >= 0); rc = nn_connect (sub2, "inproc://test"); errno_assert (rc >= 0); rc = nn_setsockopt (sub1, NN_SUB, NN_SUB_SUBSCRIBE, "", 0); errno_assert (rc == 0); rc = nn_setsockopt (sub2, NN_SUB, NN_SUB_SUBSCRIBE, "", 0); errno_assert (rc == 0); /* Publish message. */ p = nn_allocmsg (12, 0); nn_assert (p); memcpy (p, "Hello World!", 12); rc = nn_send (pub, &p, NN_MSG, 0); errno_assert (rc == 12); /* Receive messages, both messages are the same object with inproc. */ rc = nn_recv (sub1, &p1, NN_MSG, 0); errno_assert (rc == 12); rc = nn_recv (sub2, &p2, NN_MSG, 0); errno_assert (rc == 12); nn_assert (p1 == p2); rc = memcmp (p1, "Hello World!", 12); nn_assert (rc == 0); rc = memcmp (p2, "Hello World!", 12); nn_assert (rc == 0); /* Reallocate one message, both messages shouldn't be the same object anymore. */ p1 = nn_reallocmsg (p1, 15); errno_assert (p1); nn_assert (p1 != p2); memcpy (((char*) p1) + 12, " 42", 3); rc = memcmp (p1, "Hello World! 42", 15); nn_assert (rc == 0); /* Release messages. */ rc = nn_freemsg (p1); errno_assert (rc == 0); rc = nn_freemsg (p2); errno_assert (rc == 0); /* Clean up. */ nn_close (sub2); nn_close (sub1); nn_close (pub); } #endif int main () { #if 0 test_allocmsg_reqrep (); test_reallocmsg_reqrep (); test_reallocmsg_pubsub (); #endif return 0; } nanomsg-1.1.5/tools/000077500000000000000000000000001336111550300143165ustar00rootroot00000000000000nanomsg-1.1.5/tools/nanocat.c000066400000000000000000000537401336111550300161160ustar00rootroot00000000000000/* Copyright (c) 2013 Insollo Entertainment, LLC. All rights reserved. Copyright 2016 Garrett D'Amore 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. */ #include "../src/nn.h" #include "../src/pubsub.h" #include "../src/pipeline.h" #include "../src/bus.h" #include "../src/pair.h" #include "../src/survey.h" #include "../src/reqrep.h" #include "options.h" #include "../src/utils/sleep.c" #include "../src/utils/clock.c" #include #include #include #include #include #include #if !defined NN_HAVE_WINDOWS #include #endif enum echo_format { NN_NO_ECHO, NN_ECHO_RAW, NN_ECHO_ASCII, NN_ECHO_QUOTED, NN_ECHO_MSGPACK, NN_ECHO_HEX }; typedef struct nn_options { /* Global options */ int verbose; /* Socket options */ int socket_type; struct nn_string_list bind_addresses; struct nn_string_list connect_addresses; float send_timeout; float recv_timeout; struct nn_string_list subscriptions; char *socket_name; /* Output options */ float send_delay; float send_interval; struct nn_blob data_to_send; /* Input options */ enum echo_format echo_format; } nn_options_t; /* Constants to get address of in option declaration */ static const int nn_push = NN_PUSH; static const int nn_pull = NN_PULL; static const int nn_pub = NN_PUB; static const int nn_sub = NN_SUB; static const int nn_req = NN_REQ; static const int nn_rep = NN_REP; static const int nn_bus = NN_BUS; static const int nn_pair = NN_PAIR; static const int nn_surveyor = NN_SURVEYOR; static const int nn_respondent = NN_RESPONDENT; struct nn_enum_item socket_types[] = { {"PUSH", NN_PUSH}, {"PULL", NN_PULL}, {"PUB", NN_PUB}, {"SUB", NN_SUB}, {"REQ", NN_REQ}, {"REP", NN_REP}, {"BUS", NN_BUS}, {"PAIR", NN_PAIR}, {"SURVEYOR", NN_SURVEYOR}, {"RESPONDENT", NN_RESPONDENT}, {NULL, 0}, }; /* Constants to get address of in option declaration */ static const int nn_echo_raw = NN_ECHO_RAW; static const int nn_echo_ascii = NN_ECHO_ASCII; static const int nn_echo_quoted = NN_ECHO_QUOTED; static const int nn_echo_msgpack = NN_ECHO_MSGPACK; static const int nn_echo_hex = NN_ECHO_HEX; struct nn_enum_item echo_formats[] = { {"no", NN_NO_ECHO}, {"raw", NN_ECHO_RAW}, {"ascii", NN_ECHO_ASCII}, {"quoted", NN_ECHO_QUOTED}, {"msgpack", NN_ECHO_MSGPACK}, {"hex", NN_ECHO_HEX}, {NULL, 0}, }; /* Constants for conflict masks */ #define NN_MASK_SOCK 1 #define NN_MASK_WRITEABLE 2 #define NN_MASK_READABLE 4 #define NN_MASK_SOCK_SUB 8 #define NN_MASK_DATA 16 #define NN_MASK_ENDPOINT 32 #define NN_NO_PROVIDES 0 #define NN_NO_CONFLICTS 0 #define NN_NO_REQUIRES 0 #define NN_MASK_SOCK_WRITEABLE (NN_MASK_SOCK | NN_MASK_WRITEABLE) #define NN_MASK_SOCK_READABLE (NN_MASK_SOCK | NN_MASK_READABLE) #define NN_MASK_SOCK_READWRITE (NN_MASK_SOCK_WRITEABLE|NN_MASK_SOCK_READABLE) struct nn_option nn_options[] = { /* Generic options */ {"verbose", 'v', NULL, NN_OPT_INCREMENT, offsetof (nn_options_t, verbose), NULL, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_NO_REQUIRES, "Generic", NULL, "Increase verbosity of the nanocat"}, {"silent", 'q', NULL, NN_OPT_DECREMENT, offsetof (nn_options_t, verbose), NULL, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_NO_REQUIRES, "Generic", NULL, "Decrease verbosity of the nanocat"}, {"help", 'h', NULL, NN_OPT_HELP, 0, NULL, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_NO_REQUIRES, "Generic", NULL, "This help text"}, /* Socket types */ {"push", 0, "nn_push", NN_OPT_SET_ENUM, offsetof (nn_options_t, socket_type), &nn_push, NN_MASK_SOCK_WRITEABLE, NN_MASK_SOCK, NN_MASK_DATA, "Socket Types", NULL, "Use NN_PUSH socket type"}, {"pull", 0, "nn_pull", NN_OPT_SET_ENUM, offsetof (nn_options_t, socket_type), &nn_pull, NN_MASK_SOCK_READABLE, NN_MASK_SOCK, NN_NO_REQUIRES, "Socket Types", NULL, "Use NN_PULL socket type"}, {"pub", 0, "nn_pub", NN_OPT_SET_ENUM, offsetof (nn_options_t, socket_type), &nn_pub, NN_MASK_SOCK_WRITEABLE, NN_MASK_SOCK, NN_MASK_DATA, "Socket Types", NULL, "Use NN_PUB socket type"}, {"sub", 0, "nn_sub", NN_OPT_SET_ENUM, offsetof (nn_options_t, socket_type), &nn_sub, NN_MASK_SOCK_READABLE|NN_MASK_SOCK_SUB, NN_MASK_SOCK, NN_NO_REQUIRES, "Socket Types", NULL, "Use NN_SUB socket type"}, {"req", 0, "nn_req", NN_OPT_SET_ENUM, offsetof (nn_options_t, socket_type), &nn_req, NN_MASK_SOCK_READWRITE, NN_MASK_SOCK, NN_MASK_DATA, "Socket Types", NULL, "Use NN_REQ socket type"}, {"rep", 0, "nn_rep", NN_OPT_SET_ENUM, offsetof (nn_options_t, socket_type), &nn_rep, NN_MASK_SOCK_READWRITE, NN_MASK_SOCK, NN_NO_REQUIRES, "Socket Types", NULL, "Use NN_REP socket type"}, {"surveyor", 0, "nn_surveyor", NN_OPT_SET_ENUM, offsetof (nn_options_t, socket_type), &nn_surveyor, NN_MASK_SOCK_READWRITE, NN_MASK_SOCK, NN_MASK_DATA, "Socket Types", NULL, "Use NN_SURVEYOR socket type"}, {"respondent", 0, "nn_respondent", NN_OPT_SET_ENUM, offsetof (nn_options_t, socket_type), &nn_respondent, NN_MASK_SOCK_READWRITE, NN_MASK_SOCK, NN_NO_REQUIRES, "Socket Types", NULL, "Use NN_RESPONDENT socket type"}, {"bus", 0, "nn_bus", NN_OPT_SET_ENUM, offsetof (nn_options_t, socket_type), &nn_bus, NN_MASK_SOCK_READWRITE, NN_MASK_SOCK, NN_NO_REQUIRES, "Socket Types", NULL, "Use NN_BUS socket type"}, {"pair", 0, "nn_pair", NN_OPT_SET_ENUM, offsetof (nn_options_t, socket_type), &nn_pair, NN_MASK_SOCK_READWRITE, NN_MASK_SOCK, NN_NO_REQUIRES, "Socket Types", NULL, "Use NN_PAIR socket type"}, /* Socket Options */ {"bind", 0, NULL, NN_OPT_LIST_APPEND, offsetof (nn_options_t, bind_addresses), NULL, NN_MASK_ENDPOINT, NN_NO_CONFLICTS, NN_NO_REQUIRES, "Socket Options", "ADDR", "Bind socket to the address ADDR"}, {"connect", 0, NULL, NN_OPT_LIST_APPEND, offsetof (nn_options_t, connect_addresses), NULL, NN_MASK_ENDPOINT, NN_NO_CONFLICTS, NN_NO_REQUIRES, "Socket Options", "ADDR", "Connect socket to the address ADDR"}, {"bind-ipc", 'X' , NULL, NN_OPT_LIST_APPEND_FMT, offsetof (nn_options_t, bind_addresses), "ipc://%s", NN_MASK_ENDPOINT, NN_NO_CONFLICTS, NN_NO_REQUIRES, "Socket Options", "PATH", "Bind socket to the ipc address " "\"ipc://PATH\"."}, {"connect-ipc", 'x' , NULL, NN_OPT_LIST_APPEND_FMT, offsetof (nn_options_t, connect_addresses), "ipc://%s", NN_MASK_ENDPOINT, NN_NO_CONFLICTS, NN_NO_REQUIRES, "Socket Options", "PATH", "Connect socket to the ipc address " "\"ipc://PATH\"."}, {"bind-local", 'L' , NULL, NN_OPT_LIST_APPEND_FMT, offsetof (nn_options_t, bind_addresses), "tcp://127.0.0.1:%s", NN_MASK_ENDPOINT, NN_NO_CONFLICTS, NN_NO_REQUIRES, "Socket Options", "PORT", "Bind socket to the tcp address " "\"tcp://127.0.0.1:PORT\"."}, {"connect-local", 'l' , NULL, NN_OPT_LIST_APPEND_FMT, offsetof (nn_options_t, connect_addresses), "tcp://127.0.0.1:%s", NN_MASK_ENDPOINT, NN_NO_CONFLICTS, NN_NO_REQUIRES, "Socket Options", "PORT", "Connect socket to the tcp address " "\"tcp://127.0.0.1:PORT\"."}, {"recv-timeout", 0, NULL, NN_OPT_FLOAT, offsetof (nn_options_t, recv_timeout), NULL, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_MASK_READABLE, "Socket Options", "SEC", "Set timeout for receiving a message"}, {"send-timeout", 0, NULL, NN_OPT_FLOAT, offsetof (nn_options_t, send_timeout), NULL, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_MASK_WRITEABLE, "Socket Options", "SEC", "Set timeout for sending a message"}, {"socket-name", 0, NULL, NN_OPT_STRING, offsetof (nn_options_t, socket_name), NULL, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_NO_REQUIRES, "Socket Options", "NAME", "Name of the socket for statistics"}, /* Pattern-specific options */ {"subscribe", 0, NULL, NN_OPT_LIST_APPEND, offsetof (nn_options_t, subscriptions), NULL, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_MASK_SOCK_SUB, "SUB Socket Options", "PREFIX", "Subscribe to the prefix PREFIX. " "Note: socket will be subscribed to everything (empty prefix) if " "no prefixes are specified on the command-line."}, /* Input Options */ {"format", 0, NULL, NN_OPT_ENUM, offsetof (nn_options_t, echo_format), &echo_formats, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_MASK_READABLE, "Input Options", "FORMAT", "Use echo format FORMAT " "(same as the options below)"}, {"raw", 0, NULL, NN_OPT_SET_ENUM, offsetof (nn_options_t, echo_format), &nn_echo_raw, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_MASK_READABLE, "Input Options", NULL, "Dump message as is " "(Note: no delimiters are printed)"}, {"ascii", 'A', NULL, NN_OPT_SET_ENUM, offsetof (nn_options_t, echo_format), &nn_echo_ascii, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_MASK_READABLE, "Input Options", NULL, "Print ASCII part of message delimited by newline. " "All non-ascii characters replaced by dot."}, {"quoted", 'Q', NULL, NN_OPT_SET_ENUM, offsetof (nn_options_t, echo_format), &nn_echo_quoted, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_MASK_READABLE, "Input Options", NULL, "Print each message on separate line in double " "quotes with C-like character escaping"}, {"msgpack", 0, NULL, NN_OPT_SET_ENUM, offsetof (nn_options_t, echo_format), &nn_echo_msgpack, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_MASK_READABLE, "Input Options", NULL, "Print each message as msgpacked string (raw type)." " This is useful for programmatic parsing."}, {"hex", 0, NULL, NN_OPT_SET_ENUM, offsetof (nn_options_t, echo_format), &nn_echo_hex, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_MASK_READABLE, "Input Options", NULL, "Print each message on separate line in double " "quotes with hex values"}, /* Output Options */ {"interval", 'i', NULL, NN_OPT_FLOAT, offsetof (nn_options_t, send_interval), NULL, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_MASK_WRITEABLE, "Output Options", "SEC", "Send message (or request) every SEC seconds"}, {"delay", 'd', NULL, NN_OPT_FLOAT, offsetof (nn_options_t, send_delay), NULL, NN_NO_PROVIDES, NN_NO_CONFLICTS, NN_NO_REQUIRES, "Output Options", "SEC", "Wait for SEC seconds before sending message" " (useful for one-shot PUB sockets)"}, {"data", 'D', NULL, NN_OPT_BLOB, offsetof (nn_options_t, data_to_send), &echo_formats, NN_MASK_DATA, NN_MASK_DATA, NN_MASK_WRITEABLE, "Output Options", "DATA", "Send DATA to the socket and quit for " "PUB, PUSH, PAIR, BUS socket. Use DATA to reply for REP or " " RESPONDENT socket. Send DATA as request for REQ or SURVEYOR socket."}, {"file", 'F', NULL, NN_OPT_READ_FILE, offsetof (nn_options_t, data_to_send), &echo_formats, NN_MASK_DATA, NN_MASK_DATA, NN_MASK_WRITEABLE, "Output Options", "PATH", "Same as --data but get data from file PATH"}, /* Sentinel */ {NULL, 0, NULL, 0, 0, NULL, 0, 0, 0, NULL, NULL, NULL}, }; struct nn_commandline nn_cli = { "A command-line interface to nanomsg", "", nn_options, NN_MASK_SOCK | NN_MASK_ENDPOINT, }; void nn_assert_errno (int flag, char *description) { int err; if (!flag) { err = errno; fprintf (stderr, "%s: %s\n", description, nn_strerror (err)); exit (3); } } void nn_sub_init (nn_options_t *options, int sock) { int i; int rc; if (options->subscriptions.num) { for (i = 0; i < options->subscriptions.num; ++i) { rc = nn_setsockopt (sock, NN_SUB, NN_SUB_SUBSCRIBE, options->subscriptions.items[i], strlen (options->subscriptions.items[i])); nn_assert_errno (rc == 0, "Can't subscribe"); } } else { rc = nn_setsockopt (sock, NN_SUB, NN_SUB_SUBSCRIBE, "", 0); nn_assert_errno (rc == 0, "Can't subscribe"); } } void nn_set_recv_timeout (int sock, int millis) { int rc; rc = nn_setsockopt (sock, NN_SOL_SOCKET, NN_RCVTIMEO, &millis, sizeof (millis)); nn_assert_errno (rc == 0, "Can't set recv timeout"); } int nn_create_socket (nn_options_t *options) { int sock; int rc; int millis; sock = nn_socket (AF_SP, options->socket_type); nn_assert_errno (sock >= 0, "Can't create socket"); /* Generic initialization */ if (options->send_timeout >= 0) { millis = (int)(options->send_timeout * 1000); rc = nn_setsockopt (sock, NN_SOL_SOCKET, NN_SNDTIMEO, &millis, sizeof (millis)); nn_assert_errno (rc == 0, "Can't set send timeout"); } if (options->recv_timeout >= 0) { nn_set_recv_timeout (sock, (int) options->recv_timeout * 1000); } if (options->socket_name) { rc = nn_setsockopt (sock, NN_SOL_SOCKET, NN_SOCKET_NAME, options->socket_name, strlen(options->socket_name)); nn_assert_errno (rc == 0, "Can't set socket name"); } /* Specific initialization */ switch (options->socket_type) { case NN_SUB: nn_sub_init (options, sock); break; } return sock; } void nn_print_message (nn_options_t *options, char *buf, int buflen) { switch (options->echo_format) { case NN_NO_ECHO: return; case NN_ECHO_RAW: fwrite (buf, 1, buflen, stdout); break; case NN_ECHO_ASCII: for (; buflen > 0; --buflen, ++buf) { if (isprint (*buf)) { fputc (*buf, stdout); } else { fputc ('.', stdout); } } fputc ('\n', stdout); break; case NN_ECHO_QUOTED: fputc ('"', stdout); for (; buflen > 0; --buflen, ++buf) { switch (*buf) { case '\n': fprintf (stdout, "\\n"); break; case '\r': fprintf (stdout, "\\r"); break; case '\\': case '\"': fprintf (stdout, "\\%c", *buf); break; default: if (isprint (*buf)) { fputc (*buf, stdout); } else { fprintf (stdout, "\\x%02x", (unsigned char)*buf); } } } fprintf (stdout, "\"\n"); break; case NN_ECHO_MSGPACK: if (buflen < 256) { fputc ('\xc4', stdout); fputc (buflen, stdout); fwrite (buf, 1, buflen, stdout); } else if (buflen < 65536) { fputc ('\xc5', stdout); fputc (buflen >> 8, stdout); fputc (buflen & 0xff, stdout); fwrite (buf, 1, buflen, stdout); } else { fputc ('\xc6', stdout); fputc (buflen >> 24, stdout); fputc ((buflen >> 16) & 0xff, stdout); fputc ((buflen >> 8) & 0xff, stdout); fputc (buflen & 0xff, stdout); fwrite (buf, 1, buflen, stdout); } break; case NN_ECHO_HEX: fputc ('"', stdout); for (; buflen > 0; --buflen, ++buf) { fprintf (stdout, "\\x%02x", (unsigned char)*buf); } fprintf (stdout, "\"\n"); break; } fflush (stdout); } void nn_connect_socket (nn_options_t *options, int sock) { int i; int rc; for (i = 0; i < options->bind_addresses.num; ++i) { rc = nn_bind (sock, options->bind_addresses.items[i]); nn_assert_errno (rc >= 0, "Can't bind"); } for (i = 0; i < options->connect_addresses.num; ++i) { rc = nn_connect (sock, options->connect_addresses.items[i]); nn_assert_errno (rc >= 0, "Can't connect"); } } void nn_send_loop (nn_options_t *options, int sock) { int rc; uint64_t start_time; int64_t time_to_sleep, interval; interval = (int)(options->send_interval*1000); for (;;) { start_time = nn_clock_ms(); rc = nn_send (sock, options->data_to_send.data, options->data_to_send.length, 0); if (rc < 0 && errno == EAGAIN) { fprintf (stderr, "Message not sent (EAGAIN)\n"); } else { nn_assert_errno (rc >= 0, "Can't send"); } if (interval >= 0) { time_to_sleep = (start_time + interval) - nn_clock_ms(); if (time_to_sleep > 0) { nn_sleep ((int) time_to_sleep); } } else { break; } } } void nn_recv_loop (nn_options_t *options, int sock) { int rc; void *buf; for (;;) { rc = nn_recv (sock, &buf, NN_MSG, 0); if (rc < 0 && errno == EAGAIN) { continue; } else if (rc < 0 && (errno == ETIMEDOUT || errno == EFSM)) { return; /* No more messages possible */ } else { nn_assert_errno (rc >= 0, "Can't recv"); } nn_print_message (options, buf, rc); nn_freemsg (buf); } } void nn_rw_loop (nn_options_t *options, int sock) { int rc; void *buf; uint64_t start_time; int64_t time_to_sleep, interval, recv_timeout; interval = (int)(options->send_interval*1000); recv_timeout = (int)(options->recv_timeout*1000); for (;;) { start_time = nn_clock_ms(); rc = nn_send (sock, options->data_to_send.data, options->data_to_send.length, 0); if (rc < 0 && errno == EAGAIN) { fprintf (stderr, "Message not sent (EAGAIN)\n"); } else { nn_assert_errno (rc >= 0, "Can't send"); } if (options->send_interval < 0) { /* Never send any more */ nn_recv_loop (options, sock); return; } for (;;) { time_to_sleep = (start_time + interval) - nn_clock_ms(); if (time_to_sleep <= 0) { break; } if (recv_timeout >= 0 && time_to_sleep > recv_timeout) { time_to_sleep = recv_timeout; } nn_set_recv_timeout (sock, (int) time_to_sleep); rc = nn_recv (sock, &buf, NN_MSG, 0); if (rc < 0) { if (errno == EAGAIN) { continue; } else if (errno == ETIMEDOUT || errno == EFSM) { time_to_sleep = (start_time + interval) - nn_clock_ms(); if (time_to_sleep > 0) nn_sleep ((int) time_to_sleep); continue; } } nn_assert_errno (rc >= 0, "Can't recv"); nn_print_message (options, buf, rc); nn_freemsg (buf); } } } void nn_resp_loop (nn_options_t *options, int sock) { int rc; void *buf; for (;;) { rc = nn_recv (sock, &buf, NN_MSG, 0); if (rc < 0 && errno == EAGAIN) { continue; } else { nn_assert_errno (rc >= 0, "Can't recv"); } nn_print_message (options, buf, rc); nn_freemsg (buf); rc = nn_send (sock, options->data_to_send.data, options->data_to_send.length, 0); if (rc < 0 && errno == EAGAIN) { fprintf (stderr, "Message not sent (EAGAIN)\n"); } else { nn_assert_errno (rc >= 0, "Can't send"); } } } int main (int argc, char **argv) { int sock; nn_options_t options = { /* verbose */ 0, /* socket_type */ 0, /* bind_addresses */ {NULL, NULL, 0, 0}, /* connect_addresses */ {NULL, NULL, 0, 0}, /* send_timeout */ -1.f, /* recv_timeout */ -1.f, /* subscriptions */ {NULL, NULL, 0, 0}, /* socket_name */ NULL, /* send_delay */ 0.f, /* send_interval */ -1.f, /* data_to_send */ {NULL, 0, 0}, /* echo_format */ NN_NO_ECHO }; nn_parse_options (&nn_cli, &options, argc, argv); sock = nn_create_socket (&options); nn_connect_socket (&options, sock); nn_sleep((int)(options.send_delay*1000)); switch (options.socket_type) { case NN_PUB: case NN_PUSH: nn_send_loop (&options, sock); break; case NN_SUB: case NN_PULL: nn_recv_loop (&options, sock); break; case NN_BUS: case NN_PAIR: if (options.data_to_send.data) { nn_rw_loop (&options, sock); } else { nn_recv_loop (&options, sock); } break; case NN_SURVEYOR: case NN_REQ: nn_rw_loop (&options, sock); break; case NN_REP: case NN_RESPONDENT: if (options.data_to_send.data) { nn_resp_loop (&options, sock); } else { nn_recv_loop (&options, sock); } break; } nn_close (sock); nn_free_options(&nn_cli, &options); return 0; } nanomsg-1.1.5/tools/options.c000066400000000000000000000571671336111550300161750ustar00rootroot00000000000000/* Copyright (c) 2013 Insollo Entertainment, LLC. All rights reserved. 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. */ #include "options.h" #include "../src/utils/err.c" #include #include #include #include #include struct nn_parse_context { /* Initial state */ struct nn_commandline *def; struct nn_option *options; void *target; int argc; char **argv; unsigned long requires; /* Current values */ unsigned long mask; int args_left; char **arg; char *data; char **last_option_usage; }; static int nn_has_arg (struct nn_option *opt) { switch (opt->type) { case NN_OPT_INCREMENT: case NN_OPT_DECREMENT: case NN_OPT_SET_ENUM: case NN_OPT_HELP: return 0; case NN_OPT_ENUM: case NN_OPT_STRING: case NN_OPT_BLOB: case NN_OPT_FLOAT: case NN_OPT_INT: case NN_OPT_LIST_APPEND: case NN_OPT_LIST_APPEND_FMT: case NN_OPT_READ_FILE: return 1; } nn_assert (0); } static void nn_print_usage (struct nn_parse_context *ctx, FILE *stream) { int i; int first; struct nn_option *opt; fprintf (stream, " %s ", ctx->argv[0]); /* Print required options (long names) */ first = 1; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (opt->mask_set & ctx->requires) { if (first) { first = 0; fprintf (stream, "{--%s", opt->longname); } else { fprintf (stream, "|--%s", opt->longname); } } } if (!first) { fprintf (stream, "} "); } /* Print flag short options */ first = 1; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (opt->mask_set & ctx->requires) continue; /* already printed */ if (opt->shortname && !nn_has_arg (opt)) { if (first) { first = 0; fprintf (stream, "[-%c", opt->shortname); } else { fprintf (stream, "%c", opt->shortname); } } } if (!first) { fprintf (stream, "] "); } /* Print short options with arguments */ for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (opt->mask_set & ctx->requires) continue; /* already printed */ if (opt->shortname && nn_has_arg (opt) && opt->metavar) { fprintf (stream, "[-%c %s] ", opt->shortname, opt->metavar); } } fprintf (stream, "[options] \n"); /* There may be long options too */ } static char *nn_print_line (FILE *out, char *str, size_t width) { size_t i; if (strlen (str) < width) { fprintf (out, "%s", str); return ""; } for (i = width; i > 1; --i) { if (isspace (str[i])) { fprintf (out, "%.*s", (int) i, str); return str + i + 1; } } /* no break points, just print as is */ fprintf (out, "%s", str); return ""; } static void nn_print_help (struct nn_parse_context *ctx, FILE *stream) { int i; size_t optlen; struct nn_option *opt; char *last_group; char *cursor; fprintf (stream, "Usage:\n"); nn_print_usage (ctx, stream); fprintf (stream, "\n%s\n", ctx->def->short_description); last_group = NULL; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (!last_group || last_group != opt->group || strcmp (last_group, opt->group)) { fprintf (stream, "\n"); fprintf (stream, "%s:\n", opt->group); last_group = opt->group; } fprintf (stream, " --%s", opt->longname); optlen = 3 + strlen (opt->longname); if (opt->shortname) { fprintf (stream, ",-%c", opt->shortname); optlen += 3; } if (nn_has_arg (opt)) { if (opt->metavar) { fprintf (stream, " %s", opt->metavar); optlen += strlen (opt->metavar) + 1; } else { fprintf (stream, " ARG"); optlen += 4; } } if (optlen < 23) { fputs (&" "[optlen], stream); cursor = nn_print_line (stream, opt->description, 80-24); } else { cursor = opt->description; } while (*cursor) { fprintf (stream, "\n "); cursor = nn_print_line (stream, cursor, 80-24); } fprintf (stream, "\n"); } } static void nn_print_option (struct nn_parse_context *ctx, int opt_index, FILE *stream) { char *ousage; char *oend; size_t olen; struct nn_option *opt; opt = &ctx->options[opt_index]; ousage = ctx->last_option_usage[opt_index]; if (*ousage == '-') { /* Long option */ oend = strchr (ousage, '='); if (!oend) { olen = strlen (ousage); } else { olen = (oend - ousage); } if (olen != strlen (opt->longname)+2) { fprintf (stream, " %.*s[%s] ", (int)olen, ousage, opt->longname + (olen-2)); } else { fprintf (stream, " %s ", ousage); } } else if (ousage == ctx->argv[0]) { /* Binary name */ fprintf (stream, " %s (executable) ", ousage); } else { /* Short option */ fprintf (stream, " -%c (--%s) ", *ousage, opt->longname); } } static void nn_option_error (char *message, struct nn_parse_context *ctx, int opt_index) { fprintf (stderr, "%s: Option", ctx->argv[0]); nn_print_option (ctx, opt_index, stderr); fprintf (stderr, "%s\n", message); exit (1); } static void nn_memory_error (struct nn_parse_context *ctx) { fprintf (stderr, "%s: Memory error while parsing command-line", ctx->argv[0]); abort (); } static void nn_invalid_enum_value (struct nn_parse_context *ctx, int opt_index, char *argument) { struct nn_option *opt; struct nn_enum_item *items; opt = &ctx->options[opt_index]; items = (struct nn_enum_item *)opt->pointer; fprintf (stderr, "%s: Invalid value ``%s'' for", ctx->argv[0], argument); nn_print_option (ctx, opt_index, stderr); fprintf (stderr, ". Options are:\n"); for (;items->name; ++items) { fprintf (stderr, " %s\n", items->name); } exit (1); } static void nn_option_conflict (struct nn_parse_context *ctx, int opt_index) { unsigned long mask; int i; int num_conflicts; struct nn_option *opt; fprintf (stderr, "%s: Option", ctx->argv[0]); nn_print_option (ctx, opt_index, stderr); fprintf (stderr, "conflicts with the following options:\n"); mask = ctx->options[opt_index].conflicts_mask; num_conflicts = 0; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (i == opt_index) continue; if (ctx->last_option_usage[i] && opt->mask_set & mask) { num_conflicts += 1; fprintf (stderr, " "); nn_print_option (ctx, i, stderr); fprintf (stderr, "\n"); } } if (!num_conflicts) { fprintf (stderr, " "); nn_print_option (ctx, opt_index, stderr); fprintf (stderr, "\n"); } exit (1); } static void nn_print_requires (struct nn_parse_context *ctx, unsigned long mask) { int i; struct nn_option *opt; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (opt->mask_set & mask) { fprintf (stderr, " --%s\n", opt->longname); if (opt->shortname) { fprintf (stderr, " -%c\n", opt->shortname); } } } exit (1); } static void nn_option_requires (struct nn_parse_context *ctx, int opt_index) { fprintf (stderr, "%s: Option", ctx->argv[0]); nn_print_option (ctx, opt_index, stderr); fprintf (stderr, "requires at least one of the following options:\n"); nn_print_requires (ctx, ctx->options[opt_index].requires_mask); exit (1); } static void nn_append_string (struct nn_parse_context *ctx, struct nn_option *opt, char *str) { struct nn_string_list *lst; lst = (struct nn_string_list *)(((char *)ctx->target) + opt->offset); nn_assert (lst); if (lst->items) { lst->num += 1; lst->items = realloc (lst->items, sizeof (char *) * lst->num); } else { lst->items = malloc (sizeof (char *)); lst->num = 1; } if (!lst->items) { nn_memory_error (ctx); } nn_assert (lst && lst->items); lst->items [lst->num - 1] = str; } static void nn_append_string_to_free (struct nn_parse_context *ctx, struct nn_option *opt, char *str) { struct nn_string_list *lst; lst = (struct nn_string_list *)( ((char *)ctx->target) + opt->offset); nn_assert (lst); if (lst->to_free) { lst->to_free_num += 1; lst->to_free = realloc (lst->items, sizeof (char *) * lst->to_free_num); } else { lst->to_free = malloc (sizeof (char *)); lst->to_free_num = 1; } if (!lst->items) { nn_memory_error (ctx); } nn_assert (lst->to_free); lst->to_free [lst->to_free_num - 1] = str; } static void nn_process_option (struct nn_parse_context *ctx, int opt_index, char *argument) { struct nn_option *opt; struct nn_enum_item *items; char *endptr; struct nn_blob *blob; FILE *file; char *data; size_t data_len; size_t data_buf; size_t bytes_read; opt = &ctx->options[opt_index]; if (ctx->mask & opt->conflicts_mask) { nn_option_conflict (ctx, opt_index); } ctx->mask |= opt->mask_set; switch (opt->type) { case NN_OPT_HELP: nn_print_help (ctx, stdout); exit (0); return; case NN_OPT_INT: *(long *)(((char *)ctx->target) + opt->offset) = strtol (argument, &endptr, 0); if (endptr == argument || *endptr != 0) { nn_option_error ("requires integer argument", ctx, opt_index); } return; case NN_OPT_INCREMENT: *(int *)(((char *)ctx->target) + opt->offset) += 1; return; case NN_OPT_DECREMENT: *(int *)(((char *)ctx->target) + opt->offset) -= 1; return; case NN_OPT_ENUM: items = (struct nn_enum_item *)opt->pointer; for (;items->name; ++items) { if (!strcmp (items->name, argument)) { *(int *)(((char *)ctx->target) + opt->offset) = \ items->value; return; } } nn_invalid_enum_value (ctx, opt_index, argument); return; case NN_OPT_SET_ENUM: *(int *)(((char *)ctx->target) + opt->offset) = \ *(int *)(opt->pointer); return; case NN_OPT_STRING: *(char **)(((char *)ctx->target) + opt->offset) = argument; return; case NN_OPT_BLOB: blob = (struct nn_blob *)(((char *)ctx->target) + opt->offset); blob->data = argument; blob->length = strlen (argument); blob->need_free = 0; return; case NN_OPT_FLOAT: #if defined NN_HAVE_WINDOWS *(float *)(((char *)ctx->target) + opt->offset) = (float) atof (argument); #else *(float *)(((char *)ctx->target) + opt->offset) = strtof (argument, &endptr); if (endptr == argument || *endptr != 0) { nn_option_error ("requires float point argument", ctx, opt_index); } #endif return; case NN_OPT_LIST_APPEND: nn_append_string (ctx, opt, argument); return; case NN_OPT_LIST_APPEND_FMT: data_buf = strlen (argument) + strlen (opt->pointer); data = malloc (data_buf); #if defined NN_HAVE_WINDOWS data_len = _snprintf_s (data, data_buf, _TRUNCATE, opt->pointer, argument); #else data_len = snprintf (data, data_buf, opt->pointer, argument); #endif assert (data_len < data_buf); nn_append_string (ctx, opt, data); nn_append_string_to_free (ctx, opt, data); return; case NN_OPT_READ_FILE: if (!strcmp (argument, "-")) { file = stdin; } else { file = fopen (argument, "r"); if (!file) { fprintf (stderr, "Error opening file ``%s'': %s\n", argument, strerror (errno)); exit (2); } } data = malloc (4096); if (!data) nn_memory_error (ctx); data_len = 0; data_buf = 4096; for (;;) { bytes_read = fread (data + data_len, 1, data_buf - data_len, file); data_len += bytes_read; if (feof (file)) break; if (data_buf - data_len < 1024) { if (data_buf < (1 << 20)) { data_buf *= 2; /* grow twice until not too big */ } else { data_buf += 1 << 20; /* grow 1 Mb each time */ } data = realloc (data, data_buf); if (!data) nn_memory_error (ctx); } } if (data_len != data_buf) { data = realloc (data, data_len); assert (data); } if (ferror (file)) { #if defined _MSC_VER #pragma warning (push) #pragma warning (disable:4996) #endif fprintf (stderr, "Error reading file ``%s'': %s\n", argument, strerror (errno)); #if defined _MSC_VER #pragma warning (pop) #endif exit (2); } if (file != stdin) { fclose (file); } blob = (struct nn_blob *)(((char *)ctx->target) + opt->offset); blob->data = data; blob->length = data_len; blob->need_free = 1; return; } abort (); } static void nn_parse_arg0 (struct nn_parse_context *ctx) { int i; struct nn_option *opt; char *arg0; arg0 = strrchr (ctx->argv[0], '/'); if (arg0 == NULL) { arg0 = ctx->argv[0]; } else { arg0 += 1; /* Skip slash itself */ } for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) return; if (opt->arg0name && !strcmp (arg0, opt->arg0name)) { assert (!nn_has_arg (opt)); ctx->last_option_usage[i] = ctx->argv[0]; nn_process_option (ctx, i, NULL); } } } static void nn_error_ambiguous_option (struct nn_parse_context *ctx) { struct nn_option *opt; char *a, *b; char *arg; arg = ctx->data+2; fprintf (stderr, "%s: Ambiguous option ``%s'':\n", ctx->argv[0], ctx->data); for (opt = ctx->options; opt->longname; ++opt) { for (a = opt->longname, b = arg; ; ++a, ++b) { if (*b == 0 || *b == '=') { /* End of option on command-line */ fprintf (stderr, " %s\n", opt->longname); break; } else if (*b != *a) { break; } } } exit (1); } static void nn_error_unknown_long_option (struct nn_parse_context *ctx) { fprintf (stderr, "%s: Unknown option ``%s''\n", ctx->argv[0], ctx->data); exit (1); } static void nn_error_unexpected_argument (struct nn_parse_context *ctx) { fprintf (stderr, "%s: Unexpected argument ``%s''\n", ctx->argv[0], ctx->data); exit (1); } static void nn_error_unknown_short_option (struct nn_parse_context *ctx) { fprintf (stderr, "%s: Unknown option ``-%c''\n", ctx->argv[0], *ctx->data); exit (1); } static int nn_get_arg (struct nn_parse_context *ctx) { if (!ctx->args_left) return 0; ctx->args_left -= 1; ctx->arg += 1; ctx->data = *ctx->arg; return 1; } static void nn_parse_long_option (struct nn_parse_context *ctx) { struct nn_option *opt; char *a, *b; size_t longest_prefix; size_t cur_prefix; int best_match; char *arg; int i; arg = ctx->data+2; longest_prefix = 0; best_match = -1; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; for (a = opt->longname, b = arg;; ++a, ++b) { if (*b == 0 || *b == '=') { /* End of option on command-line */ cur_prefix = a - opt->longname; if (!*a) { /* Matches end of option name */ best_match = i; longest_prefix = cur_prefix; goto finish; } if (cur_prefix == longest_prefix) { best_match = -1; /* Ambiguity */ } else if (cur_prefix > longest_prefix) { best_match = i; longest_prefix = cur_prefix; } break; } else if (*b != *a) { break; } } } finish: if (best_match >= 0) { opt = &ctx->options[best_match]; ctx->last_option_usage[best_match] = ctx->data; if (arg[longest_prefix] == '=') { if (nn_has_arg (opt)) { nn_process_option (ctx, best_match, arg + longest_prefix + 1); } else { nn_option_error ("does not accept argument", ctx, best_match); } } else { if (nn_has_arg (opt)) { if (nn_get_arg (ctx)) { nn_process_option (ctx, best_match, ctx->data); } else { nn_option_error ("requires an argument", ctx, best_match); } } else { nn_process_option (ctx, best_match, NULL); } } } else if (longest_prefix > 0) { nn_error_ambiguous_option (ctx); } else { nn_error_unknown_long_option (ctx); } } static void nn_parse_short_option (struct nn_parse_context *ctx) { int i; struct nn_option *opt; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (!opt->shortname) continue; if (opt->shortname == *ctx->data) { ctx->last_option_usage[i] = ctx->data; if (nn_has_arg (opt)) { if (ctx->data[1]) { nn_process_option (ctx, i, ctx->data+1); } else { if (nn_get_arg (ctx)) { nn_process_option (ctx, i, ctx->data); } else { nn_option_error ("requires an argument", ctx, i); } } ctx->data = ""; /* end of short options anyway */ } else { nn_process_option (ctx, i, NULL); ctx->data += 1; } return; } } nn_error_unknown_short_option (ctx); } static void nn_parse_arg (struct nn_parse_context *ctx) { if (ctx->data[0] == '-') { /* an option */ if (ctx->data[1] == '-') { /* long option */ if (ctx->data[2] == 0) { /* end of options */ return; } nn_parse_long_option (ctx); } else { ctx->data += 1; /* Skip minus */ while (*ctx->data) { nn_parse_short_option (ctx); } } } else { nn_error_unexpected_argument (ctx); } } void nn_check_requires (struct nn_parse_context *ctx) { int i; struct nn_option *opt; for (i = 0;; ++i) { opt = &ctx->options[i]; if (!opt->longname) break; if (!ctx->last_option_usage[i]) continue; if (opt->requires_mask && (opt->requires_mask & ctx->mask) != opt->requires_mask) { nn_option_requires (ctx, i); } } if ((ctx->requires & ctx->mask) != ctx->requires) { fprintf (stderr, "%s: At least one of the following required:\n", ctx->argv[0]); nn_print_requires (ctx, ctx->requires & ~ctx->mask); exit (1); } } void nn_parse_options (struct nn_commandline *cline, void *target, int argc, char **argv) { struct nn_parse_context ctx; int num_options; ctx.def = cline; ctx.options = cline->options; ctx.target = target; ctx.argc = argc; ctx.argv = argv; ctx.requires = cline->required_options; for (num_options = 0; ctx.options[num_options].longname; ++num_options); ctx.last_option_usage = calloc (sizeof (char *), num_options); if (!ctx.last_option_usage) nn_memory_error (&ctx); ctx.mask = 0; ctx.args_left = argc - 1; ctx.arg = argv; nn_parse_arg0 (&ctx); while (nn_get_arg (&ctx)) { nn_parse_arg (&ctx); } nn_check_requires (&ctx); free (ctx.last_option_usage); } void nn_free_options (struct nn_commandline *cline, void *target) { int i, j; struct nn_option *opt; struct nn_blob *blob; struct nn_string_list *lst; for (i = 0;; ++i) { opt = &cline->options[i]; if (!opt->longname) break; switch(opt->type) { case NN_OPT_LIST_APPEND: case NN_OPT_LIST_APPEND_FMT: lst = (struct nn_string_list *)(((char *)target) + opt->offset); nn_assert (lst); if(lst->items) { free(lst->items); lst->items = NULL; } if(lst->to_free) { for(j = 0; j < lst->to_free_num; ++j) { free(lst->to_free[j]); } free(lst->to_free); lst->to_free = NULL; } break; case NN_OPT_READ_FILE: case NN_OPT_BLOB: blob = (struct nn_blob *)(((char *)target) + opt->offset); if(blob->need_free && blob->data) { free(blob->data); blob->need_free = 0; } break; default: break; } } } nanomsg-1.1.5/tools/options.h000066400000000000000000000051001336111550300161560ustar00rootroot00000000000000/* Copyright (c) 2013 Insollo Entertainment, LLC. All rights reserved. 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. */ #ifndef NN_OPTIONS_HEADER #define NN_OPTIONS_HEADER #include enum nn_option_type { NN_OPT_HELP, NN_OPT_INT, NN_OPT_INCREMENT, NN_OPT_DECREMENT, NN_OPT_ENUM, NN_OPT_SET_ENUM, NN_OPT_STRING, NN_OPT_BLOB, NN_OPT_FLOAT, NN_OPT_LIST_APPEND, NN_OPT_LIST_APPEND_FMT, NN_OPT_READ_FILE }; struct nn_option { /* Option names */ char *longname; char shortname; char *arg0name; /* Parsing specification */ enum nn_option_type type; int offset; /* offsetof() where to store the value */ const void *pointer; /* type specific pointer */ /* Conflict mask for options */ unsigned long mask_set; unsigned long conflicts_mask; unsigned long requires_mask; /* Group and description for --help */ char *group; char *metavar; char *description; }; struct nn_commandline { char *short_description; char *long_description; struct nn_option *options; int required_options; }; struct nn_enum_item { char *name; int value; }; struct nn_string_list { char **items; char **to_free; int num; int to_free_num; }; struct nn_blob { char *data; size_t length; int need_free; }; void nn_parse_options (struct nn_commandline *cline, void *target, int argc, char **argv); void nn_free_options (struct nn_commandline *cline, void *target); #endif /* NN_OPTIONS_HEADER */