summaryrefslogtreecommitdiff
path: root/cppe/src/IceE/UUID.cpp
diff options
context:
space:
mode:
authorDwayne Boone <dwayne@zeroc.com>2005-07-05 11:09:55 +0000
committerDwayne Boone <dwayne@zeroc.com>2005-07-05 11:09:55 +0000
commit9b8cc712d4a41d71840416776bc94ee8485bb9b3 (patch)
tree7d467fdd6a66bc2b5878d82070d45adbd5c20414 /cppe/src/IceE/UUID.cpp
parentcleaning the cache method out of ReferenceFactory (diff)
downloadice-9b8cc712d4a41d71840416776bc94ee8485bb9b3.tar.bz2
ice-9b8cc712d4a41d71840416776bc94ee8485bb9b3.tar.xz
ice-9b8cc712d4a41d71840416776bc94ee8485bb9b3.zip
Changed Ice to IceE EVERYWHERE!!!
Diffstat (limited to 'cppe/src/IceE/UUID.cpp')
-rw-r--r--cppe/src/IceE/UUID.cpp275
1 files changed, 275 insertions, 0 deletions
diff --git a/cppe/src/IceE/UUID.cpp b/cppe/src/IceE/UUID.cpp
new file mode 100644
index 00000000000..439c310bfba
--- /dev/null
+++ b/cppe/src/IceE/UUID.cpp
@@ -0,0 +1,275 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2005 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICEE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+#include <IceE/UUID.h>
+
+// On Windows, we use Windows's RPC UUID generator.
+//
+// Under WinCE we use the Cryptography functions to generate random
+// numbers which should be suitable for a "version 4" UUID.
+//
+// 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
+//
+
+
+#if defined(_WIN32_WCE)
+# include <wincrypt.h>
+#elif defined(_WIN32)
+# include <rpc.h>
+#else
+# include <IceE/StaticMutex.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, size_t len, char*& hexBuffer)
+{
+ for(size_t i = 0; i < len; i++)
+ {
+ halfByteToHex((bytes[i] & 0xF0) >> 4, hexBuffer);
+ halfByteToHex((bytes[i] & 0x0F), hexBuffer);
+ }
+}
+
+
+IceE::UUIDGenerationException::UUIDGenerationException(const char* file, int line) :
+ Exception(file, line)
+{
+}
+
+const char* IceE::UUIDGenerationException::_name = "IceE::UUIDGenerationException";
+
+#ifndef _WIN32
+//
+// Unfortunately on Linux (at least up to 2.6.9), concurrent access to /dev/urandom
+// can return the same value. Search for "Concurrent access to /dev/urandom" in the
+// linux-kernel mailing list archive for additional details.
+// Since /dev/urandom on other platforms is usually a port from Linux, this problem
+// could be widespread. Therefore, instead of using 122 random bits that could be
+// duplicated, we replace the last 15 bits of all "random" UUIDs by the last 15 bits
+// of the process id, and in each process, we serialize access to /dev/urandom using
+// a static mutex.
+//
+
+static IceE::StaticMutex staticMutex = ICEE_STATIC_MUTEX_INITIALIZER;
+static int fd = -1;
+static char myPid[2];
+
+namespace
+{
+
+//
+// Close fd at exit
+//
+class UUIDCleanup
+{
+public:
+
+ ~UUIDCleanup()
+ {
+ IceE::StaticMutex::Lock lock(staticMutex);
+ if(fd != -1)
+ {
+ close(fd);
+ fd = -1;
+ }
+ }
+};
+static UUIDCleanup uuidCleanup;
+}
+
+
+#endif
+
+const string
+IceE::UUIDGenerationException::ice_name() const
+{
+ return _name;
+}
+
+IceE::Exception*
+IceE::UUIDGenerationException::ice_clone() const
+{
+ return new UUIDGenerationException(*this);
+}
+
+void
+IceE::UUIDGenerationException::ice_throw() const
+{
+ throw *this;
+}
+
+
+string
+IceE::generateUUID()
+{
+#if defined(_WIN32 ) && !defined(_WIN32_WCE)
+
+ 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);
+
+ char* buffer = reinterpret_cast<char*>(&uuid);
+ int reads = 0;
+ size_t index = 0;
+
+#ifdef _WIN32_WCE
+ //
+ // TODO: I suspect we should cache this provider.
+ //
+ HCRYPTPROV prov;
+ if(!CryptAcquireContext(&prov, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ {
+ throw UUIDGenerationException(__FILE__, __LINE__);
+ }
+
+ memset(buffer, 0, 16);
+ if(!CryptGenRandom(prov, 16, (unsigned char*)buffer))
+ {
+ bool rc = CryptReleaseContext(prov, 0);
+ assert(rc);
+ throw UUIDGenerationException(__FILE__, __LINE__);
+ }
+
+ if(!CryptReleaseContext(prov, 0))
+ {
+ throw UUIDGenerationException(__FILE__, __LINE__);
+ }
+#else
+ {
+ //
+ // Serialize access to /dev/urandom; see comment above.
+ //
+ IceE::StaticMutex::Lock lock(staticMutex);
+ if(fd == -1)
+ {
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd == -1)
+ {
+ assert(0);
+ throw UUIDGenerationException(__FILE__, __LINE__);
+ }
+
+ //
+ // Initialize myPid as well
+ //
+ pid_t pid = getpid();
+ myPid[0] = (pid >> 8) & 0x7F;
+ myPid[1] = pid & 0xFF;
+ }
+
+
+ //
+ // Limit the number of attempts to 20 reads to avoid
+ // a potential "for ever" loop
+ //
+ while(reads <= 20 && index != sizeof(UUID))
+ {
+ ssize_t bytesRead = read(fd, buffer + index, sizeof(UUID) - index);
+
+ if(bytesRead == -1 && errno != EINTR)
+ {
+ int err = errno;
+ fprintf(stderr, "Reading /dev/urandom returned %s\n", strerror(err));
+ assert(0);
+ throw UUIDGenerationException(__FILE__, __LINE__);
+ }
+ else
+ {
+ index += bytesRead;
+ reads++;
+ }
+ }
+ }
+
+ if (index != sizeof(UUID))
+ {
+ assert(0);
+ throw UUIDGenerationException(__FILE__, __LINE__);
+ }
+
+ //
+ // Replace the end of the node by myPid (15 bits)
+ //
+ uuid.node[4] = (uuid.node[4] & 0x80) | myPid[0];
+ uuid.node[5] = myPid[1];
+#endif
+
+ //
+ // Adjust the bits that say "version 4" UUID
+ //
+ uuid.timeHighAndVersion[0] &= 0x0F;
+ uuid.timeHighAndVersion[0] |= (4 << 4);
+ uuid.clockSeqHiAndReserved &= 0x3F;
+ uuid.clockSeqHiAndReserved |= 0x80;
+
+ //
+ // 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
+}