]> git.sesse.net Git - ffmpeg/blob - libavutil/random_seed.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavutil / random_seed.c
1 /*
2  * Copyright (c) 2009 Baptiste Coudurier <baptiste.coudurier@gmail.com>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <math.h>
24 #include <time.h>
25 #include <string.h>
26 #include "timer.h"
27 #include "random_seed.h"
28 #include "sha.h"
29 #include "intreadwrite.h"
30
31 #ifndef TEST
32 #define TEST 0
33 #endif
34
35 static int read_random(uint32_t *dst, const char *file)
36 {
37     int fd = open(file, O_RDONLY);
38     int err = -1;
39
40     if (fd == -1)
41         return -1;
42     err = read(fd, dst, sizeof(*dst));
43     close(fd);
44
45     return err;
46 }
47
48 static uint32_t get_generic_seed(void)
49 {
50     uint8_t tmp[av_sha_size];
51     struct AVSHA *sha = (void*)tmp;
52     clock_t last_t  = 0;
53     static uint64_t i = 0;
54     static uint32_t buffer[512] = {0};
55     unsigned char digest[32];
56     uint64_t last_i = i;
57
58     if(TEST){
59         memset(buffer, 0, sizeof(buffer));
60         last_i = i = 0;
61     }else{
62 #ifdef AV_READ_TIME
63         buffer[13] ^= AV_READ_TIME();
64         buffer[41] ^= AV_READ_TIME()>>32;
65 #endif
66     }
67
68     for (;;) {
69         clock_t t = clock();
70
71         if(last_t == t){
72             buffer[i&511]++;
73         }else{
74             buffer[++i&511]+= (t-last_t) % 3294638521U;
75             if(last_i && i-last_i > 4 || i-last_i > 64 || TEST && i-last_i > 8)
76                 break;
77         }
78         last_t = t;
79     }
80
81     if(TEST)
82         buffer[0] = buffer[1] = 0;
83
84     av_sha_init(sha, 160);
85     av_sha_update(sha, (uint8_t*)buffer, sizeof(buffer));
86     av_sha_final(sha, digest);
87     return AV_RB32(digest) + AV_RB32(digest+32);
88 }
89
90 uint32_t av_get_random_seed(void)
91 {
92     uint32_t seed;
93
94     if (read_random(&seed, "/dev/urandom") == sizeof(seed))
95         return seed;
96     if (read_random(&seed, "/dev/random")  == sizeof(seed))
97         return seed;
98     return get_generic_seed();
99 }
100
101 #if TEST
102 #undef printf
103 #define N 256
104 #include <stdio.h>
105
106 int main(void)
107 {
108     int i, j, retry;
109     uint32_t seeds[N];
110
111     for (retry=0; retry<3; retry++){
112         for (i=0; i<N; i++){
113             seeds[i] = av_get_random_seed();
114             for (j=0; j<i; j++)
115                 if (seeds[j] == seeds[i])
116                     goto retry;
117         }
118         printf("seeds OK\n");
119         return 0;
120         retry:;
121     }
122     printf("FAIL at %d with %X\n", j, seeds[j]);
123     return 1;
124 }
125 #endif