Back to index

lightning-sunbird  0.9+nobinonly
uxrng.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 
00039 #include "primpl.h"
00040 
00041 #include <string.h>
00042 #include <unistd.h>
00043 #include <errno.h>
00044 #include <sys/time.h>
00045 
00046 
00047 #if defined(SOLARIS)
00048 
00049 static size_t
00050 GetHighResClock(void *buf, size_t maxbytes)
00051 {
00052     hrtime_t t;
00053     t = gethrtime();
00054     if (t) {
00055            return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
00056     }
00057     return 0;
00058 }
00059 
00060 #elif defined(SUNOS4)
00061 
00062 static size_t
00063 GetHighResClock(void *buf, size_t maxbytes)
00064 {
00065     return 0;
00066 }
00067 
00068 #elif defined(HPUX)
00069 
00070 #ifdef __ia64
00071 #include <ia64/sys/inline.h>
00072 
00073 static size_t
00074 GetHighResClock(void *buf, size_t maxbytes)
00075 {
00076     PRUint64 t;
00077 
00078     t = _Asm_mov_from_ar(_AREG44);
00079     return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
00080 }
00081 #else
00082 static size_t
00083 GetHighResClock(void *buf, size_t maxbytes)
00084 {
00085     extern int ret_cr16();
00086     int cr16val;
00087 
00088     cr16val = ret_cr16();
00089     return(_pr_CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val)));
00090 }
00091 #endif
00092 
00093 #elif defined(OSF1)
00094 
00095 #include <c_asm.h>
00096 
00097 /*
00098  * Use the "get the cycle counter" instruction on the alpha.
00099  * The low 32 bits completely turn over in less than a minute.
00100  * The high 32 bits are some non-counter gunk that changes sometimes.
00101  */
00102 static size_t
00103 GetHighResClock(void *buf, size_t maxbytes)
00104 {
00105     unsigned long t;
00106 
00107 #ifdef __GNUC__
00108     __asm__("rpcc %0" : "=r" (t));
00109 #else
00110     t = asm("rpcc %v0");
00111 #endif
00112     return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
00113 }
00114 
00115 #elif defined(VMS)
00116 
00117 #include <ints.h>
00118 
00119 /*
00120  * Use the "get the cycle counter" instruction on the alpha.
00121  * The low 32 bits completely turn over in less than a minute.
00122  * The high 32 bits are some non-counter gunk that changes sometimes.
00123  */
00124 static size_t
00125 GetHighResClock(void *buf, size_t maxbytes)
00126 {
00127     uint64 t;
00128 
00129     t = __RPCC();
00130     return _pr_CopyLowBits(buf, maxbytes, &t, sizeof(t));
00131 }
00132 
00133 #elif defined(AIX)
00134 
00135 static size_t
00136 GetHighResClock(void *buf, size_t maxbytes)
00137 {
00138     return 0;
00139 }
00140 
00141 #elif (defined(LINUX) || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD))
00142 #include <sys/types.h>
00143 #include <sys/stat.h>
00144 #include <fcntl.h>
00145 
00146 static int      fdDevRandom;
00147 static PRCallOnceType coOpenDevRandom;
00148 
00149 static PRStatus OpenDevRandom( void )
00150 {
00151     fdDevRandom = open( "/dev/random", O_RDONLY );
00152     return((-1 == fdDevRandom)? PR_FAILURE : PR_SUCCESS );
00153 } /* end OpenDevRandom() */
00154 
00155 static size_t GetDevRandom( void *buf, size_t size )
00156 {
00157     int bytesIn;
00158     int rc;
00159 
00160     rc = PR_CallOnce( &coOpenDevRandom, OpenDevRandom );
00161     if ( PR_FAILURE == rc ) {
00162         _PR_MD_MAP_OPEN_ERROR( errno );
00163         return(0);
00164     }
00165 
00166     bytesIn = read( fdDevRandom, buf, size );
00167     if ( -1 == bytesIn ) {
00168         _PR_MD_MAP_READ_ERROR( errno );
00169         return(0);
00170     }
00171 
00172     return( bytesIn );
00173 } /* end GetDevRandom() */
00174 
00175 static size_t
00176 GetHighResClock(void *buf, size_t maxbytes)
00177 {             
00178     return(GetDevRandom( buf, maxbytes ));
00179 }
00180 
00181 #elif defined(NCR)
00182 
00183 static size_t
00184 GetHighResClock(void *buf, size_t maxbytes)
00185 {
00186     return 0;
00187 }
00188 
00189 #elif defined(IRIX)
00190 #include <fcntl.h>
00191 #undef PRIVATE
00192 #include <sys/mman.h>
00193 #include <sys/syssgi.h>
00194 #include <sys/immu.h>
00195 #include <sys/systeminfo.h>
00196 #include <sys/utsname.h>
00197 
00198 static size_t GetHighResClock(void *buf, size_t maxbuf)
00199 {
00200     unsigned phys_addr, raddr, cycleval;
00201     static volatile unsigned *iotimer_addr = NULL;
00202     static int tries = 0;
00203     static int cntr_size;
00204     int mfd;
00205     unsigned s0[2];
00206 
00207 #ifndef SGI_CYCLECNTR_SIZE
00208 #define SGI_CYCLECNTR_SIZE      165     /* Size user needs to use to read CC */
00209 #endif
00210 
00211     if (iotimer_addr == NULL) {
00212            if (tries++ > 1) {
00213                /* Don't keep trying if it didn't work */
00214                return 0;
00215            }
00216 
00217            /*
00218            ** For SGI machines we can use the cycle counter, if it has one,
00219            ** to generate some truly random numbers
00220            */
00221            phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
00222            if (phys_addr) {
00223                int pgsz = getpagesize();
00224                int pgoffmask = pgsz - 1;
00225 
00226                raddr = phys_addr & ~pgoffmask;
00227                mfd = open("/dev/mmem", O_RDONLY);
00228                if (mfd < 0) {
00229                   return 0;
00230                }
00231                iotimer_addr = (unsigned *)
00232                   mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
00233                if (iotimer_addr == (unsigned*)-1) {
00234                   close(mfd);
00235                       iotimer_addr = NULL;
00236                       return 0;
00237                }
00238                iotimer_addr = (unsigned*)
00239                   ((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
00240                /*
00241                 * The file 'mfd' is purposefully not closed.
00242                 */
00243                cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
00244                if (cntr_size < 0) {
00245                   struct utsname utsinfo;
00246 
00247                       /* 
00248                        * We must be executing on a 6.0 or earlier system, since the
00249                        * SGI_CYCLECNTR_SIZE call is not supported.
00250                        * 
00251                        * The only pre-6.1 platforms with 64-bit counters are
00252                        * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
00253                        */
00254                       uname(&utsinfo);
00255                       if (!strncmp(utsinfo.machine, "IP19", 4) ||
00256                           !strncmp(utsinfo.machine, "IP21", 4))
00257                              cntr_size = 64;
00258                       else
00259                              cntr_size = 32;
00260                }
00261                cntr_size /= 8;     /* Convert from bits to bytes */
00262            }
00263     }
00264 
00265     s0[0] = *iotimer_addr;
00266     if (cntr_size > 4)
00267        s0[1] = *(iotimer_addr + 1);
00268     memcpy(buf, (char *)&s0[0], cntr_size);
00269     return _pr_CopyLowBits(buf, maxbuf, &s0, cntr_size);
00270 }
00271 
00272 #elif defined(SONY)
00273 
00274 static size_t
00275 GetHighResClock(void *buf, size_t maxbytes)
00276 {
00277     return 0;
00278 }
00279 
00280 #elif defined(SNI)
00281 #include <sys/times.h>
00282 
00283 static size_t
00284 GetHighResClock(void *buf, size_t maxbytes)
00285 {
00286     int ticks;
00287     struct tms buffer;
00288 
00289     ticks=times(&buffer);
00290     return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
00291 }
00292 
00293 #elif defined(NEC)
00294 
00295 static size_t
00296 GetHighResClock(void *buf, size_t maxbytes)
00297 {
00298     return 0;
00299 }
00300 #elif defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(NTO) \
00301     || defined(QNX) || defined(DARWIN) || defined(RISCOS)
00302 #include <sys/times.h>
00303 
00304 static size_t
00305 GetHighResClock(void *buf, size_t maxbytes)
00306 {
00307     int ticks;
00308     struct tms buffer;
00309 
00310     ticks=times(&buffer);
00311     return _pr_CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
00312 }
00313 #else
00314 #error! Platform undefined
00315 #endif /* defined(SOLARIS) */
00316 
00317 extern PRSize _PR_MD_GetRandomNoise( void *buf, PRSize size )
00318 {
00319     struct timeval tv;
00320     int n = 0;
00321     int s;
00322 
00323     n += GetHighResClock(buf, size);
00324     size -= n;
00325 
00326     GETTIMEOFDAY(&tv);
00327 
00328     if ( size > 0 ) {
00329         s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_usec, sizeof(tv.tv_usec));
00330         size -= s;
00331         n += s;
00332     }
00333     if ( size > 0 ) {
00334         s = _pr_CopyLowBits((char*)buf+n, size, &tv.tv_sec, sizeof(tv.tv_usec));
00335         size -= s;
00336         n += s;
00337     }
00338 
00339     return n;
00340 } /* end _PR_MD_GetRandomNoise() */