blob: 7056c2ccf3d40b71f1693b2e5965599bf9bec24b [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19#include <rdr/RandomStream.h>
20#include <rdr/Exception.h>
21#include <time.h>
22#include <stdlib.h>
23#ifndef WIN32
24#include <unistd.h>
25#include <errno.h>
26#else
27#define getpid() GetCurrentProcessId()
28#ifndef RFB_HAVE_WINCRYPT
29#pragma message(" NOTE: Not building WinCrypt-based RandomStream")
30#endif
31#endif
32
33using namespace rdr;
34
35const int DEFAULT_BUF_LEN = 256;
36
37unsigned int RandomStream::seed;
38
39RandomStream::RandomStream()
40 : offset(0)
41{
42 ptr = end = start = new U8[DEFAULT_BUF_LEN];
43
44#ifdef RFB_HAVE_WINCRYPT
45 provider = 0;
46 if (!CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, 0)) {
47 if (GetLastError() == NTE_BAD_KEYSET) {
48 if (!CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
49 fprintf(stderr, "RandomStream: unable to create keyset\n");
50 provider = 0;
51 }
52 } else {
53 fprintf(stderr, "RandomStream: unable to acquire context\n");
54 provider = 0;
55 }
56 }
57 if (!provider) {
58#else
59#ifndef WIN32
60 fp = fopen("/dev/urandom", "r");
61 if (!fp)
62 fp = fopen("/dev/random", "r");
63 if (!fp) {
64#else
65 {
66#endif
67#endif
68 fprintf(stderr,"RandomStream: warning: no OS supplied random source - using rand()\n");
69 seed += (unsigned int) time(0) + getpid() + getpid() * 987654 + rand();
70 srand(seed);
71 }
72}
73
74RandomStream::~RandomStream() {
75 delete [] start;
76
77#ifdef RFB_HAVE_WINCRYPT
78 if (provider)
79 CryptReleaseContext(provider, 0);
80#endif
81#ifndef WIN32
82 if (fp) fclose(fp);
83#endif
84}
85
86int RandomStream::pos() {
87 return offset + ptr - start;
88}
89
90int RandomStream::overrun(int itemSize, int nItems, bool wait) {
91 if (itemSize > DEFAULT_BUF_LEN)
92 throw Exception("RandomStream overrun: max itemSize exceeded");
93
94 if (end - ptr != 0)
95 memmove(start, ptr, end - ptr);
96
97 end -= ptr - start;
98 offset += ptr - start;
99 ptr = start;
100
101 int length = start + DEFAULT_BUF_LEN - end;
102
103#ifdef RFB_HAVE_WINCRYPT
104 if (provider) {
105 if (!CryptGenRandom(provider, length, (U8*)end))
106 throw rdr::SystemException("unable to CryptGenRandom", GetLastError());
107 end += length;
108 } else {
109#else
110#ifndef WIN32
111 if (fp) {
112 int n = fread((U8*)end, length, 1, fp);
113 if (n != 1)
114 throw rdr::SystemException("reading /dev/urandom or /dev/random failed",
115 errno);
116 end += length;
117 } else {
118#else
119 {
120#endif
121#endif
122 for (int i=0; i<length; i++)
123 *(U8*)end++ = (int) (256.0*rand()/(RAND_MAX+1.0));
124 }
125
126 if (itemSize * nItems > end - ptr)
127 nItems = (end - ptr) / itemSize;
128
129 return nItems;
130}