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>
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 /*****************************************************************************
29 AROS_LH2(void, UUID_Generate
,
32 AROS_LHA(uuid_type_t
, type
, D0
),
33 AROS_LHA(uuid_t
*, uuid
, A0
),
36 struct uuid_base
*, UUIDBase
, 13, UUID
)
39 Generate Universally Unique Identifier conforming the RFC 4122.
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.
50 This function always succeeds.
62 *****************************************************************************/
68 ObtainSemaphore(&LIBBASE
->uuid_GlobalLock
);
70 if (type
== UUID_TYPE_DCE_RANDOM
)
71 uuid_generate_random(uuid
, UUIDBase
);
73 uuid_generate_time(uuid
, UUIDBase
);
75 ReleaseSemaphore(&LIBBASE
->uuid_GlobalLock
);
78 char buf
[UUID_STRLEN
+1];
81 UUID_Unparse(uuid
, buf
);
82 bug("[UUID] generated UUID = %s\n", buf
);
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
)
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
;
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
;
132 if (UUIDBase
->uuid_UUIDs_ThisTick
< UUIDS_PER_TICK
)
134 UUIDBase
->uuid_UUIDs_ThisTick
++;
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
)
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
)))
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;
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
)
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
)))
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"));
212 DOSBase
= (void *)OpenLibrary("dos.library", 0);
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
;
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
)
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
);