xref: /minix3/external/bsd/libc++/dist/libcxx/src/random.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
14684ddb6SLionel Sambuc //===-------------------------- random.cpp --------------------------------===//
24684ddb6SLionel Sambuc //
34684ddb6SLionel Sambuc //                     The LLVM Compiler Infrastructure
44684ddb6SLionel Sambuc //
54684ddb6SLionel Sambuc // This file is dual licensed under the MIT and the University of Illinois Open
64684ddb6SLionel Sambuc // Source Licenses. See LICENSE.TXT for details.
74684ddb6SLionel Sambuc //
84684ddb6SLionel Sambuc //===----------------------------------------------------------------------===//
94684ddb6SLionel Sambuc 
10*0a6a1f1dSLionel Sambuc #if defined(_LIBCPP_USING_WIN32_RANDOM)
114684ddb6SLionel Sambuc // Must be defined before including stdlib.h to enable rand_s().
124684ddb6SLionel Sambuc #define _CRT_RAND_S
13*0a6a1f1dSLionel Sambuc #endif // defined(_LIBCPP_USING_WIN32_RANDOM)
144684ddb6SLionel Sambuc 
154684ddb6SLionel Sambuc #include "random"
164684ddb6SLionel Sambuc #include "system_error"
174684ddb6SLionel Sambuc 
18*0a6a1f1dSLionel Sambuc #if defined(__sun__)
194684ddb6SLionel Sambuc #define rename solaris_headers_are_broken
20*0a6a1f1dSLionel Sambuc #endif // defined(__sun__)
21*0a6a1f1dSLionel Sambuc 
22*0a6a1f1dSLionel Sambuc #include <errno.h>
23*0a6a1f1dSLionel Sambuc #include <stdio.h>
24*0a6a1f1dSLionel Sambuc #include <stdlib.h>
25*0a6a1f1dSLionel Sambuc 
26*0a6a1f1dSLionel Sambuc #if defined(_LIBCPP_USING_DEV_RANDOM)
274684ddb6SLionel Sambuc #include <fcntl.h>
284684ddb6SLionel Sambuc #include <unistd.h>
29*0a6a1f1dSLionel Sambuc #elif defined(_LIBCPP_USING_NACL_RANDOM)
30*0a6a1f1dSLionel Sambuc #include <nacl/nacl_random.h>
31*0a6a1f1dSLionel Sambuc #endif
32*0a6a1f1dSLionel Sambuc 
334684ddb6SLionel Sambuc 
344684ddb6SLionel Sambuc _LIBCPP_BEGIN_NAMESPACE_STD
354684ddb6SLionel Sambuc 
36*0a6a1f1dSLionel Sambuc #if defined(_LIBCPP_USING_ARC4_RANDOM)
37*0a6a1f1dSLionel Sambuc 
random_device(const string & __token)38*0a6a1f1dSLionel Sambuc random_device::random_device(const string& __token)
394684ddb6SLionel Sambuc {
40*0a6a1f1dSLionel Sambuc     if (__token != "/dev/urandom")
41*0a6a1f1dSLionel Sambuc         __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
42*0a6a1f1dSLionel Sambuc }
43*0a6a1f1dSLionel Sambuc 
~random_device()44*0a6a1f1dSLionel Sambuc random_device::~random_device()
45*0a6a1f1dSLionel Sambuc {
46*0a6a1f1dSLionel Sambuc }
47*0a6a1f1dSLionel Sambuc 
48*0a6a1f1dSLionel Sambuc unsigned
operator ()()49*0a6a1f1dSLionel Sambuc random_device::operator()()
50*0a6a1f1dSLionel Sambuc {
51*0a6a1f1dSLionel Sambuc     return arc4random();
52*0a6a1f1dSLionel Sambuc }
53*0a6a1f1dSLionel Sambuc 
54*0a6a1f1dSLionel Sambuc #elif defined(_LIBCPP_USING_DEV_RANDOM)
55*0a6a1f1dSLionel Sambuc 
56*0a6a1f1dSLionel Sambuc random_device::random_device(const string& __token)
57*0a6a1f1dSLionel Sambuc     : __f_(open(__token.c_str(), O_RDONLY))
58*0a6a1f1dSLionel Sambuc {
59*0a6a1f1dSLionel Sambuc     if (__f_ < 0)
60*0a6a1f1dSLionel Sambuc         __throw_system_error(errno, ("random_device failed to open " + __token).c_str());
61*0a6a1f1dSLionel Sambuc }
62*0a6a1f1dSLionel Sambuc 
63*0a6a1f1dSLionel Sambuc random_device::~random_device()
64*0a6a1f1dSLionel Sambuc {
65*0a6a1f1dSLionel Sambuc     close(__f_);
66*0a6a1f1dSLionel Sambuc }
67*0a6a1f1dSLionel Sambuc 
68*0a6a1f1dSLionel Sambuc unsigned
69*0a6a1f1dSLionel Sambuc random_device::operator()()
70*0a6a1f1dSLionel Sambuc {
71*0a6a1f1dSLionel Sambuc     unsigned r;
72*0a6a1f1dSLionel Sambuc     size_t n = sizeof(r);
73*0a6a1f1dSLionel Sambuc     char* p = reinterpret_cast<char*>(&r);
74*0a6a1f1dSLionel Sambuc     while (n > 0)
75*0a6a1f1dSLionel Sambuc     {
76*0a6a1f1dSLionel Sambuc         ssize_t s = read(__f_, p, n);
77*0a6a1f1dSLionel Sambuc         if (s == 0)
78*0a6a1f1dSLionel Sambuc             __throw_system_error(ENODATA, "random_device got EOF");
79*0a6a1f1dSLionel Sambuc         if (s == -1)
80*0a6a1f1dSLionel Sambuc         {
81*0a6a1f1dSLionel Sambuc             if (errno != EINTR)
82*0a6a1f1dSLionel Sambuc                 __throw_system_error(errno, "random_device got an unexpected error");
83*0a6a1f1dSLionel Sambuc             continue;
84*0a6a1f1dSLionel Sambuc         }
85*0a6a1f1dSLionel Sambuc         n -= static_cast<size_t>(s);
86*0a6a1f1dSLionel Sambuc         p += static_cast<size_t>(s);
87*0a6a1f1dSLionel Sambuc     }
88*0a6a1f1dSLionel Sambuc     return r;
89*0a6a1f1dSLionel Sambuc }
90*0a6a1f1dSLionel Sambuc 
91*0a6a1f1dSLionel Sambuc #elif defined(_LIBCPP_USING_NACL_RANDOM)
92*0a6a1f1dSLionel Sambuc 
93*0a6a1f1dSLionel Sambuc random_device::random_device(const string& __token)
94*0a6a1f1dSLionel Sambuc {
95*0a6a1f1dSLionel Sambuc     if (__token != "/dev/urandom")
96*0a6a1f1dSLionel Sambuc         __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
97*0a6a1f1dSLionel Sambuc     int error = nacl_secure_random_init();
98*0a6a1f1dSLionel Sambuc     if (error)
99*0a6a1f1dSLionel Sambuc         __throw_system_error(error, ("random device failed to open " + __token).c_str());
100*0a6a1f1dSLionel Sambuc }
101*0a6a1f1dSLionel Sambuc 
102*0a6a1f1dSLionel Sambuc random_device::~random_device()
103*0a6a1f1dSLionel Sambuc {
104*0a6a1f1dSLionel Sambuc }
105*0a6a1f1dSLionel Sambuc 
106*0a6a1f1dSLionel Sambuc unsigned
107*0a6a1f1dSLionel Sambuc random_device::operator()()
108*0a6a1f1dSLionel Sambuc {
109*0a6a1f1dSLionel Sambuc     unsigned r;
110*0a6a1f1dSLionel Sambuc     size_t n = sizeof(r);
111*0a6a1f1dSLionel Sambuc     size_t bytes_written;
112*0a6a1f1dSLionel Sambuc     int error = nacl_secure_random(&r, n, &bytes_written);
113*0a6a1f1dSLionel Sambuc     if (error != 0)
114*0a6a1f1dSLionel Sambuc         __throw_system_error(error, "random_device failed getting bytes");
115*0a6a1f1dSLionel Sambuc     else if (bytes_written != n)
116*0a6a1f1dSLionel Sambuc         __throw_runtime_error("random_device failed to obtain enough bytes");
117*0a6a1f1dSLionel Sambuc     return r;
118*0a6a1f1dSLionel Sambuc }
119*0a6a1f1dSLionel Sambuc 
120*0a6a1f1dSLionel Sambuc #elif defined(_LIBCPP_USING_WIN32_RANDOM)
121*0a6a1f1dSLionel Sambuc 
122*0a6a1f1dSLionel Sambuc random_device::random_device(const string& __token)
123*0a6a1f1dSLionel Sambuc {
124*0a6a1f1dSLionel Sambuc     if (__token != "/dev/urandom")
125*0a6a1f1dSLionel Sambuc         __throw_system_error(ENOENT, ("random device not supported " + __token).c_str());
1264684ddb6SLionel Sambuc }
1274684ddb6SLionel Sambuc 
1284684ddb6SLionel Sambuc random_device::~random_device()
1294684ddb6SLionel Sambuc {
1304684ddb6SLionel Sambuc }
1314684ddb6SLionel Sambuc 
1324684ddb6SLionel Sambuc unsigned
1334684ddb6SLionel Sambuc random_device::operator()()
1344684ddb6SLionel Sambuc {
1354684ddb6SLionel Sambuc     unsigned r;
1364684ddb6SLionel Sambuc     errno_t err = rand_s(&r);
1374684ddb6SLionel Sambuc     if (err)
1384684ddb6SLionel Sambuc         __throw_system_error(err, "random_device rand_s failed.");
1394684ddb6SLionel Sambuc     return r;
1404684ddb6SLionel Sambuc }
141*0a6a1f1dSLionel Sambuc 
1424684ddb6SLionel Sambuc #else
143*0a6a1f1dSLionel Sambuc #error "Random device not implemented for this architecture"
144*0a6a1f1dSLionel Sambuc #endif
1454684ddb6SLionel Sambuc 
1464684ddb6SLionel Sambuc double
entropy() const1474684ddb6SLionel Sambuc random_device::entropy() const _NOEXCEPT
1484684ddb6SLionel Sambuc {
1494684ddb6SLionel Sambuc     return 0;
1504684ddb6SLionel Sambuc }
1514684ddb6SLionel Sambuc 
1524684ddb6SLionel Sambuc _LIBCPP_END_NAMESPACE_STD
153