1 | // |
2 | // UUIDGenerator.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: UUID |
6 | // Module: UUID |
7 | // |
8 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/UUIDGenerator.h" |
16 | #include "Poco/Thread.h" |
17 | #include "Poco/RandomStream.h" |
18 | #include "Poco/DigestEngine.h" |
19 | #include "Poco/MD5Engine.h" |
20 | #include "Poco/SHA1Engine.h" |
21 | #include "Poco/SingletonHolder.h" |
22 | #include <cstring> |
23 | |
24 | |
25 | namespace Poco { |
26 | |
27 | |
28 | UUIDGenerator::UUIDGenerator(): _ticks(0), _haveNode(false) |
29 | { |
30 | } |
31 | |
32 | |
33 | UUIDGenerator::~UUIDGenerator() |
34 | { |
35 | } |
36 | |
37 | |
38 | UUID UUIDGenerator::create() |
39 | { |
40 | FastMutex::ScopedLock lock(_mutex); |
41 | |
42 | if (!_haveNode) |
43 | { |
44 | Environment::nodeId(_node); |
45 | _haveNode = true; |
46 | } |
47 | Timestamp::UtcTimeVal tv = timeStamp(); |
48 | UInt32 timeLow = UInt32(tv & 0xFFFFFFFF); |
49 | UInt16 timeMid = UInt16((tv >> 32) & 0xFFFF); |
50 | UInt16 timeHiAndVersion = UInt16((tv >> 48) & 0x0FFF) + (UUID::UUID_TIME_BASED << 12); |
51 | UInt16 clockSeq = (UInt16(_random.next() >> 4) & 0x3FFF) | 0x8000; |
52 | return UUID(timeLow, timeMid, timeHiAndVersion, clockSeq, _node); |
53 | } |
54 | |
55 | |
56 | UUID UUIDGenerator::createFromName(const UUID& nsid, const std::string& name) |
57 | { |
58 | MD5Engine md5; |
59 | return createFromName(nsid, name, md5); |
60 | } |
61 | |
62 | |
63 | UUID UUIDGenerator::createFromName(const UUID& nsid, const std::string& name, DigestEngine& de) |
64 | { |
65 | UUID::Version version = UUID::UUID_NAME_BASED; |
66 | if (dynamic_cast<SHA1Engine*>(&de)) version = UUID::UUID_NAME_BASED_SHA1; |
67 | return createFromName(nsid, name, de, version); |
68 | } |
69 | |
70 | |
71 | UUID UUIDGenerator::createFromName(const UUID& nsid, const std::string& name, DigestEngine& de, UUID::Version version) |
72 | { |
73 | poco_assert_dbg (de.digestLength() >= 16); |
74 | |
75 | UUID netNsid = nsid; |
76 | netNsid.toNetwork(); |
77 | de.reset(); |
78 | de.update(&netNsid._timeLow, sizeof(netNsid._timeLow)); |
79 | de.update(&netNsid._timeMid, sizeof(netNsid._timeMid)); |
80 | de.update(&netNsid._timeHiAndVersion, sizeof(netNsid._timeHiAndVersion)); |
81 | de.update(&netNsid._clockSeq, sizeof(netNsid._clockSeq)); |
82 | de.update(&netNsid._node[0], sizeof(netNsid._node)); |
83 | de.update(name); |
84 | char buffer[16]; |
85 | const DigestEngine::Digest& d = de.digest(); |
86 | for (int i = 0; i < 16; ++i) |
87 | { |
88 | buffer[i] = d[i]; |
89 | } |
90 | return UUID(buffer, version); |
91 | } |
92 | |
93 | |
94 | UUID UUIDGenerator::createRandom() |
95 | { |
96 | char buffer[16]; |
97 | RandomInputStream ris; |
98 | ris.read(buffer, sizeof(buffer)); |
99 | return UUID(buffer, UUID::UUID_RANDOM); |
100 | } |
101 | |
102 | |
103 | Timestamp::UtcTimeVal UUIDGenerator::timeStamp() |
104 | { |
105 | Timestamp now; |
106 | for (;;) |
107 | { |
108 | if (now != _lastTime) |
109 | { |
110 | _lastTime = now; |
111 | _ticks = 0; |
112 | break; |
113 | } |
114 | if (_ticks < 100) |
115 | { |
116 | ++_ticks; |
117 | break; |
118 | } |
119 | now.update(); |
120 | } |
121 | Timestamp::UtcTimeVal tv = now.utcTime(); |
122 | return tv + _ticks; |
123 | } |
124 | |
125 | |
126 | UUID UUIDGenerator::createOne() |
127 | { |
128 | try |
129 | { |
130 | return create(); |
131 | } |
132 | catch (Exception&) |
133 | { |
134 | return createRandom(); |
135 | } |
136 | } |
137 | |
138 | |
139 | namespace |
140 | { |
141 | static SingletonHolder<UUIDGenerator> sh; |
142 | } |
143 | |
144 | |
145 | UUIDGenerator& UUIDGenerator::defaultGenerator() |
146 | { |
147 | return *sh.get(); |
148 | } |
149 | |
150 | |
151 | } // namespace Poco |
152 | |