2 Copyright © 2007-2008, The AROS Development Team. All rights reserved.
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>
22 #include "uuid_private.h"
23 #include LC_LIBDEFS_FILE
25 static void uuid_generate_random(uuid_t
*uuid
, struct uuid_base
*UUIDBase
);
26 static void uuid_generate_time(uuid_t
*uuid
, struct uuid_base
*UUIDBase
);
28 /*****************************************************************************
31 AROS_LH2(void, UUID_Generate
,
34 AROS_LHA(uuid_type_t
, type
, D0
),
35 AROS_LHA(uuid_t
*, uuid
, A0
),
38 struct uuid_base
*, UUIDBase
, 13, UUID
)
41 Generate Universally Unique Identifier conforming the RFC 4122.
44 type - type of the identifier:
45 UUID_TYPE_DCE_RANDOM - random identifier. Do not use it on purpose
46 due to the weak source of noise on AROS.
47 UUID_TYPE_DCE_TIME - system time based identifier.
49 uuid - storage for generated UUID.
52 This function always succeeds.
64 *****************************************************************************/
70 ObtainSemaphore(&LIBBASE
->uuid_GlobalLock
);
72 if (type
== UUID_TYPE_DCE_RANDOM
)
73 uuid_generate_random(uuid
, UUIDBase
);
75 uuid_generate_time(uuid
, UUIDBase
);
77 ReleaseSemaphore(&LIBBASE
->uuid_GlobalLock
);
80 char buf
[UUID_STRLEN
+1];
83 UUID_Unparse(uuid
, buf
);
84 bug("[UUID] generated UUID = %s\n", buf
);
91 static uint32_t uuid_rand(struct uuid_base
*UUIDBase
)
93 return (UUIDBase
->uuid_RandomSeed
=
94 UUIDBase
->uuid_RandomSeed
* 1103515245 + 12345) % 0x7fffffff;
97 static void uuid_generate_random(uuid_t
*uuid
, struct uuid_base
*UUIDBase
)
102 D(bug("[UUID] Generating random UUID\n"));
104 for (i
=0; i
< 16; i
++)
105 u
[i
] = uuid_rand(UUIDBase
);
107 UUID_Unpack(u
, uuid
);
109 uuid
->clock_seq_hi_and_reserved
&= 0x3f;
110 uuid
->clock_seq_hi_and_reserved
|= 0x80;
111 uuid
->time_hi_and_version
&= 0x0fff;
112 uuid
->time_hi_and_version
|= 0x4000;
115 static void uuid_get_current_time(uuid_time_t
*time
, struct uuid_base
*UUIDBase
)
117 uuid_time_t time_now
;
123 time_now
= ((uint64_t)tv
.tv_secs
+ 2922) * 10000000 +
124 ((uint64_t)tv
.tv_micro
) * 10 +
125 ((uint64_t)0x01B21DD213814000LL
);
127 if (time_now
!= LIBBASE
->uuid_LastTime
)
129 UUIDBase
->uuid_UUIDs_ThisTick
= 0;
130 LIBBASE
->uuid_LastTime
= time_now
;
134 if (UUIDBase
->uuid_UUIDs_ThisTick
< UUIDS_PER_TICK
)
136 UUIDBase
->uuid_UUIDs_ThisTick
++;
140 *time
= time_now
+ UUIDBase
->uuid_UUIDs_ThisTick
;
143 static void uuid_get_node(uuid_node_t
*node
, struct uuid_base
*UUIDBase
)
145 if (!UUIDBase
->uuid_Initialized
)
148 DOSBase
= OpenLibrary("dos.library", 0);
150 if (!(DOSBase
&& GetVar("uuid_state", (UBYTE
*)&LIBBASE
->uuid_State
, sizeof(uuid_state_t
),
151 GVF_BINARY_VAR
| GVF_DONT_NULL_TERM
) == sizeof(uuid_state_t
)))
154 UUIDBase
->uuid_State
.ts
= UUIDBase
->uuid_LastTime
;
155 UUIDBase
->uuid_State
.cs
= uuid_rand(UUIDBase
);
156 for (i
=0; i
< 6; i
++)
158 UUIDBase
->uuid_State
.node
.nodeID
[i
] = uuid_rand(UUIDBase
);
160 UUIDBase
->uuid_State
.node
.nodeID
[0] |= 0x01;
162 LIBBASE
->uuid_Initialized
= 1;
165 SetVar("uuid_state", (UBYTE
*)&LIBBASE
->uuid_State
, sizeof(uuid_state_t
),
166 GVF_BINARY_VAR
| GVF_DONT_NULL_TERM
| GVF_SAVE_VAR
);
168 *node
= UUIDBase
->uuid_State
.node
;
171 static void uuid_get_state(uint16_t *cs
, uuid_time_t
*timestamp
, uuid_node_t
*node
, struct uuid_base
*UUIDBase
)
173 if (!UUIDBase
->uuid_Initialized
)
176 DOSBase
= OpenLibrary("dos.library", 0);
178 if (!(DOSBase
&& GetVar("uuid_state", (UBYTE
*)&LIBBASE
->uuid_State
, sizeof(uuid_state_t
),
179 GVF_BINARY_VAR
| GVF_DONT_NULL_TERM
) == sizeof(uuid_state_t
)))
182 UUIDBase
->uuid_State
.ts
= UUIDBase
->uuid_LastTime
;
183 UUIDBase
->uuid_State
.cs
= uuid_rand(UUIDBase
);
184 for (i
=0; i
< 6; i
++)
186 UUIDBase
->uuid_State
.node
.nodeID
[i
] = uuid_rand(UUIDBase
);
188 UUIDBase
->uuid_State
.node
.nodeID
[0] |= 0x01;
190 UUIDBase
->uuid_Initialized
= 1;
193 *node
= UUIDBase
->uuid_State
.node
;
194 *timestamp
= UUIDBase
->uuid_State
.ts
;
195 *cs
= UUIDBase
->uuid_State
.cs
;
198 static void uuid_set_state(uint16_t cs
, uuid_time_t timestamp
, uuid_node_t node
, struct uuid_base
*UUIDBase
)
200 UUIDBase
->uuid_State
.node
= node
;
201 UUIDBase
->uuid_State
.ts
= timestamp
;
202 UUIDBase
->uuid_State
.cs
= cs
;
204 D(bug("[UUID] uuid_set_state(). Timestamp=%08x%08x, NextUpdate=%08x%08x\n",
205 (uint32_t)(timestamp
>> 32), (uint32_t)timestamp
,
206 (uint32_t)(LIBBASE
->uuid_NextUpdate
>> 32), (uint32_t)LIBBASE
->uuid_NextUpdate
209 if (timestamp
>= LIBBASE
->uuid_NextUpdate
)
211 D(bug("[UUID] updating nonvolatile variable\n"));
214 DOSBase
= OpenLibrary("dos.library", 0);
217 SetVar("uuid_state", (UBYTE
*)&LIBBASE
->uuid_State
, sizeof(uuid_state_t
),
218 GVF_GLOBAL_ONLY
| GVF_SAVE_VAR
| LV_VAR
);
220 LIBBASE
->uuid_NextUpdate
= timestamp
+ (10 * 10 * 1000000);
224 static void uuid_generate_time(uuid_t
*uuid
, struct uuid_base
*UUIDBase
)
226 uuid_time_t time
, last_time
;
227 uuid_node_t node
, last_node
;
230 D(bug("[UUID] Generating time-based UUID\n"));
232 uuid_get_current_time(&time
, UUIDBase
);
233 uuid_get_node(&node
, UUIDBase
);
234 uuid_get_state(&clockseq
, &last_time
, &last_node
, UUIDBase
);
236 if (memcmp(&node
, &last_node
, sizeof(node
)))
237 clockseq
= uuid_rand(UUIDBase
);
238 else if (time
< last_time
)
241 uuid_set_state(clockseq
, time
, node
, UUIDBase
);
243 uuid
->time_low
= (uint32_t)(time
& 0xFFFFFFFF);
244 uuid
->time_mid
= (uint16_t)((time
>> 32) & 0xFFFF);
245 uuid
->time_hi_and_version
= (uint16_t)((time
>> 48) & 0x0FFF);
246 uuid
->time_hi_and_version
|= (1 << 12);
247 uuid
->clock_seq_low
= clockseq
& 0xFF;
248 uuid
->clock_seq_hi_and_reserved
= (clockseq
& 0x3F00) >> 8;
249 uuid
->clock_seq_hi_and_reserved
|= 0x80;
250 memcpy(&uuid
->node
, &node
, sizeof uuid
->node
);