aboutsummaryrefslogtreecommitdiff
path: root/libbutl/uuid-macos.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-08-22 17:26:08 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-08-22 17:36:23 +0200
commitfebb9c275b5247df596876e4eea7fa17b7ec45e7 (patch)
tree214a192cc6b019fb25a659cfdb84601da74438bf /libbutl/uuid-macos.cxx
parentf8fc81a5c9fcd986473797df9286c6c9fef683bf (diff)
Add support for UUID generation
Diffstat (limited to 'libbutl/uuid-macos.cxx')
-rw-r--r--libbutl/uuid-macos.cxx81
1 files changed, 81 insertions, 0 deletions
diff --git a/libbutl/uuid-macos.cxx b/libbutl/uuid-macos.cxx
new file mode 100644
index 0000000..1003501
--- /dev/null
+++ b/libbutl/uuid-macos.cxx
@@ -0,0 +1,81 @@
+// file : libbutl/uuid-macos.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BUILD2_BOOTSTRAP
+
+#include <libbutl/uuid.hxx>
+
+#include <CoreFoundation/CFUUID.h>
+
+#include <cassert>
+#include <cstring> // memcpy()
+
+using namespace std;
+
+namespace butl
+{
+ void
+ uuid_throw_weak (); // uuid.cxx
+
+ uuid uuid_system_generator::
+ generate (bool strong)
+ {
+ // The common way to generate a UUID on Mac OS is with the CFUUIDCreate()
+ // function from the CoreFoundation framework. Interestingly, if we look
+ // at the implementation (yes, the CF source code is available), we will
+ // see that it uses the <uuid/uuid.h> API which looks like a customized
+ // implementation from e2fsprogs that itself is a precursor to libuuid
+ // from util-linux.
+ //
+ // More specifically (and at least as of CF version 1153.18), it calls
+ // uuid_generate_random() unless the CFUUIDVersionNumber environment
+ // variable is set to 1, in which case it calls uuid_generate_time(). It
+ // also appears to serialize these calls so the implementation should be
+ // thread-safe (see the Linux implementation for background; this is also
+ // the reason why we don't want to use the low-level API directly even if
+ // we provide our own synchronization: if other code in the process calls
+ // CFUUIDCreate() then we will end up with a race).
+ //
+ // In theory the use of uuid_generate_random() is bad news since it will
+ // produce weak pseudo-random UUIDs if no high-quality randomness is
+ // available (unlike uuid_generate() which will only produce strong random
+ // UUIDs falling back to the MAC/time-based ones; see uuid_generate(3) for
+ // details).
+ //
+ // In practice (and at least as of Mac OS libc version 1244.30), however,
+ // uuid_generate_random() uses arc4random(3) which reportedly produces
+ // high-quality randomness (and uuid_generate() simply always calls it).
+ //
+ CFUUIDRef h (CFUUIDCreate (NULL));
+ CFUUIDBytes d (CFUUIDGetUUIDBytes (h));
+ CFRelease (h);
+
+ uint8_t a[16];
+ memcpy (a, &d, 16); // CFUUIDBytes is POD.
+
+ uuid r (a);
+ assert (r.variant () == uuid_variant::dce); // Sanity check.
+
+ // If this is a MAC/time-based UUID, then it's possible the time was not
+ // obtained in a collision-safe manner (looking at the implementation this
+ // seems to be the case; see the Linux implementation for background).
+ //
+ if (strong && r.version () != uuid_version::random)
+ uuid_throw_weak ();
+
+ return r;
+ }
+
+ void uuid_system_generator::
+ initialize ()
+ {
+ }
+
+ void uuid_system_generator::
+ terminate ()
+ {
+ }
+}
+
+#endif // BUILD2_BOOTSTRAP