1//===-------------------------- random.cpp --------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is dual licensed under the MIT and the University of Illinois Open 6// Source Licenses. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include <__config> 11 12#if defined(_LIBCPP_USING_WIN32_RANDOM) 13// Must be defined before including stdlib.h to enable rand_s(). 14#define _CRT_RAND_S 15#endif // defined(_LIBCPP_USING_WIN32_RANDOM) 16 17#include "random" 18#include "system_error" 19 20#if defined(__sun__) 21#define rename solaris_headers_are_broken 22#endif // defined(__sun__) 23 24#include <errno.h> 25#include <stdio.h> 26#include <stdlib.h> 27 28#if defined(_LIBCPP_USING_DEV_RANDOM) 29#include <fcntl.h> 30#include <unistd.h> 31#elif defined(_LIBCPP_USING_NACL_RANDOM) 32#include <nacl/nacl_random.h> 33#endif 34 35 36_LIBCPP_BEGIN_NAMESPACE_STD 37 38#if defined(_LIBCPP_USING_ARC4_RANDOM) 39 40random_device::random_device(const string& __token) 41{ 42 if (__token != "/dev/urandom") 43 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 44} 45 46random_device::~random_device() 47{ 48} 49 50unsigned 51random_device::operator()() 52{ 53 return arc4random(); 54} 55 56#elif defined(_LIBCPP_USING_DEV_RANDOM) 57 58random_device::random_device(const string& __token) 59 : __f_(open(__token.c_str(), O_RDONLY)) 60{ 61 if (__f_ < 0) 62 __throw_system_error(errno, ("random_device failed to open " + __token).c_str()); 63} 64 65random_device::~random_device() 66{ 67 close(__f_); 68} 69 70unsigned 71random_device::operator()() 72{ 73 unsigned r; 74 size_t n = sizeof(r); 75 char* p = reinterpret_cast<char*>(&r); 76 while (n > 0) 77 { 78 ssize_t s = read(__f_, p, n); 79 if (s == 0) 80 __throw_system_error(ENODATA, "random_device got EOF"); 81 if (s == -1) 82 { 83 if (errno != EINTR) 84 __throw_system_error(errno, "random_device got an unexpected error"); 85 continue; 86 } 87 n -= static_cast<size_t>(s); 88 p += static_cast<size_t>(s); 89 } 90 return r; 91} 92 93#elif defined(_LIBCPP_USING_NACL_RANDOM) 94 95random_device::random_device(const string& __token) 96{ 97 if (__token != "/dev/urandom") 98 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 99 int error = nacl_secure_random_init(); 100 if (error) 101 __throw_system_error(error, ("random device failed to open " + __token).c_str()); 102} 103 104random_device::~random_device() 105{ 106} 107 108unsigned 109random_device::operator()() 110{ 111 unsigned r; 112 size_t n = sizeof(r); 113 size_t bytes_written; 114 int error = nacl_secure_random(&r, n, &bytes_written); 115 if (error != 0) 116 __throw_system_error(error, "random_device failed getting bytes"); 117 else if (bytes_written != n) 118 __throw_runtime_error("random_device failed to obtain enough bytes"); 119 return r; 120} 121 122#elif defined(_LIBCPP_USING_WIN32_RANDOM) 123 124random_device::random_device(const string& __token) 125{ 126 if (__token != "/dev/urandom") 127 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 128} 129 130random_device::~random_device() 131{ 132} 133 134unsigned 135random_device::operator()() 136{ 137 unsigned r; 138 errno_t err = rand_s(&r); 139 if (err) 140 __throw_system_error(err, "random_device rand_s failed."); 141 return r; 142} 143 144#else 145#error "Random device not implemented for this architecture" 146#endif 147 148double 149random_device::entropy() const _NOEXCEPT 150{ 151 return 0; 152} 153 154_LIBCPP_END_NAMESPACE_STD 155