Last active
July 30, 2024 00:22
-
-
Save 61131/77c5a4af7cbb037ab4b81954fc17cfa0 to your computer and use it in GitHub Desktop.
Universally unique identifiers (UUIDv4) generation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <fcntl.h> | |
#include <time.h> | |
#include <sys/stat.h> | |
#include <sys/time.h> | |
#include "uuid.h" | |
struct uuid { | |
uint32_t time_low; | |
uint16_t time_mid; | |
uint16_t time_hi_and_version; | |
uint16_t clock_seq; | |
uint8_t node[6]; | |
}; | |
static void _random_get_bytes(void *buf, size_t n); | |
static int _random_get_fd(void); | |
static void _uuid_pack(const struct uuid *uu, uuid_t out); | |
static void uuid_unpack(const uuid_t in, struct uuid *uu); | |
static void | |
_random_get_bytes(void *buf, size_t n) { | |
unsigned char *cp; | |
size_t c; | |
ssize_t rv; | |
int fail, fd, i; | |
cp = (unsigned char *)buf; | |
c = n; | |
fd = _random_get_fd(); | |
if (fd >= 0) { | |
fail = 0; | |
while (c > 0) { | |
rv = read(fd, cp, c); | |
if (rv <= 0) { | |
if (fail++ > 16) { | |
break; | |
} | |
continue; | |
} | |
c -= rv; | |
cp += rv; | |
fail = 0; | |
} | |
close(fd); | |
} | |
for (cp = buf, i = 0; i < n; i++) { | |
*cp++ ^= (rand() >> 7) & 0xff; | |
} | |
} | |
static int | |
_random_get_fd(void) { | |
struct timeval tv; | |
int fd, i; | |
gettimeofday(&tv, 0); | |
fd = open("/dev/urandom", O_RDONLY); | |
if (fd < 0) { | |
fd = open("/dev/random", O_RDONLY|O_NONBLOCK); | |
} | |
if (fd >= 0) { | |
i = fcntl(fd, F_GETFD); | |
if (i >= 0) { | |
fcntl(fd, F_SETFD, i | FD_CLOEXEC); | |
} | |
} | |
srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); | |
gettimeofday(&tv, 0); | |
for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1f; i > 0; i--) { | |
rand(); | |
} | |
return fd; | |
} | |
static void | |
_uuid_pack(const struct uuid *uu, uuid_t out) { | |
uint32_t tmp; | |
unsigned char *ptr = out; | |
tmp = uu->time_low; | |
ptr[3] = (unsigned char) tmp; | |
tmp >>= 8; | |
ptr[2] = (unsigned char) tmp; | |
tmp >>= 8; | |
ptr[1] = (unsigned char) tmp; | |
tmp >>= 8; | |
ptr[0] = (unsigned char) tmp; | |
tmp = uu->time_mid; | |
ptr[5] = (unsigned char) tmp; | |
tmp >>= 8; | |
ptr[4] = (unsigned char) tmp; | |
tmp = uu->time_hi_and_version; | |
ptr[7] = (unsigned char) tmp; | |
tmp >>= 8; | |
ptr[6] = (unsigned char) tmp; | |
tmp = uu->clock_seq; | |
ptr[9] = (unsigned char) tmp; | |
tmp >>= 8; | |
ptr[8] = (unsigned char) tmp; | |
memcpy(ptr + 10, uu->node, 6); | |
} | |
static void | |
_uuid_unpack(const uuid_t in, struct uuid *uu) | |
{ | |
const uint8_t *ptr = in; | |
uint32_t tmp; | |
tmp = *ptr++; | |
tmp = (tmp << 8) | *ptr++; | |
tmp = (tmp << 8) | *ptr++; | |
tmp = (tmp << 8) | *ptr++; | |
uu->time_low = tmp; | |
tmp = *ptr++; | |
tmp = (tmp << 8) | *ptr++; | |
uu->time_mid = tmp; | |
tmp = *ptr++; | |
tmp = (tmp << 8) | *ptr++; | |
uu->time_hi_and_version = tmp; | |
tmp = *ptr++; | |
tmp = (tmp << 8) | *ptr++; | |
uu->clock_seq = tmp; | |
memcpy(uu->node, ptr, 6); | |
} | |
void | |
uuid_format(uuid_t uu, char *buf) { | |
struct uuid uuid; | |
_uuid_unpack(uu, &uuid); | |
sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", | |
uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, | |
uuid.clock_seq >> 8, uuid.clock_seq & 0xff, | |
uuid.node[0], uuid.node[1], uuid.node[2], | |
uuid.node[3], uuid.node[4], uuid.node[5]); | |
} | |
void | |
uuid_generate_random(uuid_t out) { | |
uuid_t buf; | |
struct uuid uu; | |
_random_get_bytes(buf, sizeof(buf)); | |
_uuid_unpack(buf, &uu); | |
uu.clock_seq = (uu.clock_seq & 0x3fff) | 0x8000; | |
uu.time_hi_and_version = (uu.time_hi_and_version & 0x0fff) | 0x4000; | |
_uuid_pack(&uu, out); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _UUID_H_ | |
#define _UUID_H_ | |
typedef unsigned char uuid_t[16]; | |
void uuid_format(uuid_t uu, char *buf); | |
void uuid_generate_random(uuid_t out); | |
#endif /* _UUID_H_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment