9 #include 10
11 static int get_random_fd (void)
12 {
13 static int fd = -2;
14
15 if (fd == -2)
16 {
17 fd = open ("/dev/random", O_RDONLY | O_NONBLOCK);
18 if (fd == -1)
19 fd = open ("/dev/urandom", O_RDONLY | O_NONBLOCK);
20 }
21
22 return fd;
23 }
24
25 /*
26 * Generate a series of random bytes. Use /dev/random if possible,
27 * and if not, use /dev/urandom.
28 */
29 void get_random_bytes(void* buf, int nbytes)
30 {
31 int i, fd = get_random_fd();
32 int lose_counter = 0;
33 char *cp = (char*)buf;
34 struct timeval tv;
35 static unsigned seed = 0;
36
37 if (fd >= 0)
38 {
39 while (nbytes > 0)
40 {
41 i = read (fd, cp, nbytes);
42 if ((i < 0) &&
43 ((errno == EINTR) || (errno == EAGAIN)))
44 continue;
45
46 if (i <= 0)
47 {
48 if (lose_counter++ == 8)
49 break;
50
51 continue;
52 }
53 nbytes -= i;
54 cp += i;
55 lose_counter = 0;
56 }
57 }
58
59 for (i = 0; i < nbytes; i++)
60 {
61 if (seed == 0)
62 {
63 gettimeofday(&tv, 0);
64 seed = (getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec;
65 }
66 *cp++ = rand_r(&seed) & 0xFF;
67 }
68
69 return;
70 }[/code]
13行: 定义fd为静态变量,这样只打开一次设备。
17 - 19行: 无阻塞模式打开/dev/random设备。如果该设备打开失败尝试打开/dev/urandom。
29行: void get_random_bytes(void* buf, int nbytes)函数是提供给用户的接口,用户调用这个函数就可以得到随机数。
37-57行: read有可能返回的字节数小于请求的字节数。这时候就循环读直到读够了所请求的大小。这样最多重复8次。然后返回。
59-67行: 如果上面重复8次都没有读够所请求的字节数,则我们自己生成随机数来填充。
注意:打开的fd我们并没有关闭,请您根据自己需求在合适的地方关闭。