Did some performance experiments and added code for Barrett reduction.
[libgcrypt.git] / cipher / rndw32.c
1 /* rndw32.c  -  W32 entropy gatherer
2  * Copyright (C) 1999, 2000, 2002, 2003, 2007 Free Software Foundation, Inc.
3  * Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-1999
4  *
5  * This file is part of Libgcrypt.
6  *
7  *************************************************************************
8  * The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann.
9  * Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this
10  * copyright notice:
11  *
12  * This module is part of the cryptlib continuously seeded pseudorandom
13  * number generator.  For usage conditions, see lib_rand.c
14  *
15  * [Here is the notice from lib_rand.c, which is now called dev_sys.c]
16  *
17  * This module and the misc/rnd*.c modules represent the cryptlib
18  * continuously seeded pseudorandom number generator (CSPRNG) as described in
19  * my 1998 Usenix Security Symposium paper "The generation of random numbers
20  * for cryptographic purposes".
21  *
22  * The CSPRNG code is copyright Peter Gutmann (and various others) 1996,
23  * 1997, 1998, 1999, all rights reserved.  Redistribution of the CSPRNG
24  * modules and use in source and binary forms, with or without modification,
25  * are permitted provided that the following conditions are met:
26  *
27  * 1. Redistributions of source code must retain the above copyright notice
28  *    and this permission notice in its entirety.
29  *
30  * 2. Redistributions in binary form must reproduce the copyright notice in
31  *    the documentation and/or other materials provided with the distribution.
32  *
33  * 3. A copy of any bugfixes or enhancements made must be provided to the
34  *    author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the
35  *    baseline version of the code.
36  *
37  * ALTERNATIVELY, the code may be distributed under the terms of the GNU
38  * General Public License, version 2 or any later version published by the
39  * Free Software Foundation, in which case the provisions of the GNU GPL are
40  * required INSTEAD OF the above restrictions.
41  *
42  * Although not required under the terms of the GPL, it would still be nice if
43  * you could make any changes available to the author to allow a consistent
44  * code base to be maintained
45  *************************************************************************
46  */
47
48 #include <config.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <assert.h>
52 #include <errno.h>
53 #include <string.h>
54
55 #include <windows.h>
56
57
58 #include "types.h"
59 #include "g10lib.h"
60 #include "rand-internal.h"
61
62
63 static int debug_me;
64
65 /*
66  * Definitions which are missing from the current GNU Windows32Api
67  */
68
69 #ifndef TH32CS_SNAPHEAPLIST
70 #define TH32CS_SNAPHEAPLIST 1
71 #define TH32CS_SNAPPROCESS  2
72 #define TH32CS_SNAPTHREAD   4
73 #define TH32CS_SNAPMODULE   8
74 #define TH32CS_SNAPALL      (1|2|4|8)
75 #define TH32CS_INHERIT      0x80000000
76 #endif /*TH32CS_SNAPHEAPLIST*/
77
78 #ifndef IOCTL_DISK_PERFORMANCE
79 #define IOCTL_DISK_PERFORMANCE  0x00070020
80 #endif
81 #ifndef VER_PLATFORM_WIN32_WINDOWS
82 #define VER_PLATFORM_WIN32_WINDOWS 1
83 #endif
84
85 /* This used to be (6*8+5*4+8*2), but Peter Gutmann figured a larger
86    value in a newer release. So we use a far larger value. */
87 #define SIZEOF_DISK_PERFORMANCE_STRUCT 256
88
89
90 typedef struct {
91     DWORD dwSize;
92     DWORD th32ProcessID;
93     DWORD th32HeapID;
94     DWORD dwFlags;
95 } HEAPLIST32;
96
97 typedef struct {
98     DWORD dwSize;
99     HANDLE hHandle;
100     DWORD dwAddress;
101     DWORD dwBlockSize;
102     DWORD dwFlags;
103     DWORD dwLockCount;
104     DWORD dwResvd;
105     DWORD th32ProcessID;
106     DWORD th32HeapID;
107 } HEAPENTRY32;
108
109 typedef struct {
110     DWORD dwSize;
111     DWORD cntUsage;
112     DWORD th32ProcessID;
113     DWORD th32DefaultHeapID;
114     DWORD th32ModuleID;
115     DWORD cntThreads;
116     DWORD th32ParentProcessID;
117     LONG  pcPriClassBase;
118     DWORD dwFlags;
119     char  szExeFile[260];
120 } PROCESSENTRY32;
121
122 typedef struct {
123     DWORD dwSize;
124     DWORD cntUsage;
125     DWORD th32ThreadID;
126     DWORD th32OwnerProcessID;
127     LONG  tpBasePri;
128     LONG  tpDeltaPri;
129     DWORD dwFlags;
130 } THREADENTRY32;
131
132 typedef struct {
133     DWORD dwSize;
134     DWORD th32ModuleID;
135     DWORD th32ProcessID;
136     DWORD GlblcntUsage;
137     DWORD ProccntUsage;
138     BYTE  *modBaseAddr;
139     DWORD modBaseSize;
140     HMODULE hModule;
141     char  szModule[256];
142     char  szExePath[260];
143 } MODULEENTRY32;
144
145
146
147 /* Type definitions for function pointers to call Toolhelp32 functions
148  * used with the windows95 gatherer */
149 typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme);
150 typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte);
151 typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe);
152 typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl);
153 typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID,
154                                    DWORD th32HeapID);
155 typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe);
156 typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID);
157
158 /* Type definitions for function pointers to call NetAPI32 functions */
159 typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService,
160                                            DWORD dwLevel, DWORD dwOptions,
161                                            LPBYTE * lpBuffer);
162 typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer);
163 typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer);
164
165
166 /* When we query the performance counters, we allocate an initial buffer and
167  * then reallocate it as required until RegQueryValueEx() stops returning
168  * ERROR_MORE_DATA.  The following values define the initial buffer size and
169  * step size by which the buffer is increased
170  */
171 #define PERFORMANCE_BUFFER_SIZE         65536   /* Start at 64K */
172 #define PERFORMANCE_BUFFER_STEP         16384   /* Step by 16K */
173
174
175 static void
176 slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester )
177 {
178     static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
179     static MODULEWALK pModule32First = NULL;
180     static MODULEWALK pModule32Next = NULL;
181     static PROCESSWALK pProcess32First = NULL;
182     static PROCESSWALK pProcess32Next = NULL;
183     static THREADWALK pThread32First = NULL;
184     static THREADWALK pThread32Next = NULL;
185     static HEAPLISTWALK pHeap32ListFirst = NULL;
186     static HEAPLISTWALK pHeap32ListNext = NULL;
187     static HEAPFIRST pHeap32First = NULL;
188     static HEAPNEXT pHeap32Next = NULL;
189     HANDLE hSnapshot;
190
191
192     /* initialize the Toolhelp32 function pointers */
193     if ( !pCreateToolhelp32Snapshot ) {
194         HANDLE hKernel;
195
196         if ( debug_me )
197             log_debug ("rndw32#slow_gatherer_95: init toolkit\n" );
198
199         /* Obtain the module handle of the kernel to retrieve the addresses
200          * of the Toolhelp32 functions */
201         if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) {
202             log_fatal ( "rndw32: can't get module handle\n" );
203         }
204
205         /* Now get pointers to the functions */
206         pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel,
207                                                   "CreateToolhelp32Snapshot");
208         pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First");
209         pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next");
210         pProcess32First = (PROCESSWALK) GetProcAddress (hKernel,
211                                                         "Process32First");
212         pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel,
213                                                        "Process32Next");
214         pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First");
215         pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next");
216         pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel,
217                                                           "Heap32ListFirst");
218         pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel,
219                                                          "Heap32ListNext");
220         pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First");
221         pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next");
222
223         if (    !pCreateToolhelp32Snapshot
224              || !pModule32First || !pModule32Next
225              || !pProcess32First || !pProcess32Next
226              || !pThread32First  || !pThread32Next
227              || !pHeap32ListFirst || !pHeap32ListNext
228              || !pHeap32First     || !pHeap32Next  ) {
229             log_fatal ( "rndw32: failed to get a toolhelp function\n" );
230         }
231     }
232
233     /* Take a snapshot of everything we can get to which is currently
234      *  in the system */
235     if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) {
236         log_fatal ( "rndw32: failed to take a toolhelp snapshot\n" );
237     }
238
239     /* Walk through the local heap */
240     {   HEAPLIST32 hl32;
241         hl32.dwSize = sizeof (HEAPLIST32);
242         if (pHeap32ListFirst (hSnapshot, &hl32)) {
243             if ( debug_me )
244                 log_debug ("rndw32#slow_gatherer_95: walk heap\n" );
245             do {
246                 HEAPENTRY32 he32;
247
248                 /* First add the information from the basic Heaplist32 struct */
249                 (*add) ( &hl32, sizeof (hl32), requester );
250
251                 /* Now walk through the heap blocks getting information
252                  * on each of them */
253                 he32.dwSize = sizeof (HEAPENTRY32);
254                 if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){
255                     do {
256                         (*add) ( &he32, sizeof (he32), requester );
257                     } while (pHeap32Next (&he32));
258                 }
259             } while (pHeap32ListNext (hSnapshot, &hl32));
260         }
261     }
262
263
264     /* Walk through all processes */
265     {   PROCESSENTRY32 pe32;
266         pe32.dwSize = sizeof (PROCESSENTRY32);
267         if (pProcess32First (hSnapshot, &pe32)) {
268             if ( debug_me )
269                 log_debug ("rndw32#slow_gatherer_95: walk processes\n" );
270             do {
271                 (*add) ( &pe32, sizeof (pe32), requester );
272             } while (pProcess32Next (hSnapshot, &pe32));
273         }
274     }
275
276     /* Walk through all threads */
277     {   THREADENTRY32 te32;
278         te32.dwSize = sizeof (THREADENTRY32);
279         if (pThread32First (hSnapshot, &te32)) {
280             if ( debug_me )
281                 log_debug ("rndw32#slow_gatherer_95: walk threads\n" );
282             do {
283                 (*add) ( &te32, sizeof (te32), requester );
284             } while (pThread32Next (hSnapshot, &te32));
285         }
286     }
287
288     /* Walk through all modules associated with the process */
289     {   MODULEENTRY32 me32;
290         me32.dwSize = sizeof (MODULEENTRY32);
291         if (pModule32First (hSnapshot, &me32)) {
292             if ( debug_me )
293                 log_debug ("rndw32#slow_gatherer_95: walk modules\n" );
294             do {
295                 (*add) ( &me32, sizeof (me32), requester );
296             } while (pModule32Next (hSnapshot, &me32));
297         }
298     }
299
300     CloseHandle (hSnapshot);
301 }
302
303
304
305 static void
306 slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester )
307 {
308     static int is_initialized = 0;
309     static NETSTATISTICSGET pNetStatisticsGet = NULL;
310     static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
311     static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
312     static int is_workstation = 1;
313
314     static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
315     PERF_DATA_BLOCK *pPerfData;
316     HANDLE hDevice, hNetAPI32 = NULL;
317     DWORD dwSize, status;
318     int nDrive;
319
320     if ( !is_initialized ) {
321         HKEY hKey;
322
323         if ( debug_me )
324             log_debug ("rndw32#slow_gatherer_nt: init toolkit\n" );
325         /* Find out whether this is an NT server or workstation if necessary */
326         if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
327                           "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
328                           0, KEY_READ, &hKey) == ERROR_SUCCESS) {
329             BYTE szValue[32];
330             dwSize = sizeof (szValue);
331
332             if ( debug_me )
333                 log_debug ("rndw32#slow_gatherer_nt: check product options\n" );
334             status = RegQueryValueEx (hKey, "ProductType", 0, NULL,
335                                       szValue, &dwSize);
336             if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) {
337                 /* Note: There are (at least) three cases for ProductType:
338                  * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
339                  * NT Server acting as a Domain Controller */
340                 is_workstation = 0;
341                 if ( debug_me )
342                     log_debug ("rndw32: this is a NT server\n");
343             }
344             RegCloseKey (hKey);
345         }
346
347         /* Initialize the NetAPI32 function pointers if necessary */
348         if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) {
349             if ( debug_me )
350                 log_debug ("rndw32#slow_gatherer_nt: netapi32 loaded\n" );
351             pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,
352                                                        "NetStatisticsGet");
353             pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,
354                                                        "NetApiBufferSize");
355             pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,
356                                                        "NetApiBufferFree");
357
358             if ( !pNetStatisticsGet
359                  || !pNetApiBufferSize || !pNetApiBufferFree ) {
360                 FreeLibrary (hNetAPI32);
361                 hNetAPI32 = NULL;
362                 log_debug ("rndw32: No NETAPI found\n" );
363             }
364         }
365
366         is_initialized = 1;
367     }
368
369     /* Get network statistics.  Note: Both NT Workstation and NT Server by
370      * default will be running both the workstation and server services.  The
371      * heuristic below is probably useful though on the assumption that the
372      * majority of the network traffic will be via the appropriate service.
373      * In any case the network statistics return almost no randomness */
374     {   LPBYTE lpBuffer;
375         if (hNetAPI32 && !pNetStatisticsGet (NULL,
376                            is_workstation ? L"LanmanWorkstation" :
377                            L"LanmanServer", 0, 0, &lpBuffer) ) {
378             if ( debug_me )
379                 log_debug ("rndw32#slow_gatherer_nt: get netstats\n" );
380             pNetApiBufferSize (lpBuffer, &dwSize);
381             (*add) ( lpBuffer, dwSize,requester );
382             pNetApiBufferFree (lpBuffer);
383         }
384     }
385
386     /* Get disk I/O statistics for all the hard drives */
387     for (nDrive = 0;; nDrive++) {
388         char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT];
389         char szDevice[50];
390
391         /* Check whether we can access this device */
392         sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive);
393         hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
394                               NULL, OPEN_EXISTING, 0, NULL);
395         if (hDevice == INVALID_HANDLE_VALUE)
396             break;
397
398         /* Note: This only works if you have turned on the disk performance
399          * counters with 'diskperf -y'.  These counters are off by default */
400         if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
401                              diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT,
402                              &dwSize, NULL))
403         {
404             if ( debug_me )
405                 log_debug ("rndw32#slow_gatherer_nt: iostats drive %d\n",
406                                                                   nDrive );
407             (*add) (diskPerformance, dwSize, requester );
408         }
409         else {
410             log_info ("NOTE: you should run 'diskperf -y' "
411                       "to enable the disk statistics\n");
412         }
413         CloseHandle (hDevice);
414     }
415
416 #if 0 /* we don't need this in GnuPG  */
417     /* Wait for any async keyset driver binding to complete.  You may be
418      * wondering what this call is doing here... the reason it's necessary is
419      * because RegQueryValueEx() will hang indefinitely if the async driver
420      * bind is in progress.  The problem occurs in the dynamic loading and
421      * linking of driver DLL's, which work as follows:
422      *
423      * hDriver = LoadLibrary( DRIVERNAME );
424      * pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 );
425      * pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 );
426      *
427      * If RegQueryValueEx() is called while the GetProcAddress()'s are in
428      * progress, it will hang indefinitely.  This is probably due to some
429      * synchronisation problem in the NT kernel where the GetProcAddress()
430      * calls affect something like a module reference count or function
431      * reference count while RegQueryValueEx() is trying to take a snapshot
432      * of the statistics, which include the reference counts.  Because of
433      * this, we have to wait until any async driver bind has completed
434      * before we can call RegQueryValueEx() */
435     waitSemaphore (SEMAPHORE_DRIVERBIND);
436 #endif
437
438     /* Get information from the system performance counters.  This can take
439      * a few seconds to do.  In some environments the call to
440      * RegQueryValueEx() can produce an access violation at some random time
441      * in the future, adding a short delay after the following code block
442      * makes the problem go away.  This problem is extremely difficult to
443      * reproduce, I haven't been able to get it to occur despite running it
444      * on a number of machines.  The best explanation for the problem is that
445      * on the machine where it did occur, it was caused by an external driver
446      * or other program which adds its own values under the
447      * HKEY_PERFORMANCE_DATA key.  The NT kernel calls the required external
448      * modules to map in the data, if there's a synchronisation problem the
449      * external module would write its data at an inappropriate moment,
450      * causing the access violation.  A low-level memory checker indicated
451      * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an
452      * interminable number of calls down inside RegQueryValueEx(), was
453      * overwriting memory (it wrote twice the allocated size of a buffer to a
454      * buffer allocated by the NT kernel).  This may be what's causing the
455      * problem, but since it's in the kernel there isn't much which can be
456      * done.
457      *
458      * In addition to these problems the code in RegQueryValueEx() which
459      * estimates the amount of memory required to return the performance
460      * counter information isn't very accurate, since it always returns a
461      * worst-case estimate which is usually nowhere near the actual amount
462      * required.  For example it may report that 128K of memory is required,
463      * but only return 64K of data */
464     {   pPerfData =  gcry_xmalloc (cbPerfData);
465         for (;;) {
466             dwSize = cbPerfData;
467             if ( debug_me )
468                 log_debug ("rndw32#slow_gatherer_nt: get perf data\n" );
469             status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
470                                       NULL, (LPBYTE) pPerfData, &dwSize);
471             if (status == ERROR_SUCCESS) {
472                 if (!memcmp (pPerfData->Signature, L"PERF", 8)) {
473                     (*add) ( pPerfData, dwSize, requester );
474                 }
475                 else
476                     log_debug ( "rndw32: no PERF signature\n");
477                 break;
478             }
479             else if (status == ERROR_MORE_DATA) {
480                 cbPerfData += PERFORMANCE_BUFFER_STEP;
481                 pPerfData = gcry_realloc (pPerfData, cbPerfData);
482             }
483             else {
484                 log_debug ( "rndw32: get performance data problem\n");
485                 break;
486             }
487         }
488         gcry_free (pPerfData);
489     }
490     /* Although this isn't documented in the Win32 API docs, it's necessary
491        to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
492        implicitly opened on the first call to RegQueryValueEx()).  If this
493        isn't done then any system components which provide performance data
494        can't be removed or changed while the handle remains active */
495     RegCloseKey (HKEY_PERFORMANCE_DATA);
496 }
497
498
499 int
500 _gcry_rndw32_gather_random (void (*add)(const void*, size_t,
501                                         enum random_origins),
502                             enum random_origins origin,
503                             size_t length, int level )
504 {
505   static int is_initialized;
506   static int is_windowsNT, has_toolhelp;
507
508
509   if ( !level )
510     return 0;
511   /* We don't differentiate between level 1 and 2 here because there
512      is no internal entropy pool as a scary resource.  It may all work
513      slower, but because our entropy source will never block but
514      deliver some not easy to measure entropy, we assume level 2.  */
515
516   if ( !is_initialized )
517     {
518       OSVERSIONINFO osvi = { sizeof( osvi ) };
519       DWORD platform;
520       
521       GetVersionEx( &osvi );
522       platform = osvi.dwPlatformId;
523       is_windowsNT = platform == VER_PLATFORM_WIN32_NT;
524       has_toolhelp = (platform == VER_PLATFORM_WIN32_WINDOWS
525                       || (is_windowsNT && osvi.dwMajorVersion >= 5));
526
527       if ( platform == VER_PLATFORM_WIN32s ) 
528         log_fatal("can't run on a W32s platform\n" );
529       is_initialized = 1;
530       if ( debug_me )
531         log_debug ("rndw32#gather_random: platform=%d\n", (int)platform );
532     }
533   
534   
535   if ( debug_me )
536     log_debug ("rndw32#gather_random: ori=%d len=%u lvl=%d\n",
537                origin, (unsigned int)length, level );
538   
539   if ( has_toolhelp )
540     slow_gatherer_windows95 ( add, origin );
541   if ( is_windowsNT )
542     slow_gatherer_windowsNT ( add, origin );
543   
544   return 0;
545 }
546
547
548 void
549 _gcry_rndw32_gather_random_fast (void (*add)(const void*, size_t, 
550                                              enum random_origins),
551                                  enum random_origins origin)
552 {
553   static int addedFixedItems = 0;
554   
555   if ( debug_me )
556     log_debug ("rndw32#gather_random_fast: ori=%d\n", origin );
557   
558   /* Get various basic pieces of system information: Handle of active
559      window, handle of window with mouse capture, handle of clipboard
560      owner handle of start of clpboard viewer list, pseudohandle of
561      current process, current process ID, pseudohandle of current
562      thread, current thread ID, handle of desktop window, handle of
563      window with keyboard focus, whether system queue has any events,
564      cursor position for last message, 1 ms time for last message,
565      handle of window with clipboard open, handle of process heap,
566      handle of procs window station, types of events in input queue,
567      and milliseconds since Windows was started.  */
568   
569   {
570     byte buffer[20*sizeof(ulong)], *bufptr;
571
572     bufptr = buffer;
573 #define ADD(f)  do { ulong along = (ulong)(f);                  \
574                      memcpy (bufptr, &along, sizeof (along) );  \
575                      bufptr += sizeof (along);                  \
576                    } while (0)
577
578     ADD ( GetActiveWindow ());
579     ADD ( GetCapture ());
580     ADD ( GetClipboardOwner ());
581     ADD ( GetClipboardViewer ());
582     ADD ( GetCurrentProcess ());
583     ADD ( GetCurrentProcessId ());
584     ADD ( GetCurrentThread ());
585     ADD ( GetCurrentThreadId ());
586     ADD ( GetDesktopWindow ());
587     ADD ( GetFocus ());
588     ADD ( GetInputState ());
589     ADD ( GetMessagePos ());
590     ADD ( GetMessageTime ());
591     ADD ( GetOpenClipboardWindow ());
592     ADD ( GetProcessHeap ());
593     ADD ( GetProcessWindowStation ());
594     ADD ( GetQueueStatus (QS_ALLEVENTS));
595     ADD ( GetTickCount ());
596     
597     assert ( bufptr-buffer < sizeof (buffer) );
598     (*add) ( buffer, bufptr-buffer, origin );
599 #undef ADD
600   }
601
602   /* Get multiword system information: Current caret position, current
603      mouse cursor position.  */
604   {     
605     POINT point;
606     
607     GetCaretPos (&point);
608     (*add) ( &point, sizeof (point), origin );
609     GetCursorPos (&point);
610     (*add) ( &point, sizeof (point), origin );
611   }
612
613   /* Get percent of memory in use, bytes of physical memory, bytes of
614      free physical memory, bytes in paging file, free bytes in paging
615      file, user bytes of address space, and free user bytes.  */
616   {     
617     MEMORYSTATUS memoryStatus;
618
619     memoryStatus.dwLength = sizeof (MEMORYSTATUS);
620     GlobalMemoryStatus (&memoryStatus);
621     (*add) ( &memoryStatus, sizeof (memoryStatus), origin );
622   }
623
624   /* Get thread and process creation time, exit time, time in kernel
625      mode, and time in user mode in 100ns intervals.  */
626   {
627     HANDLE handle;
628     FILETIME creationTime, exitTime, kernelTime, userTime;
629     DWORD minimumWorkingSetSize, maximumWorkingSetSize;
630
631     handle = GetCurrentThread ();
632     GetThreadTimes (handle, &creationTime, &exitTime,
633                     &kernelTime, &userTime);
634     (*add) ( &creationTime, sizeof (creationTime), origin );
635     (*add) ( &exitTime, sizeof (exitTime), origin );
636     (*add) ( &kernelTime, sizeof (kernelTime), origin );
637     (*add) ( &userTime, sizeof (userTime), origin );
638     
639     handle = GetCurrentProcess ();
640     GetProcessTimes (handle, &creationTime, &exitTime,
641                      &kernelTime, &userTime);
642     (*add) ( &creationTime, sizeof (creationTime), origin );
643     (*add) ( &exitTime, sizeof (exitTime), origin );
644     (*add) ( &kernelTime, sizeof (kernelTime), origin );
645     (*add) ( &userTime, sizeof (userTime), origin );
646     
647     /* Get the minimum and maximum working set size for the current
648        process.  */
649     GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,
650                               &maximumWorkingSetSize);
651     (*add) ( &minimumWorkingSetSize,
652              sizeof (minimumWorkingSetSize), origin );
653     (*add) ( &maximumWorkingSetSize,
654              sizeof (maximumWorkingSetSize), origin );
655   }
656   
657
658   /* The following are fixed for the lifetime of the process so we only
659    * add them once */
660   if (!addedFixedItems)
661     {
662       STARTUPINFO startupInfo;
663
664       /* Get name of desktop, console window title, new window
665          position and size, window flags, and handles for stdin,
666          stdout, and stderr.  */
667       startupInfo.cb = sizeof (STARTUPINFO);
668       GetStartupInfo (&startupInfo);
669       (*add) ( &startupInfo, sizeof (STARTUPINFO), origin );
670       addedFixedItems = 1;
671     }
672
673   /* The performance of QPC varies depending on the architecture it's
674      running on and on the OS.  Under NT it reads the CPU's 64-bit
675      timestamp counter (at least on a Pentium and newer '486's, it
676      hasn't been tested on anything without a TSC), under Win95 it
677      reads the 1.193180 MHz PIC timer.  There are vague mumblings in
678      the docs that it may fail if the appropriate hardware isn't
679      available (possibly '386's or MIPS machines running NT), but
680      who's going to run NT on a '386?.  */
681   {     
682     LARGE_INTEGER performanceCount;
683     
684     if (QueryPerformanceCounter (&performanceCount))
685       {
686         if ( debug_me )
687           log_debug ("rndw32#gather_random_fast: perf data\n");
688         (*add) (&performanceCount, sizeof (performanceCount), origin);
689       }
690     else
691       { 
692         /* Millisecond accuracy at best... */
693         DWORD aword = GetTickCount ();
694         (*add) (&aword, sizeof (aword), origin );
695       }
696   }
697 }
698