/* * The contents of this file are subject to the AOLserver Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://aolserver.lcs.mit.edu/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is AOLserver Code and related documentation * distributed by AOL. * * The Initial Developer of the Original Code is America Online, * Inc. Portions created by AOL are Copyright (C) 1999 America Online, * Inc. All Rights Reserved. * * Alternatively, the contents of this file may be used under the terms * of the GNU General Public License (the "GPL"), in which case the * provisions of GPL are applicable instead of those above. If you wish * to allow use of your version of this file only under the terms of the * GPL and not to allow others to use your version of this file under the * License, indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by the GPL. * If you do not delete the provisions above, a recipient may use your * version of this file under either the License or the GPL. */ /* * random.c -- * * This file implements the "ns_rand" command. */ #include "nsd.h" #if defined(__APPLE__) #define HAVE_BSD_RANDOM 1 #define HAVE_RAND48 0 #elif defined(WIN32) #define HAVE_BSD_RANDOM 0 #define HAVE_RAND48 0 #else #define HAVE_BSD_RANDOM 0 #define HAVE_RAND48 1 #endif #ifdef NOTDEF /* * Local functions defined in this file */ static void CounterThread(void); static unsigned long raw_truerand(void); /* * These static variables are used the GenerateSeed routine to generate * an array of random seeds. */ static volatile unsigned long Counter; /* counter in counting thread */ static volatile char counterRun; /* flag that controls the outer loop * in the counting thread */ static volatile char keepCounting; /* flag that controls the inner loop * in the counting thread */ static Ns_Sema counterSema; /* semaphore that controls the * counting thread */ #endif /* *========================================================================== * Exported functions *========================================================================== */ /* *---------------------------------------------------------------------- * * NsTclRandCmd -- * * This procedure implements the AOLserver Tcl * * ns_rand ?maximum? * * command. * * Results: * The Tcl result string contains a random number, either a * double >= 0.0 and < 1.0 or a integer >= 0 and < max. * * Side effects: * None external. * * Note: * Interpreters share the static variables which randomizes the * the random numbers even more. * *---------------------------------------------------------------------- */ int NsTclRandCmd(ClientData dummy, Tcl_Interp *interp, int argc, char **argv) { double d; int max; if (argc > 2) { Tcl_AppendResult(interp, argv[0], ": wrong number args: should be \"", argv[0], " ?maximum?\"", (char *) NULL); return TCL_ERROR; } if (argc == 2) { if (Tcl_GetInt(interp, argv[1], &max) != TCL_OK) { return TCL_ERROR; } else if (max <= 0) { Tcl_AppendResult(interp, "invalid max \"", argv[1], "\": must be > 0", NULL); return TCL_ERROR; } } d = drand48(); if (argc == 1) { Tcl_PrintDouble(interp, d, interp->result); } else { sprintf(interp->result, "%d", (int) (d * max)); } return TCL_OK; } /* *---------------------------------------------------------------------- * * Ns_DRand -- * * Return a random double value between 0 and 1.0. * * Results: * Random double. * * Side effects: * Will generate random seed on first call. * *---------------------------------------------------------------------- */ #ifdef NOTDEF double Ns_DRand(void) { static int initialized; if (!initialized) { Ns_MasterLock(); if (!initialized) { unsigned long seed = 0xdeadbeef; Ns_GenSeeds(&seed, 1); #if HAVE_RAND48 srand48(seed); #elif HAVE_BSD_RANDOM srandom((unsigned int) seed); #else srand((unsigned int) seed); #endif initialized = 1; } Ns_MasterUnlock(); } #if HAVE_RAND48 return drand48(); #elif HAVE_BSD_RANDOM return ((double) random() / (LONG_MAX + 1.0)); #else return ((double) rand() / (RAND_MAX + 1.0)); #endif } /* *---------------------------------------------------------------------- * * Ns_GenSeeds -- * * Calculate an array of random seeds used by both Ns_DRand() and * the old SSL module. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Ns_GenSeeds(unsigned long *seedsPtr, int nseeds) { Ns_Thread thr; unsigned long seed; Ns_Log(Notice, "generating %d random seed%s...", nseeds, nseeds > 1 ? "s" : ""); Ns_MasterLock(); Ns_SemaInit(&counterSema, 0); counterRun = 1; Ns_ThreadCreate((Ns_ThreadProc *) CounterThread, NULL, 0, &thr); while (nseeds-- > 0) { *seedsPtr++ = raw_truerand(); } counterRun = 0; Ns_SemaPost(&counterSema, 1); Ns_MasterUnlock(); Ns_ThreadJoin(&thr, NULL); Ns_SemaDestroy(&counterSema); Ns_Log(Notice, "seed generation complete."); } /* *---------------------------------------------------------------------- * * CounterThread -- * * Generate a random seed. This routine runs as a separate thread * where it imcrements a counter some indeterminate number of times. * The assumption is that this thread runs for a sufficiently long time * to be preempted an arbitrary number of times by the kernel threads * scheduler. * * Results: * * Side effects: * None external. * *---------------------------------------------------------------------- */ static void CounterThread(void) { while (counterRun) { Ns_SemaWait(&counterSema); if (counterRun) { while (keepCounting) { Counter++; } } } } /* *========================================================================== * AT&T Seed Generation Code *========================================================================== */ /* * The authors of this software are Don Mitchell and Matt Blaze. * Copyright (c) 1995 by AT&T. * Permission to use, copy, and modify this software without fee * is hereby granted, provided that this entire notice is included in * all copies of any software which is or includes a copy or * modification of this software and in all copies of the supporting * documentation for such software. * * This software may be subject to United States export controls. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ #define MSEC_TO_COUNT 31 /* duration of thread counting in milliseconds */ #define ROULETTE_PRE_ITERS 10 static unsigned long roulette(void); static unsigned long raw_truerand(void) { int i; for (i = 0; i < ROULETTE_PRE_ITERS; i++) { roulette(); } return roulette(); } static unsigned long roulette(void) { static unsigned long ocount, randbuf; struct timeval tv; Counter = 0; keepCounting = 1; Ns_SemaPost(&counterSema, 1); tv.tv_sec = (time_t)0; tv.tv_usec = MSEC_TO_COUNT * 1000; select(0, NULL, NULL, NULL, &tv); keepCounting = 0; Counter ^= (Counter >> 3) ^ (Counter >> 6) ^ (ocount); Counter &= 0x7; ocount = Counter; randbuf = (randbuf<<3) ^ Counter; return randbuf; } #endif