summaryrefslogtreecommitdiff
path: root/cpp/src/IceUtil/UUID.cpp
diff options
context:
space:
mode:
authorBernard Normier <bernard@zeroc.com>2003-04-12 15:42:19 +0000
committerBernard Normier <bernard@zeroc.com>2003-04-12 15:42:19 +0000
commit13eacdd52936ecd6800f959f84fff53e5339e969 (patch)
tree3063ca8d7bd6a25f1878af3d1801d1273a5b68d5 /cpp/src/IceUtil/UUID.cpp
parentAdded support for setting environment variables (diff)
downloadice-13eacdd52936ecd6800f959f84fff53e5339e969.tar.bz2
ice-13eacdd52936ecd6800f959f84fff53e5339e969.tar.xz
ice-13eacdd52936ecd6800f959f84fff53e5339e969.zip
Updated UUID Unix implementation to use /dev/urandom directly instead of
through E2FSPROGS libuuid.
Diffstat (limited to 'cpp/src/IceUtil/UUID.cpp')
-rw-r--r--cpp/src/IceUtil/UUID.cpp126
1 files changed, 117 insertions, 9 deletions
diff --git a/cpp/src/IceUtil/UUID.cpp b/cpp/src/IceUtil/UUID.cpp
index 70932f32eb6..db3070a8e9e 100644
--- a/cpp/src/IceUtil/UUID.cpp
+++ b/cpp/src/IceUtil/UUID.cpp
@@ -15,17 +15,71 @@
#include <IceUtil/UUID.h>
#include <IceUtil/Unicode.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
+
+#include <assert.h>
+
#ifdef _WIN32
# include <rpc.h>
#else
-extern "C" // uuid/uuid.h seems to miss extern "C" declarations.
-{
-# include <uuid/uuid.h>
-}
+#include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <unistd.h>
#endif
using namespace std;
+// 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, int len, char*& hexBuffer)
+{
+ for(int i = 0; i < len; i++)
+ {
+ halfByteToHex((bytes[i] & 0xF0) >> 4, hexBuffer);
+ halfByteToHex((bytes[i] & 0x0F), hexBuffer);
+ }
+}
+
+
+IceUtil::UUIDGenerationException::UUIDGenerationException(const char* file, int line) :
+ Exception(file, line)
+{}
+
+string
+IceUtil::UUIDGenerationException::ice_name() const
+{
+ return "IceUtil::UUIDGenerationException";
+}
+
+IceUtil::Exception*
+IceUtil::UUIDGenerationException::ice_clone() const
+{
+ return new UUIDGenerationException(*this);
+}
+
+void
+IceUtil::UUIDGenerationException::ice_throw() const
+{
+ throw *this;
+}
+
+
string
IceUtil::generateUUID()
{
@@ -55,13 +109,67 @@ IceUtil::generateUUID()
#else
- uuid_t uuid;
- uuid_generate(uuid);
+ // On Linux, /dev/random, even when used in blocking mode, sometimes
+ // fails or returns fewer bytes.
+ // Maybe we should use a combination of version 4 UUIDs (with /dev/random),
+ // and version 1 UUIDs (MAC address + time), when /dev/random is exhausted?
+
+ int fd = open("/dev/urandom", O_RDONLY);
+
+ if (fd == -1)
+ {
+ assert(0);
+ throw UUIDGenerationException(__FILE__, __LINE__);
+ }
+
+ 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);
+
+ ssize_t bytesRead = read(fd, &uuid, sizeof(UUID));
+
+ if (bytesRead != sizeof(UUID))
+ {
+ assert(0);
+ close(fd);
+ throw UUIDGenerationException(__FILE__, __LINE__);
+ }
+
+ close(fd);
+
+ // Adjust the bits that say "version 4" UUID
+ //
+ uuid.timeHighAndVersion[0] &= 0x0F;
+ uuid.timeHighAndVersion[0] |= (3 << 4);
+ uuid.clockSeqHiAndReserved &= 0x3F;
+ uuid.clockSeqHiAndReserved |= 0x80;
- char str[37];
- uuid_unparse(uuid, str);
+ // 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 str;
+ return uuidString;
#endif
}