Skip to content

Instantly share code, notes, and snippets.

@61131
Last active July 30, 2024 00:22
Show Gist options
  • Save 61131/77c5a4af7cbb037ab4b81954fc17cfa0 to your computer and use it in GitHub Desktop.
Save 61131/77c5a4af7cbb037ab4b81954fc17cfa0 to your computer and use it in GitHub Desktop.
Universally unique identifiers (UUIDv4) generation
#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);
}
#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