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 #if defined(_WIN32) 11 // Must be defined before including stdlib.h to enable rand_s(). 12 #define _CRT_RAND_S 13 #include <stdio.h> 14 #endif // defined(_WIN32) 15 16 #include "random" 17 #include "system_error" 18 19 #if defined(__sun__) 20 #define rename solaris_headers_are_broken 21 #endif // defined(__sun__) 22 #if !defined(_WIN32) 23 #include <fcntl.h> 24 #include <unistd.h> 25 #endif // !defined(_WIN32) 26 #include <errno.h> 27 #if defined(_LIBCPP_USING_NACL_RANDOM) 28 #include <nacl/nacl_random.h> 29 #endif // defined(_LIBCPP_USING_NACL_RANDOM) 30 31 _LIBCPP_BEGIN_NAMESPACE_STD 32 33 #if defined(_WIN32) 34 35 random_device::random_device(const string&) 36 { 37 } 38 39 random_device::~random_device() 40 { 41 } 42 43 unsigned 44 random_device::operator()() 45 { 46 unsigned r; 47 errno_t err = rand_s(&r); 48 if (err) 49 __throw_system_error(err, "random_device rand_s failed."); 50 return r; 51 } 52 53 #elif defined(_LIBCPP_USING_NACL_RANDOM) 54 55 random_device::random_device(const string& __token) 56 { 57 if (__token != "/dev/urandom") 58 __throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); 59 int error = nacl_secure_random_init(); 60 if (error) 61 __throw_system_error(error, ("random device failed to open " + __token).c_str()); 62 } 63 64 random_device::~random_device() 65 { 66 } 67 68 unsigned 69 random_device::operator()() 70 { 71 unsigned r; 72 size_t n = sizeof(r); 73 char* p = reinterpret_cast<char*>(&r); 74 size_t bytes_written; 75 int error = nacl_secure_random(&r, n, &bytes_written); 76 if (error != 0) 77 __throw_system_error(error, "random_device failed getting bytes"); 78 else if (bytes_written != n) 79 __throw_runtime_error("random_device failed to obtain enough bytes"); 80 return r; 81 } 82 83 #else // !defined(_WIN32) && !defined(_LIBCPP_USING_NACL_RANDOM) 84 85 random_device::random_device(const string& __token) 86 : __f_(open(__token.c_str(), O_RDONLY)) 87 { 88 if (__f_ < 0) 89 __throw_system_error(errno, ("random_device failed to open " + __token).c_str()); 90 } 91 92 random_device::~random_device() 93 { 94 close(__f_); 95 } 96 97 unsigned 98 random_device::operator()() 99 { 100 unsigned r; 101 size_t n = sizeof(r); 102 char* p = reinterpret_cast<char*>(&r); 103 while (n > 0) 104 { 105 ssize_t s = read(__f_, p, n); 106 if (s == 0) 107 __throw_system_error(ENODATA, "random_device got EOF"); 108 if (s == -1) 109 { 110 if (errno != EINTR) 111 __throw_system_error(errno, "random_device got an unexpected error"); 112 continue; 113 } 114 n -= static_cast<size_t>(s); 115 p += static_cast<size_t>(s); 116 } 117 return r; 118 } 119 120 #endif // defined(_WIN32) || defined(_LIBCPP_USING_NACL_RANDOM) 121 122 double 123 random_device::entropy() const _NOEXCEPT 124 { 125 return 0; 126 } 127 128 _LIBCPP_END_NAMESPACE_STD 129