diff --git a/Knot.files b/Knot.files index e60b931fd367211156b9ccdbe811956ea0f60bf5..f364dccaad656272b557db1cdb163ad30c457fdd 100644 --- a/Knot.files +++ b/Knot.files @@ -105,8 +105,12 @@ src/common/ref.h src/common/modified_tree.h src/common/general-tree.h src/common/general-tree.c -src/common/WELL1024a.c -src/common/WELL1024a.h +src/common/dSFMT.c +src/common/dSFMT.h +src/common/dSFMT-params.h +src/common/dSFMT-params521.h +src/common/prng.c +src/common/prng.h src/common/fdset.h src/common/fdset.c src/common/fdset_poll.h diff --git a/configure.ac b/configure.ac index b824a43362b2e64b01ec5fca8a701585d0d9f962..ca9fc04cf20ce33382aac1dfe73de604e1092e30 100644 --- a/configure.ac +++ b/configure.ac @@ -130,6 +130,9 @@ AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T +# Set PRNG parameters +AC_DEFINE([DSFMT_MEXP], [521], [DSFMT parameters.]) + # Checks for library functions. AC_FUNC_FORK AC_FUNC_MMAP diff --git a/src/Makefile.am b/src/Makefile.am index f8d81e5d213272ddc3ff788e6671f773b488e2c7..e73b2bfb4d020fc6dfed9b58f3b2e70ed7496dc8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -252,8 +252,12 @@ libknots_la_SOURCES = \ common/ref.c \ common/errors.h \ common/errors.c \ - common/WELL1024a.h \ - common/WELL1024a.c \ + common/dSFMT.h \ + common/dSFMT-params.h \ + common/dSFMT-params521.h \ + common/dSFMT.c \ + common/prng.h \ + common/prng.c \ common/fdset.h \ common/fdset.c \ common/fdset_poll.h \ diff --git a/src/common/prng.c b/src/common/prng.c new file mode 100644 index 0000000000000000000000000000000000000000..ca87b0de4b745e9b84ecd4632627c5b6cada4eaf --- /dev/null +++ b/src/common/prng.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <time.h> +#include <sys/time.h> + +#include "prng.h" +#include "dSFMT.h" + +/*! \brief TLS unique key for each thread seed. */ +static pthread_key_t tls_prng_key; +static pthread_once_t tls_prng_once = PTHREAD_ONCE_INIT; + +static void tls_prng_deinit(void *ptr) +{ + free(ptr); +} + +static void tls_prng_deinit_main() +{ + tls_prng_deinit(pthread_getspecific(tls_prng_key)); +} + +static void tls_prng_init() +{ + (void) pthread_key_create(&tls_prng_key, tls_prng_deinit); + atexit(tls_prng_deinit_main); // Main thread cleanup +} + +double tls_rand() +{ + /* Setup PRNG state for current thread. */ + (void)pthread_once(&tls_prng_once, tls_prng_init); + + /* Create PRNG state if not exists. */ + dsfmt_t* s = pthread_getspecific(tls_prng_key); + if (!s) { + /* Initialize seed from system PRNG generator. */ + uint32_t seed = 0; + FILE *fp = fopen("/dev/urandom", "r"); + if (fp == NULL) { + fp = fopen("/dev/random", "r"); + } + if (fp != NULL) { + if (fread(&seed, sizeof(uint32_t), 1, fp) != 1) { + fclose(fp); + fp = NULL; + } + } + if (fp == NULL) { + fprintf(stderr, "error: PRNG: cannot seed from " + "/dev/urandom, seeding from local time\n"); + struct timeval tv; + if (gettimeofday(&tv, NULL) == 0) { + seed = (uint32_t)(tv.tv_sec ^ tv.tv_usec); + } else { + /* Last resort. */ + seed = (uint32_t)time(NULL); + } + } else { + fclose(fp); + } + + /* Initialize PRNG state. */ + s = malloc(sizeof(dsfmt_t)); + if (s == NULL) { + fprintf(stderr, "error: PRNG: not enough memory\n"); + return .0; + } else { + dsfmt_init_gen_rand(s, seed); + (void)pthread_setspecific(tls_prng_key, s); + } + } + + return dsfmt_genrand_close_open(s); +} diff --git a/src/common/prng.h b/src/common/prng.h new file mode 100644 index 0000000000000000000000000000000000000000..9f17a780d93a403efb64178afa80b8b3fc00a45d --- /dev/null +++ b/src/common/prng.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +/*! + * \file prng.h + * + * \author Marek Vavrusa <marek.vavrusa@nic.cz> + * + * \brief Pseudo-random number generator interface. + * + * Interface for accessing underlying PRNG. + * + * \addtogroup common_lib + * @{ + */ + +#ifndef _KNOTD_PRNG_H_ +#define _KNOTD_PRNG_H_ + +/*! + * \brief Get pseudorandom number from PRNG initialized in thread-local storage. + * + * No need for initialization, TLS will take care of it. + * + * \retval Pseudorandom number. + */ +double tls_rand(); + +#endif //_KNOTD_ACL_H_ diff --git a/src/knot/server/tcp-handler.c b/src/knot/server/tcp-handler.c index 2fdc354bd7c2c2257f32d210b4c68b849087627f..71452e9cc238d3e3791671caef5bbd8c6c91587d 100644 --- a/src/knot/server/tcp-handler.c +++ b/src/knot/server/tcp-handler.c @@ -28,7 +28,7 @@ #include "common/sockaddr.h" #include "common/skip-list.h" #include "common/fdset.h" -#include "common/WELL1024a.h" +#include "common/prng.h" #include "knot/common.h" #include "knot/server/tcp-handler.h" #include "knot/server/xfr-handler.h" diff --git a/src/knot/server/xfr-handler.c b/src/knot/server/xfr-handler.c index cec3f53c568638748f521381eae052e6375d8300..bc55434e4e43ec18ff351fa293f53efa69dc5196 100644 --- a/src/knot/server/xfr-handler.c +++ b/src/knot/server/xfr-handler.c @@ -39,7 +39,7 @@ #include "libknot/util/error.h" #include "libknot/tsig-op.h" #include "common/evsched.h" -#include "common/WELL1024a.h" +#include "common/prng.h" /* Constants */ #define XFR_BUFFER_SIZE 65535 /*! Do not change this - maximum value for UDP packet length. */ diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index bd23c7d64d1bab33ce172cb93a0a808a4429beb8..8616ebd53e4a617c2bbc7b0ffaaabb7fa18c8840 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -17,7 +17,7 @@ #include <sys/stat.h> #include "common/lists.h" -#include "common/WELL1024a.h" +#include "common/prng.h" #include "libknot/dname.h" #include "libknot/util/wire.h" #include "knot/zone/zone-dump-text.h" diff --git a/src/libknot/util/utils.c b/src/libknot/util/utils.c index 17b33a73ea14eb44c28d14bcb205a1f6f02876d8..04e12c52225ebe7bb08c7e40f60bd6ae4bf3d4af 100644 --- a/src/libknot/util/utils.c +++ b/src/libknot/util/utils.c @@ -22,7 +22,7 @@ #include "common.h" #include "util/utils.h" -#include "common/WELL1024a.h" +#include "common/prng.h" /*----------------------------------------------------------------------------*/