1 | /* MiniDLNA project |
---|
2 | * |
---|
3 | * http://sourceforge.net/projects/minidlna/ |
---|
4 | * |
---|
5 | * Much of this code and ideas for this code have been taken |
---|
6 | * from Helge Deller's proposed Linux kernel patch (which |
---|
7 | * apparently never made it upstream), and some from Busybox. |
---|
8 | * |
---|
9 | * MiniDLNA media server |
---|
10 | * Copyright (C) 2009 Justin Maggard |
---|
11 | * |
---|
12 | * This file is part of MiniDLNA. |
---|
13 | * |
---|
14 | * MiniDLNA is free software; you can redistribute it and/or modify |
---|
15 | * it under the terms of the GNU General Public License version 2 as |
---|
16 | * published by the Free Software Foundation. |
---|
17 | * |
---|
18 | * MiniDLNA is distributed in the hope that it will be useful, |
---|
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
21 | * GNU General Public License for more details. |
---|
22 | * |
---|
23 | * You should have received a copy of the GNU General Public License |
---|
24 | * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>. |
---|
25 | */ |
---|
26 | #include <stdio.h> |
---|
27 | #include <stdlib.h> |
---|
28 | #include <time.h> |
---|
29 | #include <fcntl.h> |
---|
30 | #include <unistd.h> |
---|
31 | #include <sys/syscall.h> |
---|
32 | #include <string.h> |
---|
33 | #include <net/if.h> |
---|
34 | #include <sys/ioctl.h> |
---|
35 | #include <sys/time.h> |
---|
36 | #include <errno.h> |
---|
37 | |
---|
38 | #include "getifaddr.h" |
---|
39 | #include "log.h" |
---|
40 | |
---|
41 | #define ETH_ALEN 6 |
---|
42 | #define NSEC_PER_SEC 1000000000L |
---|
43 | #define NSEC_PER_MSEC 1000000L |
---|
44 | |
---|
45 | static u_int32_t clock_seq; |
---|
46 | static const u_int32_t clock_seq_max = 0x3fff; /* 14 bits */ |
---|
47 | static int clock_seq_initialized; |
---|
48 | |
---|
49 | unsigned long long |
---|
50 | monotonic_us(void) |
---|
51 | { |
---|
52 | struct timespec ts; |
---|
53 | |
---|
54 | syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts); |
---|
55 | return ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000; |
---|
56 | } |
---|
57 | |
---|
58 | int |
---|
59 | read_bootid_node(unsigned char *buf, size_t size) |
---|
60 | { |
---|
61 | FILE *boot_id; |
---|
62 | |
---|
63 | if(size != 6) |
---|
64 | return -1; |
---|
65 | |
---|
66 | boot_id = fopen("/proc/sys/kernel/random/boot_id", "r"); |
---|
67 | if(!boot_id) |
---|
68 | return -1; |
---|
69 | if((fseek(boot_id, 24, SEEK_SET) < 0) || |
---|
70 | (fscanf(boot_id, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", |
---|
71 | &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5]) != 6)) |
---|
72 | { |
---|
73 | fclose(boot_id); |
---|
74 | return -1; |
---|
75 | } |
---|
76 | |
---|
77 | fclose(boot_id); |
---|
78 | return 0; |
---|
79 | } |
---|
80 | |
---|
81 | static void |
---|
82 | read_random_bytes(unsigned char *buf, size_t size) |
---|
83 | { |
---|
84 | int i; |
---|
85 | pid_t pid; |
---|
86 | |
---|
87 | i = open("/dev/urandom", O_RDONLY); |
---|
88 | if(i >= 0) |
---|
89 | { |
---|
90 | read(i, buf, size); |
---|
91 | close(i); |
---|
92 | } |
---|
93 | /* Paranoia. /dev/urandom may be missing. |
---|
94 | * rand() is guaranteed to generate at least [0, 2^15) range, |
---|
95 | * but lowest bits in some libc are not so "random". */ |
---|
96 | srand(monotonic_us()); |
---|
97 | pid = getpid(); |
---|
98 | while(1) |
---|
99 | { |
---|
100 | for(i = 0; i < size; i++) |
---|
101 | buf[i] ^= rand() >> 5; |
---|
102 | if(pid == 0) |
---|
103 | break; |
---|
104 | srand(pid); |
---|
105 | pid = 0; |
---|
106 | } |
---|
107 | } |
---|
108 | |
---|
109 | void |
---|
110 | init_clockseq(void) |
---|
111 | { |
---|
112 | unsigned char buf[4]; |
---|
113 | |
---|
114 | read_random_bytes(buf, 4); |
---|
115 | memcpy(&clock_seq, &buf, sizeof(clock_seq)); |
---|
116 | clock_seq &= clock_seq_max; |
---|
117 | clock_seq_initialized = 1; |
---|
118 | } |
---|
119 | |
---|
120 | int |
---|
121 | generate_uuid(unsigned char uuid_out[16]) |
---|
122 | { |
---|
123 | static u_int64_t last_time_all; |
---|
124 | static unsigned int clock_seq_started; |
---|
125 | static char last_node[6] = { 0, 0, 0, 0, 0, 0 }; |
---|
126 | |
---|
127 | struct timespec ts; |
---|
128 | u_int64_t time_all; |
---|
129 | int inc_clock_seq = 0; |
---|
130 | |
---|
131 | unsigned char mac[6]; |
---|
132 | int mac_error; |
---|
133 | |
---|
134 | memset(&mac, '\0', sizeof(mac)); |
---|
135 | /* Get the spatially unique node identifier */ |
---|
136 | |
---|
137 | mac_error = getsyshwaddr((char *)mac, sizeof(mac)); |
---|
138 | |
---|
139 | if(!mac_error) |
---|
140 | { |
---|
141 | memcpy(&uuid_out[10], mac, ETH_ALEN); |
---|
142 | } |
---|
143 | else |
---|
144 | { |
---|
145 | /* use bootid's nodeID if no network interface found */ |
---|
146 | DPRINTF(E_INFO, L_HTTP, "Could not find MAC. Use bootid's nodeID.\n"); |
---|
147 | if( read_bootid_node(&uuid_out[10], 6) != 0) |
---|
148 | { |
---|
149 | DPRINTF(E_INFO, L_HTTP, "bootid node not successfully read.\n"); |
---|
150 | read_random_bytes(&uuid_out[10], 6); |
---|
151 | } |
---|
152 | } |
---|
153 | |
---|
154 | if(memcmp(last_node, uuid_out+10, 6) != 0) |
---|
155 | { |
---|
156 | inc_clock_seq = 1; |
---|
157 | memcpy(last_node, uuid_out+10, 6); |
---|
158 | } |
---|
159 | |
---|
160 | /* Determine 60-bit timestamp value. For UUID version 1, this is |
---|
161 | * represented by Coordinated Universal Time (UTC) as a count of 100- |
---|
162 | * nanosecond intervals since 00:00:00.00, 15 October 1582 (the date of |
---|
163 | * Gregorian reform to the Christian calendar). |
---|
164 | */ |
---|
165 | syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts); |
---|
166 | time_all = ((u_int64_t)ts.tv_sec) * (NSEC_PER_SEC / 100); |
---|
167 | time_all += ts.tv_nsec / 100; |
---|
168 | |
---|
169 | /* add offset from Gregorian Calendar to Jan 1 1970 */ |
---|
170 | time_all += 12219292800000ULL * (NSEC_PER_MSEC / 100); |
---|
171 | time_all &= 0x0fffffffffffffffULL; /* limit to 60 bits */ |
---|
172 | |
---|
173 | /* Determine clock sequence (max. 14 bit) */ |
---|
174 | if(!clock_seq_initialized) |
---|
175 | { |
---|
176 | init_clockseq(); |
---|
177 | clock_seq_started = clock_seq; |
---|
178 | } |
---|
179 | else |
---|
180 | { |
---|
181 | if(inc_clock_seq || time_all <= last_time_all) |
---|
182 | { |
---|
183 | clock_seq = (clock_seq + 1) & clock_seq_max; |
---|
184 | if(clock_seq == clock_seq_started) |
---|
185 | { |
---|
186 | clock_seq = (clock_seq - 1) & clock_seq_max; |
---|
187 | } |
---|
188 | } |
---|
189 | else |
---|
190 | clock_seq_started = clock_seq; |
---|
191 | } |
---|
192 | last_time_all = time_all; |
---|
193 | |
---|
194 | /* Fill in timestamp and clock_seq values */ |
---|
195 | uuid_out[3] = (u_int8_t)time_all; |
---|
196 | uuid_out[2] = (u_int8_t)(time_all >> 8); |
---|
197 | uuid_out[1] = (u_int8_t)(time_all >> 16); |
---|
198 | uuid_out[0] = (u_int8_t)(time_all >> 24); |
---|
199 | uuid_out[5] = (u_int8_t)(time_all >> 32); |
---|
200 | uuid_out[4] = (u_int8_t)(time_all >> 40); |
---|
201 | uuid_out[7] = (u_int8_t)(time_all >> 48); |
---|
202 | uuid_out[6] = (u_int8_t)(time_all >> 56); |
---|
203 | |
---|
204 | uuid_out[8] = clock_seq >> 8; |
---|
205 | uuid_out[9] = clock_seq & 0xff; |
---|
206 | |
---|
207 | /* Set UUID version to 1 --- time-based generation */ |
---|
208 | uuid_out[6] = (uuid_out[6] & 0x0F) | 0x10; |
---|
209 | /* Set the UUID variant to DCE */ |
---|
210 | uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80; |
---|
211 | |
---|
212 | return 0; |
---|
213 | } |
---|
214 | |
---|
215 | /* Places a null-terminated 37-byte time-based UUID string in the buffer pointer to by buf. |
---|
216 | * A large enough buffer must already be allocated. */ |
---|
217 | int |
---|
218 | get_uuid_string(char *buf) |
---|
219 | { |
---|
220 | unsigned char uuid[16]; |
---|
221 | |
---|
222 | if( generate_uuid(uuid) != 0 ) |
---|
223 | return -1; |
---|
224 | |
---|
225 | sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", |
---|
226 | uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], |
---|
227 | uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]); |
---|
228 | buf[36] = '\0'; |
---|
229 | |
---|
230 | return 0; |
---|
231 | } |
---|