// SPDX-License-Identifier: 0BSD


#ifndef __RANDOM_H___
#define __RANDOM_H___

#include <errno.h>
#include <stddef.h>
#include <unistd.h>
#if __has_include(<sys/random.h>)
#include <sys/random.h>
#endif
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <bcrypt.h>
#endif


typedef struct {
	int fd;
} random_t;

static bool random_data(random_t * random, void * data_ptr, size_t data_len) {
#ifdef _WIN32
	(void)random;
	if(BCryptGenRandom(NULL, data_ptr, data_len, BCRYPT_USE_SYSTEM_PREFERRED_RNG))
		return false;
#elif defined(HAVE_GETENTROPY)
	(void)random;
	if(getentropy(data_ptr, data_len))
		return false;
#else
	if(random->fd == -1)
		random->fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
	if(random->fd == -1)
		random->fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
	if(random->fd < 0) {
		random->fd = -2;
		return false;
	}

	char * data_itr = data_ptr;
	while(data_len) {
		ssize_t rd = read(random->fd, data_itr, data_len);
		if(rd == -1) {
			if(errno == EINTR)
				continue;
			return false;
		}
		data_itr += rd;
		data_len -= rd;
	}
#endif
	return true;
}

static void random_destroy(random_t * random) {
	if(random->fd >= 0)
		close(random->fd);
}


#endif
