diff options
| author | Garrett D'Amore <garrett@damore.org> | 2017-01-08 15:28:37 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2017-01-08 17:33:05 -0800 |
| commit | c5b5bd910507520f7974a156a1de9d187f23bc2f (patch) | |
| tree | 9766716c795d88fe902c7196696c1389d76717ba | |
| parent | 4b166dd8ae417b818a5ba214d8f2e648ac1d5be9 (diff) | |
| download | nng-c5b5bd910507520f7974a156a1de9d187f23bc2f.tar.gz nng-c5b5bd910507520f7974a156a1de9d187f23bc2f.tar.bz2 nng-c5b5bd910507520f7974a156a1de9d187f23bc2f.zip | |
New ISAAC pRNG. This replaces other local hacks for random data.
Platforms must seed the pRNGs by offering an nni_plat_seed_prng()
routine. Implementations for POSIX using various options (including
the /dev/urandom device) are supplied.
| -rw-r--r-- | src/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/core/init.c | 6 | ||||
| -rw-r--r-- | src/core/nng_impl.h | 1 | ||||
| -rw-r--r-- | src/core/pipe.c | 2 | ||||
| -rw-r--r-- | src/core/platform.h | 13 | ||||
| -rw-r--r-- | src/core/random.c | 195 | ||||
| -rw-r--r-- | src/core/random.h | 26 | ||||
| -rw-r--r-- | src/platform/posix/posix_config.h | 25 | ||||
| -rw-r--r-- | src/platform/posix/posix_debug.c | 56 | ||||
| -rw-r--r-- | src/platform/posix/posix_rand.c | 86 | ||||
| -rw-r--r-- | src/platform/posix/posix_thread.c | 32 | ||||
| -rw-r--r-- | src/protocol/reqrep/req.c | 2 | ||||
| -rw-r--r-- | src/protocol/survey/survey.c | 3 |
13 files changed, 374 insertions, 76 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ac029bc9..12700a5c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -49,6 +49,8 @@ set (NNG_SOURCES core/platform.h core/protocol.c core/protocol.h + core/random.c + core/random.h core/socket.c core/socket.h core/thread.c @@ -63,6 +65,7 @@ set (NNG_SOURCES platform/posix/posix_clock.c platform/posix/posix_debug.c platform/posix/posix_net.c + platform/posix/posix_rand.c platform/posix/posix_thread.c protocol/pair/pair.c diff --git a/src/core/init.c b/src/core/init.c index 3ae10a21..f10173c8 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -14,6 +14,11 @@ static int nni_init_helper(void) { + int rv; + + if ((rv = nni_random_init()) != 0) { + return (rv); + } nni_tran_init(); return (0); } @@ -30,5 +35,6 @@ void nni_fini(void) { nni_tran_fini(); + nni_random_fini(); nni_plat_fini(); } diff --git a/src/core/nng_impl.h b/src/core/nng_impl.h index 4c00a522..6bf0900d 100644 --- a/src/core/nng_impl.h +++ b/src/core/nng_impl.h @@ -31,6 +31,7 @@ #include "core/panic.h" #include "core/platform.h" #include "core/protocol.h" +#include "core/random.h" #include "core/thread.h" #include "core/transport.h" diff --git a/src/core/pipe.c b/src/core/pipe.c index 249e887c..0633dea9 100644 --- a/src/core/pipe.c +++ b/src/core/pipe.c @@ -190,7 +190,7 @@ nni_pipe_start(nni_pipe *pipe) // happen if we wrap -- i.e. we've had 4 billion or so pipes. // XXX: consider making this a hash table!! nni_pipe *check; - pipe->p_id = nni_plat_nextid() & 0x7FFFFFFF; + pipe->p_id = nni_random() & 0x7FFFFFFF; collide = 0; NNI_LIST_FOREACH (&sock->s_pipes, check) { if ((pipe != check) && (check->p_id == pipe->p_id)) { diff --git a/src/core/platform.h b/src/core/platform.h index b1662cc1..5a504dec 100644 --- a/src/core/platform.h +++ b/src/core/platform.h @@ -152,13 +152,6 @@ extern int nni_plat_init(int (*)(void)); // will be called until nni_platform_init is called. extern void nni_plat_fini(void); -// nni_plat_nextid is used to generate a new pipe ID. This should be an -// increasing value, taken from a random starting point. (The randomness -// helps ensure we don't confuse pipe IDs from other connections.) The -// value must be obtained in a threadsafe way (e.g. via an atomic counter -// or under a lock protection.) -extern uint32_t nni_plat_nextid(void); - // nni_plat_strerror allows the platform to use additional error messages // for additional error codes. The err code passed in should be the // equivalent of errno or GetLastError, without the NNG_ESYSERR component. @@ -215,6 +208,12 @@ extern int nni_plat_tcp_send(nni_plat_tcpsock *, nni_iov *, int); // full, or an error condition occurs. extern int nni_plat_tcp_recv(nni_plat_tcpsock *, nni_iov *, int); +// 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); + // Actual platforms we support. This is included up front so that we can // get the specific types that are supplied by the platform. #if defined(PLATFORM_POSIX) diff --git a/src/core/random.c b/src/core/random.c new file mode 100644 index 00000000..b2ce0ef7 --- /dev/null +++ b/src/core/random.c @@ -0,0 +1,195 @@ +// +// 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. +// + +#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) +{ + register uint32_t i, x, y; + + ctx->cc++; // cc incremented once per 256 results + ctx->bb += ctx->cc; // then combined with bb + + for (i = 0; i < 256; ++i) { + x = ctx->mm[i]; + 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_init(void) +{ + // minimally, grab the system clock + nni_isaac_ctx *ctx = &nni_random_ctx; + int rv; + + if ((rv = nni_mtx_init(&ctx->mx)) != 0) { + return (rv); + } + + 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_fini(void) +{ + nni_mtx_fini(&nni_random_ctx.mx); +} diff --git a/src/core/random.h b/src/core/random.h new file mode 100644 index 00000000..cf365380 --- /dev/null +++ b/src/core/random.h @@ -0,0 +1,26 @@ +// +// 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_init initializes the pRNG subsystem. This includes obtaining +// suitable seeding material from the platform. +extern int nni_random_init(void); + +// nni_random_fini destroys the pRNG subsystem. +extern void nni_random_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_config.h b/src/platform/posix/posix_config.h index 6d282f63..e1bafd5c 100644 --- a/src/platform/posix/posix_config.h +++ b/src/platform/posix/posix_config.h @@ -27,23 +27,38 @@ // is defined. Platforms that don't use POSIX clocks will probably // ignore any setting here. // -// #define NNG_HAVE_ARC4RANDOM -// This indicates that the platform has the superior arc4random function -// for getting entropy. -// // #define NNG_HAVE_BACKTRACE // If your system has a working backtrace(), and backtrace_symbols(), // along with <execinfo.h>, you can define this to get richer backtrace // information for debugging. +// +// #define NNG_USE_GETRANDOM +// #define NNG_USE_GETENTROPY +// #define NNG_USE_ARC4RANDOM +// #define NNG_USE_DEVURANDOM +// Thesse are options for obtaining entropy to seed the pRNG. +// All known modern UNIX variants can support NNG_USE_DEVURANDOM, +// but the other options are better still, but not portable. #include <time.h> +// These are things about systems we know about. +#ifdef __APPLE__ // MacOS X used to lack CLOCK_MONOTONIC. Now it has it, but its // buggy, condition variables set to use it wake early. -#ifdef __APPLE__ #define NNG_USE_CLOCKID CLOCK_REALTIME +// macOS 10.12 has getentropy(), but arc4random() is good enough +// and works on older releases. +#define NNG_USE_ARC4RANDOM 1 #endif // __APPLE__ +// It should never hurt to use DEVURANDOM, since if the device does not +// exist then we won't open it. (Provided: it would be bad if the device +// exists but has somehow very very different semantics. We don't know +// of any such concerns.) This won't be used if any of the other options +// are defined and work. +#define NNG_USE_DEVURANDOM 1 + #define NNG_USE_CLOCKID CLOCK_REALTIME #ifndef CLOCK_REALTIME #define NNG_USE_GETTIMEOFDAY diff --git a/src/platform/posix/posix_debug.c b/src/platform/posix/posix_debug.c index a956d777..71006b25 100644 --- a/src/platform/posix/posix_debug.c +++ b/src/platform/posix/posix_debug.c @@ -55,35 +55,35 @@ static struct { int nng_err; } nni_plat_errnos[] = { - NNI_ERR(EINTR, NNG_EINTR) - NNI_ERR(EINVAL, NNG_EINVAL) - NNI_ERR(ENOMEM, NNG_ENOMEM) - NNI_ERR(EACCES, NNG_EPERM) - NNI_ERR(EADDRINUSE, NNG_EADDRINUSE) - NNI_ERR(EADDRNOTAVAIL, NNG_EADDRINVAL) - NNI_ERR(EAFNOSUPPORT, NNG_ENOTSUP) - NNI_ERR(EAGAIN, NNG_EAGAIN) - NNI_ERR(EBADF, NNG_ECLOSED) - NNI_ERR(EBUSY, NNG_EBUSY) - NNI_ERR(ECONNABORTED, NNG_ECLOSED) - NNI_ERR(ECONNREFUSED, NNG_ECONNREFUSED) - NNI_ERR(ECONNRESET, NNG_ECLOSED) - NNI_ERR(EHOSTUNREACH, NNG_EUNREACHABLE) - NNI_ERR(ENETUNREACH, NNG_EUNREACHABLE) - NNI_ERR(ENAMETOOLONG, NNG_EINVAL) - NNI_ERR(ENOENT, NNG_ENOENT) - NNI_ERR(ENOBUFS, NNG_ENOMEM) - NNI_ERR(ENOPROTOOPT, NNG_ENOTSUP) - NNI_ERR(ENOSYS, NNG_ENOTSUP) - NNI_ERR(ENOTSUP, NNG_ENOTSUP) - NNI_ERR(EPERM, NNG_EPERM) - NNI_ERR(EPIPE, NNG_ECLOSED) - NNI_ERR(EPROTO, NNG_EPROTO) + NNI_ERR(EINTR, NNG_EINTR) + NNI_ERR(EINVAL, NNG_EINVAL) + NNI_ERR(ENOMEM, NNG_ENOMEM) + NNI_ERR(EACCES, NNG_EPERM) + NNI_ERR(EADDRINUSE, NNG_EADDRINUSE) + NNI_ERR(EADDRNOTAVAIL, NNG_EADDRINVAL) + NNI_ERR(EAFNOSUPPORT, NNG_ENOTSUP) + NNI_ERR(EAGAIN, NNG_EAGAIN) + NNI_ERR(EBADF, NNG_ECLOSED) + NNI_ERR(EBUSY, NNG_EBUSY) + NNI_ERR(ECONNABORTED, NNG_ECLOSED) + NNI_ERR(ECONNREFUSED, NNG_ECONNREFUSED) + NNI_ERR(ECONNRESET, NNG_ECLOSED) + NNI_ERR(EHOSTUNREACH, NNG_EUNREACHABLE) + NNI_ERR(ENETUNREACH, NNG_EUNREACHABLE) + NNI_ERR(ENAMETOOLONG, NNG_EINVAL) + NNI_ERR(ENOENT, NNG_ENOENT) + NNI_ERR(ENOBUFS, NNG_ENOMEM) + NNI_ERR(ENOPROTOOPT, NNG_ENOTSUP) + NNI_ERR(ENOSYS, NNG_ENOTSUP) + NNI_ERR(ENOTSUP, NNG_ENOTSUP) + NNI_ERR(EPERM, NNG_EPERM) + NNI_ERR(EPIPE, NNG_ECLOSED) + NNI_ERR(EPROTO, NNG_EPROTO) NNI_ERR(EPROTONOSUPPORT, NNG_ENOTSUP) - NNI_ERR(ETIME, NNG_ETIMEDOUT) - NNI_ERR(ETIMEDOUT, NNG_ETIMEDOUT) - NNI_ERR(EWOULDBLOCK, NNG_EAGAIN) - NNI_ERR(0, 0) // must be last + NNI_ERR(ETIME, NNG_ETIMEDOUT) + NNI_ERR(ETIMEDOUT, NNG_ETIMEDOUT) + NNI_ERR(EWOULDBLOCK, NNG_EAGAIN) + NNI_ERR(0, 0) // must be last }; int diff --git a/src/platform/posix/posix_rand.c b/src/platform/posix/posix_rand.c new file mode 100644 index 00000000..65d1c031 --- /dev/null +++ b/src/platform/posix/posix_rand.c @@ -0,0 +1,86 @@ +// +// 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. +// + +// POSIX clock stuff. +#include "core/nng_impl.h" + +#ifdef PLATFORM_POSIX_RANDOM + +#include <time.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/utsname.h> +#include <fcntl.h> + +#ifdef NNG_USE_GETRANDOM +#include <linux/random.h> +#endif + +#ifdef 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; + int i; + +#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, buffz); + (void) close(fd); + } +#endif + + // As a speical 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. + 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 // PLATFORM_POSIX_RANDOM diff --git a/src/platform/posix/posix_thread.c b/src/platform/posix/posix_thread.c index e4e5e74b..991a08db 100644 --- a/src/platform/posix/posix_thread.c +++ b/src/platform/posix/posix_thread.c @@ -24,7 +24,6 @@ static pthread_mutex_t nni_plat_lock = PTHREAD_MUTEX_INITIALIZER; static int nni_plat_inited = 0; static int nni_plat_forked = 0; -static int nni_plat_next = 0; pthread_condattr_t nni_cvattr; pthread_mutexattr_t nni_mxattr; @@ -34,18 +33,6 @@ pthread_mutexattr_t nni_mxattr; int nni_plat_devnull = -1; -uint32_t -nni_plat_nextid(void) -{ - uint32_t id; - - pthread_mutex_lock(&nni_plat_lock); - id = nni_plat_next++; - pthread_mutex_unlock(&nni_plat_lock); - return (id); -} - - int nni_plat_mtx_init(nni_plat_mtx *mtx) { @@ -270,25 +257,6 @@ nni_plat_init(int (*helper)(void)) return (NNG_ENOMEM); } - // Generate a starting ID (used for Pipe IDs) -#ifdef NNG_HAVE_ARC4RANDOM - nni_plat_next = arc4random(); -#else - while (nni_plat_next == 0) { - uint16_t xsub[3]; - nni_time now = nni_clock(); - pid_t pid = getpid(); - - xsub[0] = (uint16_t) now; - xsub[1] = (uint16_t) (now >> 16); - xsub[2] = (uint16_t) (now >> 24); - xsub[0] ^= (uint16_t) pid; - xsub[1] ^= (uint16_t) (pid >> 16); - xsub[2] ^= (uint16_t) (pid >> 24); - nni_plat_next = nrand48(xsub); - } -#endif - if (pthread_atfork(NULL, NULL, nni_atfork_child) != 0) { pthread_mutex_unlock(&nni_plat_lock); (void) close(nni_plat_devnull); diff --git a/src/protocol/reqrep/req.c b/src/protocol/reqrep/req.c index 3c3bba9c..5b9671f8 100644 --- a/src/protocol/reqrep/req.c +++ b/src/protocol/reqrep/req.c @@ -58,7 +58,7 @@ nni_req_sock_init(void **reqp, nni_sock *sock) return (rv); } // this is "semi random" start for request IDs. - req->nextid = (nni_clock() >> 32) ^ (nni_clock() & 0xffffffff); + req->nextid = nni_random(); req->retry = NNI_SECOND * 60; req->sock = sock; req->reqmsg = NULL; diff --git a/src/protocol/survey/survey.c b/src/protocol/survey/survey.c index cb600dc3..9def9292 100644 --- a/src/protocol/survey/survey.c +++ b/src/protocol/survey/survey.c @@ -54,8 +54,7 @@ nni_surv_sock_init(void **sp, nni_sock *nsock) return (rv); } NNI_LIST_INIT(&psock->pipes, nni_surv_pipe, node); - // this is "semi random" start for request IDs. - psock->nextid = (nni_clock() >> 32) ^ (nni_clock() & 0xffffffff); + psock->nextid = nni_random(); psock->nsock = nsock; psock->raw = 0; psock->survtime = NNI_SECOND * 60; |
