summaryrefslogtreecommitdiff
path: root/cpp/src/IceUtil/UUID.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IceUtil/UUID.cpp')
-rw-r--r--cpp/src/IceUtil/UUID.cpp162
1 files changed, 162 insertions, 0 deletions
diff --git a/cpp/src/IceUtil/UUID.cpp b/cpp/src/IceUtil/UUID.cpp
new file mode 100644
index 00000000000..fbff5d7b3bd
--- /dev/null
+++ b/cpp/src/IceUtil/UUID.cpp
@@ -0,0 +1,162 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceUtil/UUID.h>
+
+// On Windows, we use Windows's RPC UUID generator.
+// On other platforms, we use a high quality random number generator
+// (/dev/random) to generate "version 4" UUIDs, as described in
+// http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-00.txt
+
+#ifdef _WIN32
+# include <rpc.h>
+#else
+# include <IceUtil/Random.h>
+# include <sys/types.h>
+# include <unistd.h>
+#endif
+
+using namespace std;
+
+#ifndef _WIN32
+
+namespace
+{
+
+char myPid[2];
+
+}
+
+namespace IceUtilInternal
+{
+
+//
+// Initialize the pid.
+//
+class PidInitializer
+{
+public:
+
+ PidInitializer()
+ {
+ pid_t p = getpid();
+ myPid[0] = (p >> 8) & 0x7F;
+ myPid[1] = p & 0xFF;
+ }
+};
+
+PidInitializer pidInitializer;
+
+};
+#endif
+
+namespace
+{
+
+// Helper char to hex functions
+//
+inline void halfByteToHex(unsigned char hb, char*& hexBuffer)
+{
+ if(hb < 10)
+ {
+ *hexBuffer++ = '0' + hb;
+ }
+ else
+ {
+ *hexBuffer++ = 'A' + (hb - 10);
+ }
+}
+
+inline void bytesToHex(unsigned char* bytes, size_t len, char*& hexBuffer)
+{
+ for(size_t i = 0; i < len; i++)
+ {
+ halfByteToHex((bytes[i] & 0xF0) >> 4, hexBuffer);
+ halfByteToHex((bytes[i] & 0x0F), hexBuffer);
+ }
+}
+
+}
+
+string
+IceUtil::generateUUID()
+{
+#ifdef _WIN32
+
+ UUID uuid;
+ UuidCreate(&uuid);
+
+ unsigned char* str;
+
+ UuidToString(&uuid, &str);
+
+ string result = reinterpret_cast<char*>(str);
+
+ RpcStringFree(&str);
+ return result;
+
+#else
+ struct UUID
+ {
+ unsigned char timeLow[4];
+ unsigned char timeMid[2];
+ unsigned char timeHighAndVersion[2];
+ unsigned char clockSeqHiAndReserved;
+ unsigned char clockSeqLow;
+ unsigned char node[6];
+ };
+ UUID uuid;
+
+ assert(sizeof(UUID) == 16);
+
+ //
+ // Get a random sequence of bytes. Instead of using 122 random
+ // bits that could be duplicated (because of a bug with some Linux
+ // kernels and potentially other Unix platforms -- see comment in
+ // Random.cpp), we replace the last 15 bits of all "random"
+ // Randoms by the last 15 bits of the process id.
+ //
+ char* buffer = reinterpret_cast<char*>(&uuid);
+ IceUtilInternal::generateRandom(buffer, static_cast<int>(sizeof(UUID)));
+
+ //
+ // Adjust the bits that say "version 4" UUID
+ //
+ uuid.timeHighAndVersion[0] &= 0x0F;
+ uuid.timeHighAndVersion[0] |= (4 << 4);
+ uuid.clockSeqHiAndReserved &= 0x3F;
+ uuid.clockSeqHiAndReserved |= 0x80;
+
+ //
+ // Replace the end of the node by myPid (15 bits)
+ //
+ uuid.node[4] = (uuid.node[4] & 0x80) | myPid[0];
+ uuid.node[5] = myPid[1];
+
+ //
+ // Convert to a UUID string
+ //
+ char uuidString[16 * 2 + 4 + 1]; // 16 bytes, 4 '-' and a final '\0'
+ char* uuidIndex = uuidString;
+ bytesToHex(uuid.timeLow, sizeof(uuid.timeLow), uuidIndex);
+ *uuidIndex++ = '-';
+ bytesToHex(uuid.timeMid, sizeof(uuid.timeMid), uuidIndex);
+ *uuidIndex++ = '-';
+ bytesToHex(uuid.timeHighAndVersion, sizeof(uuid.timeHighAndVersion), uuidIndex);
+ *uuidIndex++ = '-';
+ bytesToHex(&uuid.clockSeqHiAndReserved, sizeof(uuid.clockSeqHiAndReserved), uuidIndex);
+ bytesToHex(&uuid.clockSeqLow, sizeof(uuid.clockSeqLow), uuidIndex);
+ *uuidIndex++ = '-';
+ bytesToHex(uuid.node, sizeof(uuid.node), uuidIndex);
+ *uuidIndex = '\0';
+
+ return uuidString;
+
+#endif
+}