Line data Source code
1 : #include "random.h" 2 : 3 : #include <bitset> 4 : #include <random> 5 : 6 : #include "hex.h" 7 : #include "platform_util.h" 8 : 9 : namespace datadog { 10 : namespace tracing { 11 : namespace { 12 : 13 : extern "C" void on_fork(); 14 : 15 : class Uint64Generator { 16 : std::mt19937_64 generator_; 17 : std::uniform_int_distribution<std::uint64_t> distribution_; 18 : 19 : public: 20 1 : Uint64Generator() { 21 1 : seed_with_random(); 22 : // If a process links to this library and then calls `fork`, the 23 : // `generator_` in the parent and child processes will produce the exact 24 : // same sequence of values, which is bad. 25 : // A subsequent call to `exec` would remedy this, but nginx in particular 26 : // does not call `exec` after forking its worker processes. 27 : // So, we use `at_fork_in_child` to re-seed `generator_` in the child 28 : // process after `fork`. 29 1 : (void)at_fork_in_child(&on_fork); 30 1 : } 31 : 32 85054 : std::uint64_t operator()() { return distribution_(generator_); } 33 : 34 1 : void seed_with_random() { generator_.seed(std::random_device{}()); } 35 : }; 36 : 37 : thread_local Uint64Generator thread_local_generator; 38 : 39 0 : void on_fork() { thread_local_generator.seed_with_random(); } 40 : 41 : } // namespace 42 : 43 85054 : std::uint64_t random_uint64() { return thread_local_generator(); } 44 : 45 1072 : std::string uuid() { 46 : // clang-format off 47 : // It's not all random. From most significant to least significant, the 48 : // bits look like this: 49 : // 50 : // xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 0100xxxx xxxxxxxx 10xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 51 : // 52 : // where the "0" and "1" are hard-coded bits, and all of the "x" are random. 53 : // See RFC 4122 for more information. 54 : // clang-format on 55 1072 : std::bitset<64> high = random_uint64(); 56 1072 : std::bitset<64> low = random_uint64(); 57 : 58 : // Set "0100" for the most significant bits of the 59 : // second-to-least-significant byte of `high`. 60 1072 : high[15] = 0; 61 1072 : high[14] = 1; 62 1072 : high[13] = 0; 63 1072 : high[12] = 0; 64 : 65 : // Set "10" for the most significant bits of `low`. 66 1072 : low[63] = 1; 67 1072 : low[62] = 0; 68 : 69 1072 : std::string result; 70 1072 : std::string hexed = hex_padded(high.to_ullong()); 71 1072 : result += hexed.substr(0, 8); 72 1072 : result += '-'; 73 1072 : result += hexed.substr(8, 4); 74 1072 : result += '-'; 75 1072 : result += hexed.substr(12); 76 1072 : result += '-'; 77 1072 : hexed = hex_padded(low.to_ullong()); 78 1072 : result += hexed.substr(0, 4); 79 1072 : result += '-'; 80 1072 : result += hexed.substr(4); 81 : 82 2144 : return result; 83 1072 : } 84 : 85 : } // namespace tracing 86 : } // namespace datadog