[njs] Math.random() method.

Igor Sysoev igor at sysoev.ru
Thu Mar 24 15:16:59 UTC 2016


details:   http://hg.nginx.org/njs/rev/7ad8820b9c74
branches:  
changeset: 87:7ad8820b9c74
user:      Igor Sysoev <igor at sysoev.ru>
date:      Wed Mar 23 15:49:46 2016 +0300
description:
Math.random() method.

diffstat:

 Makefile                      |    6 +-
 njs/njs_array.c               |    1 +
 njs/njs_boolean.c             |    1 +
 njs/njs_builtin.c             |    1 +
 njs/njs_disassembler.c        |    1 +
 njs/njs_extern.c              |    1 +
 njs/njs_function.c            |    1 +
 njs/njs_generator.c           |    1 +
 njs/njs_lexer.c               |    1 +
 njs/njs_lexer_keyword.c       |    1 +
 njs/njs_math.c                |   21 ++++
 njs/njs_nonrecursive_parser.c |    1 +
 njs/njs_number.c              |   15 ++-
 njs/njs_object.c              |    1 +
 njs/njs_parser.c              |    1 +
 njs/njs_parser_expression.c   |    1 +
 njs/njs_regexp.c              |    1 +
 njs/njs_string.c              |    1 +
 njs/njs_variable.c            |    1 +
 njs/njs_vm.c                  |    1 +
 njs/njs_vm.h                  |    2 +
 njs/njscript.c                |    1 +
 njs/test/njs_unit_test.c      |    9 +-
 nxt/Makefile                  |   12 ++
 nxt/auto/configure            |    1 +
 nxt/auto/getrandom            |   24 +++++
 nxt/nxt_random.c              |  179 ++++++++++++++++++++++++++++++++++++++++++
 nxt/nxt_random.h              |   37 ++++++++
 nxt/nxt_types.h               |    3 +
 nxt/test/Makefile             |   11 ++
 nxt/test/random_unit_test.c   |   60 ++++++++++++++
 31 files changed, 387 insertions(+), 11 deletions(-)

diffs (757 lines):

diff -r e3bc4f6f3480 -r 7ad8820b9c74 Makefile
--- a/Makefile	Wed Mar 23 15:27:14 2016 +0300
+++ b/Makefile	Wed Mar 23 15:49:46 2016 +0300
@@ -34,6 +34,7 @@ NXT_BUILDDIR =	build
 	$(NXT_BUILDDIR)/nxt_array.o \
 	$(NXT_BUILDDIR)/nxt_rbtree.o \
 	$(NXT_BUILDDIR)/nxt_lvlhsh.o \
+	$(NXT_BUILDDIR)/nxt_random.o \
 	$(NXT_BUILDDIR)/nxt_malloc.o \
 	$(NXT_BUILDDIR)/nxt_mem_cache_pool.o \
 
@@ -63,6 +64,7 @@ NXT_BUILDDIR =	build
 		$(NXT_BUILDDIR)/nxt_array.o \
 		$(NXT_BUILDDIR)/nxt_rbtree.o \
 		$(NXT_BUILDDIR)/nxt_lvlhsh.o \
+		$(NXT_BUILDDIR)/nxt_random.o \
 		$(NXT_BUILDDIR)/nxt_malloc.o \
 		$(NXT_BUILDDIR)/nxt_mem_cache_pool.o \
 
@@ -370,12 +372,14 @@ tarball:
 		njs/njs_disassembler.c
 
 $(NXT_BUILDDIR)/njs_unit_test: \
+	$(NXT_BUILDDIR)/libnxt.a \
 	$(NXT_BUILDDIR)/libnjs.a \
 	njs/test/njs_unit_test.c \
 
 	$(NXT_CC) -o $(NXT_BUILDDIR)/njs_unit_test $(NXT_CFLAGS) \
 		-I$(NXT_LIB) -Injs \
 		njs/test/njs_unit_test.c \
-		$(NXT_BUILDDIR)/libnjs.a -lm $(NXT_PCRE_LIB)
+		$(NXT_BUILDDIR)/libnjs.a \
+		-lm $(NXT_PCRE_LIB)
 
 include $(NXT_LIB)/Makefile
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_array.c
--- a/njs/njs_array.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_array.c	Wed Mar 23 15:49:46 2016 +0300
@@ -11,6 +11,7 @@
 #include <nxt_djb_hash.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_boolean.c
