--- uuid.c 2004/01/09 21:01:04 1.8
+++ uuid.c 2004/01/09 21:59:57 1.9
@@ -33,6 +33,10 @@
#include <string.h>
#include <unistd.h>
#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
#include "config.h"
#include "uuid.h"
@@ -398,17 +402,137 @@
return UUID_RC_OK;
}
+/* pseudo-random number generator (PRNG) */
+static void uuid_prng_getdata(uuid_uint8_t *data_ptr, size_t data_len)
+{
+ static int initialized = FALSE;
+ static int fd = -1;
+ struct timeval tv;
+ pid_t pid;
+ size_t n;
+ size_t i;
+ uuid_uint8_t *p;
+ int cnt;
+
+ if (!initialized) {
+ /* try to open the system PRNG device */
+ if ((fd = open("/dev/urandom", O_RDONLY)) == -1)
+ fd = open("/dev/random", O_RDONLY|O_NONBLOCK);
+ if (fd != -1)
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ /* seed the PRNG once */
+ gettimeofday(&tv, NULL);
+ pid = getpid();
+ srand((unsigned int)(
+ ((uuid_uint32_t)pid << 16)
+ ^ (uuid_uint32_t)pid
+ ^ (uuid_uint32_t)tv.tv_sec
+ ^ (uuid_uint32_t)tv.tv_usec));
+
+ /* crank the PRNG a few times */
+ gettimeofday(&tv, NULL);
+ for (i = (unsigned int)(tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
+ (void)rand();
+
+ initialized = TRUE;
+ }
+
+ /* try to gather data from the system PRNG device */
+ if (fd != -1) {
+ p = data_ptr;
+ n = data_len;
+ cnt = 0;
+ while (n > 0) {
+ i = read(fd, (void *)p, n);
+ if (i <= 0) {
+ if (cnt++ > 16)
+ break;
+ continue;
+ }
+ n -= i;
+ p += i;
+ cnt = 0;
+ }
+ }
+
+ /* always also apply the weaker PRNG. In case the stronger PRNG device
+ based source failed, this is the only remaining randomness, of course */
+ for (p = data_ptr, n = 0; n < data_len; n++)
+ *p++ ^= (uuid_uint8_t)(((uuid_uint32_t)rand() >> 7) & 0xFF);
+
+ return;
+}
+
+/* brand UUID with version and variant */
+static void uuid_brand(uuid_t *uuid, int version)
+{
+ /* set version (as given) */
+ uuid->time_hi_and_version &= 0x0fff;
+ uuid->time_hi_and_version |= (((uuid_uint16_t)version & 0x0fff) << 12);
+
+ /* set variant (always DCE 1.1 only) */
+ uuid->clock_seq_hi_and_reserved &= ~((0x03) << 6);
+ uuid->clock_seq_hi_and_reserved |= (0x02 << 6);
+ return;
+}
+
+/* generate UUID version 1: time, clock and node based */
+static uuid_rc_t uuid_generate_v1(uuid_t *uuid, unsigned int mode, va_list ap)
+{
+ /* brand with version and variant */
+ uuid_brand(uuid, 1);
+
+ /* FIXME */
+
+ return UUID_RC_OK;
+}
+
+/* generate UUID version 3: name based */
+static uuid_rc_t uuid_generate_v3(uuid_t *uuid, unsigned int mode, va_list ap)
+{
+ /* brand with version and variant */
+ uuid_brand(uuid, 3);
+
+ /* FIXME */
+
+ return UUID_RC_OK;
+}
+
+/* generate UUID version 4: random number based */
+static uuid_rc_t uuid_generate_v4(uuid_t *uuid, unsigned int mode, va_list ap)
+{
+ /* fill with random data */
+ uuid_prng_getdata((void *)uuid, sizeof(uuid_t));
+
+ /* brand with version and variant */
+ uuid_brand(uuid, 4);
+
+ return UUID_RC_OK;
+}
+
uuid_rc_t uuid_generate(uuid_t *uuid, unsigned int mode, ...)
{
va_list ap;
+ uuid_rc_t rc;
/* sanity check argument(s) */
if (uuid == NULL)
return UUID_RC_ARG;
+
+ /* dispatch into version dependent generation functions */
va_start(ap, mode);
- /* FIXME */
+ if (mode & UUID_VERSION1)
+ rc = uuid_generate_v1(uuid, mode, ap);
+ else if (mode & UUID_VERSION3)
+ rc = uuid_generate_v3(uuid, mode, ap);
+ else if (mode & UUID_VERSION4)
+ rc = uuid_generate_v4(uuid, mode, ap);
+ else
+ rc = UUID_RC_ARG;
va_end(ap);
- return UUID_RC_OK;
+
+ return rc;
}
uuid_rc_t uuid_dump(uuid_t *uuid, char **str)
|