AnCH Framework  0.1
Another C++ Hack Framework
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages
uuid.hpp
1 /*
2  ANCH Framework: ANother C++ Hack is a C++ framework based on C++11 standard
3  Copyright (C) 2012 Vincent Lachenal
4 
5  This file is part of ANCH Framework.
6 
7  ANCH Framework is free software: you can redistribute it and/or modify
8  it under the terms of the GNU Lesser General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  ANCH Framework is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public License
18  along with ANCH Framework. If not, see <http://www.gnu.org/licenses/>.
19 */
20 #ifndef _ANCH_UUID_H_
21 #define _ANCH_UUID_H_
22 
23 #include <iostream>
24 #include <iomanip>
25 #include <sstream>
26 #include <ctime>
27 #include <chrono>
28 #include <limits>
29 #include <random>
30 #include <functional>
31 
32 #include "device/network.hpp"
33 #include "crypto/hash/md5.hpp"
34 #include "crypto/hash/sha1.hpp"
35 
36 
37 namespace anch {
38 
50  class Uuid {
51  public:
59  enum Version {
62 
65 
68 
71 
74  };
75 
76  // Attributes +
77  private:
79  static const uint64_t TIME_LOW_MASK = 0x00000000FFFFFFFF;
80 
82  static const uint64_t TIME_MID_MASK = 0x000000000000FFFF;
83 
85  static const uint64_t TIME_HIGH_MASK = 0x0000000000000FFF;
86 
88  static const uint32_t SEQ_LOW_MASK = 0x00FF;
89 
91  static const uint32_t SEQ_HIGH_MASK = 0x3F00;
92 
94  uint32_t _lowTime;
95 
97  uint16_t _midTime;
98 
100  uint16_t _highTime;
101 
103  uint16_t _clockSeqLow;
104 
106  uint16_t _clockSeqHighRes;
107 
109  uint64_t _node;
110 
112  anch::Uuid::Version _version;
113  // Attributes -
114 
115 
116  // Constructors +
117  public:
121  Uuid() {
122  // Nothing to do
123  }
124 
130  Uuid(const Uuid& uuid): _lowTime(uuid._lowTime),
131  _midTime(uuid._midTime),
132  _highTime(uuid._highTime),
133  _clockSeqLow(uuid._clockSeqLow),
134  _clockSeqHighRes(uuid._clockSeqHighRes),
135  _node(uuid._node) {
136  // Nothing to do
137  }
138  // Constructors -
139 
140  // Destructor +
141  public:
145  virtual ~Uuid() {
146  // Nothing to do
147  }
148  // Destructor -
149 
150  // Methods +
151  public:
159  static void generateUuid(Uuid& uuid,
160  anch::Uuid::Version version = anch::Uuid::Version::RANDOM,
161  const std::string& data = "") {
162  // Initialize random seed +
163  std::chrono::time_point<std::chrono::high_resolution_clock> now = std::chrono::high_resolution_clock::now();
164  auto epoch = now.time_since_epoch();
165  int64_t timestamp = (std::chrono::duration_cast<std::chrono::nanoseconds>(epoch).count());
166  getRandomEngine().seed(timestamp);
167  // Initialize random seed -
168 
169  uuid._version = version;
170 
171  switch(version) {
172  case Uuid::Version::MAC_ADDRESS:
173  generateUuidVersion1(uuid, data);
174  break;
175  case Uuid::Version::DCE_SECURITY:
176  // TODO implements this algorithm version
177  break;
178  case Uuid::Version::MD5_HASH:
179  generateUuidVersion3(uuid,data);
180  break;
181  case Uuid::Version::RANDOM:
182  generateUuidVersion4(uuid);
183  break;
184  case Uuid::Version::SHA1_HASH:
185  generateUuidVersion5(uuid,data);
186  break;
187  default:
188  // Nothing to do
189  break;
190  }
191  }
192 
200  static void generateUuidVersion1(Uuid& uuid,
201  const std::string& macAddress = "") {
202  // Timestamp +
203  uint64_t timestamp = getUtcTimestamp();
204  uuid._lowTime = timestamp & TIME_LOW_MASK;
205  uuid._midTime = (timestamp >> 32) & TIME_MID_MASK;
206  uuid._highTime = (timestamp >> 48) & TIME_HIGH_MASK;
207  // Timestamp -
208 
209  // Sequence +
210  uint16_t clockSeq = getDistSeq()(getRandomEngine());
211  uuid._clockSeqLow = clockSeq & SEQ_LOW_MASK;
212  uuid._clockSeqHighRes = (clockSeq & SEQ_HIGH_MASK) >> 8;
213  uuid._clockSeqHighRes |= 0x80;
214  // Sequence -
215 
216  // MAC address +
217  std::string macAddr = macAddress;
218  if(macAddr == "") {
219  for(auto iter : anch::device::Network::getInterfaces()) {
220  const anch::device::NetworkInterface iface = iter.second;
221  if(!iface.isLocalhost()) {
222  macAddr = iface.getMacAddress();
223  }
224  }
225  }
226  std::size_t pos = 0;
227  std::size_t last = 0;
228  std::string macHexStr = "";
229  do {
230  if(pos != 0) {
231  last = pos + 1;
232  }
233  pos = macAddr.find(':', last);
234  macHexStr += macAddr.substr(last, pos - last);
235  } while(pos != std::string::npos);
236  uuid._node = std::stoull(macHexStr,0,16);
237  // MAC address -
238  }
239 
246  static void generateUuidVersion3(Uuid& uuid, const std::string& data) {
247  anch::crypto::MD5 hash(data);
248  const std::array<uint8_t,16>& digest = hash.digest();
249 
250  // Timestamp +
251  uuid._lowTime = digest[0]
252  + (static_cast<uint32_t>(digest[1]) << 8)
253  + (static_cast<uint32_t>(digest[2]) << 16)
254  + (static_cast<uint32_t>(digest[3]) << 24);
255  uuid._midTime = digest[4]
256  + (static_cast<uint16_t>(digest[5]) << 8);
257  uuid._highTime = digest[6]
258  + (static_cast<uint16_t>(digest[7]) << 8);
259  uuid._highTime = uuid._highTime & TIME_HIGH_MASK;
260  // Timestamp -
261 
262  // Sequence +
263  uuid._clockSeqLow = digest[9];
264  uuid._clockSeqHighRes = digest[8];
265  uuid._clockSeqHighRes |= 0x80;
266  // Sequence -
267 
268  // Node +
269  uuid._node = digest[10]
270  + (static_cast<uint64_t>(digest[11]) << 8)
271  + (static_cast<uint64_t>(digest[12]) << 16)
272  + (static_cast<uint64_t>(digest[13]) << 24)
273  + (static_cast<uint64_t>(digest[14]) << 32)
274  + (static_cast<uint64_t>(digest[15]) << 40);
275  // Node -
276  }
277 
283  static void generateUuidVersion4(Uuid& uuid) {
284  static std::uniform_int_distribution<uint16_t> dist16;
285  static std::uniform_int_distribution<uint32_t> dist32;
286  static std::uniform_int_distribution<uint64_t> dist64(0, 0xFFFFFFFFFFFF); // Max 12 hexadecimal digits
287 
288  // Timestamp +
289  uuid._lowTime = dist32(getRandomEngine());
290  uuid._midTime = dist16(getRandomEngine());
291  uuid._highTime = dist16(getRandomEngine()) & TIME_HIGH_MASK;
292  // Timestamp -
293 
294  // Sequence +
295  uint16_t clockSeq = getDistSeq()(getRandomEngine());
296  uuid._clockSeqLow = clockSeq & SEQ_LOW_MASK;
297  uuid._clockSeqHighRes = (clockSeq & SEQ_HIGH_MASK) >> 8;
298  uuid._clockSeqHighRes |= 0x80;
299  // Sequence -
300 
301  // Node +
302  uuid._node = dist64(getRandomEngine());
303  // Node -
304  }
305 
312  static void generateUuidVersion5(Uuid& uuid, const std::string& data) {
313  anch::crypto::SHA1 hash(data);
314  const std::array<uint8_t,20>& digest = hash.digest();
315 
316  // Timestamp +
317  uuid._lowTime = digest[0]
318  + (static_cast<uint32_t>(digest[1]) << 8)
319  + (static_cast<uint32_t>(digest[2]) << 16)
320  + (static_cast<uint32_t>(digest[3]) << 24);
321  uuid._midTime = digest[4]
322  + (static_cast<uint16_t>(digest[5]) << 8);
323  uuid._highTime = digest[6]
324  + (static_cast<uint16_t>(digest[7]) << 8);
325  uuid._highTime = uuid._highTime & TIME_HIGH_MASK;
326  // Timestamp -
327 
328  // Sequence +
329  uuid._clockSeqLow = digest[9];
330  uuid._clockSeqHighRes = digest[8];
331  uuid._clockSeqHighRes |= 0x80;
332  // Sequence -
333 
334  // Node +
335  uuid._node = digest[10]
336  + (static_cast<uint64_t>(digest[11]) << 8)
337  + (static_cast<uint64_t>(digest[12]) << 16)
338  + (static_cast<uint64_t>(digest[13]) << 24)
339  + (static_cast<uint64_t>(digest[14]) << 32)
340  + (static_cast<uint64_t>(digest[15]) << 40);
341  // Node -
342  }
343 
344  private:
350  static uint64_t getUtcTimestamp() {
351  static const uint64_t UTC_OFFSET = 0x01B21DD213814000;
352  std::chrono::time_point<std::chrono::high_resolution_clock> now = std::chrono::high_resolution_clock::now();
353  auto epoch = now.time_since_epoch();
354  int64_t timestamp = (std::chrono::duration_cast<std::chrono::nanoseconds>(epoch).count()) / 100;
355  return UTC_OFFSET + (uint64_t)timestamp;
356  }
357 
363  static inline std::mt19937& getRandomEngine() {
364  static std::mt19937 engine;
365  return engine;
366  }
367 
373  static inline std::uniform_int_distribution<uint16_t>& getDistSeq() {
374  static std::uniform_int_distribution<uint16_t> distSeq(0, SEQ_HIGH_MASK);
375  return distSeq;
376  }
377 
378  public:
384  std::string toString() const {
385  std::ostringstream out;
386  out << std::hex
387  << std::setfill('0') << std::setw(8) << _lowTime << '-'
388  << std::setfill('0') << std::setw(4) << _midTime << '-'
389  << std::setfill('0') << std::setw(1) << _version
390  << std::setfill('0') << std::setw(3) << _highTime << '-'
391  << std::setfill('0') << std::setw(2) << _clockSeqHighRes
392  << std::setfill('0') << std::setw(2) << _clockSeqLow << '-'
393  << std::setfill('0') << std::setw(12) << _node;
394  return out.str();
395  }
396  // Methods -
397 
398 
399  // Accessors +
400  public:
406  inline uint32_t getLowTime() const {
407  return _lowTime;
408  }
409 
415  inline uint16_t getMidTime() const {
416  return _midTime;
417  }
418 
424  inline uint16_t getHighTime() const {
425  return _highTime;
426  }
427 
433  inline uint16_t getClockSeqLow() const {
434  return _clockSeqLow;
435  }
436 
442  inline uint16_t getClockSeqHighRes() const {
443  return _clockSeqHighRes;
444  }
445 
451  inline uint64_t getNode() const {
452  return _node;
453  }
454 
461  return _version;
462  }
463  // Accessors -
464 
465  };
466 
467 }
468 
478 template<class CharT, class Traits>
479 std::basic_ostream<CharT, Traits>&
480 operator<<(std::basic_ostream<CharT, Traits>& out, const anch::Uuid& uuid) {
481  std::ios_base::fmtflags flags = out.flags(); // Save current flags
482  out << std::hex
483  << std::setfill('0') << std::setw(8) << uuid.getLowTime() << '-'
484  << std::setfill('0') << std::setw(4) << uuid.getMidTime() << '-'
485  << std::setfill('0') << std::setw(1) << uuid.getVersion()
486  << std::setfill('0') << std::setw(3) << uuid.getHighTime() << '-'
487  << std::setfill('0') << std::setw(2) << uuid.getClockSeqHighRes()
488  << std::setfill('0') << std::setw(2) << uuid.getClockSeqLow() << '-'
489  << std::setfill('0') << std::setw(12) << uuid.getNode();
490  out.flags(flags); // Restore flags
491  return out;
492 }
493 
494 #endif // _ANCH_UUID_H_
uint32_t getLowTime() const
Definition: uuid.hpp:406
Uuid()
Definition: uuid.hpp:121
uint16_t getClockSeqHighRes() const
Definition: uuid.hpp:442
Definition: uuid.hpp:73
Definition: networkInterface.hpp:38
const std::string & getMacAddress() const
Definition: networkInterface.hpp:112
Definition: uuid.hpp:61
uint16_t getMidTime() const
Definition: uuid.hpp:415
Definition: uuid.hpp:67
virtual ~Uuid()
Definition: uuid.hpp:145
Definition: uuid.hpp:70
Definition: uuid.hpp:64
Version
Definition: uuid.hpp:59
static void generateUuidVersion3(Uuid &uuid, const std::string &data)
Definition: uuid.hpp:246
uint16_t getHighTime() const
Definition: uuid.hpp:424
static void generateUuidVersion4(Uuid &uuid)
Definition: uuid.hpp:283
AnCH framework base namespace.
Definition: base64.hpp:28
virtual const std::array< uint8_t, 20 > & digest() const override
Definition: sha1.cpp:72
Uuid(const Uuid &uuid)
Definition: uuid.hpp:130
UUID generator and parser.
Definition: uuid.hpp:50
bool isLocalhost() const
Definition: networkInterface.hpp:157
uint16_t getClockSeqLow() const
Definition: uuid.hpp:433
MD5 hash algorithm implementation.
Definition: md5.hpp:40
static void generateUuid(Uuid &uuid, anch::Uuid::Version version=anch::Uuid::Version::RANDOM, const std::string &data="")
Definition: uuid.hpp:159
static const std::map< std::string, anch::device::NetworkInterface > & getInterfaces()
Definition: network.cpp:104
std::string toString() const
Definition: uuid.hpp:384
static void generateUuidVersion1(Uuid &uuid, const std::string &macAddress="")
Definition: uuid.hpp:200
uint64_t getNode() const
Definition: uuid.hpp:451
static void generateUuidVersion5(Uuid &uuid, const std::string &data)
Definition: uuid.hpp:312
anch::Uuid::Version getVersion() const
Definition: uuid.hpp:460
virtual const std::array< uint8_t, 16 > & digest() const override
Definition: md5.cpp:73
SHA1 hash algorithm implementation.
Definition: sha1.hpp:38