mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-18 20:57:56 +00:00
124 lines
3.9 KiB
C
124 lines
3.9 KiB
C
/*
|
|
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.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "lang.h" // for FALLTHROUGH
|
|
#define __SERVAL_DNA__SERVAL_UUID_H_INLINE
|
|
#include "serval_uuid.h"
|
|
#include "os.h"
|
|
#include "str.h"
|
|
#include "sodium.h" // for randombytes_buf()
|
|
|
|
#include <assert.h>
|
|
#ifdef HAVE_ARPA_INET_H
|
|
# include <arpa/inet.h>
|
|
#endif
|
|
|
|
enum serval_uuid_version serval_uuid_get_version(const serval_uuid_t *uuid)
|
|
{
|
|
assert(serval_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 serval_uuid_set_version(serval_uuid_t *uuid, enum serval_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(serval_uuid_is_valid(uuid));
|
|
uuid->u.record.time_hi_and_version = htons((ntohs(uuid->u.record.time_hi_and_version) & 0xfff) | version_bits);
|
|
}
|
|
|
|
int serval_uuid_generate_random(serval_uuid_t *uuid)
|
|
{
|
|
randombytes_buf(uuid->u.binary, sizeof uuid->u.binary);
|
|
// The following discards 6 random bits.
|
|
uuid->u.record.clock_seq_hi_and_reserved &= 0x3f;
|
|
uuid->u.record.clock_seq_hi_and_reserved |= 0x80;
|
|
serval_uuid_set_version(uuid, UUID_VERSION_RANDOM);
|
|
return 0;
|
|
}
|
|
|
|
strbuf strbuf_uuid(strbuf sb, const serval_uuid_t *uuid)
|
|
{
|
|
assert(serval_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:
|
|
strbuf_putc(sb, '-');
|
|
strbuf_putc(sb, hexdigit_lower[uuid->u.binary[i] >> 4]);
|
|
strbuf_putc(sb, hexdigit_lower[uuid->u.binary[i] & 0xf]);
|
|
break;
|
|
default:
|
|
strbuf_putc(sb, hexdigit_lower[uuid->u.binary[i] >> 4]);
|
|
strbuf_putc(sb, hexdigit_lower[uuid->u.binary[i] & 0xf]);
|
|
}
|
|
}
|
|
return sb;
|
|
}
|
|
|
|
char *serval_uuid_to_str(const serval_uuid_t *uuid, char *const dst)
|
|
{
|
|
strbuf b = strbuf_local(dst, SERVAL_UUID_STRLEN + 1);
|
|
strbuf_uuid(b, uuid);
|
|
assert(!strbuf_overrun(b));
|
|
return dst;
|
|
}
|
|
|
|
int str_to_serval_uuid(const char *const str, serval_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 + SERVAL_UUID_STRLEN);
|
|
ret = serval_uuid_is_valid(uuid);
|
|
}
|
|
if (afterp)
|
|
*afterp = end;
|
|
if (ret == 0 || (!afterp && *end))
|
|
return 0;
|
|
return 1;
|
|
}
|