UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
uuid.cpp
Go to the documentation of this file.
1/**************************************************************************
2 *
3 * Copyright (C) 2022+ GPL 3 and higher by Ingo Höft, <Ingo@Hoeft-online.de>
4 * Redistribution only with this Copyright remark. Last modified: 2025-05-05
5 * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
6 * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
7 * Digital Equipment Corporation, Maynard, Mass.
8 * Copyright (c) 1998 Microsoft.
9 * To anyone who acknowledges that this file is provided "AS IS"
10 * without any express or implied warranty: permission to use, copy,
11 * modify, and distribute this file for any purpose is hereby
12 * granted without fee, provided that the above copyright notices and
13 * this notice appears in all source code copies, and that none of
14 * the names of Open Software Foundation, Inc., Hewlett-Packard
15 * Company, or Digital Equipment Corporation be used in advertising
16 * or publicity pertaining to distribution of the software without
17 * specific, written prior permission. Neither Open Software
18 * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment
19 * Corporation makes any representations about the suitability of
20 * this software for any purpose.
21 *
22 **************************************************************************/
32#include <uuid.hpp>
33#include <UPnPsdk/port_sock.hpp>
34#include <UPnPsdk/synclog.hpp>
35
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <time.h>
42
43namespace {
44
46pthread_mutex_t uuid_mutex;
47
57
62
66inline void format_uuid_v1(uuid_upnp* uid, uint16_t clock_seq,
67 uuid_time_t timestamp, uuid_node_t node) {
68 /* Construct a version 1 uuid with the information we've gathered
69 * plus a few constants. */
70 uid->time_low = (uint32_t)(timestamp & 0xFFFFFFFF);
71 uid->time_mid = (uint16_t)((timestamp >> 32) & 0xFFFF);
72 uid->time_hi_and_version = (uint16_t)((timestamp >> 48) & 0x0FFF);
73 uid->time_hi_and_version |= (1 << 12);
74 uid->clock_seq_low = (uint8_t)(clock_seq & 0xFF);
75 uid->clock_seq_hi_and_reserved = (uint8_t)((clock_seq & 0x3F00) >> 8);
76 uid->clock_seq_hi_and_reserved |= 0x80;
77 memcpy(&uid->node, &node, sizeof uid->node);
78}
79
87inline int read_state(uint16_t* clockseq, uuid_time_t* timestamp,
88 uuid_node_t* node) {
89 if (!stateInited)
90 return 0;
91 *clockseq = st.cs;
92 *timestamp = st.ts;
93 *node = st.node;
94
95 return 1;
96}
97
101inline void write_state(uint16_t clockseq, uuid_time_t timestamp,
102 uuid_node_t node) {
103 static uuid_time_t next_save;
104
105 if (!stateInited) {
106 next_save = timestamp;
107 stateInited = 1;
108 };
109 /* always save state to volatile shared state. */
110 st.cs = clockseq;
111 st.ts = timestamp;
112 st.node = node;
113 if (timestamp >= next_save) {
114 /* schedule next save for 10 seconds from now. */
115 next_save = timestamp + (10 * 10 * 1000 * 1000);
116 };
117}
118
124inline void get_current_time(uuid_time_t* timestamp) {
125 uuid_time_t time_now;
126 static uuid_time_t time_last;
127 static uint16_t uuids_this_tick;
128 static int inited = 0;
129
130 if (!inited) {
131 uuids_this_tick = UUIDS_PER_TICK;
132 inited = 1;
133 };
134 while (1) {
135 get_system_time(&time_now);
136 /* if clock reading changed since last UUID generated... */
137 if (time_last != time_now) {
138 /* reset count of uuids gen'd with this clock reading.
139 */
140 uuids_this_tick = 0;
141 break;
142 };
143 if (uuids_this_tick < UUIDS_PER_TICK) {
144 uuids_this_tick++;
145 break;
146 };
147 /* going too fast for our clock; spin. */
148 };
149 /* add the count of uuids to low order bits of the clock reading. */
150 *timestamp = time_now + uuids_this_tick;
151 time_last = *timestamp;
152}
153
158inline uint16_t true_random() {
159 static int inited = 0;
160 uuid_time_t time_now;
161
162 if (!inited) {
163 get_system_time(&time_now);
164 time_now = time_now / UUIDS_PER_TICK;
165 srand((unsigned int)(((time_now >> 32) ^ time_now) & 0xffffffff));
166 inited = 1;
167 };
168
169 return (uint16_t)(rand());
170}
171
175inline void format_uuid_v3(uuid_upnp* uid, unsigned char hash[16]) {
176 /* Construct a version 3 uuid with the (pseudo-)random number plus a few
177 * constants. */
178 memcpy(uid, hash, sizeof(uuid_upnp));
179 /* convert UUID to local byte order. */
180 uid->time_low = ntohl(uid->time_low);
181 uid->time_mid = ntohs(uid->time_mid);
182 uid->time_hi_and_version = ntohs(uid->time_hi_and_version);
183 /* put in the variant and version bits. */
184 uid->time_hi_and_version &= 0x0FFF;
185 uid->time_hi_and_version |= (3 << 12);
186 uid->clock_seq_hi_and_reserved &= 0x3F;
187 uid->clock_seq_hi_and_reserved |= 0x80;
188}
189
191#define CHECK(f1, f2) \
192 if (f1 != f2) \
193 return f1 < f2 ? -1 : 1;
194
195} // anonymous namespace
196
197
199 pthread_mutex_init(&uuid_mutex, NULL); // always returns 0.
200}
201
203 int ret = pthread_mutex_destroy(&uuid_mutex);
204 // Returns only EBUSY
205 if (ret != 0)
206 UPnPsdk_LOGCRIT(
207 "MSG1149") "POSIX thread destroy uuid_mutex fails with EBUSY.";
208 return ret;
209}
210
212 uuid_time_t timestamp;
213 uuid_time_t last_time;
214 uint16_t clockseq;
215 uuid_node_t node;
216 uuid_node_t last_node;
217 int f;
218
219 /* acquire system wide lock so we're alone. */
220 pthread_mutex_lock(&uuid_mutex);
221 /* get current time. */
222 get_current_time(&timestamp);
223 /* get node ID. */
225 /* get saved state from NV storage. */
226 f = read_state(&clockseq, &last_time, &last_node);
227 /* if no NV state, or if clock went backwards, or node ID changed
228 * (e.g., net card swap) change clockseq. */
229 if (!f || memcmp(&node, &last_node, sizeof(uuid_node_t)))
230 clockseq = true_random();
231 else if (timestamp < last_time)
232 clockseq++;
233 /* stuff fields into the UUID. */
234 format_uuid_v1(uid, clockseq, timestamp, node);
235 /* save the state for next time. */
236 write_state(clockseq, timestamp, node);
237 pthread_mutex_unlock(&uuid_mutex);
238
239 return 1;
240}
241
242void upnp_uuid_unpack(uuid_upnp* u, char* out) {
243 snprintf(out, 44,
244 "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
245 (unsigned int)u->time_low, u->time_mid, u->time_hi_and_version,
247 u->node[1], u->node[2], u->node[3], u->node[4], u->node[5]);
248}
249
252 uuid_upnp* uid,
255 uuid_upnp nsid,
257 void* name,
259 int namelen) {
260 MD5_CTX c;
261 unsigned char hash[16];
262 uuid_upnp net_nsid; /* context UUID in network byte order */
263
264 /* put name space ID in network byte order so it hashes the same no
265 * matter what endian machine we're on. */
266 net_nsid = nsid;
267 net_nsid.time_low = htonl(net_nsid.time_low);
268 net_nsid.time_mid = htons(net_nsid.time_mid);
269 net_nsid.time_hi_and_version = htons(net_nsid.time_hi_and_version);
270 MD5Init(&c);
271 MD5Update(&c, (unsigned char*)&net_nsid, sizeof(uuid_upnp));
272 MD5Update(&c, name, (unsigned int)namelen);
273 MD5Final(hash, &c);
274 /* the hash is in network byte order at this point. */
275 format_uuid_v3(uid, hash);
276}
277
279 int i;
280
281 CHECK(u1->time_low, u2->time_low);
282 CHECK(u1->time_mid, u2->time_mid);
286 for (i = 0; i < 6; i++) {
287 if (u1->node[i] < u2->node[i])
288 return -1;
289 if (u1->node[i] > u2->node[i])
290 return 1;
291 }
292
293 return 0;
294}
void MD5Update(MD5_CTX *, const void *, size_t)
MD5 Update.
Definition md5.cpp:82
void MD5Init(MD5_CTX *)
MD5 Initialisation.
Definition md5.cpp:70
void MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx)
MD5 Final.
Definition md5.cpp:119
MD5 Context.
Definition md5.hpp:38
uuid_state st
UUID generator persistent state.
Definition uuid.cpp:59
void get_current_time(uuid_time_t *timestamp)
Get time as 60 bit 100ns ticks since whenever.
Definition uuid.cpp:124
int read_state(uint16_t *clockseq, uuid_time_t *timestamp, uuid_node_t *node)
Read UUID generator state from non-volatile store.
Definition uuid.cpp:87
uint16_t true_random()
generate a crypto-quality random number. This sample doesn't do that.
Definition uuid.cpp:158
void write_state(uint16_t clockseq, uuid_time_t timestamp, uuid_node_t node)
Save UUID generator state back to non-volatile storage.
Definition uuid.cpp:101
void format_uuid_v3(uuid_upnp *uid, unsigned char hash[16])
Make a UUID from a (pseudo)random 128 bit number.
Definition uuid.cpp:175
void format_uuid_v1(uuid_upnp *uid, uint16_t clock_seq, uuid_time_t timestamp, uuid_node_t node)
Make a UUID from the timestamp, clockseq, and node ID.
Definition uuid.cpp:66
int stateInited
Flag if UUID generator persistent state is initiated.
Definition uuid.cpp:61
pthread_mutex_t uuid_mutex
Mutex to synchronize the uuid creation process.
Definition uuid.cpp:46
Data type for UUID generator persistent state.
Definition uuid.cpp:49
Specifications to be portable with sockets between different platforms.
Define macro for synced logging to the console for detailed info and debug.
void get_ieee_node_identifier(uuid_node_t *node)
System dependent call to get IEEE node identifier.
Definition sysdep.cpp:41
uint64_t uuid_time_t
UUID time.
Definition sysdep.hpp:48
void get_system_time(uuid_time_t *uuid_time)
System dependent call to get the current system time.
Definition sysdep.cpp:57
constexpr int UUIDS_PER_TICK
set the following to the number of 100ns ticks of the actual resolution of your system's clock
Definition sysdep.hpp:45
node ID
Definition sysdep.hpp:51
void uuid_create_from_name(uuid_upnp *uid, uuid_upnp nsid, void *name, int namelen)
Create a UUID using a "name" from a "name space".
Definition uuid.cpp:250
void uuidMutexInit()
Initialize mutex for synchronizing the uuid creation process.
Definition uuid.cpp:198
int uuid_compare(uuid_upnp *u1, uuid_upnp *u2)
Compare two UUID's "lexically".
Definition uuid.cpp:278
#define CHECK(f1, f2)
Macro to compare times.
Definition uuid.cpp:191
void upnp_uuid_unpack(uuid_upnp *u, char *out)
Unpack a UUID.
Definition uuid.cpp:242
int uuidMutexDestroy()
Destroy mutex for synchronizing the uuid creation process.
Definition uuid.cpp:202
int uuid_create(uuid_upnp *uid)
Generate a UUID.
Definition uuid.cpp:211
Manage UUIDs.
uint8_t clock_seq_hi_and_reserved
Member variable.
Definition uuid.hpp:48
uint16_t time_mid
Member variable.
Definition uuid.hpp:46
uint32_t time_low
Member variable.
Definition uuid.hpp:45
uint8_t node[6]
Member variable.
Definition uuid.hpp:50
uint8_t clock_seq_low
Member variable.
Definition uuid.hpp:49
uint16_t time_hi_and_version
Member variable.
Definition uuid.hpp:47
uuid UPNP
Definition uuid.hpp:42