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