"Fossies" - the Fresh Open Source Software Archive

Member "minidlna-1.3.0/uuid.c" (24 Nov 2020, 6360 Bytes) of package /linux/privat/minidlna-1.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "uuid.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2.1_vs_1.3.0.

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