mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-16 02:03:07 -07:00
Add fallback for random number generator
`getrandom()` is available since Linux 3.17 (2014/10/05) yet there are older devices that don't meet this requirement. Closes #22691. PR #22723.
This commit is contained in:
parent
9133b16431
commit
f51ad39ad9
4 changed files with 49 additions and 8 deletions
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
uint32_t Utils::Random::rand(const uint32_t min, const uint32_t max)
|
uint32_t Utils::Random::rand(const uint32_t min, const uint32_t max)
|
||||||
{
|
{
|
||||||
static RandomLayer layer;
|
static const RandomLayer layer;
|
||||||
|
|
||||||
// new distribution is cheap: https://stackoverflow.com/a/19036349
|
// new distribution is cheap: https://stackoverflow.com/a/19036349
|
||||||
std::uniform_int_distribution<uint32_t> uniform(min, max);
|
std::uniform_int_distribution<uint32_t> uniform(min, max);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
@ -44,6 +45,27 @@ namespace
|
||||||
|
|
||||||
RandomLayer()
|
RandomLayer()
|
||||||
{
|
{
|
||||||
|
if (::getrandom(nullptr, 0, 0) < 0)
|
||||||
|
{
|
||||||
|
if (errno == ENOSYS)
|
||||||
|
{
|
||||||
|
// underlying kernel does not implement this system call
|
||||||
|
// fallback to `urandom`
|
||||||
|
m_randDev = fopen("/dev/urandom", "rb");
|
||||||
|
if (!m_randDev)
|
||||||
|
qFatal("Failed to open /dev/urandom. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qFatal("getrandom() error. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~RandomLayer()
|
||||||
|
{
|
||||||
|
if (m_randDev)
|
||||||
|
fclose(m_randDev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr result_type min()
|
static constexpr result_type min()
|
||||||
|
@ -56,7 +78,15 @@ namespace
|
||||||
return std::numeric_limits<result_type>::max();
|
return std::numeric_limits<result_type>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
result_type operator()()
|
result_type operator()() const
|
||||||
|
{
|
||||||
|
if (!m_randDev)
|
||||||
|
return getRandomViaAPI();
|
||||||
|
return getRandomViaFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
result_type getRandomViaAPI() const
|
||||||
{
|
{
|
||||||
const int RETRY_MAX = 3;
|
const int RETRY_MAX = 3;
|
||||||
|
|
||||||
|
@ -68,10 +98,21 @@ namespace
|
||||||
return buf;
|
return buf;
|
||||||
|
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
qFatal("getrandom() error. Reason: %s. Error code: %d.", std::strerror(errno), errno);
|
qFatal("getrandom() error. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
qFatal("getrandom() failed. Reason: too many retries.");
|
qFatal("getrandom() failed. Reason: too many retries.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result_type getRandomViaFile() const
|
||||||
|
{
|
||||||
|
result_type buf = 0;
|
||||||
|
if (fread(&buf, sizeof(buf), 1, m_randDev) == 1)
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
qFatal("Read /dev/urandom error. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *m_randDev = nullptr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace
|
||||||
: m_randDev {fopen("/dev/urandom", "rb")}
|
: m_randDev {fopen("/dev/urandom", "rb")}
|
||||||
{
|
{
|
||||||
if (!m_randDev)
|
if (!m_randDev)
|
||||||
qFatal("Failed to open /dev/urandom. Reason: %s. Error code: %d.", std::strerror(errno), errno);
|
qFatal("Failed to open /dev/urandom. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
~RandomLayer()
|
~RandomLayer()
|
||||||
|
@ -67,10 +67,10 @@ namespace
|
||||||
result_type operator()() const
|
result_type operator()() const
|
||||||
{
|
{
|
||||||
result_type buf = 0;
|
result_type buf = 0;
|
||||||
if (fread(&buf, sizeof(buf), 1, m_randDev) != 1)
|
if (fread(&buf, sizeof(buf), 1, m_randDev) == 1)
|
||||||
qFatal("Read /dev/urandom error. Reason: %s. Error code: %d.", std::strerror(errno), errno);
|
return buf;
|
||||||
|
|
||||||
return buf;
|
qFatal("Read /dev/urandom error. Reason: \"%s\". Error code: %d.", std::strerror(errno), errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace
|
||||||
return std::numeric_limits<result_type>::max();
|
return std::numeric_limits<result_type>::max();
|
||||||
}
|
}
|
||||||
|
|
||||||
result_type operator()()
|
result_type operator()() const
|
||||||
{
|
{
|
||||||
result_type buf = 0;
|
result_type buf = 0;
|
||||||
const bool result = m_processPrng(reinterpret_cast<PBYTE>(&buf), sizeof(buf));
|
const bool result = m_processPrng(reinterpret_cast<PBYTE>(&buf), sizeof(buf));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue