Closed Bug 279521 Opened 20 years ago Closed 19 years ago

Add a way to generate UUIDs

Categories

(Core :: XPCOM, enhancement)

enhancement
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: Biesinger, Assigned: vlad)

References

Details

(Keywords: fixed1.8.1)

Attachments

(1 file, 7 obsolete files)

would be nice if xpcom provided a way to programmatically generate UUIDs.

I have a patch for this, most of it done by Marja.
Attached patch patch (obsolete) — Splinter Review
something like this...
Attachment #173692 - Flags: review?(dougt)
nsIUUID sounds to me like it is an uuid. But it isn't. maybe name it
nsIUUIDGenerator or nsIUUIDService?
Generator, please, not Service.  Generator tells you what it does, while Service
really does not.
We already have MD5 code in the tree, and it is exposed via
nsISignatureVerifier.  Did you consider using that?  It looks like you're
putting this in XPCOM, which means that using nsISignatureVerifier would be
somewhat of a problem, and maybe you want this to work even when PSM is not
present?  There may be subtle issues with adding crypto code outside of PSM. 
Can the implementation of this interface simply live in PSM?

The algo uses gethostname.  What if that returns "localhost" or "127.0.0.1"?  Do
we need to worry about that common case?  Doesn't NSS/PSM have access to a
better source of random data?  Could we leverage that at all?  The comment in
get_random_info seems to suggest that we can play with that code a bit since it
mentions a previous version including "struct sysinfo" in the input.
> https://bugzilla.mozilla.org/show_bug.cgi?id=279521
> 
> 
> darin@meer.net changed:
> 
>            What    |Removed                     |Added
> ----------------------------------------------------------------------------
>                  CC|                            |wtchang@redhat.com
> 
> 
> 
> 
> ------- Additional Comments From darin@meer.net  2005-02-09 09:21 PST
> -------
> We already have MD5 code in the tree, and it is exposed via
> nsISignatureVerifier.  Did you consider using that?  It looks like you're
> putting this in XPCOM, which means that using nsISignatureVerifier would be
> somewhat of a problem, and maybe you want this to work even when PSM is not
> present?  There may be subtle issues with adding crypto code outside of PSM.
> 
> Can the implementation of this interface simply live in PSM?

I'm quite new here and I don't know what PSM is or why it would be problematic 
to use nsISignatureVerifier. 

I simply want to have a way to generate urn uuids from javascript (ids for 
Annotea shared bookmarks and topics) and as the code already existed in 
Mozilla I was hoping to make it available through an interface also to others. 

It does not have to be its own XPCOM package, if it makes more sense to add it 
to another XPCOM package that's fine too. And the suggestion of changing the 
name to nsIUUIDGenerator if kept in its own package is good.

The code to Mozilla probably came from http://www.ietf.org/internet-
drafts/draft-mealling-uuid-urn-05.txt but I haven't checked if they are 
exactly same right now. I understood the draft was not far from being accepted 
so maybe it already is.

Marja
> 
> The algo uses gethostname.  What if that returns "localhost" or "127.0.0.1"? 
> Do
> we need to worry about that common case?  Doesn't NSS/PSM have access to a
> better source of random data?  Could we leverage that at all?  The comment
> in
> get_random_info seems to suggest that we can play with that code a bit since
> it
> mentions a previous version including "struct sysinfo" in the input.
> 
> 
> -- 
> Configure bugmail: https://bugzilla.mozilla.org/userprefs.cgi?tab=email
> 
darin: not everyone builds psm and this is one of those times when having
interfaces in a global location instead of a module would make some sense....
timeless: there won't be a global place for interfaces, but among the producing
and consuming modules, there ought to be a most-primitive consumer in which to
locate the interface.  Then producers (more derived in the build process) can
implement that interface (so can consumers as derived or moreso than the one
that hosts the interface).

Dependencies form a partial order, and humans can t-sort pretty well for small
set size.

/be
I would really like a uuid generator for a searchplugins-as-extensions patch I'm
working on (and I don't mind depending on PSM, if we want to put the impl
there): can we resolve whatever issues are remaining?
(In reply to comment #8)
> I would really like a uuid generator for a searchplugins-as-extensions patch I'm
> working on (and I don't mind depending on PSM, if we want to put the impl
> there): can we resolve whatever issues are remaining?

I thought this was already getting to the tree. I'm not sure how it will happen
processwise?

As I said earlier my goal is to be able to use this easily from javascript to
create "urn:uid:..." identifiers.

I'm not sure what PSM is or how using that would affect that goal. I really hope
it does not mean I need to do more compiling as I still have problems with the
Windows libraries in some cases (versions) and I could not get help to my
questions concerning that.

XPCOM would work well for me.

Marja
A couple of issues with the patch...

nsIUUID is a horrible interface name for a generator, same with
@mozilla.org/uuid for the contractid.  nsIUIIDGenerator &&
@mozilla.org/uuid-generator;1 would be preferable.

Do we really need a new subdirectory in xpcom for this?  It seems like all we
need is nsIUUIDGenerator.idl and nsUUIDGenerator.h/cpp somewhere, even if the
.cpp is somewhat large.

What license is the code taken from mod_dav under?  Is it compatible with (and
can be used under) MPL/GPL/LGPL?
Attached patch random uuid generator (obsolete) — Splinter Review
Here's my take on this.. just generates random-based UUIDs.  It would be
possible to create platform-specific implementations that return stronger IIDs,
and change what UUID generator is returned by the uuid-generator contract ID on
a per-platform basis, but this should be good enough to be usable.
Attachment #188643 - Flags: review?(shaver)
Comment on attachment 188643 [details] [diff] [review]
random uuid generator

r=shaver, let's double up with darin.
Attachment #188643 - Flags: superreview?(darin)
Attachment #188643 - Flags: review?(shaver)
Attachment #188643 - Flags: review+
Comment on attachment 188643 [details] [diff] [review]
random uuid generator

>Index: xpcom/base/nsRandomUUIDGenerator.cpp

>+    PR_GetRandomNoise(id, sizeof(nsIID));

According to the documentation for PR_GetRandomNoise, size does
matter.  You need to check that the returned PRSize value is
equal to sizeof(nsIID).  If it is less, which can happen, then
all of |id| would not be initialized to a random value.  If this
is not a problem somehow, then a comment in the code is at least
warranted.


>Index: xpcom/build/nsXPCOMCID.h

>+/**
>+ * UUID generator
>+ */
>+#define NS_UUID_GENERATOR_CID \
>+{ 0x706d36bb, 0xbf79, 0x4293, \
>+{ 0x81, 0xf2, 0x8f, 0x68, 0x28, 0xc1, 0x8f, 0x9d } }
>+#define NS_UUID_GENERATOR_CONTRACTID "@mozilla.org/uuid-generator;1"

We are not consistent about exposing CIDs and ContractIDs,
but I think that it would be better to only expose ContractIDs
here.  Or, is there some reason why someone would want to get
at exactly this implementation of the contract?  IOW, just put
the CID definition in your nsUUIDGenerator.h file.
Attachment #188643 - Flags: superreview?(darin) → superreview-
(In reply to comment #13)
> (From update of attachment 188643 [details] [diff] [review] [edit])
> >Index: xpcom/base/nsRandomUUIDGenerator.cpp
> 
> >+    PR_GetRandomNoise(id, sizeof(nsIID));
> 
> According to the documentation for PR_GetRandomNoise, size does
> matter.  You need to check that the returned PRSize value is
> equal to sizeof(nsIID).  If it is less, which can happen, then
> all of |id| would not be initialized to a random value.  If this
> is not a problem somehow, then a comment in the code is at least
> warranted.

Youch, I didn't read the return value comment there.  Ok, will fix. 
PR_GetRandomNoise isn't all /that/ random, but it should still be good enough
for an initial implementation.  I don't think that we have any good sources of
entropy that we can get at from xpcom.
Attached patch random uuid generator (obsolete) — Splinter Review
Ok, we correctly use the return value from GetRandomNoise now and abort if we
can't get any noise.  Moved the CID to nsRandomUUIDGenerator.h as well.
Attachment #188643 - Attachment is obsolete: true
Attachment #188716 - Flags: superreview?(darin)
Attachment #188716 - Flags: review?(shaver)
Comment on attachment 188716 [details] [diff] [review]
random uuid generator

Don't use PR_GetRandomNoise.  It has two problems.
1. It's simply not the right function.	Its purpose
is to get true randomness, which you would feed into
a pseudorandom number generator (PRNG).  A PRNG is what
you should be using.  2. It is not well implemented.

A good PRNG is the PK11_GenerateRandom function in
the NSS library.  I remember that Mozilla does not
have direct access to the NSS library and must go
through mozilla/security/manager.  If so, you will
need to implement a new method in mozilla/security/manager
that exposes the functionality of PK11_GenerateRandom
to Mozilla.  I found an unimplemented method
nsCrypto::Random, which might be appropriate.

http://lxr.mozilla.org/mozilla/source/security/manager/ssl/src/nsCrypto.cpp#204
3
Attachment #188716 - Flags: superreview?(darin)
Attachment #188716 - Flags: review?(shaver)
Attachment #188716 - Flags: review-
(In reply to comment #16)
> (From update of attachment 188716 [details] [diff] [review] [edit])
> Don't use PR_GetRandomNoise.  It has two problems.
> 1. It's simply not the right function.	Its purpose
> is to get true randomness, which you would feed into
> a pseudorandom number generator (PRNG).  A PRNG is what
> you should be using.  2. It is not well implemented.

I understand that the purpose is to get true randomness; right now it only does
that on platforms that have /dev/random (linux and the bsds).  I can certainly
use it as input for the libc PRNG via initstate/random, but that's not available
on win32.  It can fall back to rand/srand on windows (or whatever platform SDK
functions are there for for randomness), I guess.  I didn't see any PRNG
implementation in NSPR -- did I miss one? 

> A good PRNG is the PK11_GenerateRandom function in
> the NSS library.  I remember that Mozilla does not
> have direct access to the NSS library and must go
> through mozilla/security/manager.  If so, you will
> need to implement a new method in mozilla/security/manager
> that exposes the functionality of PK11_GenerateRandom
> to Mozilla.  I found an unimplemented method
> nsCrypto::Random, which might be appropriate.

That's all well and good, except that xpcom can't depend on NSS/secman.
On windows why don't we just use the platform uuid generator?
if we need to be using NSS to generate better UUID, then this implementation
should live in PSM.

Does anyone need to use this impl. when PSM isn't there?
(In reply to comment #19)
> if we need to be using NSS to generate better UUID, then this implementation
> should live in PSM.
> 
> Does anyone need to use this impl. when PSM isn't there?

In some theoretical world where people want to use individual components of our
platform, I can see someone wanting to generate UUIDs without PSM.  In reality,
noone is going to be using xpcom without most of the rest of our platform. 
Also, if I'm looking for something that will generate UUIDs, PSM wouldn't be
near the top of the list of places I'd look, but maybe that's just me.  A lot of
the current codebase is structured around that theoretical world, though.

I've got a patch coming shortly (as soon as I find a win32 box to test on) that
uses random() & friends on unix, and just uses UuidCreate on windows.
that patch sounds like it will solve the current problem.

also, I think you will want to use CoCreateGuid() on windows.
rand and srand are not suitable for situations where
you need the pseudorandom numbers to be unpredictable.
In those situations you need to use a cryptographic
PRNG such as PK11_GenerateRandom.

For generating UUIDs you may not need that property.
I think the property you need is "collision free".
A secure hash algorithm such as MD5 or SHA-1 can
give you that property.
Mozilla stores my user profile in a directory named
C:\Documents and Settings\wtc\Application Data\Mozilla\Profiles\wtc\h5x3whmf.slt.

I guess the code that generates the "h5x3whmf" string
would meet your need?
> That's all well and good, except that xpcom can't depend on NSS/secman.

It can using an XPCOM interface defined in mozilla/xpcom/ somewhere.  In fact,
why not just implement nsIUUIDGenerator in PSM?  Define the interface in
mozilla/xpcom/ as you have, but implement it in PSM.  We do this sort of thing
elsewhere.
> I guess the code that generates the "h5x3whmf" string
> would meet your need?

That code uses srand and rand.  It uses the time of day as the seed.
Attached patch random uuid generator, take 3 (obsolete) — Splinter Review
Let's try this again.

On the three platforms we care about:

Linux/BSDs: PR_GetRandomNoise uses /dev/random to get randomness; we feed that
into initstate()/random() (I can't believe there's a libc function called
"initstate")

MacOS X: same as Linux/BSDs

Windows: We use CoCreateGuid (which just calls UuidCreate, but eh!) and it
creates something that's presumably globally unique.
Attachment #188716 - Attachment is obsolete: true
Attachment #188729 - Flags: superreview?(darin)
Blah, posted the patch before I saw Darin's comment about just implementing the
component in PSM.  Yes, I guess I can do that, if that's preferable.
(In reply to comment #20)
> In some theoretical world where people want to use individual components of our
> platform, I can see someone wanting to generate UUIDs without PSM.

some people do use standalone xpcom, I think... they might want this...
Who uses standalone XPCOM that we care about?

But I'd rather use the platform's services here rather than having to initialize
PSM in order to get a GUID.  (I can see wanting to use this facility early in
startup to generate UUIDs for ephemeral extensions or whatnot.)
(In reply to comment #14)
>I don't think that we have any good sources of entropy that we can get at from
xpcom.
Our entropy collector lives in, yes you guessed it, our old friend PSM.
Comment on attachment 188729 [details] [diff] [review]
random uuid generator, take 3

I don't think you need an explict init method on this interface. |generateUUID|
could just call init internally if the state is not initalized.
Comment on attachment 188729 [details] [diff] [review]
random uuid generator, take 3

according to msdn, UuidCreate isn't support everywhere you think:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/rpc/uuidcr
eate.asp

I think you should use CoCreateGuid:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/html/8d5ce
dea-8c2b-4918-99db-1a000989f178.asp
Comment on attachment 188729 [details] [diff] [review]
random uuid generator, take 3

Blah, this is the wrong version of the patch.. I was confused why dougt was
bringing up CoCreateGuid again when I did use CoCreateGuid, except apparently
not in this diff. =/

New patch coming soon without the Init.

(FTR, doug, CoCreateGuid is defined to just call UuidCreate, the MSDN links you
gave explicitly say so! :)
Attachment #188729 - Flags: superreview?(darin)
Attached patch uuid generator, take 4 (obsolete) — Splinter Review
Ok, no more Init method, and use CoCreateGuid on win32.  (nsID and GUID are
supposed to be compatible structures, right?)
Attachment #188729 - Attachment is obsolete: true
Attachment #188746 - Flags: superreview?(darin)
Attached patch uuid generator, take 5 (obsolete) — Splinter Review
Patches late at night are bad, and lead to uninitialized variables.
Attachment #188746 - Attachment is obsolete: true
Attachment #188752 - Flags: superreview?(darin)
Attachment #188752 - Flags: review?(shaver)
why not use NS_GENERIC_FACTORY_CONSTRUCTOR_INIT? That avoids having to check
mInitialized each time.
Assignee: cbiesinger → vladimir
also: should this use a threadsafe isupports impl (the class seems to be
threadsafe, at least with that init change I suggested)? and, is it supposed to
be used as a service or a normal component?
Comment on attachment 188752 [details] [diff] [review]
uuid generator, take 5

r=shaver with biesi's two comments (NS_GENERIC_FACTORY_CONSTRUCTOR_INIT and
threadsafe nsISupports impl) addressed.
Attachment #188752 - Flags: review?(shaver) → review+
So, if I create two of these generators, and init them both and then ask each to
generate a GUID for me, will random() do the right thing?  Yeah, I think so. 
Now, what if the same thing is done on two threads?  Maybe we don't care.
the question is: Is this supposed to be used as a service or as a component?
Using it as a service seems like a good idea, since it avoids that problem. 
Perhaps it wants to be renamed to indicate that it is intended to be a service?
nsIUUIDGeneratorService?
not that i care one way or the other... but...

we don't have to have a rule requiring interface names suffixed with Service to
ensure that users will use GetService to aquire them.  The IDL should state that
this is a servcie and, maybe, the implementation's factory should protect to
ensure that it remains a singleton.

but I do not dislike the name you proposed.

I'm fine with the current interface name, and the interface name doesn't need to
indicate how the component that implements that interface should be
instantiated.  That is best documented alongside the ContractID for the component.

As I said before, maybe there is no concern here.  I don't know if the OS
implementation of initstate/random is re-entrant, but probably it is.
Comment on attachment 188752 [details] [diff] [review]
uuid generator, take 5

>Index: xpcom/base/nsIUUIDGenerator.idl

>+
>+[scriptable, uuid(138ad1b2-c694-41cc-b201-333ce936d8b8)]
>+interface nsIUUIDGenerator : nsISupports

please add a comment above the interface describing
what this interface is for, etc.


>+{
>+  /**
>+   * Obtains a new GUID using appropriate platform-specific methods to
>+   * obtain an IID that can be considered to be globally unique.
>+   *
>+   * @returns an nsIID filled in with a new GUID.
>+   *
>+   * @throws NS_ERROR_FAILURE if a UUID cannot be generated (e.g. if
>+   * an underlying source of randomness is not available)
>+   */
>+  nsIIDPtr generateUUID();
>+};

I recomment being consist with terminology.  Replace GUID with UUID.

I think the return type should be nsIDPtr instead of nsIIDPtr because
this is not solely for use with generating interface IDs.  you could
use it to generate UUIDs for any purpose, so keep the type name generic.

Do we want a version of this function that is [noscript] that allows
the caller to pass in an allocated nsID struct?  That way the caller
can allocate the nsID struct on the stack instead of being forced to
heap allocate the object?


>Index: xpcom/base/nsRandomUUIDGenerator.cpp

>+#if !defined(WIN32)
>+#include <stdlib.h>
>+#else
>+#include <windows.h>
>+#endif

Prefer XP_WIN to WIN32 in preprocessor fu.  Also, I think it's
slightly cleaner to write:

  #if defined(XP_WIN)
  #include <windows.h>
  #else
  #include <stdlib.h>
  #endif


>+nsresult
>+nsRandomUUIDGenerator::Init()
>+{
>+#if !defined(WIN32)

Again, I would put the XP_WIN case first.  No reason for the "!"


>+    unsigned int seed;
>+
>+    PRSize bytes = 0;
>+    while (bytes < sizeof(seed)) {
>+        PRSize nbytes = PR_GetRandomNoise(((unsigned char *)&seed)+bytes, sizeof(seed)-bytes);
>+        if (nbytes == 0) {
>+            return NS_ERROR_FAILURE;
>+        }
>+        bytes += nbytes;
>+    }
>+
>+    initstate(seed, mState, sizeof(mState));
>+
>+    mRBytes = 4;

What happens on 64-bit platforms where sizeof(long) is 8?
Is RAND_MAX always at most 0xffffffff on these platforms?


>+    NS_ASSERTION(sizeof(GUID) == sizeof(nsIID), "GUID and nsIID aren't the same size!");

This assertion is pretty gratuitous, but ok ;-)


>+    nsIID *id = new nsIID;

s/nsIID/nsID/


>Index: xpcom/build/nsXPCOMCID.h

>+/**
>+ * UUID generator
>+ */
>+#define NS_UUID_GENERATOR_CONTRACTID "@mozilla.org/uuid-generator;1"

Historically, this header file has only been used to record frozen
contract IDs.  Is this a frozen contract ID?  If so, then please be
sure to include documentation about what interfaces this class
implements.  I'm not sure we want to freeze this guy.
Attachment #188752 - Flags: superreview?(darin) → superreview-
Sounds good; I'll get a new patch up incorporating the comments over the weekend.

As for RAND_MAX, I think it's 0x7fffffff everywhere -- but I'm i'm not positive;
worst case the nrbytes bit just means we'll end up using only 4 of the generated
bytes instead of 7-8.
Comment on attachment 173692 [details] [diff] [review]
patch

removing old request flag.
Attachment #173692 - Flags: review?(dougt) → review-
Resurrecting this, as a bunch of people have asked me about the functionality recently.

(In reply to comment #46)
> Do we want a version of this function that is [noscript] that allows
> the caller to pass in an allocated nsID struct?  That way the caller
> can allocate the nsID struct on the stack instead of being forced to
> heap allocate the object?

Do we?  I can go either way; what would be a name for the noscript function?  generateUUIDShared?
Attached patch uuid-generator-6.patch (obsolete) — Splinter Review
Updated.
Attachment #173692 - Attachment is obsolete: true
Attachment #188752 - Attachment is obsolete: true
Attachment #203585 - Flags: review?(darin)
Comment on attachment 203585 [details] [diff] [review]
uuid-generator-6.patch

>--- xpcom/base/nsRandomUUIDGenerator.cpp	

>+NS_IMETHODIMP
>+nsRandomUUIDGenerator::GenerateUUID(nsID** ret)
>+{
>+    nsID *id = new nsID;

perhaps you should use NS_Alloc instead of 'new' to ensure that the
correct heap allocator is used across XPCOM boundaries.


>+        delete id;

NS_Free


>--- xpcom/build/nsXPComInit.cpp	b7a64c3a770fcce7b569b92179b2dda36aa4def3

>+#define NS_UUID_GENERATOR_CONTRACTID "@mozilla.org/uuid-generator;1"
>+#define NS_UUID_GENERATOR_CLASSNAME "UUID Generator"
>+#define NS_UUID_GENERATOR_CID NS_RANDOM_UUID_GENERATOR_CID

I think these should be moved to nsUUIDGenerator.h.  Not sure why
there is a NS_UUID_GENERATOR_CID and a NS_RANDOM_UUID_GENERATOR_CID.
Seems like you only need one of those defines.
Attachment #203585 - Flags: review?(darin) → review-
Updated with review comments.  I went and changed the nsRandomUUIDGenerator implementation class name to nsUUIDGenerator as well -- at one point I thought it might be useful to support multiple UUID generators, e.g. one that always generates a random-type UUID and another that generates a host-based UUID or something, but I realize now that that isn't all that useful.
Attachment #203585 - Attachment is obsolete: true
Attachment #203824 - Flags: superreview?(shaver)
Attachment #203824 - Flags: review?(darin)
Attachment #203824 - Flags: review?(darin) → review+
Comment on attachment 203824 [details] [diff] [review]
uuid-generator-7.patch

sr=shaver, I should say.
Attachment #203824 - Flags: superreview?(shaver) → superreview+
Checked in
Status: NEW → RESOLVED
Closed: 19 years ago
Resolution: --- → FIXED
By the way, shouldn't this hit the 1.8 branch at some point? Any plans?
I'd really like to use this for bug 326506.  Could we get this in on the branch?
Blocks: 326506
So surely we're going to want this for Firefox 2, which means that this should hit the 1.8 branch soon? I'll gladly spin the 1.8 patch if that's all that's holding us up here. Or maybe there's some other reason why no progress has been made on getting this into the 1.8 branch?
Blocks: 330712
Comment on attachment 203824 [details] [diff] [review]
uuid-generator-7.patch

would like to land this on the branch for use by the metrics service.  I tested that the code compiles cleanly with no changes.
Attachment #203824 - Flags: approval-branch-1.8.1?(darin)
Comment on attachment 203824 [details] [diff] [review]
uuid-generator-7.patch

a=darin
Attachment #203824 - Flags: approval-branch-1.8.1?(darin) → approval-branch-1.8.1+
checked in on the branch
Keywords: fixed1.8.1
Depends on: 334983
Depends on: 335549
Depends on: 320646
Depends on: 327161
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: