update experimental gcc 6 patch to gcc 6.1.0 release
[AROS.git] / workbench / libs / uuid / uuid_generate.c
blob344c7c8376f1a8c42067b9f7cf27925655384cb6
1 /*
2 Copyright © 2007-2008, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 1
8 #include <aros/symbolsets.h>
9 #include <aros/debug.h>
10 #include <aros/libcall.h>
11 #include <proto/exec.h>
12 #include <proto/uuid.h>
13 #include <proto/timer.h>
14 #include <proto/dos.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <ctype.h>
20 #include "uuid_private.h"
21 #include LC_LIBDEFS_FILE
23 static void uuid_generate_random(uuid_t *uuid, struct uuid_base *UUIDBase);
24 static void uuid_generate_time(uuid_t *uuid, struct uuid_base *UUIDBase);
26 /*****************************************************************************
28 NAME */
29 AROS_LH2(void, UUID_Generate,
31 /* SYNOPSIS */
32 AROS_LHA(uuid_type_t, type, D0),
33 AROS_LHA(uuid_t *, uuid, A0),
35 /* LOCATION */
36 struct uuid_base *, UUIDBase, 13, UUID)
38 /* FUNCTION
39 Generate Universally Unique Identifier conforming the RFC 4122.
41 INPUTS
42 type - type of the identifier:
43 UUID_TYPE_DCE_RANDOM - random identifier. Do not use it on purpose
44 due to the weak source of noise on AROS.
45 UUID_TYPE_DCE_TIME - system time based identifier.
47 uuid - storage for generated UUID.
49 RESULT
50 This function always succeeds.
52 NOTES
54 EXAMPLE
56 BUGS
58 SEE ALSO
60 INTERNALS
62 *****************************************************************************/
64 AROS_LIBFUNC_INIT
66 ASSERT(uuid);
68 ObtainSemaphore(&LIBBASE->uuid_GlobalLock);
70 if (type == UUID_TYPE_DCE_RANDOM)
71 uuid_generate_random(uuid, UUIDBase);
72 else
73 uuid_generate_time(uuid, UUIDBase);
75 ReleaseSemaphore(&LIBBASE->uuid_GlobalLock);
77 D({
78 char buf[UUID_STRLEN+1];
79 buf[UUID_STRLEN] = 0;
81 UUID_Unparse(uuid, buf);
82 bug("[UUID] generated UUID = %s\n", buf);
85 AROS_LIBFUNC_EXIT
89 static uint32_t uuid_rand(struct uuid_base *UUIDBase)
91 return (UUIDBase->uuid_RandomSeed =
92 UUIDBase->uuid_RandomSeed * 1103515245 + 12345) % 0x7fffffff;
95 static void uuid_generate_random(uuid_t *uuid, struct uuid_base *UUIDBase)
97 uint8_t u[16];
98 int i;
100 D(bug("[UUID] Generating random UUID\n"));
102 for (i=0; i < 16; i++)
103 u[i] = uuid_rand(UUIDBase);
105 UUID_Unpack(u, uuid);
107 uuid->clock_seq_hi_and_reserved &= 0x3f;
108 uuid->clock_seq_hi_and_reserved |= 0x80;
109 uuid->time_hi_and_version &= 0x0fff;
110 uuid->time_hi_and_version |= 0x4000;
113 static void uuid_get_current_time(uuid_time_t *time, struct uuid_base *UUIDBase)
115 uuid_time_t time_now;
116 struct timeval tv;
118 for (;;)
120 GetSysTime(&tv);
121 time_now = ((uint64_t)tv.tv_secs + 2922) * 10000000 +
122 ((uint64_t)tv.tv_micro) * 10 +
123 ((uint64_t)0x01B21DD213814000LL);
125 if (time_now != LIBBASE->uuid_LastTime)
127 UUIDBase->uuid_UUIDs_ThisTick = 0;
128 LIBBASE->uuid_LastTime = time_now;
129 break;
132 if (UUIDBase->uuid_UUIDs_ThisTick < UUIDS_PER_TICK)
134 UUIDBase->uuid_UUIDs_ThisTick++;
135 break;
138 *time = time_now + UUIDBase->uuid_UUIDs_ThisTick;
141 static void uuid_get_node(uuid_node_t *node, struct uuid_base *UUIDBase)
143 if (!UUIDBase->uuid_Initialized)
145 if (!DOSBase)
146 DOSBase = (void *)OpenLibrary("dos.library", 0);
148 if (!(DOSBase && GetVar("uuid_state", (UBYTE*)&LIBBASE->uuid_State, sizeof(uuid_state_t),
149 GVF_BINARY_VAR | GVF_DONT_NULL_TERM) == sizeof(uuid_state_t)))
151 int i;
152 UUIDBase->uuid_State.ts = UUIDBase->uuid_LastTime;
153 UUIDBase->uuid_State.cs = uuid_rand(UUIDBase);
154 for (i=0; i < 6; i++)
156 UUIDBase->uuid_State.node.nodeID[i] = uuid_rand(UUIDBase);
158 UUIDBase->uuid_State.node.nodeID[0] |= 0x01;
160 LIBBASE->uuid_Initialized = 1;
162 if (DOSBase)
163 SetVar("uuid_state", (UBYTE*)&LIBBASE->uuid_State, sizeof(uuid_state_t),
164 GVF_BINARY_VAR | GVF_DONT_NULL_TERM | GVF_SAVE_VAR);
166 *node = UUIDBase->uuid_State.node;
169 static void uuid_get_state(uint16_t *cs, uuid_time_t *timestamp, uuid_node_t *node, struct uuid_base *UUIDBase)
171 if (!UUIDBase->uuid_Initialized)
173 if (!DOSBase)
174 DOSBase = (void *)OpenLibrary("dos.library", 0);
176 if (!(DOSBase && GetVar("uuid_state", (UBYTE*)&LIBBASE->uuid_State, sizeof(uuid_state_t),
177 GVF_BINARY_VAR | GVF_DONT_NULL_TERM) == sizeof(uuid_state_t)))
179 int i;
180 UUIDBase->uuid_State.ts = UUIDBase->uuid_LastTime;
181 UUIDBase->uuid_State.cs = uuid_rand(UUIDBase);
182 for (i=0; i < 6; i++)
184 UUIDBase->uuid_State.node.nodeID[i] = uuid_rand(UUIDBase);
186 UUIDBase->uuid_State.node.nodeID[0] |= 0x01;
188 UUIDBase->uuid_Initialized = 1;
191 *node = UUIDBase->uuid_State.node;
192 *timestamp = UUIDBase->uuid_State.ts;
193 *cs = UUIDBase->uuid_State.cs;
196 static void uuid_set_state(uint16_t cs, uuid_time_t timestamp, uuid_node_t node, struct uuid_base *UUIDBase)
198 UUIDBase->uuid_State.node = node;
199 UUIDBase->uuid_State.ts = timestamp;
200 UUIDBase->uuid_State.cs = cs;
202 D(bug("[UUID] uuid_set_state(). Timestamp=%08x%08x, NextUpdate=%08x%08x\n",
203 (uint32_t)(timestamp >> 32), (uint32_t)timestamp,
204 (uint32_t)(LIBBASE->uuid_NextUpdate >> 32), (uint32_t)LIBBASE->uuid_NextUpdate
207 if (timestamp >= LIBBASE->uuid_NextUpdate)
209 D(bug("[UUID] updating nonvolatile variable\n"));
211 if (!DOSBase)
212 DOSBase = (void *)OpenLibrary("dos.library", 0);
214 if (DOSBase)
215 SetVar("uuid_state", (UBYTE*)&LIBBASE->uuid_State, sizeof(uuid_state_t),
216 GVF_GLOBAL_ONLY | GVF_SAVE_VAR | LV_VAR);
218 LIBBASE->uuid_NextUpdate = timestamp + (10 * 10 * 1000000);
222 static void uuid_generate_time(uuid_t *uuid, struct uuid_base *UUIDBase)
224 uuid_time_t time, last_time;
225 uuid_node_t node, last_node;
226 uint16_t clockseq;
228 D(bug("[UUID] Generating time-based UUID\n"));
230 uuid_get_current_time(&time, UUIDBase);
231 uuid_get_node(&node, UUIDBase);
232 uuid_get_state(&clockseq, &last_time, &last_node, UUIDBase);
234 if (memcmp(&node, &last_node, sizeof(node)))
235 clockseq = uuid_rand(UUIDBase);
236 else if (time < last_time)
237 clockseq++;
239 uuid_set_state(clockseq, time, node, UUIDBase);
241 uuid->time_low = (uint32_t)(time & 0xFFFFFFFF);
242 uuid->time_mid = (uint16_t)((time >> 32) & 0xFFFF);
243 uuid->time_hi_and_version = (uint16_t)((time >> 48) & 0x0FFF);
244 uuid->time_hi_and_version |= (1 << 12);
245 uuid->clock_seq_low = clockseq & 0xFF;
246 uuid->clock_seq_hi_and_reserved = (clockseq & 0x3F00) >> 8;
247 uuid->clock_seq_hi_and_reserved |= 0x80;
248 memcpy(&uuid->node, &node, sizeof uuid->node);