1 /* Generate sizeof(uint32_t) bytes of as random data as possible to seed
6 #include <jansson_private_config.h>
28 #ifdef HAVE_SYS_STAT_H
32 #ifdef HAVE_SYS_TIME_H
36 #ifdef HAVE_SYS_TYPES_H
37 #include <sys/types.h>
41 /* For GetModuleHandle(), GetProcAddress() and GetCurrentProcessId() */
48 static uint32_t buf_to_uint32(char *data
) {
52 for (i
= 0; i
< sizeof(uint32_t); i
++)
53 result
= (result
<< 8) | (unsigned char)data
[i
];
61 #if !defined(_WIN32) && defined(USE_URANDOM)
62 static int seed_from_urandom(uint32_t *seed
) {
63 /* Use unbuffered I/O if we have open(), close() and read(). Otherwise
64 fall back to fopen() */
66 char data
[sizeof(uint32_t)];
69 #if defined(HAVE_OPEN) && defined(HAVE_CLOSE) && defined(HAVE_READ)
71 urandom
= open("/dev/urandom", O_RDONLY
);
75 ok
= read(urandom
, data
, sizeof(uint32_t)) == sizeof(uint32_t);
80 urandom
= fopen("/dev/urandom", "rb");
84 ok
= fread(data
, 1, sizeof(uint32_t), urandom
) == sizeof(uint32_t);
91 *seed
= buf_to_uint32(data
);
96 /* Windows Crypto API */
97 #if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
100 typedef BOOL (WINAPI
*CRYPTACQUIRECONTEXTA
)(HCRYPTPROV
*phProv
, LPCSTR pszContainer
, LPCSTR pszProvider
, DWORD dwProvType
, DWORD dwFlags
);
101 typedef BOOL (WINAPI
*CRYPTGENRANDOM
)(HCRYPTPROV hProv
, DWORD dwLen
, BYTE
*pbBuffer
);
102 typedef BOOL (WINAPI
*CRYPTRELEASECONTEXT
)(HCRYPTPROV hProv
, DWORD dwFlags
);
104 static int seed_from_windows_cryptoapi(uint32_t *seed
)
106 HINSTANCE hAdvAPI32
= NULL
;
107 CRYPTACQUIRECONTEXTA pCryptAcquireContext
= NULL
;
108 CRYPTGENRANDOM pCryptGenRandom
= NULL
;
109 CRYPTRELEASECONTEXT pCryptReleaseContext
= NULL
;
110 HCRYPTPROV hCryptProv
= 0;
111 BYTE data
[sizeof(uint32_t)];
114 hAdvAPI32
= GetModuleHandle(TEXT("advapi32.dll"));
115 if(hAdvAPI32
== NULL
)
118 pCryptAcquireContext
= (CRYPTACQUIRECONTEXTA
)GetProcAddress(hAdvAPI32
, "CryptAcquireContextA");
119 if (!pCryptAcquireContext
)
122 pCryptGenRandom
= (CRYPTGENRANDOM
)GetProcAddress(hAdvAPI32
, "CryptGenRandom");
123 if (!pCryptGenRandom
)
126 pCryptReleaseContext
= (CRYPTRELEASECONTEXT
)GetProcAddress(hAdvAPI32
, "CryptReleaseContext");
127 if (!pCryptReleaseContext
)
130 if (!pCryptAcquireContext(&hCryptProv
, NULL
, NULL
, PROV_RSA_FULL
, CRYPT_VERIFYCONTEXT
))
133 ok
= pCryptGenRandom(hCryptProv
, sizeof(uint32_t), data
);
134 pCryptReleaseContext(hCryptProv
, 0);
139 *seed
= buf_to_uint32((char *)data
);
144 /* gettimeofday() and getpid() */
145 static int seed_from_timestamp_and_pid(uint32_t *seed
) {
146 #ifdef HAVE_GETTIMEOFDAY
147 /* XOR of seconds and microseconds */
149 gettimeofday(&tv
, NULL
);
150 *seed
= (uint32_t)tv
.tv_sec
^ (uint32_t)tv
.tv_usec
;
153 *seed
= (uint32_t)time(NULL
);
156 /* XOR with PID for more randomness */
158 *seed
^= (uint32_t)GetCurrentProcessId();
159 #elif defined(HAVE_GETPID)
160 *seed
^= (uint32_t)getpid();
166 static uint32_t generate_seed() {
170 #if !defined(_WIN32) && defined(USE_URANDOM)
171 if (seed_from_urandom(&seed
) == 0)
175 #if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
176 if (seed_from_windows_cryptoapi(&seed
) == 0)
181 /* Fall back to timestamp and PID if no better randomness is
183 seed_from_timestamp_and_pid(&seed
);
186 /* Make sure the seed is never zero */
194 volatile uint32_t hashtable_seed
= 0;
196 #if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32))
197 static volatile char seed_initialized
= 0;
199 void json_object_seed(size_t seed
) {
200 uint32_t new_seed
= (uint32_t)seed
;
202 if (hashtable_seed
== 0) {
203 if (__atomic_test_and_set(&seed_initialized
, __ATOMIC_RELAXED
) == 0) {
204 /* Do the seeding ourselves */
206 new_seed
= generate_seed();
208 __atomic_store_n(&hashtable_seed
, new_seed
, __ATOMIC_RELEASE
);
210 /* Wait for another thread to do the seeding */
212 #ifdef HAVE_SCHED_YIELD
215 } while(__atomic_load_n(&hashtable_seed
, __ATOMIC_ACQUIRE
) == 0);
219 #elif defined(HAVE_SYNC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32))
220 void json_object_seed(size_t seed
) {
221 uint32_t new_seed
= (uint32_t)seed
;
223 if (hashtable_seed
== 0) {
225 /* Explicit synchronization fences are not supported by the
226 __sync builtins, so every thread getting here has to
227 generate the seed value.
229 new_seed
= generate_seed();
233 if (__sync_bool_compare_and_swap(&hashtable_seed
, 0, new_seed
)) {
234 /* We were the first to seed */
237 /* Wait for another thread to do the seeding */
238 #ifdef HAVE_SCHED_YIELD
242 } while(hashtable_seed
== 0);
245 #elif defined(_WIN32)
246 static long seed_initialized
= 0;
247 void json_object_seed(size_t seed
) {
248 uint32_t new_seed
= (uint32_t)seed
;
250 if (hashtable_seed
== 0) {
251 if (InterlockedIncrement(&seed_initialized
) == 1) {
252 /* Do the seeding ourselves */
254 new_seed
= generate_seed();
256 hashtable_seed
= new_seed
;
258 /* Wait for another thread to do the seeding */
261 } while (hashtable_seed
== 0);
266 /* Fall back to a thread-unsafe version */
267 void json_object_seed(size_t seed
) {
268 uint32_t new_seed
= (uint32_t)seed
;
270 if (hashtable_seed
== 0) {
272 new_seed
= generate_seed();
274 hashtable_seed
= new_seed
;