/explore/lib/mt/uid.cc

https://github.com/ptr/complement · C++ · 233 lines · 143 code · 54 blank · 36 comment · 19 complexity · e766b9ddaebedba1466d4cffb90670c5 MD5 · raw file

  1. // -*- C++ -*-
  2. /*
  3. * Copyright (c) 2006, 2008-2011
  4. * Petr Ovtchenkov
  5. *
  6. * Licensed under the Academic Free License version 3.0
  7. *
  8. */
  9. #include <config/feature.h>
  10. #include <algorithm>
  11. #include <iterator>
  12. #if !defined(STLPORT) && defined(__GNUC__) && !defined(__GXX_EXPERIMENTAL_CXX0X__)
  13. // for copy_n
  14. # include <ext/algorithm>
  15. #endif
  16. #include <mt/uid.h>
  17. #include <sstream>
  18. #include <fstream>
  19. #include <iomanip>
  20. #include <cstring>
  21. #include <stdexcept>
  22. #if !defined(STLPORT) && defined(__GNUC__) && (__GNUC__ >= 5)
  23. #include <system_error>
  24. #else
  25. #include <mt/system_error>
  26. #endif
  27. #include <misc/md5.h>
  28. #include <sys/sysctl.h>
  29. #include <linux/sysctl.h>
  30. #include <uuid/uuid.h>
  31. #include <iostream>
  32. namespace std {
  33. #if !defined(STLPORT) && defined(__GNUC__) && !defined(__GXX_EXPERIMENTAL_CXX0X__)
  34. using __gnu_cxx::copy_n;
  35. #endif
  36. std::ostream& operator <<( std::ostream& s, const xmt::uuid_type& uid )
  37. {
  38. char b[37];
  39. uuid_unparse_lower( uid.u.b, b );
  40. return s << b;
  41. /*
  42. #ifdef STLPORT
  43. std::ios_base::fmtflags f = s.flags( 0 );
  44. #else // i.e. libstdc++
  45. std::ios_base::fmtflags f = s.flags( static_cast<std::ios_base::fmtflags>(0) );
  46. #endif
  47. s << hex << setfill('0')
  48. << setw(2) << static_cast<unsigned>(uid.u.b[0])
  49. << setw(2) << static_cast<unsigned>(uid.u.b[1])
  50. << setw(2) << static_cast<unsigned>(uid.u.b[2])
  51. << setw(2) << static_cast<unsigned>(uid.u.b[3]) << '-'
  52. << setw(2) << static_cast<unsigned>(uid.u.b[4])
  53. << setw(2) << static_cast<unsigned>(uid.u.b[5]) << '-'
  54. << setw(2) << static_cast<unsigned>(uid.u.b[6])
  55. << setw(2) << static_cast<unsigned>(uid.u.b[7]) << '-'
  56. << setw(2) << static_cast<unsigned>(uid.u.b[8])
  57. << setw(2) << static_cast<unsigned>(uid.u.b[9]) << '-'
  58. << setw(2) << static_cast<unsigned>(uid.u.b[10])
  59. << setw(2) << static_cast<unsigned>(uid.u.b[11])
  60. << setw(2) << static_cast<unsigned>(uid.u.b[12])
  61. << setw(2) << static_cast<unsigned>(uid.u.b[13])
  62. << setw(2) << static_cast<unsigned>(uid.u.b[14])
  63. << setw(2) << static_cast<unsigned>(uid.u.b[15]);
  64. s.flags( f );
  65. return s;
  66. */
  67. }
  68. std::istream& operator >>( std::istream& s, xmt::uuid_type& uid )
  69. {
  70. if ( !std::istream::sentry( s ) ) {
  71. return s;
  72. }
  73. char b[37];
  74. s.read( b, 36 );
  75. b[36] = '\0';
  76. if ( !s.fail() ) {
  77. if ( uuid_parse( b, uid.u.b ) < 0 ) {
  78. for ( char *r = b + 35; r >= b; --r ) {
  79. s.putback( *r );
  80. }
  81. s.setstate( std::ios_base::failbit );
  82. }
  83. } else {
  84. for ( char *r = b + s.gcount() - 1; r >= b; --r ) {
  85. s.putback( *r );
  86. }
  87. }
  88. return s;
  89. }
  90. } // namespace std
  91. namespace xmt {
  92. const uuid_type nil_uuid = { { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; // NIL UUID
  93. namespace detail {
  94. using namespace std;
  95. using namespace xmt;
  96. struct __uid_init
  97. {
  98. __uid_init();
  99. static uuid_type _host_id;
  100. int err;
  101. };
  102. uuid_type __uid_init::_host_id;
  103. __uid_init::__uid_init() :
  104. err( 0 )
  105. {
  106. ifstream boot_id( "/proc/sys/kernel/random/boot_id" );
  107. if ( boot_id.is_open() && boot_id.good() ) {
  108. boot_id >> _host_id;
  109. } else {
  110. static size_t n = sizeof(uuid_type);
  111. static int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_BOOT_ID };
  112. err = sysctl( mib, sizeof(mib)/sizeof(mib[0]), &_host_id, &n, (void*)0, 0 );
  113. }
  114. }
  115. } // namespace detail
  116. using namespace std;
  117. uuid_type::operator string() const
  118. {
  119. ostringstream s;
  120. s << *this;
  121. return s.str();
  122. }
  123. const char *hostid_str() throw (runtime_error)
  124. {
  125. static char b[37] = "";
  126. if ( b[0] == 0 ) {
  127. uuid_unparse_lower( hostid().u.b, b );
  128. }
  129. return b;
  130. }
  131. const xmt::uuid_type& hostid() throw (runtime_error)
  132. {
  133. static detail::__uid_init _uid;
  134. if ( _uid.err != 0 ) {
  135. throw system_error( _uid.err, system_category(), "boot_id" );
  136. }
  137. return detail::__uid_init::_host_id;
  138. }
  139. std::string uid_str() throw (runtime_error)
  140. {
  141. char b[37];
  142. uuid_type id;
  143. uuid_generate_random( id.u.b );
  144. uuid_unparse_lower( id.u.b, b );
  145. return std::string( b, 36 );
  146. }
  147. xmt::uuid_type uid() throw (runtime_error)
  148. {
  149. uuid_type id;
  150. uuid_generate_random( id.u.b );
  151. return id;
  152. }
  153. const uuid_type ns_url = { { { 0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 } } }; // UUID namespace URL
  154. const uuid_type ns_oid = { { { 0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 } } }; // UUID namespace ISO OID
  155. const uuid_type ns_x500 = { { { 0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 } } }; // UUID namespace X.500 DN
  156. xmt::uuid_type uid_md5( const void* s, size_t n )
  157. {
  158. uuid_type id;
  159. MD5_CTX context;
  160. MD5Init( &context );
  161. MD5Update( &context, ns_oid.u.b, 16 ); // namespace ISO OID
  162. MD5Update( &context, reinterpret_cast<const uint8_t*>(s), n );
  163. MD5Final( id.u.b, &context );
  164. id.u.b[6] &= 0x0f;
  165. id.u.b[6] |= 0x30; // UUID version 3
  166. id.u.b[8] &= 0x3f;
  167. id.u.b[8] |= 0x80; // UUID variant DCE
  168. return id;
  169. }
  170. int uid_version( const xmt::uuid_type& id )
  171. {
  172. return static_cast<int>(id.u.b[6] >> 4);
  173. }
  174. int uid_variant( const xmt::uuid_type& id )
  175. {
  176. return static_cast<int>(id.u.b[8] >> 6);
  177. }
  178. } // namespace xmt