aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--src/CMakeLists.txt373
-rw-r--r--src/core/init.c4
-rw-r--r--src/core/nng_impl.h1
-rw-r--r--src/core/platform.h7
-rw-r--r--src/core/random.c202
-rw-r--r--src/core/random.h26
-rw-r--r--src/platform/posix/posix_rand.c88
-rw-r--r--src/platform/posix/posix_rand_arc4random.c24
-rw-r--r--src/platform/posix/posix_rand_getrandom.c40
-rw-r--r--src/platform/posix/posix_rand_urandom.c58
-rw-r--r--src/platform/windows/win_rand.c28
-rw-r--r--tests/platform.c77
13 files changed, 376 insertions, 556 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c13365f4..2789e0bd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -221,9 +221,6 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Android")
elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
add_definitions(-DNNG_PLATFORM_POSIX)
add_definitions(-DNNG_PLATFORM_DARWIN)
- # macOS 10.12 and later have getentropy, but the older releases
- # have ARC4_RANDOM, and that is sufficient to our needs.
- add_definitions(-DNNG_USE_ARC4RANDOM)
set(NNG_PLATFORM_POSIX ON)
elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
@@ -325,7 +322,6 @@ else ()
nng_check_func(lockf NNG_HAVE_LOCKF)
nng_check_func(flock NNG_HAVE_FLOCK)
- nng_check_func(getentropy NNG_HAVE_GETENTROPY)
nng_check_func(getrandom NNG_HAVE_GETRANDOM)
nng_check_func(arc4random_buf NNG_HAVE_ARC4RANDOM)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f5e2eca0..1b177aa1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,6 +1,6 @@
#
+# Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
# Copyright 2018 Capitar IT Group BV <info@capitar.com>
-# Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
# 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.
@@ -24,7 +24,7 @@
# IN THE SOFTWARE.
#
-add_library (${PROJECT_NAME}
+add_library(${PROJECT_NAME}
nng.c
${PROJECT_SOURCE_DIR}/include/nng/nng.h)
@@ -34,148 +34,145 @@ if (NNG_TESTS)
${PROJECT_SOURCE_DIR}/tests/testutil.c
${PROJECT_SOURCE_DIR}/tests/testutil.h
${PROJECT_SOURCE_DIR}/include/nng/nng.h)
-endif()
-
-set (NNG_SRCS
-
- core/defs.h
-
- core/aio.c
- core/aio.h
- core/clock.c
- core/clock.h
- core/device.c
- core/device.h
- core/dialer.c
- core/dialer.h
- core/file.c
- core/file.h
- core/idhash.c
- core/idhash.h
- core/init.c
- core/init.h
- core/list.c
- core/list.h
- core/listener.c
- core/listener.h
- core/lmq.c
- core/lmq.h
- core/message.c
- core/message.h
- core/msgqueue.c
- core/msgqueue.h
- core/nng_impl.h
- core/options.c
- core/options.h
- core/pollable.c
- core/pollable.h
- core/panic.c
- core/panic.h
- core/pipe.c
- core/pipe.h
- core/platform.h
- core/protocol.c
- core/protocol.h
- core/random.c
- core/random.h
- core/reap.c
- core/reap.h
- core/socket.c
- core/socket.h
- core/sockimpl.h
- core/stats.c
- core/stats.h
- core/stream.c
- core/stream.h
- core/strs.c
- core/strs.h
- core/taskq.c
- core/taskq.h
- core/thread.c
- core/thread.h
- core/timer.c
- core/timer.h
- core/transport.c
- core/transport.h
- core/url.c
- core/url.h
-)
+endif ()
+
+set(NNG_SRCS
+
+ core/defs.h
+
+ core/aio.c
+ core/aio.h
+ core/clock.c
+ core/clock.h
+ core/device.c
+ core/device.h
+ core/dialer.c
+ core/dialer.h
+ core/file.c
+ core/file.h
+ core/idhash.c
+ core/idhash.h
+ core/init.c
+ core/init.h
+ core/list.c
+ core/list.h
+ core/listener.c
+ core/listener.h
+ core/lmq.c
+ core/lmq.h
+ core/message.c
+ core/message.h
+ core/msgqueue.c
+ core/msgqueue.h
+ core/nng_impl.h
+ core/options.c
+ core/options.h
+ core/pollable.c
+ core/pollable.h
+ core/panic.c
+ core/panic.h
+ core/pipe.c
+ core/pipe.h
+ core/platform.h
+ core/protocol.c
+ core/protocol.h
+ core/reap.c
+ core/reap.h
+ core/socket.c
+ core/socket.h
+ core/sockimpl.h
+ core/stats.c
+ core/stats.h
+ core/stream.c
+ core/stream.h
+ core/strs.c
+ core/strs.h
+ core/taskq.c
+ core/taskq.h
+ core/thread.c
+ core/thread.h
+ core/timer.c
+ core/timer.h
+ core/transport.c
+ core/transport.h
+ core/url.c
+ core/url.h
+ )
if (NNG_PLATFORM_POSIX)
- find_package (Threads REQUIRED)
+ find_package(Threads REQUIRED)
list(APPEND NNG_LIBS Threads::Threads)
- set (NNG_SRCS ${NNG_SRCS}
- platform/posix/posix_impl.h
- platform/posix/posix_aio.h
- platform/posix/posix_ipc.h
- platform/posix/posix_config.h
- platform/posix/posix_pollq.h
- platform/posix/posix_tcp.h
-
- platform/posix/posix_alloc.c
- platform/posix/posix_atomic.c
- platform/posix/posix_clock.c
- platform/posix/posix_debug.c
- platform/posix/posix_file.c
- platform/posix/posix_ipcconn.c
- platform/posix/posix_ipcdial.c
- platform/posix/posix_ipclisten.c
- platform/posix/posix_pipe.c
- platform/posix/posix_rand.c
- platform/posix/posix_resolv_gai.c
- platform/posix/posix_sockaddr.c
- platform/posix/posix_tcpconn.c
- platform/posix/posix_tcpdial.c
- platform/posix/posix_tcplisten.c
- platform/posix/posix_thread.c
- platform/posix/posix_udp.c
- )
+ set(NNG_SRCS ${NNG_SRCS}
+ platform/posix/posix_impl.h
+ platform/posix/posix_aio.h
+ platform/posix/posix_ipc.h
+ platform/posix/posix_config.h
+ platform/posix/posix_pollq.h
+ platform/posix/posix_tcp.h
+
+ platform/posix/posix_alloc.c
+ platform/posix/posix_atomic.c
+ platform/posix/posix_clock.c
+ platform/posix/posix_debug.c
+ platform/posix/posix_file.c
+ platform/posix/posix_ipcconn.c
+ platform/posix/posix_ipcdial.c
+ platform/posix/posix_ipclisten.c
+ platform/posix/posix_pipe.c
+ platform/posix/posix_resolv_gai.c
+ platform/posix/posix_sockaddr.c
+ platform/posix/posix_tcpconn.c
+ platform/posix/posix_tcpdial.c
+ platform/posix/posix_tcplisten.c
+ platform/posix/posix_thread.c
+ platform/posix/posix_udp.c
+ )
if (NNG_HAVE_PORT_CREATE)
- set (NNG_SRCS ${NNG_SRCS}
- platform/posix/posix_pollq_port.c
- )
+ set(NNG_SRCS ${NNG_SRCS} platform/posix/posix_pollq_port.c)
elseif (NNG_HAVE_KQUEUE)
- set (NNG_SRCS ${NNG_SRCS}
- platform/posix/posix_pollq_kqueue.c
- )
+ set(NNG_SRCS ${NNG_SRCS} platform/posix/posix_pollq_kqueue.c)
elseif (NNG_HAVE_EPOLL AND NNG_HAVE_EVENTFD)
- set (NNG_SRCS ${NNG_SRCS}
- platform/posix/posix_pollq_epoll.c
- )
- else()
- set (NNG_SRCS ${NNG_SRCS}
- platform/posix/posix_pollq_poll.c
- )
- endif()
-endif()
+ set(NNG_SRCS ${NNG_SRCS} platform/posix/posix_pollq_epoll.c)
+ else ()
+ set(NNG_SRCS ${NNG_SRCS} platform/posix/posix_pollq_poll.c)
+ endif ()
+
+ if (NNG_HAVE_ARC4RANDOM)
+ set(NNG_SRCS ${NNG_SRCS} platform/posix/posix_rand_arc4random.c)
+ elseif (NNG_HAVE_GETRANDOM)
+ set(NNG_SRCS ${NNG_SRCS} platform/posix/posix_rand_getrandom.c)
+ else ()
+ set(NNG_SRCS ${NNG_SRCS} platform/posix/posix_rand_urandom.c)
+ endif ()
+endif ()
if (NNG_PLATFORM_WINDOWS)
- set (NNG_SRCS ${NNG_SRCS}
- platform/windows/win_impl.h
- platform/windows/win_ipc.h
- platform/windows/win_tcp.h
-
- platform/windows/win_clock.c
- platform/windows/win_debug.c
- platform/windows/win_file.c
- platform/windows/win_io.c
- platform/windows/win_ipcconn.c
- platform/windows/win_ipcdial.c
- platform/windows/win_ipclisten.c
- platform/windows/win_pipe.c
- platform/windows/win_rand.c
- platform/windows/win_resolv.c
- platform/windows/win_sockaddr.c
- platform/windows/win_tcp.c
- platform/windows/win_tcpconn.c
- platform/windows/win_tcpdial.c
- platform/windows/win_tcplisten.c
- platform/windows/win_thread.c
- platform/windows/win_udp.c
- )
-endif()
+ set(NNG_SRCS ${NNG_SRCS}
+ platform/windows/win_impl.h
+ platform/windows/win_ipc.h
+ platform/windows/win_tcp.h
+
+ platform/windows/win_clock.c
+ platform/windows/win_debug.c
+ platform/windows/win_file.c
+ platform/windows/win_io.c
+ platform/windows/win_ipcconn.c
+ platform/windows/win_ipcdial.c
+ platform/windows/win_ipclisten.c
+ platform/windows/win_pipe.c
+ platform/windows/win_rand.c
+ platform/windows/win_resolv.c
+ platform/windows/win_sockaddr.c
+ platform/windows/win_tcp.c
+ platform/windows/win_tcpconn.c
+ platform/windows/win_tcpdial.c
+ platform/windows/win_tcplisten.c
+ platform/windows/win_thread.c
+ platform/windows/win_udp.c
+ )
+endif ()
add_subdirectory(compat/nanomsg)
@@ -207,8 +204,8 @@ include_directories(AFTER SYSTEM ${PROJECT_SOURCE_DIR}/src ${NNG_INCS})
add_definitions(${NNG_DEFS})
-foreach(_PKG IN ITEMS ${NNG_PKGS})
- find_package(${_PKG} REQUIRED)
+foreach (_PKG IN ITEMS ${NNG_PKGS})
+ find_package(${_PKG} REQUIRED)
endforeach ()
# Library
@@ -216,10 +213,10 @@ target_sources(${PROJECT_NAME} PRIVATE ${NNG_SRCS})
if (NNG_TESTS)
target_sources(${PROJECT_NAME}_testlib PRIVATE ${NNG_SRCS})
- target_link_libraries (${PROJECT_NAME}_testlib PUBLIC ${NNG_LIBS})
+ target_link_libraries(${PROJECT_NAME}_testlib PUBLIC ${NNG_LIBS})
target_compile_definitions(${PROJECT_NAME}_testlib PUBLIC NNG_STATIC_LIB NNG_TEST_LIB)
- target_include_directories (${PROJECT_NAME}_testlib PUBLIC ${PROJECT_SOURCE_DIR}/include)
-endif()
+ target_include_directories(${PROJECT_NAME}_testlib PUBLIC ${PROJECT_SOURCE_DIR}/include)
+endif ()
# When building shared libraries we prefer to suppress default symbol
# visibility, so that only the symbols that should be exposed in the
@@ -229,55 +226,55 @@ if (BUILD_SHARED_LIBS)
if (NNG_HIDDEN_VISIBILITY)
target_compile_definitions(${PROJECT_NAME} PRIVATE -DNNG_HIDDEN_VISIBILITY)
set_target_properties(${PROJECT_NAME} PROPERTIES C_VISIBILITY_PRESET hidden)
- endif()
-else()
+ endif ()
+else ()
target_compile_definitions(${PROJECT_NAME} PUBLIC -DNNG_STATIC_LIB)
-endif()
+endif ()
-set_target_properties (${PROJECT_NAME}
- PROPERTIES SOVERSION ${NNG_ABI_SOVERSION} VERSION "${NNG_ABI_VERSION}")
+set_target_properties(${PROJECT_NAME}
+ PROPERTIES SOVERSION ${NNG_ABI_SOVERSION} VERSION "${NNG_ABI_VERSION}")
# 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})
-
-set_target_properties (${PROJECT_NAME} ${PROJECT_NAME}
- PROPERTIES FRAMEWORK OFF)
-
-target_link_libraries (${PROJECT_NAME} PRIVATE ${NNG_LIBS})
-
-target_include_directories (${PROJECT_NAME} INTERFACE $<INSTALL_INTERFACE:include>
-$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
-
-target_include_directories (${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/include)
-
-install (TARGETS ${PROJECT_NAME}
- EXPORT ${PROJECT_NAME}-target
- FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Library
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Library
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Library
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Tools
-)
-
-install (EXPORT ${PROJECT_NAME}-target
- FILE ${PROJECT_NAME}-targets.cmake
- NAMESPACE nng::
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
- COMPONENT Library
-)
-
-export (EXPORT ${PROJECT_NAME}-target
- FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-targets.cmake
- NAMESPACE nng::)
+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})
+
+set_target_properties(${PROJECT_NAME} ${PROJECT_NAME}
+ PROPERTIES FRAMEWORK OFF)
+
+target_link_libraries(${PROJECT_NAME} PRIVATE ${NNG_LIBS})
+
+target_include_directories(${PROJECT_NAME} INTERFACE $<INSTALL_INTERFACE:include>
+ $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
+
+target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/include)
+
+install(TARGETS ${PROJECT_NAME}
+ EXPORT ${PROJECT_NAME}-target
+ FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Library
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Library
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Library
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Tools
+ )
+
+install(EXPORT ${PROJECT_NAME}-target
+ FILE ${PROJECT_NAME}-targets.cmake
+ NAMESPACE nng::
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
+ COMPONENT Library
+ )
+
+export(EXPORT ${PROJECT_NAME}-target
+ FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-targets.cmake
+ NAMESPACE nng::)
# Install the header files.
install(DIRECTORY ../include/nng
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
- COMPONENT Headers)
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ COMPONENT Headers)
# Promote settings to parent
set(NNG_LIBS ${NNG_LIBS} PARENT_SCOPE)
@@ -300,13 +297,13 @@ set(version_config "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.c
set(project_config "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake")
write_basic_package_version_file("${version_config}"
- VERSION ${NNG_PACKAGE_VERSION}
- COMPATIBILITY SameMajorVersion
-)
+ VERSION ${NNG_PACKAGE_VERSION}
+ COMPATIBILITY SameMajorVersion
+ )
configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake.in "${project_config}"
- INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
- PATH_VARS INCLUDE_INSTALL_DIRS)
+ INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
+ PATH_VARS INCLUDE_INSTALL_DIRS)
install(FILES "${project_config}" "${version_config}"
- DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
- COMPONENT Library)
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
+ COMPONENT Library)
diff --git a/src/core/init.c b/src/core/init.c
index 60736fb7..4749516f 100644
--- a/src/core/init.c
+++ b/src/core/init.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
@@ -32,7 +32,6 @@ nni_init_helper(void)
((rv = nni_reap_sys_init()) != 0) ||
((rv = nni_timer_sys_init()) != 0) ||
((rv = nni_aio_sys_init()) != 0) ||
- ((rv = nni_random_sys_init()) != 0) ||
((rv = nni_sock_sys_init()) != 0) ||
((rv = nni_listener_sys_init()) != 0) ||
((rv = nni_dialer_sys_init()) != 0) ||
@@ -77,7 +76,6 @@ nni_fini(void)
nni_listener_sys_fini();
nni_sock_sys_fini();
nni_reap_drain();
- nni_random_sys_fini();
nni_aio_sys_fini();
nni_timer_sys_fini();
nni_taskq_sys_fini();
diff --git a/src/core/nng_impl.h b/src/core/nng_impl.h
index 0dcc976f..cfcd0e08 100644
--- a/src/core/nng_impl.h
+++ b/src/core/nng_impl.h
@@ -40,7 +40,6 @@
#include "core/panic.h"
#include "core/pollable.h"
#include "core/protocol.h"
-#include "core/random.h"
#include "core/reap.h"
#include "core/stats.h"
#include "core/stream.h"
diff --git a/src/core/platform.h b/src/core/platform.h
index b56f9a68..355ef7eb 100644
--- a/src/core/platform.h
+++ b/src/core/platform.h
@@ -208,11 +208,8 @@ extern void nni_plat_sleep(nni_duration);
// Entropy Support
//
-// nni_plat_seed_prng seeds the PRNG subsystem. The specified number
-// of bytes of entropy should be stashed. When possible, cryptographic
-// quality entropy sources should be used. Note that today we prefer
-// to seed up to 256 bytes of data.
-extern void nni_plat_seed_prng(void *, size_t);
+// nni_random returns a cryptographically secure random uint32.
+uint32_t nni_random(void);
// nni_plat_init is called to allow the platform the chance to
// do any necessary initialization. This routine MUST be idempotent,
diff --git a/src/core/random.c b/src/core/random.c
deleted file mode 100644
index 2d899f21..00000000
--- a/src/core/random.c
+++ /dev/null
@@ -1,202 +0,0 @@
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This software is supplied under the terms of the MIT License, a
-// copy of which should be located in the distribution where this
-// file was obtained (LICENSE.txt). A copy of the license may also be
-// found online at https://opensource.org/licenses/MIT.
-//
-
-#include "core/nng_impl.h"
-
-// This is ISAAC, a (reputedly) cryptographically secure PRNG that is also
-// quite efficient. While the particular adjustments to fit in our code
-// base are under our copyright, the actual algorithm itself, as well as
-// sample implementations, are part of the public domain. See this:
-// http://www.burtleburtle.net/bob/c/readable.c
-//
-// Our changes include making this code thread safe/reentrant, and naming
-// and style changes, to fit C99.
-
-typedef struct {
- // the rsl is the actual results, and the randcnt is the length
- // of the results.
- uint32_t randrsl[256];
- uint32_t randcnt;
-
- // lock to protect concurrent access
- nni_mtx mx;
-
- // more or less internal state
- uint32_t mm[256];
- uint32_t aa;
- uint32_t bb;
- uint32_t cc;
-} nni_isaac_ctx;
-
-static void
-nni_isaac(nni_isaac_ctx *ctx)
-{
- ctx->cc++; // cc incremented once per 256 results
- ctx->bb += ctx->cc; // then combined with bb
-
- for (uint32_t i = 0; i < 256; ++i) {
- uint32_t x = ctx->mm[i];
- uint32_t y;
- switch (i % 4) {
- case 0:
- ctx->aa ^= (ctx->aa << 13);
- break;
- case 1:
- ctx->aa ^= (ctx->aa >> 6);
- break;
- case 2:
- ctx->aa ^= (ctx->aa << 2);
- break;
- case 3:
- ctx->aa ^= (ctx->aa >> 16);
- break;
- }
- ctx->aa += ctx->mm[(i + 128) % 256];
- ctx->mm[i] = y = ctx->mm[(x >> 2) % 256] + ctx->aa + ctx->bb;
- ctx->randrsl[i] = ctx->bb = ctx->mm[(y >> 10) % 256] + x;
-
- // Note that bits 2..9 are chosen from x but 10..17 are chosen
- // from y. The only important thing here is that 2..9 and
- // 10..17 don't overlap. 2..9 and 10..17 were then chosen
- // for speed in the optimized version (rand.c)
-
- // See http://burtleburtle.net/bob/rand/isaac.html
- // for further explanations and analysis.
- }
-}
-
-// if (flag!=0), then use the contents of randrsl[] to initialize mm[].
-#define nni_isaac_mix(a, b, c, d, e, f, g, h) \
- { \
- a ^= b << 11; \
- d += a; \
- b += c; \
- b ^= c >> 2; \
- e += b; \
- c += d; \
- c ^= d << 8; \
- f += c; \
- d += e; \
- d ^= e >> 16; \
- g += d; \
- e += f; \
- e ^= f << 10; \
- h += e; \
- f += g; \
- f ^= g >> 4; \
- a += f; \
- g += h; \
- g ^= h << 8; \
- b += g; \
- h += a; \
- h ^= a >> 9; \
- c += h; \
- a += b; \
- }
-
-static void
-nni_isaac_randinit(nni_isaac_ctx *ctx, int flag)
-{
- int i;
- uint32_t a, b, c, d, e, f, g, h;
-
- ctx->aa = ctx->bb = ctx->cc = 0;
- a = b = c = d = e = f = g = h = 0x9e3779b9; // the golden ratio
-
- for (i = 0; i < 4; ++i) { // scramble it
- nni_isaac_mix(a, b, c, d, e, f, g, h);
- }
-
- for (i = 0; i < 256; i += 8) { // fill in mm[] with messy stuff
- if (flag) { // use all the information in the seed
- a += ctx->randrsl[i];
- b += ctx->randrsl[i + 1];
- c += ctx->randrsl[i + 2];
- d += ctx->randrsl[i + 3];
- e += ctx->randrsl[i + 4];
- f += ctx->randrsl[i + 5];
- g += ctx->randrsl[i + 6];
- h += ctx->randrsl[i + 7];
- }
- nni_isaac_mix(a, b, c, d, e, f, g, h);
- ctx->mm[i] = a;
- ctx->mm[i + 1] = b;
- ctx->mm[i + 2] = c;
- ctx->mm[i + 3] = d;
- ctx->mm[i + 4] = e;
- ctx->mm[i + 5] = f;
- ctx->mm[i + 6] = g;
- ctx->mm[i + 7] = h;
- }
-
- if (flag) {
- // do a second pass to make all of the seed affect all of mm
- for (i = 0; i < 256; i += 8) {
- a += ctx->mm[i];
- b += ctx->mm[i + 1];
- c += ctx->mm[i + 2];
- d += ctx->mm[i + 3];
- e += ctx->mm[i + 4];
- f += ctx->mm[i + 5];
- g += ctx->mm[i + 6];
- h += ctx->mm[i + 7];
- nni_isaac_mix(a, b, c, d, e, f, g, h);
- ctx->mm[i] = a;
- ctx->mm[i + 1] = b;
- ctx->mm[i + 2] = c;
- ctx->mm[i + 3] = d;
- ctx->mm[i + 4] = e;
- ctx->mm[i + 5] = f;
- ctx->mm[i + 6] = g;
- ctx->mm[i + 7] = h;
- }
- }
-
- nni_isaac(ctx); // fill in the first set of results
- ctx->randcnt = 256; // prepare to use the first set of results
-}
-
-static nni_isaac_ctx nni_random_ctx;
-
-int
-nni_random_sys_init(void)
-{
- // minimally, grab the system clock
- nni_isaac_ctx *ctx = &nni_random_ctx;
-
- nni_mtx_init(&ctx->mx);
- nni_plat_seed_prng(ctx->randrsl, sizeof(ctx->randrsl));
- nni_isaac_randinit(ctx, 1);
- return (0);
-}
-
-uint32_t
-nni_random(void)
-{
- uint32_t rv;
- nni_isaac_ctx *ctx = &nni_random_ctx;
-
- nni_mtx_lock(&ctx->mx);
- if (ctx->randcnt < 1) {
- nni_isaac(ctx);
- ctx->randcnt = 256;
- }
- ctx->randcnt--;
- rv = ctx->randrsl[ctx->randcnt];
- nni_mtx_unlock(&ctx->mx);
-
- return (rv);
-}
-
-void
-nni_random_sys_fini(void)
-{
- nni_mtx_fini(&nni_random_ctx.mx);
-}
diff --git a/src/core/random.h b/src/core/random.h
deleted file mode 100644
index 33229b09..00000000
--- a/src/core/random.h
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
-//
-// 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.
-//
-
-#ifndef CORE_RANDOM_H
-#define CORE_RANDOM_H
-
-// nni_random_sys_init initializes the pRNG subsystem. This includes obtaining
-// suitable seeding material from the platform.
-extern int nni_random_sys_init(void);
-
-// nni_random_sys_fini destroys the pRNG subsystem.
-extern void nni_random_sys_fini(void);
-
-// nni_random returns a random 32-bit integer. Note that this routine is
-// thread-safe/reentrant. The pRNG is very robust, should be of crypto
-// quality. However, its usefulness for cryptography will be determined
-// by the quality of the seeding material provided by the platform.
-extern uint32_t nni_random(void);
-
-#endif // CORE_RANDOM_H
diff --git a/src/platform/posix/posix_rand.c b/src/platform/posix/posix_rand.c
deleted file mode 100644
index 2b704e2f..00000000
--- a/src/platform/posix/posix_rand.c
+++ /dev/null
@@ -1,88 +0,0 @@
-//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
-// Copyright 2018 Capitar IT Group BV <info@capitar.com>
-//
-// This software is supplied under the terms of the MIT License, a
-// copy of which should be located in the distribution where this
-// file was obtained (LICENSE.txt). A copy of the license may also be
-// found online at https://opensource.org/licenses/MIT.
-//
-
-// POSIX clock stuff.
-#include "core/nng_impl.h"
-
-#ifdef NNG_PLATFORM_POSIX
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-#include <time.h>
-#include <unistd.h>
-
-#if defined(NNG_USE_GETRANDOM)
-#include <linux/random.h>
-#elif defined(NNG_USE_GETENTROPY)
-#include <sys/random.h>
-#endif
-
-// This structure represents the very barest minimum that we can use as
-// a source of entropy. We mix these into our initial entropy, but really
-// really really you want to have more data than this available, especially
-// for cryptographic applications.
-struct nni_plat_prng_x {
- nni_time now;
- pid_t pid;
- uid_t uid;
- struct utsname uts;
-};
-
-void
-nni_plat_seed_prng(void *buf, size_t bufsz)
-{
- struct nni_plat_prng_x x;
- size_t i;
-
- memset(buf, 0, bufsz);
-
-#if defined(NNG_USE_GETRANDOM)
- // Latest Linux has a nice API here.
- (void) getrandom(buf, bufsz, 0);
-#elif defined(NNG_USE_GETENTROPY)
- // Modern BSD systems prefer this, but can only generate 256 bytes
- (void) getentropy(buf, bufsz > 256 ? 256 : 0);
-#elif defined(NNG_USE_ARC4RANDOM)
- // This uses BSD style pRNG seeded from the kernel in libc.
- (void) arc4random_buf(buf, bufsz);
-#elif defined(NNG_USE_DEVURANDOM)
- // The historic /dev/urandom device. This is not as a good as
- // a system call, since file descriptor attacks are possible,
- // and it may need special permissions. We choose /dev/urandom
- // over /dev/random to avoid diminishing the system entropy.
- int fd;
-
- if ((fd = open("/dev/urandom", O_RDONLY)) >= 0) {
- (void) read(fd, buf, bufsz);
- (void) close(fd);
- }
-#endif
-
- // As a special extra guard, let's mixin the data from the
- // following system calls. This ensures that even on the most
- // limited of systems, we have at least *some* level of randomness.
- // The mixing is done in a way to avoid diminishing entropy we may
- // have already collected.
- memset(&x, 0, sizeof(x)); // satisfy valgrind
- x.now = nni_clock();
- x.pid = getpid();
- x.uid = getuid();
- uname(&x.uts);
-
- for (i = 0; (i < bufsz) && (i < sizeof(x)); i++) {
- ((uint8_t *) buf)[i] ^= ((uint8_t *) &x)[i];
- }
-}
-
-#endif // NNG_PLATFORM_POSIX
diff --git a/src/platform/posix/posix_rand_arc4random.c b/src/platform/posix/posix_rand_arc4random.c
new file mode 100644
index 00000000..a3cc265b
--- /dev/null
+++ b/src/platform/posix/posix_rand_arc4random.c
@@ -0,0 +1,24 @@
+//
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+// arc4random is the preferred source of cryptographic random numbers
+// on any platform where it is found.
+#include <stdlib.h>
+
+#include "core/nng_impl.h"
+
+#ifdef NNG_HAVE_ARC4RANDOM
+
+uint32_t
+nni_random(void)
+{
+ return (arc4random());
+}
+
+#endif \ No newline at end of file
diff --git a/src/platform/posix/posix_rand_getrandom.c b/src/platform/posix/posix_rand_getrandom.c
new file mode 100644
index 00000000..489b2c76
--- /dev/null
+++ b/src/platform/posix/posix_rand_getrandom.c
@@ -0,0 +1,40 @@
+//
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+// getrandom is not as nice as arc4random, but on platforms where it
+// exists and arc4random does not, we should use it.
+//
+// getrandom will block only if the urandom device is not seeded yet.
+// That can only happen during very early boot (earlier than we should
+// normally be running. This is the only time it can fail with correct
+// arguments, and then only if it is interrupted with a signal.
+
+#include <sys/random.h>
+
+#include "core/nng_impl.h"
+
+#ifdef NNG_HAVE_GETRANDOM
+
+uint32_t
+nni_random(void)
+{
+ uint32_t val;
+
+ // Documentation claims that as long as we are not using
+ // GRND_RANDOM and buflen < 256, this should never fail.
+ // The exception here is that we could fail if for some
+ // reason we got a signal while blocked at very early boot
+ // (i.e. /dev/urandom was not yet seeded).
+ if (getrandom(&val, sizeof(val), 0) != sizeof(val)) {
+ nni_panic("getrandom failed");
+ }
+ return (val);
+}
+
+#endif \ No newline at end of file
diff --git a/src/platform/posix/posix_rand_urandom.c b/src/platform/posix/posix_rand_urandom.c
new file mode 100644
index 00000000..32ea6a51
--- /dev/null
+++ b/src/platform/posix/posix_rand_urandom.c
@@ -0,0 +1,58 @@
+//
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "core/nng_impl.h"
+
+// The historic /dev/urandom device. This is not as a good as
+// a system call, since file descriptor attacks are possible, and it may
+// need special permissions. Modern advice is to always use /dev/urandom
+// unless you have very particular reasons for doing otherwise.
+// If you're in this code base, you're probably on either an ancient OS,
+// or one of the off-beat ones that hasn't updated for support with
+// arc4random or getrandom.
+
+// We could use ISAAC or something like that to seed it only once,
+// but instead we just keep our file descriptor open. This will have
+// the apparent effect of leaking these file descriptors across fork.
+
+static int urandom_fd = -1;
+static pthread_mutex_t urandom_lock = PTHREAD_MUTEX_INITIALIZER;
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0u
+#endif
+
+uint32_t
+nni_random(void)
+{
+ int fd;
+ uint32_t val;
+
+ (void) pthread_mutex_lock(&urandom_lock);
+ if ((fd = urandom_fd) == -1) {
+ if ((fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC)) < 0) {
+ (void) pthread_mutex_unlock(&urandom_lock);
+ nni_panic("failed to open /dev/urandom");
+ }
+ urandom_fd = fd;
+ }
+ (void) pthread_mutex_unlock(&urandom_lock);
+
+ if (read(fd, &val, sizeof(val)) != sizeof(val)) {
+ nni_panic("failed reading /dev/urandom");
+ }
+ return (val);
+} \ No newline at end of file
diff --git a/src/platform/windows/win_rand.c b/src/platform/windows/win_rand.c
index afe703ef..21568a81 100644
--- a/src/platform/windows/win_rand.c
+++ b/src/platform/windows/win_rand.c
@@ -1,5 +1,5 @@
//
-// Copyright 2017 Garrett D'Amore <garrett@damore.org>
+// Copyright 2020 Staysail Systems, Inc. <info@staysail.tech>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
@@ -11,22 +11,24 @@
#ifdef NNG_PLATFORM_WINDOWS
+#ifndef _CRT_RAND_S
+#define _CRT_RAND_S
+#endif
+
#include <stdlib.h>
-void
-nni_plat_seed_prng(void *buf, size_t bufsz)
+uint32_t
+nni_random(void)
{
unsigned val;
- // The rand_s routine uses RtlGenRandom to get high quality
- // pseudo random numbers (i.e. numbers that should be good enough
- // for use with crypto keying.)
- while (bufsz > sizeof(val)) {
- rand_s(&val);
- memcpy(buf, &val, sizeof(val));
- buf = (((char *) buf) + sizeof(val));
- bufsz -= sizeof(val);
- }
+ // rand_s is claimed by Microsoft to generate cryptographically
+ // secure numbers. It also is claimed that this will only fail
+ // for EINVAL if val is NULL (not the case here). Other error
+ // conditions might be possible, but we have no way to tell.
+ // For now we just ignore that possibility.
+ rand_s(&val);
+ return ((uint32_t)val);
}
-#endif // NNG_PLATFORM_WINDOWS
+#endif // NNG_PLATFORM_WINDOWS \ No newline at end of file
diff --git a/tests/platform.c b/tests/platform.c
index 7546fa7f..fc9eb210 100644
--- a/tests/platform.c
+++ b/tests/platform.c
@@ -66,10 +66,10 @@ test_clock(void)
TEST_CHECK(usdelta >= 200);
TEST_CHECK(usdelta < 500); // increased tolerance for CIs
if (msdelta > usdelta) {
- TEST_CHECK((msdelta - usdelta) < 50);
+ TEST_CHECK((msdelta - usdelta) < 50);
} else {
- TEST_CHECK((usdelta - msdelta) < 50);
- }
+ TEST_CHECK((usdelta - msdelta) < 50);
+ }
}
void
@@ -108,40 +108,65 @@ test_thread(void)
nng_thread_destroy(thr);
TEST_CHECK(aa.cnt == 1);
- nng_cv_free(aa.cv);
+ nng_cv_free(aa.cv);
nng_mtx_free(aa.mx);
}
void
test_condvar(void)
{
- nng_thread * thr;
- int rv;
- struct addarg aa;
-
- TEST_CHECK(nng_mtx_alloc(&aa.mx) == 0);
- TEST_CHECK(nng_cv_alloc(&aa.cv, aa.mx) == 0);
- aa.cnt = 0;
-
- TEST_CHECK((rv = nng_thread_create(&thr, add, &aa)) == 0);
-
- nng_mtx_lock(aa.mx);
- while (aa.cnt == 0) {
- nng_cv_wait(aa.cv);
- }
- nng_mtx_unlock(aa.mx);
- nng_thread_destroy(thr);
- TEST_CHECK(aa.cnt == 1);
-
- nng_cv_free(aa.cv);
- nng_mtx_free(aa.mx);
+ nng_thread * thr;
+ int rv;
+ struct addarg aa;
+
+ TEST_CHECK(nng_mtx_alloc(&aa.mx) == 0);
+ TEST_CHECK(nng_cv_alloc(&aa.cv, aa.mx) == 0);
+ aa.cnt = 0;
+
+ TEST_CHECK((rv = nng_thread_create(&thr, add, &aa)) == 0);
+
+ nng_mtx_lock(aa.mx);
+ while (aa.cnt == 0) {
+ nng_cv_wait(aa.cv);
+ }
+ nng_mtx_unlock(aa.mx);
+ nng_thread_destroy(thr);
+ TEST_CHECK(aa.cnt == 1);
+
+ nng_cv_free(aa.cv);
+ nng_mtx_free(aa.mx);
+}
+
+void
+test_random(void)
+{
+ int same = 0;
+ uint32_t values[1000];
+
+ for (int i = 0; i < 1000; i++) {
+ values[i] = nng_random();
+ }
+ for (int i = 0; i < 1000; i++) {
+ for (int j = 0; j < i; j++) {
+ if (values[j] == values[i]) {
+ same++;
+ }
+ }
+ }
+
+ // 1% reproduction is *highly* unlikely.
+ // There are 4 billion possible options, we are only looking at
+ // 1000 of them. In general, it would be an extreme outlier
+ // to see more than 2 repeats, unless you RNG is biased.
+ TEST_CHECK_(same < 5, "fewer than 5 in 1000 repeats: %d", same);
}
TEST_LIST = {
{ "sleep", test_sleep },
{ "clock", test_clock },
{ "mutex", test_mutex },
- { "thread", test_thread },
- { "condvar", test_condvar },
+ { "thread", test_thread },
+ { "condvar", test_condvar },
+ { "random", test_random },
{ NULL, NULL },
};