Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 # include <config.h>
00023 #endif
00024
00025 #ifdef HAVE_ERRNO_H
00026 # include <errno.h>
00027 #endif
00028
00029 #ifdef HAVE_UNISTD_H
00030 # include <unistd.h>
00031 #endif
00032
00033 #ifdef HAVE_SYS_TYPES_H
00034 # include <sys/types.h>
00035 #endif
00036
00037 #ifdef HAVE_SYS_STAT_H
00038 # include <sys/stat.h>
00039 #endif
00040
00041 #ifdef HAVE_FCNTL_H
00042 # include <fcntl.h>
00043 #endif
00044
00045 #ifdef HAVE_STDIO_H
00046 # include <stdio.h>
00047 #endif
00048
00049 #ifdef HAVE_STDLIB_H
00050 # include <stdlib.h>
00051 #endif
00052
00053 #ifdef HAVE_STRING_H
00054 # include <string.h>
00055 #endif
00056
00057 #ifdef HAVE_ASSERT_H
00058 # include <assert.h>
00059 #endif
00060
00061 #include "../../intl.h"
00062
00063 #include "pwgenexception.h"
00064 #include "rng.h"
00065
00066
00067 using namespace YAPET::PWGEN;
00068
00069 int RNG::rng_available = 0;
00070
00071 void
00072 RNG::check_availability() throw (PWGenException) {
00073 if (access ("/dev/random", R_OK) == 0)
00074 rng_available |= DEVRANDOM;
00075
00076 if (access ("/dev/urandom", R_OK) == 0 )
00077 rng_available |= DEVURANDOM;
00078
00079 #ifdef HAVE_LRAND48
00080 rng_available |= LRAND48;
00081 #endif
00082 #ifdef HAVE_RAND
00083 rng_available |= RAND;
00084 #endif
00085 assert (rng_available != 0);
00086
00087 if (rng_available == 0)
00088 throw PWGenNoRNGException();
00089 }
00090
00091 int
00092 RNG::getAvailableRNGs() {
00093 check_availability();
00094 return rng_available;
00095 }
00096
00104 void
00105 RNG::init_rng (RNGENGINE request) throw (PWGenException) {
00106 assert (rng_available != 0);
00107
00108 if (rng_available == 0)
00109 throw PWGenException (_ ("Unable to initialize RNG when none is available") );
00110
00111 if (! (rng_available & request) )
00112 throw PWGenRNGNotAvailable();
00113
00114 switch (request) {
00115 case DEVRANDOM:
00116 fd = open ("/dev/random", O_RDONLY);
00117
00118 if ( fd < 0 )
00119 throw PWGenException (_ ("Unable to open /dev/random") );
00120
00121 break;
00122 case DEVURANDOM:
00123 fd = open ("/dev/urandom", O_RDONLY);
00124
00125 if ( fd < 0 )
00126 throw PWGenException (_ ("Unable to open /dev/urandom") );
00127
00128 break;
00129 case LRAND48:
00130 #if defined(HAVE_SRAND48) && defined(HAVE_TIME)
00131 srand48 (time (NULL) );
00132 #endif
00133 break;
00134 case RAND:
00135 #if defined(HAVE_RAND) && defined(HAVE_TIME)
00136 srand (time (NULL) );
00137 #endif
00138 break;
00139 case AUTO:
00140 assert (0);
00141 throw PWGenException (_ ("Unexpected RNG Engine (AUTO)") );
00142
00143 case NONE:
00144 throw PWGenException (_ ("The requested RNG Engine (NONE) is invalid.") );
00145 }
00146
00147 rng_used = request;
00148 rng_initialized = true;
00149 }
00150
00160 size_t
00161 RNG::devrandom (size_t ceil) throw (PWGenException) {
00162 assert (rng_initialized);
00163 assert (rng_used == DEVRANDOM || rng_used == DEVURANDOM);
00164 assert (fd > -1);
00165 size_t buff;
00166
00167
00168
00169 size_t nleft;
00170 ssize_t nread;
00171 size_t *ptr;
00172
00173 ptr = &buff;
00174 nleft = sizeof(size_t);
00175 while( nleft > 0) {
00176 errno = 0;
00177 if ( (nread = read (fd, ptr, nleft )) < 0) {
00178
00179 switch (errno) {
00180 case EAGAIN:
00181 case EINTR:
00182
00183 break;
00184 default: {
00185 char errmsg[1024];
00186 snprintf(errmsg, 1024, "%s (%s)", _ ("Read to few bytes on /dev/[u]random."),
00187 strerror(errno));
00188 throw PWGenException ( errmsg );
00189 }
00190 };
00191 } else {
00192 if (nread == 0) {
00193
00194 break;
00195 }
00196 nleft -= nread;
00197 ptr += nread;
00198 }
00199 }
00200
00201 if (buff > ceil)
00202 return buff % ceil;
00203
00204 return buff;
00205 }
00206
00207 size_t
00208 RNG::_lrand48 (size_t ceil) throw() {
00209 assert (rng_initialized);
00210 assert (rng_used == LRAND48);
00211 #ifdef HAVE_LRAND48
00212 long val = lrand48();
00213
00214 if ( (size_t) val > ceil)
00215 return val % ceil;
00216
00217 return (size_t) val;
00218 #else
00219 assert (0);
00220 throw PWGenRNGNotAvailable (_ ("lrand48() not available on system") );
00221
00222 return 0;
00223 #endif
00224 }
00225
00226 size_t
00227 RNG::_rand (size_t ceil) throw() {
00228 assert (rng_initialized);
00229 assert (rng_used == RAND);
00230 assert (RAND_MAX >= ceil);
00231 #ifdef HAVE_RAND
00232 int val = rand();
00233
00234 if ( (size_t) val > ceil)
00235 return val % ceil;
00236
00237 return (size_t) val;
00238 #else
00239 assert (0);
00240 throw PWGenRNGNotAvailable (_ ("rand() not available on system") );
00241
00242 return 0;
00243 #endif
00244 }
00245
00262 RNG::RNG (RNGENGINE request) throw (PWGenException) : fd (-1),
00263 rng_initialized (false),
00264 rng_used (NONE) {
00265 check_availability();
00266
00267 if (request != AUTO) {
00268 init_rng (request);
00269 } else {
00270 assert (rng_available != 0);
00271
00272
00273 if (rng_available & DEVURANDOM) {
00274 init_rng (DEVURANDOM);
00275 return;
00276 }
00277
00278 if (rng_available & DEVRANDOM) {
00279 init_rng (DEVRANDOM);
00280 return;
00281 }
00282
00283 if (rng_available & LRAND48) {
00284 init_rng (LRAND48);
00285 return;
00286 }
00287
00288 if (rng_available & RAND) {
00289 init_rng (RAND);
00290 return;
00291 }
00292 }
00293 }
00294
00295
00296
00297
00298 RNG::RNG (const RNG& r) throw (PWGenException) {
00299 assert (r.rng_initialized);
00300
00301
00302 if ( (r.rng_used == DEVRANDOM) ||
00303 (r.rng_used == DEVURANDOM) ) {
00304 assert (r.fd > -1);
00305 fd = dup (r.fd);
00306
00307 if (fd < 0)
00308 throw PWGenException ("Unable to duplicate file descriptor");
00309 } else {
00310 assert (r.fd == -1);
00311 fd = r.fd;
00312 }
00313
00314
00315 rng_initialized = r.rng_initialized;
00316 rng_used = r.rng_used;
00317 rng_available = r.rng_available;
00318
00319 if (rng_used == LRAND48)
00320 init_rng (LRAND48);
00321
00322 if (rng_used == RAND)
00323 init_rng (RAND);
00324 }
00325
00326 RNG::~RNG() throw() {
00327 if (rng_used == DEVRANDOM ||
00328 rng_used == DEVURANDOM) {
00329 assert (fd > 0);
00330 close (fd);
00331 } else {
00332 assert (fd == -1);
00333 }
00334 }
00335
00336 size_t
00337 RNG::getRandomNumber (size_t ceil) throw (PWGenException) {
00338 assert(ceil > 0);
00339 if (ceil == 0) return 0;
00340 assert (rng_initialized == true);
00341
00342 switch (rng_used) {
00343 case DEVRANDOM:
00344 case DEVURANDOM:
00345 return devrandom (ceil);
00346 case LRAND48:
00347 return _lrand48 (ceil);
00348 case RAND:
00349 return _rand (ceil);
00350
00351 case AUTO:
00352 assert (0);
00353 throw PWGenException (_ ("Unexpected RNG Engine (AUTO)") );
00354 case NONE:
00355 throw PWGenException (_ ("The requested RNG Engine (NONE) is invalid.") );
00356 }
00357
00358
00359 return 0;
00360 }
00361
00362 const RNG&
00363 RNG::operator= (const RNG & r) throw() {
00364 if (&r == this) return *this;
00365
00366 assert (r.rng_initialized);
00367
00368
00369 if (rng_used == DEVRANDOM ||
00370 rng_used == DEVURANDOM) {
00371 assert (fd > -1);
00372 close (fd);
00373 fd = -1;
00374 } else {
00375 assert (fd == -1);
00376 }
00377
00378
00379 if ( (r.rng_used == DEVRANDOM) ||
00380 (r.rng_used == DEVURANDOM) ) {
00381 assert (r.fd > -1);
00382 fd = dup (r.fd);
00383
00384 if (fd < 0)
00385 throw PWGenException ("Unable to duplicate file descriptor");
00386 } else {
00387 assert (r.fd == -1);
00388 fd = r.fd;
00389 }
00390
00391
00392 rng_initialized = r.rng_initialized;
00393 rng_used = r.rng_used;
00394 rng_available = r.rng_available;
00395
00396 if (rng_used == LRAND48)
00397 init_rng (LRAND48);
00398
00399 if (rng_used == RAND)
00400 init_rng (RAND);
00401
00402 return *this;
00403 }