1 /*
2 * Copyright (c) 2012 Tim Ruehsen
3 * Copyright (c) 2016-2021 Free Software Foundation, Inc.
4 *
5 * This file is part of libwget.
6 *
7 * Libwget is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Libwget is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with libwget. If not, see <https://www.gnu.org/licenses/>.
19 *
20 *
21 * a multi-thread safe wrapper around gnulib random_r()
22 *
23 * Changelog
24 * 22.01.2016 Tim Ruehsen created
25 *
26 */
27
28 #include <config.h>
29
30 #include <stddef.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <time.h>
34 #ifdef _WIN32
35 # include <process.h> /* getpid() */
36 #endif
37
38 #include <wget.h>
39 #include "private.h"
40
41 /**
42 * \file
43 * \brief Random functions
44 * \defgroup libwget-random Random functions
45 * @{
46 *
47 * This is wrapper code around gnulib's srandom_r() and random_r() with automatic seeding
48 */
49
50 static int seeded;
51 static char statebuf[64];
52 static struct random_data state;
53 static wget_thread_mutex mutex;
54 static bool initialized;
55
random_init(void)56 static void __attribute__ ((constructor)) random_init(void)
57 {
58 if (!initialized) {
59 wget_thread_mutex_init(&mutex);
60 initialized = 1;
61 }
62 }
63
random_exit(void)64 static void __attribute__ ((destructor)) random_exit(void)
65 {
66 if (initialized) {
67 wget_thread_mutex_destroy(&mutex);
68 initialized = 0;
69 }
70 }
71
72 /**
73 * Random API initialization, allocating/preparing the internal resources.
74 *
75 * On systems with automatic library constructors, this function
76 * doesn't have to be called explicitly.
77 *
78 * This function is not thread-safe.
79 */
wget_random_init(void)80 void wget_random_init(void)
81 {
82 random_init();
83 }
84
85 /**
86 * Random API deinitialization, free'ing all internal resources.
87 *
88 * On systems with automatic library destructors, this function
89 * doesn't have to be called explicitly.
90 *
91 * This function is not thread-safe.
92 */
wget_random_exit(void)93 void wget_random_exit(void)
94 {
95 random_exit();
96 }
97
98 /**
99 * \return Random value between 0 and RAND_MAX
100 *
101 * This functions wraps around gnulib's random_r(). It performs a thread-safe seeding on the first use,
102 * if not done before by wget_srandom();
103 */
wget_random(void)104 int wget_random(void)
105 {
106 int32_t r;
107
108 wget_thread_mutex_lock(mutex);
109
110 if (!seeded) {
111 // seed random generator, used e.g. by Digest Authentication and --random-wait
112 initstate_r((unsigned)(time(NULL) ^ getpid()), statebuf, sizeof(statebuf), &state);
113 seeded = 1;
114 }
115
116 if (random_r(&state, &r))
117 r = 0; // return 0 on failure
118
119 wget_thread_mutex_unlock(mutex);
120
121 return (int)r;
122 }
123
124 /**
125 * \param[in] seed Value to seed the random generator
126 *
127 * This functions wraps around srandom_r() to make a thread-safe seeding for wget_random().
128 */
wget_srandom(unsigned int seed)129 void wget_srandom(unsigned int seed)
130 {
131 wget_thread_mutex_lock(mutex);
132
133 initstate_r(seed, statebuf, sizeof(statebuf), &state);
134 seeded = 1;
135
136 wget_thread_mutex_unlock(mutex);
137 }
138
139 /**@}*/
140