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 "config.h"
27#include <stdio.h>
28#include <stdlib.h>
29#include <time.h>
30#include <fcntl.h>
31#include <unistd.h>
32#include <string.h>
33#include <sys/ioctl.h>
34#include <sys/time.h>
35#include <errno.h>
36#if HAVE_MACH_MACH_TIME_H
37#include <mach/mach_time.h>
38#elif HAVE_CLOCK_GETTIME_SYSCALL
39#include <sys/syscall.h>
40#endif
41
42#include "uuid.h"
43#include "getifaddr.h"
44#include "log.h"
45
46static uint32_t clock_seq;
47static const uint32_t clock_seq_max = 0x3fff; /* 14 bits */
48static int clock_seq_initialized;
49
50#ifndef CLOCK_MONOTONIC
51#define CLOCK_MONOTONIC CLOCK_REALTIME
52#endif
53
54unsigned long long
55monotonic_us(void)
56{
57	struct timespec ts;
58
59#if HAVE_CLOCK_GETTIME
60	clock_gettime(CLOCK_MONOTONIC, &ts);
61#elif HAVE_CLOCK_GETTIME_SYSCALL
62	syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts);
63#elif HAVE_MACH_MACH_TIME_H
64	return mach_absolute_time();
65#else
66	struct timeval tv;
67	gettimeofday(&tv, 0);
68	TIMEVAL_TO_TIMESPEC(&tv, &ts);
69#endif
70	return ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000;
71}
72
73int
74read_bootid_node(unsigned char *buf, size_t size)
75{
76	FILE *boot_id;
77
78	if(size != 6)
79		return -1;
80
81	boot_id = fopen("/proc/sys/kernel/random/boot_id", "r");
82	if(!boot_id)
83		return -1;
84	if((fseek(boot_id, 24, SEEK_SET) < 0) ||
85	   (fscanf(boot_id, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
86		   &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5]) != 6))
87	{
88		fclose(boot_id);
89		return -1;
90	}
91
92	fclose(boot_id);
93	return 0;
94}
95
96static void
97read_random_bytes(unsigned char *buf, size_t size)
98{
99	int i;
100	pid_t pid;
101
102	i = open("/dev/urandom", O_RDONLY);
103	if(i >= 0)
104	{
105		if (read(i, buf, size) == -1)
106			DPRINTF(E_MAXDEBUG, L_GENERAL, "Failed to read random bytes\n");
107		close(i);
108	}
109	/* Paranoia. /dev/urandom may be missing.
110	 * rand() is guaranteed to generate at least [0, 2^15) range,
111	 * but lowest bits in some libc are not so "random".  */
112	srand(monotonic_us());
113	pid = getpid();
114	while(1)
115	{
116		for(i = 0; i < size; i++)
117			buf[i] ^= rand() >> 5;
118		if(pid == 0)
119			break;
120		srand(pid);
121		pid = 0;
122	}
123}
124
125void
126init_clockseq(void)
127{
128	unsigned char buf[4];
129
130	read_random_bytes(buf, 4);
131	memcpy(&clock_seq, &buf, sizeof(clock_seq));
132	clock_seq &= clock_seq_max;
133	clock_seq_initialized = 1;
134}
135
136int
137generate_uuid(unsigned char uuid_out[16])
138{
139	static uint64_t last_time_all;
140	static unsigned int clock_seq_started;
141	static char last_node[6] = { 0, 0, 0, 0, 0, 0 };
142
143	struct timespec ts;
144	uint64_t time_all;
145	int inc_clock_seq = 0;
146
147	unsigned char mac[6];
148	int mac_error;
149
150	memset(&mac, '\0', sizeof(mac));
151	/* Get the spatially unique node identifier */
152
153	mac_error = getsyshwaddr((char *)mac, sizeof(mac));
154
155	if(!mac_error)
156	{
157		memcpy(&uuid_out[10], mac, ETH_ALEN);
158	}
159	else
160	{
161		/* use bootid's nodeID if no network interface found */
162		DPRINTF(E_INFO, L_HTTP, "Could not find MAC.  Use bootid's nodeID.\n");
163		if( read_bootid_node(&uuid_out[10], 6) != 0)
164		{
165			DPRINTF(E_INFO, L_HTTP, "bootid node not successfully read.\n");
166			read_random_bytes(&uuid_out[10], 6);
167		}
168	}
169
170	if(memcmp(last_node, uuid_out+10, 6) != 0)
171	{
172		inc_clock_seq = 1;
173		memcpy(last_node, uuid_out+10, 6);
174	}
175
176	/* Determine 60-bit timestamp value. For UUID version 1, this is
177	 * represented by Coordinated Universal Time (UTC) as a count of 100-
178	 * nanosecond intervals since 00:00:00.00, 15 October 1582 (the date of
179	 * Gregorian reform to the Christian calendar).
180	 */
181#if HAVE_CLOCK_GETTIME
182	clock_gettime(CLOCK_REALTIME, &ts);
183#elif HAVE_CLOCK_GETTIME_SYSCALL
184	syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts);
185#else
186	struct timeval tv;
187	gettimeofday(&tv, 0);
188	TIMEVAL_TO_TIMESPEC(&tv, &ts);
189#endif
190	time_all = ((uint64_t)ts.tv_sec) * (NSEC_PER_SEC / 100);
191	time_all += ts.tv_nsec / 100;
192
193	/* add offset from Gregorian Calendar to Jan 1 1970 */
194	time_all += 12219292800000ULL * (NSEC_PER_MSEC / 100);
195	time_all &= 0x0fffffffffffffffULL; /* limit to 60 bits */
196
197	/* Determine clock sequence (max. 14 bit) */
198	if(!clock_seq_initialized)
199	{
200		init_clockseq();
201		clock_seq_started = clock_seq;
202	}
203	else
204	{
205		if(inc_clock_seq || time_all <= last_time_all)
206		{
207			clock_seq = (clock_seq + 1) & clock_seq_max;
208			if(clock_seq == clock_seq_started)
209			{
210				clock_seq = (clock_seq - 1) & clock_seq_max;
211			}
212		}
213		else
214			clock_seq_started = clock_seq;
215	}
216	last_time_all = time_all;
217
218	/* Fill in timestamp and clock_seq values */
219	uuid_out[3] = (uint8_t)time_all;
220	uuid_out[2] = (uint8_t)(time_all >> 8);
221	uuid_out[1] = (uint8_t)(time_all >> 16);
222	uuid_out[0] = (uint8_t)(time_all >> 24);
223	uuid_out[5] = (uint8_t)(time_all >> 32);
224	uuid_out[4] = (uint8_t)(time_all >> 40);
225	uuid_out[7] = (uint8_t)(time_all >> 48);
226	uuid_out[6] = (uint8_t)(time_all >> 56);
227
228	uuid_out[8] = clock_seq >> 8;
229	uuid_out[9] = clock_seq & 0xff;
230
231	/* Set UUID version to 1 --- time-based generation */
232	uuid_out[6] = (uuid_out[6] & 0x0F) | 0x10;
233	/* Set the UUID variant to DCE */
234	uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80;
235
236	return 0;
237}
238
239/* Places a null-terminated 37-byte time-based UUID string in the buffer pointer to by buf.
240 * A large enough buffer must already be allocated. */
241int
242get_uuid_string(char *buf)
243{
244	unsigned char uuid[16];
245
246	if( generate_uuid(uuid) != 0 )
247		return -1;
248
249	sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
250	        uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], uuid[8],
251	        uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
252	buf[36] = '\0';
253
254	return 0;
255}
256