--- a/njs/njs_boolean.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_boolean.c	Wed Mar 23 15:49:46 2016 +0300
@@ -9,6 +9,7 @@
 #include <nxt_stub.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_builtin.c
--- a/njs/njs_builtin.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_builtin.c	Wed Mar 23 15:49:46 2016 +0300
@@ -9,6 +9,7 @@
 #include <nxt_stub.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_disassembler.c
--- a/njs/njs_disassembler.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_disassembler.c	Wed Mar 23 15:49:46 2016 +0300
@@ -9,6 +9,7 @@
 #include <nxt_stub.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_extern.c
--- a/njs/njs_extern.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_extern.c	Wed Mar 23 15:49:46 2016 +0300
@@ -12,6 +12,7 @@
 #include <nxt_djb_hash.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_function.c
--- a/njs/njs_function.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_function.c	Wed Mar 23 15:49:46 2016 +0300
@@ -10,6 +10,7 @@
 #include <nxt_stub.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_generator.c
--- a/njs/njs_generator.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_generator.c	Wed Mar 23 15:49:46 2016 +0300
@@ -9,6 +9,7 @@
 #include <nxt_stub.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_lexer.c
--- a/njs/njs_lexer.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_lexer.c	Wed Mar 23 15:49:46 2016 +0300
@@ -10,6 +10,7 @@
 #include <nxt_djb_hash.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_lexer_keyword.c
--- a/njs/njs_lexer_keyword.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_lexer_keyword.c	Wed Mar 23 15:49:46 2016 +0300
@@ -10,6 +10,7 @@
 #include <nxt_djb_hash.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_math.c
--- a/njs/njs_math.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_math.c	Wed Mar 23 15:49:46 2016 +0300
@@ -10,6 +10,7 @@
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
 #include <nxt_mem_cache_pool.h>
+#include <nxt_random.h>
 #include <njscript.h>
 #include <njs_vm.h>
 #include <njs_number.h>
