random_provider_posix.ipp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /* boost uuid/detail/random_provider_posix implementation
  2. *
  3. * Copyright Jens Maurer 2000
  4. * Copyright 2007 Andy Tompkins.
  5. * Copyright Steven Watanabe 2010-2011
  6. * Copyright 2017 James E. King III
  7. *
  8. * Distributed under the Boost Software License, Version 1.0. (See
  9. * accompanying file LICENSE_1_0.txt or copy at
  10. * https://www.boost.org/LICENSE_1_0.txt)
  11. *
  12. * $Id$
  13. */
  14. #include <boost/config.hpp>
  15. #include <boost/core/ignore_unused.hpp>
  16. #include <boost/move/core.hpp>
  17. #include <boost/throw_exception.hpp>
  18. #include <boost/uuid/entropy_error.hpp>
  19. #include <cerrno>
  20. #include <cstddef>
  21. #include <fcntl.h> // open
  22. #include <sys/stat.h>
  23. #include <sys/types.h>
  24. #if defined(BOOST_HAS_UNISTD_H)
  25. #include <unistd.h>
  26. #endif
  27. #ifndef BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_CLOSE
  28. #define BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_CLOSE ::close
  29. #endif
  30. #ifndef BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_OPEN
  31. #define BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_OPEN ::open
  32. #endif
  33. #ifndef BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_READ
  34. #define BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_READ ::read
  35. #endif
  36. namespace boost {
  37. namespace uuids {
  38. namespace detail {
  39. class random_provider_base
  40. {
  41. BOOST_MOVABLE_BUT_NOT_COPYABLE(random_provider_base)
  42. public:
  43. random_provider_base()
  44. : fd_(-1)
  45. {
  46. int flags = O_RDONLY;
  47. #if defined(O_CLOEXEC)
  48. flags |= O_CLOEXEC;
  49. #endif
  50. fd_ = BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_OPEN("/dev/urandom", flags);
  51. if (BOOST_UNLIKELY(-1 == fd_))
  52. {
  53. int err = errno;
  54. BOOST_THROW_EXCEPTION(entropy_error(err, "open /dev/urandom"));
  55. }
  56. }
  57. random_provider_base(BOOST_RV_REF(random_provider_base) that) BOOST_NOEXCEPT : fd_(that.fd_)
  58. {
  59. that.fd_ = -1;
  60. }
  61. random_provider_base& operator= (BOOST_RV_REF(random_provider_base) that) BOOST_NOEXCEPT
  62. {
  63. destroy();
  64. fd_ = that.fd_;
  65. that.fd_ = -1;
  66. return *this;
  67. }
  68. ~random_provider_base() BOOST_NOEXCEPT
  69. {
  70. destroy();
  71. }
  72. //! Obtain entropy and place it into a memory location
  73. //! \param[in] buf the location to write entropy
  74. //! \param[in] siz the number of bytes to acquire
  75. void get_random_bytes(void *buf, std::size_t siz)
  76. {
  77. std::size_t offset = 0;
  78. while (offset < siz)
  79. {
  80. ssize_t sz = BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_READ(
  81. fd_, static_cast<char *>(buf) + offset, siz - offset);
  82. if (BOOST_UNLIKELY(sz < 0))
  83. {
  84. int err = errno;
  85. if (err == EINTR)
  86. continue;
  87. BOOST_THROW_EXCEPTION(entropy_error(err, "read"));
  88. }
  89. offset += sz;
  90. }
  91. }
  92. private:
  93. void destroy() BOOST_NOEXCEPT
  94. {
  95. if (fd_ >= 0)
  96. {
  97. boost::ignore_unused(BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_CLOSE(fd_));
  98. }
  99. }
  100. private:
  101. int fd_;
  102. };
  103. } // detail
  104. } // uuids
  105. } // boost