mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-18 10:46:23 +00:00
Add uuid_t and UUID primitive functions
This commit is contained in:
parent
b44046d612
commit
50bbb722d0
@ -10,6 +10,7 @@ HDRS= fifo.h \
|
||||
rotbuf.h \
|
||||
mem.h \
|
||||
os.h \
|
||||
uuid.h \
|
||||
strbuf.h \
|
||||
strbuf_helpers.h \
|
||||
sha2.h \
|
||||
|
@ -69,6 +69,7 @@ SERVAL_SOURCES = \
|
||||
$(SERVAL_BASE)strbuf.c \
|
||||
$(SERVAL_BASE)strbuf_helpers.c \
|
||||
$(SERVAL_BASE)strlcpy.c \
|
||||
$(SERVAL_BASE)uuid.c \
|
||||
$(SERVAL_BASE)vomp.c \
|
||||
$(SERVAL_BASE)vomp_console.c \
|
||||
$(SERVAL_BASE)xprintf.c \
|
||||
|
107
uuid.c
Normal file
107
uuid.c
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
Serval DNA Universally Unique Identifier support
|
||||
Copyright (C) 2013 Serval Project Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#define __SERVALDNA_UUID_H_INLINE
|
||||
#include "uuid.h"
|
||||
#include "os.h"
|
||||
#include "str.h"
|
||||
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
enum uuid_version uuid_get_version(const uuid_t *uuid)
|
||||
{
|
||||
assert(uuid_is_valid(uuid));
|
||||
switch (ntohs(uuid->u.record.time_hi_and_version) & 0xf000) {
|
||||
case 0x1000: return UUID_VERSION_TIME_BASED;
|
||||
case 0x2000: return UUID_VERSION_DCE_SECURITY;
|
||||
case 0x3000: return UUID_VERSION_NAME_MD5;
|
||||
case 0x4000: return UUID_VERSION_RANDOM;
|
||||
case 0x5000: return UUID_VERSION_NAME_SHA1;
|
||||
}
|
||||
return UUID_VERSION_UNSUPPORTED;
|
||||
}
|
||||
|
||||
void uuid_set_version(uuid_t *uuid, enum uuid_version version)
|
||||
{
|
||||
uint16_t version_bits;
|
||||
switch (version) {
|
||||
case UUID_VERSION_TIME_BASED: version_bits = 0x1000; break;
|
||||
case UUID_VERSION_DCE_SECURITY: version_bits = 0x2000; break;
|
||||
case UUID_VERSION_NAME_MD5: version_bits = 0x3000; break;
|
||||
case UUID_VERSION_RANDOM: version_bits = 0x4000; break;
|
||||
case UUID_VERSION_NAME_SHA1: version_bits = 0x5000; break;
|
||||
default: abort();
|
||||
}
|
||||
assert(uuid_is_valid(uuid));
|
||||
uuid->u.record.time_hi_and_version = htons((ntohs(uuid->u.record.time_hi_and_version) & 0xfff) | version_bits);
|
||||
}
|
||||
|
||||
int uuid_generate_random(uuid_t *uuid)
|
||||
{
|
||||
if (urandombytes(uuid->u.binary, sizeof uuid->u.binary) == -1)
|
||||
return -1;
|
||||
// The following discards 6 random bits.
|
||||
uuid->u.record.clock_seq_hi_and_reserved &= 0x3f;
|
||||
uuid->u.record.clock_seq_hi_and_reserved |= 0x80;
|
||||
uuid_set_version(uuid, UUID_VERSION_RANDOM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uuid_to_str(const uuid_t *uuid, char *dst)
|
||||
{
|
||||
assert(uuid_is_valid(uuid));
|
||||
unsigned i;
|
||||
for (i = 0; i != sizeof uuid->u.binary; ++i) {
|
||||
switch (i) {
|
||||
case 4: case 6: case 8: case 10:
|
||||
*dst++ = '-';
|
||||
default:
|
||||
*dst++ = hexdigit[uuid->u.binary[i] >> 4];
|
||||
*dst++ = hexdigit[uuid->u.binary[i] & 0xf];
|
||||
}
|
||||
}
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
int str_to_uuid(const char *str, uuid_t *uuid, const char **afterp)
|
||||
{
|
||||
const char *end = str;
|
||||
int ret = 0;
|
||||
if ( strn_fromhex(uuid->u.binary, 4, end, &end) == 4
|
||||
&& *end == '-'
|
||||
&& strn_fromhex(uuid->u.binary + 4, 2, end + 1, &end) == 2
|
||||
&& *end == '-'
|
||||
&& strn_fromhex(uuid->u.binary + 6, 2, end + 1, &end) == 2
|
||||
&& *end == '-'
|
||||
&& strn_fromhex(uuid->u.binary + 8, 2, end + 1, &end) == 2
|
||||
&& *end == '-'
|
||||
&& strn_fromhex(uuid->u.binary + 10, 6, end + 1, &end) == 6
|
||||
) {
|
||||
assert(end == str + 36);
|
||||
ret = uuid_is_valid(uuid);
|
||||
}
|
||||
if (afterp)
|
||||
*afterp = end;
|
||||
if (ret == 0 || (!afterp && *end))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
113
uuid.h
Normal file
113
uuid.h
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
Serval DNA Universally Unique Identifier support
|
||||
Copyright (C) 2013 Serval Project Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __SERVALDNA_UUID_H
|
||||
#define __SERVALDNA_UUID_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef __SERVALDNA_UUID_H_INLINE
|
||||
# if __GNUC__ && !__GNUC_STDC_INLINE__
|
||||
# define __SERVALDNA_UUID_H_INLINE extern inline
|
||||
# else
|
||||
# define __SERVALDNA_UUID_H_INLINE inline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* A UUID is defined by RFC-4122 as a 128-bit identifier with the two most
|
||||
* significant bits of the ninth byte being 1 and 0, which indicates the
|
||||
* "variant" that is described by the RFC. Other variants exist, but are not
|
||||
* supported here, and are treated as INVALID by the functions defined below.
|
||||
* Any attempt to pass an invalid UUID to a function that requires a valid UUID
|
||||
* as input will probably result in the calling process being aborted (see
|
||||
* SIGABRT, abort(3)).
|
||||
*
|
||||
* In a valid UUID, the four lowest significant bits of the seventh byte define
|
||||
* the "version" of the UUID, which essentially indicates how it was generated.
|
||||
* The RFC defines five SUPPORTED versions. Any other version is UNSUPPORTED.
|
||||
*
|
||||
* The fields in the UUID 'record' structure are stored in network byte order,
|
||||
* so code wishing to make use of the record structure must use ntohl(3) and
|
||||
* ntohs(3) to read values, and htonl(3) and htons(3) to assign values.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
typedef struct uuid {
|
||||
union {
|
||||
struct {
|
||||
uint32_t time_low;
|
||||
uint16_t time_mid;
|
||||
uint16_t time_hi_and_version;
|
||||
uint8_t clock_seq_hi_and_reserved;
|
||||
uint8_t clock_seq_low;
|
||||
unsigned char node[6]; // uint48_t
|
||||
} record;
|
||||
unsigned char binary[16];
|
||||
} u;
|
||||
} uuid_t;
|
||||
|
||||
enum uuid_version {
|
||||
UUID_VERSION_UNSUPPORTED = 0,
|
||||
UUID_VERSION_TIME_BASED = 1,
|
||||
UUID_VERSION_DCE_SECURITY = 2,
|
||||
UUID_VERSION_NAME_MD5 = 3,
|
||||
UUID_VERSION_RANDOM = 4,
|
||||
UUID_VERSION_NAME_SHA1 = 5
|
||||
};
|
||||
|
||||
__SERVALDNA_UUID_H_INLINE int uuid_is_valid(const uuid_t *any_uuid) {
|
||||
return (any_uuid->u.record.clock_seq_hi_and_reserved & 0xc0) == 0x80;
|
||||
}
|
||||
|
||||
enum uuid_version uuid_get_version(const uuid_t *valid_uuid);
|
||||
void uuid_set_version(uuid_t *valid_uuid, enum uuid_version);
|
||||
|
||||
/* Returns -1 if error (eg, cannot open /dev/urandom), 0 if successful.
|
||||
*/
|
||||
int uuid_generate_random(uuid_t *dest_uuid);
|
||||
|
||||
/* Formats the given valid UUID in its canonical string representation:
|
||||
* XXXXXXXX-VXXX-MXXX-XXXXXXXXXXXX
|
||||
* where X is any hex digit
|
||||
* V is 1, 2, 3, 4 or 5 (supported versions) or any other hex digit
|
||||
* (unsupported versions)
|
||||
* M is 8, 9, A or B (high two bits are variant 01)
|
||||
*
|
||||
* The 'dst' argument must point to a buffer of 37 bytes. The first 36 bytes
|
||||
* are filled with the representation shown above, and the 37th byte dst[36] is
|
||||
* set to NUL '\0'.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
void uuid_to_str(const uuid_t *valid_uuid, char *dst);
|
||||
|
||||
/* Parse a canonical UUID string (as generated by uuid_to_str()) into a valid
|
||||
* UUID, which may or not be supported.
|
||||
*
|
||||
* Returns 1 if a valid UUID is parsed, storing the value in *result (unless result is NULL) and
|
||||
* storing a pointer to the immediately succeeding character in *afterp. If afterp is NULL then
|
||||
* returns 0 unless the immediately succeeding character is a NUL '\0'. If no UUID is parsed or
|
||||
* if the UUID is not valid, then returns 0, leaving *result unchanged and
|
||||
* setting setting *afterp to point to the character where parsing failed.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int str_to_uuid(const char *str, uuid_t *result, const char **afterp);
|
||||
|
||||
#endif //__SERVALDNA_OS_H
|
Loading…
Reference in New Issue
Block a user