@@ -298,6 +299,20 @@ njs_object_math_pow(njs_vm_t *vm, njs_va
 
 
 static njs_ret_t
+njs_object_math_random(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+    njs_index_t unused)
+{
+    double  num;
+
+    num = nxt_random(&vm->random) / 4294967296.0;
+
+    njs_number_set(&vm->retval, num);
+
+    return NXT_OK;
+}
+
+
+static njs_ret_t
 njs_object_math_round(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
 {
@@ -520,6 +535,12 @@ static const njs_object_prop_t  njs_math
 
     {
         .type = NJS_METHOD,
+        .name = njs_string("random"),
+        .value = njs_native_function(njs_object_math_random, 0, ),
+    },
+
+    {
+        .type = NJS_METHOD,
         .name = njs_string("round"),
         .value = njs_native_function(njs_object_math_round, 0,
                      NJS_SKIP_ARG, NJS_NUMBER_ARG),
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_nonrecursive_parser.c
--- a/njs/njs_nonrecursive_parser.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_nonrecursive_parser.c	Wed Mar 23 15:49:46 2016 +0300
@@ -10,6 +10,7 @@
 #include <nxt_stub.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_number.c
--- a/njs/njs_number.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_number.c	Wed Mar 23 15:49:46 2016 +0300
@@ -9,6 +9,7 @@
 #include <nxt_stub.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
@@ -163,7 +164,7 @@ njs_number_to_string(njs_vm_t *vm, njs_v
     const njs_value_t *number)
 {
     u_char             *p;
-    double             num;
+    double             n, num;
     size_t             size;
     const char         *fmt;
     const njs_value_t  *value;
@@ -184,10 +185,18 @@ njs_number_to_string(njs_vm_t *vm, njs_v
         }
 
     } else {
-        if (fabs(num) < 1000000) {
+        n = fabs(num);
+
+        if (n == 0) {
             fmt = "%g";
 
-        } else if (fabs(num) < 1e20) {
+        } else if (n < 1) {
+            fmt = "%f";
+
+        } else if (n < 1000000) {
+            fmt = "%g";
+
+        } else if (n < 1e20) {
             fmt = "%1.f";
 
         } else {
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_object.c
--- a/njs/njs_object.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_object.c	Wed Mar 23 15:49:46 2016 +0300
@@ -10,6 +10,7 @@
 #include <nxt_djb_hash.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_parser.c
--- a/njs/njs_parser.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_parser.c	Wed Mar 23 15:49:46 2016 +0300
@@ -10,6 +10,7 @@
 #include <nxt_utf8.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_parser_expression.c
--- a/njs/njs_parser_expression.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_parser_expression.c	Wed Mar 23 15:49:46 2016 +0300
@@ -11,6 +11,7 @@
 #include <nxt_stub.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_regexp.c
--- a/njs/njs_regexp.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_regexp.c	Wed Mar 23 15:49:46 2016 +0300
@@ -13,6 +13,7 @@
 #include <nxt_djb_hash.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_malloc.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_string.c
--- a/njs/njs_string.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_string.c	Wed Mar 23 15:49:46 2016 +0300
@@ -13,6 +13,7 @@
 #include <nxt_djb_hash.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_malloc.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_variable.c
--- a/njs/njs_variable.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_variable.c	Wed Mar 23 15:49:46 2016 +0300
@@ -12,6 +12,7 @@
 #include <nxt_djb_hash.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_vm.c
--- a/njs/njs_vm.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_vm.c	Wed Mar 23 15:49:46 2016 +0300
@@ -11,6 +11,7 @@
 #include <nxt_djb_hash.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njs_vm.h
--- a/njs/njs_vm.h	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njs_vm.h	Wed Mar 23 15:49:46 2016 +0300
@@ -774,6 +774,8 @@ struct njs_vm_s {
     njs_regexp_pattern_t     *pattern;
 
     nxt_array_t              *code;  /* of njs_vm_code_t */
+
+    nxt_random_t             random;
 };
 
 
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/njscript.c
--- a/njs/njscript.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/njscript.c	Wed Mar 23 15:49:46 2016 +0300
@@ -10,6 +10,7 @@
 #include <nxt_stub.h>
 #include <nxt_array.h>
 #include <nxt_lvlhsh.h>
+#include <nxt_random.h>
 #include <nxt_malloc.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
diff -r e3bc4f6f3480 -r 7ad8820b9c74 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Wed Mar 23 15:27:14 2016 +0300
+++ b/njs/test/njs_unit_test.c	Wed Mar 23 15:49:46 2016 +0300
@@ -3919,12 +3919,6 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Math.PI"),
       nxt_string("3.14159") },
 
-    { nxt_string("Math.E"),
-      nxt_string("2.71828") },
-
-    { nxt_string("Math.SQRT2"),
-      nxt_string("1.41421") },
-
     { nxt_string("Math.abs(5)"),
       nxt_string("5") },
 
@@ -3970,7 +3964,8 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Math.pow()"),
       nxt_string("NaN") },
 
-    /* ES5: Must be "[object Math]". */
+    /* ES5FIX: "[object Math]". */
+
     { nxt_string("Math"),
       nxt_string("[object Object]") },
 
diff -r e3bc4f6f3480 -r 7ad8820b9c74 nxt/Makefile
--- a/nxt/Makefile	Wed Mar 23 15:27:14 2016 +0300
+++ b/nxt/Makefile	Wed Mar 23 15:49:46 2016 +0300
@@ -9,6 +9,7 @@ NXT_LIB =	nxt
 	$(NXT_BUILDDIR)/nxt_queue.o \
 	$(NXT_BUILDDIR)/nxt_rbtree.o \
 	$(NXT_BUILDDIR)/nxt_lvlhsh.o \
+	$(NXT_BUILDDIR)/nxt_random.o \
 	$(NXT_BUILDDIR)/nxt_malloc.o \
 	$(NXT_BUILDDIR)/nxt_mem_cache_pool.o \
 
@@ -19,6 +20,7 @@ NXT_LIB =	nxt
 		$(NXT_BUILDDIR)/nxt_rbtree.o \
 		$(NXT_BUILDDIR)/nxt_lvlhsh.o \
 		$(NXT_BUILDDIR)/nxt_malloc.o \
+		$(NXT_BUILDDIR)/nxt_random.o \
 		$(NXT_BUILDDIR)/nxt_mem_cache_pool.o \
 
 $(NXT_BUILDDIR)/nxt_murmur_hash.o: \
@@ -102,6 +104,16 @@ NXT_LIB =	nxt
 		-I$(NXT_LIB) \
 		$(NXT_LIB)/nxt_malloc.c
 
+$(NXT_BUILDDIR)/nxt_random.o: \
+	$(NXT_LIB)/nxt_types.h \
+	$(NXT_LIB)/nxt_clang.h \
+	$(NXT_LIB)/nxt_random.h \
+	$(NXT_LIB)/nxt_random.c \
+
+	$(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_random.o $(NXT_CFLAGS) \
+		-I$(NXT_LIB) \
+		$(NXT_LIB)/nxt_random.c
+
 $(NXT_BUILDDIR)/nxt_mem_cache_pool.o: \
 	$(NXT_LIB)/nxt_types.h \
 	$(NXT_LIB)/nxt_clang.h \
diff -r e3bc4f6f3480 -r 7ad8820b9c74 nxt/auto/configure
--- a/nxt/auto/configure	Wed Mar 23 15:27:14 2016 +0300
+++ b/nxt/auto/configure	Wed Mar 23 15:49:46 2016 +0300
@@ -52,4 +52,5 @@ END
 . ${NXT_AUTO}os
 . ${NXT_AUTO}clang
 . ${NXT_AUTO}memalign
+. ${NXT_AUTO}getrandom
 . ${NXT_AUTO}pcre
diff -r e3bc4f6f3480 -r 7ad8820b9c74 nxt/auto/getrandom
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nxt/auto/getrandom	Wed Mar 23 15:49:46 2016 +0300
@@ -0,0 +1,24 @@
+
+# Copyright (C) Igor Sysoev
+# Copyright (C) NGINX, Inc.
+
+
+# Linux 3.17 getrandom().
+
+nxt_feature="getrandom()"
+nxt_feature_name=NXT_HAVE_GETRANDOM
+nxt_feature_run=
+nxt_feature_incs=
+nxt_feature_libs=
+nxt_feature_test="#include <unistd.h>
+                  #include <sys/syscall.h>
+                  #include <linux/random.h>
+
+                  int main() {
+                      char  buf[4];
+
+                      (void) syscall(SYS_getrandom, buf, 4, 0);
+
+                      return 0;
+                  }"
+. ${NXT_AUTO}feature
diff -r e3bc4f6f3480 -r 7ad8820b9c74 nxt/nxt_random.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nxt/nxt_random.c	Wed Mar 23 15:49:46 2016 +0300
@@ -0,0 +1,179 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+
+#include <nxt_types.h>
+#include <nxt_clang.h>
+#include <nxt_random.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <unistd.h>
+#if (NXT_HAVE_GETRANDOM)
+#include <sys/syscall.h>
+#include <linux/random.h>
+#endif
+
+
+/*
+ * The pseudorandom generator based on OpenBSD arc4random.  Although
+ * it is usually stated that arc4random uses RC4 pseudorandom generation
+ * algorithm they are actually different in nxt_random_add().
+ */
+
+
+#define NXT_RANDOM_KEY_SIZE  128
+
+
+nxt_inline uint8_t nxt_random_byte(nxt_random_t *r);
+
+
+void
+nxt_random_init(nxt_random_t *r, nxt_pid_t pid)
+{
+    nxt_uint_t  i;
+
+    r->count = 0;
+    r->pid = pid;
+    r->i = 0;
+    r->j = 0;
+
+    for (i = 0; i < 256; i++) {
+        r->s[i] = i;
+    }
+}
+
+
+void
+nxt_random_stir(nxt_random_t *r, nxt_pid_t pid)
+{
+    int             fd;
+    ssize_t         n;
+    struct timeval  tv;
+    union {
+        uint32_t    value[3];
+        u_char      bytes[NXT_RANDOM_KEY_SIZE];
+    } key;
+
+    if (r->pid == 0) {
+        nxt_random_init(r, pid);
+    }
+
+    r->pid = pid;
+
+    n = 0;
+
+#if (NXT_HAVE_GETRANDOM)
+
+    /* Linux 3.17 getrandom(), it is not available in Glibc. */
+
+    n = syscall(SYS_getrandom, key, NXT_RANDOM_KEY_SIZE, 0));
+
+#endif
+
+    if (n != NXT_RANDOM_KEY_SIZE) {
+        fd = open("/dev/urandom", O_RDONLY);
+
+        if (fd >= 0) {
+            n = read(fd, &key, NXT_RANDOM_KEY_SIZE);
+            (void) close(fd);
+        }
+    }
+
+    if (n != NXT_RANDOM_KEY_SIZE) {
+        (void) gettimeofday(&tv, NULL);
+
+        /* XOR with stack garbage. */
+
+        key.value[0] ^= tv.tv_usec;
+        key.value[1] ^= tv.tv_sec;
+        key.value[2] ^= getpid();
+    }
+
+    nxt_random_add(r, key.bytes, NXT_RANDOM_KEY_SIZE);
+
+    /* Drop the first 3072 bytes. */
+    for (n = 3072; n != 0; n--) {
+        (void) nxt_random_byte(r);
+    }
+
+    /* Stir again after 1,600,000 bytes. */
+    r->count = 400000;
+}
+
+
+void
+nxt_random_add(nxt_random_t *r, const u_char *key, uint32_t len)
+{
+    uint8_t   val;
+    uint32_t  n;
+
+    for (n = 0; n < 256; n++) {
+        val = r->s[r->i];
+        r->j += val + key[n % len];
+
+        r->s[r->i] = r->s[r->j];
+        r->s[r->j] = val;
+
+        r->i++;
+    }
+
+    /* This index is not decremented in RC4 algorithm. */
+    r->i--;
+
+    r->j = r->i;
+}
+
+
+uint32_t
+nxt_random(nxt_random_t *r)
+{
+    uint32_t    val;
+    nxt_pid_t   pid;
+    nxt_bool_t  new_pid;
+
+    new_pid = 0;
+    pid = r->pid;
+
+    if (pid != -1) {
+        pid = getpid();
+
+        if (pid != r->pid) {
+            new_pid = 1;
+        }
+    }
+
+    r->count--;
+
+    if (r->count <= 0 || new_pid) {
+        nxt_random_stir(r, pid);
+    }
+
+    val  = nxt_random_byte(r) << 24;
+    val |= nxt_random_byte(r) << 16;
+    val |= nxt_random_byte(r) << 8;
+    val |= nxt_random_byte(r);
+
+    return val;
+}
+
+
+nxt_inline uint8_t
+nxt_random_byte(nxt_random_t *r)
+{
+    uint8_t  si, sj;
+
+    r->i++;
+    si = r->s[r->i];
+    r->j += si;
+
+    sj = r->s[r->j];
+    r->s[r->i] = sj;
+    r->s[r->j] = si;
+
+    si += sj;
+
+    return r->s[si];
+}
diff -r e3bc4f6f3480 -r 7ad8820b9c74 nxt/nxt_random.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nxt/nxt_random.h	Wed Mar 23 15:49:46 2016 +0300
@@ -0,0 +1,37 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#ifndef _NXT_RANDOM_H_INCLUDED_
+#define _NXT_RANDOM_H_INCLUDED_
+
+
+typedef struct {
+    int32_t    count;
+    nxt_pid_t  pid;
+    uint8_t    i;
+    uint8_t    j;
+    uint8_t    s[256];
+} nxt_random_t;
+
+
+/*
+ * The nxt_random_t structure must be either initialized with zeros
+ * or initialized by nxt_random_init() function.  The later is intended
+ * mainly for unit test.  nxt_random() automatically stirs itself if
+ * process pid changed after fork().  This pid testing can be disabled by
+ * passing -1 as the pid argument to nxt_random_init() or nxt_random_stir()
+ * functions.  The testing can be later enabled by passing any positive
+ * number, for example, a real pid number.
+ */
+
+NXT_EXPORT void nxt_random_init(nxt_random_t *r, nxt_pid_t pid);
+NXT_EXPORT void nxt_random_stir(nxt_random_t *r, nxt_pid_t pid);
+NXT_EXPORT void nxt_random_add(nxt_random_t *r, const u_char *key,
+    uint32_t len);
+NXT_EXPORT uint32_t nxt_random(nxt_random_t *r);
+
+
+#endif /* _NXT_RANDOM_H_INCLUDED_ */
diff -r e3bc4f6f3480 -r 7ad8820b9c74 nxt/nxt_types.h
--- a/nxt/nxt_types.h	Wed Mar 23 15:27:14 2016 +0300
+++ b/nxt/nxt_types.h	Wed Mar 23 15:49:46 2016 +0300
@@ -90,4 +90,7 @@ typedef time_t         nxt_time_t;
 #endif
 
 
+typedef pid_t          nxt_pid_t;
+
+
 #endif /* _NXT_TYPES_H_INCLUDED_ */
diff -r e3bc4f6f3480 -r 7ad8820b9c74 nxt/test/Makefile
--- a/nxt/test/Makefile	Wed Mar 23 15:27:14 2016 +0300
+++ b/nxt/test/Makefile	Wed Mar 23 15:49:46 2016 +0300
@@ -1,9 +1,11 @@
 
 lib_test: \
+	$(NXT_BUILDDIR)/random_unit_test \
 	$(NXT_BUILDDIR)/rbtree_unit_test \
 	$(NXT_BUILDDIR)/lvlhsh_unit_test \
 	$(NXT_BUILDDIR)/utf8_unit_test \
 
+	$(NXT_BUILDDIR)/random_unit_test
 	$(NXT_BUILDDIR)/rbtree_unit_test
 	$(NXT_BUILDDIR)/lvlhsh_unit_test
 	$(NXT_BUILDDIR)/utf8_unit_test
@@ -43,3 +45,12 @@ lib_test: \
 		$(NXT_BUILDDIR)/nxt_murmur_hash.o \
 		$(NXT_BUILDDIR)/nxt_mem_cache_pool.o \
 		$(NXT_BUILDDIR)/nxt_malloc.o
+
+$(NXT_BUILDDIR)/random_unit_test: \
+	$(NXT_BUILDDIR)/nxt_random.o \
+	$(NXT_LIB)/test/random_unit_test.c \
+
+	$(NXT_CC) -o $(NXT_BUILDDIR)/random_unit_test $(NXT_CFLAGS) \
+		-I$(NXT_LIB) \
+		$(NXT_LIB)/test/random_unit_test.c \
+		$(NXT_BUILDDIR)/nxt_random.o
diff -r e3bc4f6f3480 -r 7ad8820b9c74 nxt/test/random_unit_test.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nxt/test/random_unit_test.c	Wed Mar 23 15:49:46 2016 +0300
@@ -0,0 +1,60 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <nxt_types.h>
+#include <nxt_clang.h>
+#include <nxt_stub.h>
+#include <nxt_random.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static nxt_int_t
+random_unit_test()
+{
+    nxt_uint_t    n;
+    nxt_random_t  r;
+
+    nxt_random_init(&r, -1);
+
+    r.count = 400000;
+
+    nxt_random_add(&r, (u_char *) "arc4random", sizeof("arc4random") - 1);
+
+    /*
+     * Test arc4random() numbers.
+     * RC4 pseudorandom numbers would be 0x4642AFC3 and 0xBAF0FFF0.
+     */
+
+    if (nxt_random(&r) == 0xD6270B27) {
+
+        for (n = 100000; n != 0; n--) {
+            (void) nxt_random(&r);
+        }
+
+        if (nxt_random(&r) == 0x6FCAE186) {
+            printf("random unit test passed\n");
+
+            nxt_random_stir(&r, getpid());
+
+            printf("random unit test: 0x%08X\n", nxt_random(&r));
+
+            return NXT_OK;
+        }
+    }
+
+    printf("random unit test failed\n");
+
+    return NXT_ERROR;
+}
+
+
+int
+main(void)
+{
+    return random_unit_test();
+}



More information about the nginx-devel mailing list