Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

738 lines
26 KiB

  1. /*
  2. * gennt.c v0.14 May 15, 1996
  3. *
  4. ****************************************************************************
  5. * *
  6. * (C) Copyright 1995 DIGITAL EQUIPMENT CORPORATION *
  7. * *
  8. * This software is an unpublished work protected under the *
  9. * the copyright laws of the United States of America, all *
  10. * rights reserved. *
  11. * *
  12. * In the event this software is licensed for use by the United *
  13. * States Government, all use, duplication or disclosure by the *
  14. * United States Government is subject to restrictions as set *
  15. * forth in either subparagraph (c)(1)(ii) of the Rights in *
  16. * Technical Data And Computer Software Clause at DFARS *
  17. * 252.227-7013, or the Commercial Computer Software Restricted *
  18. * Rights Clause at FAR 52.221-19, whichever is applicable. *
  19. * *
  20. ****************************************************************************
  21. *
  22. * Facility:
  23. *
  24. * SNMP Extension Agent
  25. *
  26. * Abstract:
  27. *
  28. * This module contains the code for dealing with the generic logic for
  29. * processing the SNMP request. It is table driven. No user modification
  30. * should be done.
  31. *
  32. * Functions:
  33. *
  34. * ResolveVarBind()
  35. * FindClass()
  36. * ResolveGetNext()
  37. *
  38. * Author:
  39. * Miriam Amos Nihart, Kathy Faust
  40. *
  41. * Date:
  42. * 2/17/95
  43. *
  44. * Revision History:
  45. * 6/22/95 krw0001 FindClass - modify to stop checking for valid variable - we only care about valid
  46. * class.
  47. * Rewrite ResolveGetNext
  48. * 6/26/95 ags FindClass - stop checking for valid variable
  49. * Rewrite ResolveGetNext
  50. * 7/31/95 ags SNMP_oidfree works with CRTDLL.lib, hence use them.
  51. * 2/14/96 ags v0.11 one fix for the getnext bug found by Cindy
  52. * 3/19/96 kff v0.12 modified for trap support
  53. * 4/19/96 ags v0.13 Modified to get rid of trap.c in case of no traps.
  54. * 5/15/96 cs v0.14 Modified FindClass in the backward walkthru to tighten
  55. * up the verification
  56. */
  57. #include <windows.h>
  58. #include <malloc.h>
  59. #include <stdio.h>
  60. #include <snmp.h>
  61. #include "mib.h"
  62. #include "mib_xtrn.h"
  63. #include "smint.h"
  64. extern DWORD dwTimeZero ;
  65. UINT
  66. SnmpUtilOidMatch(AsnObjectIdentifier *pOid1, AsnObjectIdentifier *pOid2)
  67. {
  68. unsigned long int nScan = min(pOid1->idLength, pOid2->idLength);
  69. unsigned long int i;
  70. for (i = 0; i < nScan; i++)
  71. {
  72. if (pOid1->ids[i] != pOid2->ids[i])
  73. break;
  74. }
  75. return i;
  76. }
  77. /*
  78. * ResolveVarBind
  79. *
  80. * Resolves a single variable binding. Modifies the variable value pair
  81. * on a GET or a GET-NEXT.
  82. *
  83. * Arguments:
  84. *
  85. * VarBind pointer to the variable value pair
  86. * PduAction type of request - get, set, or getnext
  87. *
  88. * Return Codes:
  89. *
  90. * Standard PDU error codes.
  91. *
  92. */
  93. UINT
  94. ResolveVarBind( IN OUT RFC1157VarBind *VarBind , // Variable Binding to resolve
  95. IN UINT PduAction ) // Action specified in PDU
  96. {
  97. unsigned long int cindex ; // index into the class info table
  98. unsigned long int vindex ; // index into the class's var table
  99. UINT instance_array[ MAX_STRING_LEN ] ;
  100. UINT status ;
  101. UINT result ; // SNMP PDU error status
  102. AsnObjectIdentifier instance ;
  103. InstanceName native_instance ;
  104. instance.ids = instance_array ;
  105. // Determine which class the VarBind is for
  106. status = FindClass( VarBind, &cindex ) ;
  107. if ( status )
  108. {
  109. if ( PduAction != MIB_ACTION_GETNEXT )
  110. {
  111. // Check for valid variable as this is a get or set
  112. CHECK_VARIABLE( VarBind, cindex, vindex, status ) ;
  113. if ( !status )
  114. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  115. // Check for valid instance
  116. status = ( *class_info[ cindex ].FindInstance )
  117. ( (ObjectIdentifier *)&(VarBind->name) ,
  118. (ObjectIdentifier *)&instance ) ;
  119. if ( status != SNMP_ERRORSTATUS_NOERROR )
  120. return status ;
  121. // Check for access
  122. CHECK_ACCESS( cindex, vindex, PduAction, status ) ;
  123. if ( !status )
  124. {
  125. if ( PduAction == MIB_ACTION_SET )
  126. return SNMP_ERRORSTATUS_NOTWRITABLE ;
  127. else
  128. return SNMP_ERRORSTATUS_GENERR ;
  129. }
  130. // Ok to do the get or set
  131. if ( PduAction == MIB_ACTION_GET )
  132. {
  133. status = ( *class_info[ cindex ].ConvertInstance )
  134. ( (ObjectIdentifier *)&instance, &native_instance ) ;
  135. if ( status == FAILURE )
  136. return SNMP_ERRORSTATUS_GENERR ;
  137. result = ( *class_info[ cindex ].variable[ vindex].SMIGet )
  138. ( VarBind , cindex, vindex, &native_instance ) ;
  139. }
  140. else
  141. {
  142. if ( VarBind->value.asnType !=
  143. class_info[ cindex ].variable[ vindex ].type )
  144. return SNMP_ERRORSTATUS_BADVALUE ;
  145. status = ( *class_info[ cindex ].ConvertInstance )
  146. ( (ObjectIdentifier *)&instance, &native_instance ) ;
  147. if ( status == FAILURE )
  148. return SNMP_ERRORSTATUS_GENERR ;
  149. result = ( *class_info[ cindex ].variable[ vindex ].SMISet )
  150. ( VarBind, cindex, vindex, &native_instance ) ;
  151. }
  152. }
  153. else // This is a GETNEXT
  154. {
  155. //
  156. // Call ResolveGetNext() to determine which class, variable, and
  157. // instance to do a Get on.
  158. //
  159. status = ResolveGetNext( VarBind, &cindex, &vindex, &instance ) ;
  160. if ( status == SUCCESS )
  161. {
  162. status = ( *class_info[ cindex ].ConvertInstance )
  163. ( (ObjectIdentifier *)&instance, &native_instance ) ;
  164. if ( status == FAILURE )
  165. return SNMP_ERRORSTATUS_GENERR ;
  166. result = ( *class_info[ cindex ].variable[ vindex ].SMIGet )
  167. ( VarBind, cindex, vindex, &native_instance ) ;
  168. }
  169. else
  170. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  171. }
  172. }
  173. else
  174. {
  175. //
  176. // No class found, but its a GETNEXT.. we need to find the class that has the longest
  177. // with the requested oid and forward the request to it
  178. //
  179. if (PduAction == MIB_ACTION_GETNEXT)
  180. {
  181. unsigned long int ci; // index into the class info table
  182. unsigned long int nLongestMatch; // max number of ids that matched between names
  183. unsigned long int nCurrentMatch; // matching number of IDs at the current iteration
  184. // scan the class_info table, relying on the fact that the table is ordered
  185. // ordered ascendingly on the class OID.
  186. for (ci = 0, nLongestMatch = 0; ci < CLASS_TABLE_MAX; ci++)
  187. {
  188. // pick up the number of matching ids between the VarBind and the class name..
  189. nCurrentMatch = SnmpUtilOidMatch(&VarBind->name, class_info[ci].oid);
  190. // store in cindex the first class with the highest match number
  191. if (nCurrentMatch > nLongestMatch)
  192. {
  193. cindex = ci;
  194. nLongestMatch = nCurrentMatch;
  195. }
  196. }
  197. // only if VarBind name is longer than the match number we need to look
  198. // for an even better match
  199. if (VarBind->name.idLength > nLongestMatch)
  200. {
  201. for (;cindex < CLASS_TABLE_MAX; cindex++)
  202. {
  203. // make sure we don't go over the range with the longest Match
  204. if (SnmpUtilOidMatch(&VarBind->name, class_info[cindex].oid) != nLongestMatch)
  205. break;
  206. // if the class matches entirely into the VarBind name, check if the first ID
  207. // that follows in VarBind name is inside the range supported by the class
  208. if (class_info[cindex].oid->idLength == nLongestMatch)
  209. {
  210. // this is a hack - we rely the var_index is always 1 more than number of ids in
  211. // the class_info name. Since VarBind has already a name longer than nLongestMatch
  212. // no buffer overrun happens here.
  213. // if the VarBind name is in the right range, then we found the class - just break the loop
  214. // (don't forget, var_index is '1' based)
  215. if(VarBind->name.ids[class_info[cindex].var_index - 1] <= class_info[cindex].max_index)
  216. break;
  217. }
  218. else
  219. {
  220. // the VarBind name is longer than the IDs that match, the class_info name is the same
  221. // the first ID that follows in both names can't be equal, so we can break the loop if
  222. // the VarBind name is just in front of it.
  223. if (VarBind->name.ids[nLongestMatch] < class_info[cindex].oid->ids[nLongestMatch])
  224. break;
  225. }
  226. }
  227. }
  228. if (cindex < CLASS_TABLE_MAX )
  229. vindex = class_info[cindex].min_index ;
  230. else
  231. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  232. SNMP_oidfree( &VarBind->name ) ;
  233. SNMP_oidcpy( &VarBind->name ,
  234. class_info[ cindex ].variable[ vindex ].oid ) ;
  235. status = ResolveGetNext( VarBind, &cindex, &vindex, &instance ) ;
  236. if ( status == SUCCESS )
  237. {
  238. status = ( *class_info[ cindex ].ConvertInstance )
  239. ( (ObjectIdentifier *)&instance, &native_instance ) ;
  240. if ( status == FAILURE )
  241. return SNMP_ERRORSTATUS_GENERR ;
  242. result = ( *class_info[ cindex ].variable[ vindex ].SMIGet )
  243. ( VarBind, cindex, vindex, &native_instance ) ;
  244. }
  245. }
  246. else
  247. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  248. }
  249. ( *class_info[ cindex ].FreeInstance )( &native_instance ) ;
  250. return result ;
  251. } /* end of ResolveVarBind() */
  252. /*
  253. * FindClass
  254. *
  255. * This routine determines the class by walking the class_info table
  256. * backwards and comparing the class oids. The table is walked
  257. * backwards because it assumes that the classes are listed in
  258. * increasing order. For example,
  259. *
  260. * Group Name Group Identifier
  261. *
  262. * group1 1.3.6.1.4.1.36.2.78
  263. * table1 1.3.6.1.4.1.36.2.78.9
  264. * table2 1.3.6.1.4.1.36.2.78.10
  265. *
  266. * We need to look for the longest exact match on the oid thus we
  267. * walk the table backwards.
  268. *
  269. * Arguments:
  270. *
  271. * VarBind Variable value pair
  272. * class Index into the class_info
  273. *
  274. * Return Codes:
  275. *
  276. * SUCCESS Class is valid, return index into class_info
  277. * FAILURE Invalid class
  278. *
  279. */
  280. UINT
  281. FindClass( IN RFC1157VarBind *VarBind ,
  282. IN OUT UINT *cindex )
  283. {
  284. int index ;
  285. UINT status, vindex ;
  286. UINT length ;
  287. for ( index = CLASS_TABLE_MAX - 1 ; index >= 0 ; index-- )
  288. {
  289. if ( class_info[ index ].table )
  290. // skip over the entry code -- kkf, why?
  291. // length = class_info[ index ].var_index - 2 ;
  292. length = class_info[ index ].var_index - 1 ;
  293. else
  294. length = class_info[ index ].var_index - 1 ;
  295. status = SNMP_oidncmp( &VarBind->name ,
  296. class_info[ index ].oid ,
  297. length ) ;
  298. // if the oid don't match the class or it is shorter than the
  299. // class go on to the next one.
  300. // If the oid requested is shorter than the class we can't stop
  301. // otherwise we'll point to a wrong (longest match) class.
  302. if (status != 0 ||
  303. VarBind->name.idLength < class_info[ index ].var_index)
  304. continue;
  305. vindex = VarBind->name.ids[ class_info[ index ].var_index - 1 ] ;
  306. // cs - added the vindex verification to make sure that the varbind
  307. // oid definitely belongs in this class (fixed partial table oids)
  308. if ( vindex >= class_info[ index ].min_index &&
  309. vindex <= class_info[ index ].max_index)
  310. {
  311. *cindex = index ;
  312. return SUCCESS ;
  313. }
  314. }
  315. // Failed to match by walking list backwards (longest match)
  316. // so OID supplied is shorter than expected (e.g., partial OID supplied)
  317. // Try matching by forward walking...
  318. for (index = 0; index < CLASS_TABLE_MAX; index++ ) {
  319. status = SNMP_oidncmp( &VarBind->name ,
  320. class_info[ index ].oid ,
  321. VarBind->name.idLength ) ;
  322. if ( status == 0 ) {
  323. *cindex = index ;
  324. return SUCCESS ;
  325. }
  326. }
  327. return FAILURE ;
  328. } /* end of FindClass() */
  329. /*
  330. * ResolveGetNext
  331. *
  332. * Determines the class, the variable and the instance that the
  333. * GetNext request is to be performed on. This is a recursive
  334. * routine. The input arguments VarBind and class may be modified
  335. * as part of the resolution.
  336. *
  337. * The rules for getnext are:
  338. * 1. No instance and no variable specified so return the first
  339. * variable for the first instance.
  340. * 2. No instance specified but a variable is specified so return
  341. * the variable for the first instance.
  342. * 3. An instance and a variable are specified
  343. * Follow 3a,4b for Non Tables
  344. * Follow 3b, 4b, 5b for Tables
  345. *
  346. * 3a.Return the next variable for the instance.
  347. * 4a.An instance and a variable are specified but the variable is the
  348. * last variable in the group so return the first variable for the
  349. * next group.
  350. * If there is no next group return FAILURE.
  351. *
  352. * 3b. Return the variable for the next instance ( walk down the column).
  353. * 4b. Reached the bottom of the column, start at the top of next column.
  354. * 5b. An instance and a variable are specified but it is the last
  355. * variable and the last instace so roll to the next group (class).
  356. * If there is no next group return FAILURE.
  357. *
  358. * Arguments:
  359. *
  360. * VarBind Variable value pair
  361. * cindex Index into the class_info
  362. * vindex address to specify variable for the get
  363. *
  364. * Return Codes:
  365. *
  366. * SUCCESS Able to resolve the request to a class, variable
  367. * and instance
  368. * FAILURE Unable to resolve the request within this MIB
  369. *
  370. */
  371. UINT
  372. ResolveGetNext( IN OUT RFC1157VarBind *VarBind ,
  373. IN OUT UINT *cindex ,
  374. IN OUT UINT *vindex ,
  375. OUT AsnObjectIdentifier *instance )
  376. {
  377. UINT status ;
  378. access_mode_t tmpAccess ;
  379. /*
  380. * We've come in with a pointer to the class, to start with
  381. * Do we have a variable specified?
  382. */
  383. *vindex = 0 ;
  384. if (VarBind->name.idLength < class_info[ *cindex ].var_index ) {
  385. /*
  386. * No variable specified. so pick the first variable (if it exists)
  387. * to start the search for a valid variable.
  388. * If not roll over to the next class.
  389. * Instnace is 0 for non Tables, and the first instance for Tables.
  390. */
  391. if ( class_info[ *cindex ].min_index <= class_info[ *cindex ].max_index) {
  392. *vindex = class_info[ *cindex ].min_index ;
  393. goto StartSearchAt;
  394. } else {
  395. goto BumpClass;
  396. }
  397. } else {
  398. /*
  399. * Yes, a variable is specified.
  400. * If it is below min_index, start testing for a valid variable at the min_index.
  401. * If it is ablove max_index roll over to the next class.
  402. * If we change the variable, Instance is reset to the first (or the only) Instance.
  403. */
  404. *vindex = VarBind->name.ids[ class_info[ *cindex ].var_index - 1 ] ;
  405. if ( *vindex < class_info[ *cindex ].min_index) {
  406. *vindex = class_info[ *cindex ].min_index ;
  407. goto StartSearchAt;
  408. }
  409. if ( *vindex > class_info[ *cindex ].max_index)
  410. goto BumpClass;
  411. /*
  412. * A valid variable for this class is specified. Table & NonTable are treated
  413. * differently.
  414. * In case of Non Tables:
  415. * if instance is specified, we start the serach for a valid variable at the
  416. * next variable.
  417. * if no instnace is specified, we start search at the specified variable.
  418. *
  419. * In case of Tables:
  420. * We may have
  421. * a. No Instance start at the 1st Instance
  422. * b. Partial instance start at the 1st Instance
  423. * c. Invalid instance start at the 1st Instance
  424. * d. Valid Instance start at the next Instance
  425. * All these cases will be handled by the FindNextInstance
  426. * Hence first check that access of the given vaiable, if it is readable
  427. * get the Next Instance. If not start the search for a valid variable at the next
  428. * variable.
  429. */
  430. if ( class_info[ *cindex ].table == NON_TABLE ) {
  431. /* test for the Instance */
  432. if ( VarBind->name.idLength > class_info[ *cindex ].var_index)
  433. (*vindex)++ ;
  434. goto StartSearchAt;
  435. } else {
  436. /* Start Table case */
  437. tmpAccess = class_info[ *cindex ].variable[ *vindex ].access_mode ;
  438. if ( ( tmpAccess == NSM_READ_ONLY ) || (tmpAccess == NSM_READ_WRITE) ) {
  439. /*
  440. * readable Variable, walk down the column
  441. */
  442. status = ( *class_info[ *cindex ].FindNextInstance )
  443. ( (ObjectIdentifier *)&(VarBind->name) ,
  444. (ObjectIdentifier *)instance ) ;
  445. if (status == SNMP_ERRORSTATUS_NOERROR) {
  446. SNMP_oidfree ( &VarBind->name ) ;
  447. SNMP_oidcpy ( &VarBind->name,
  448. class_info[*cindex ].variable[*vindex].oid ) ;
  449. SNMP_oidappend ( &VarBind->name, instance );
  450. return SUCCESS ;
  451. /* we are all done */
  452. }
  453. }
  454. /*
  455. * Either at end of the column, or variable specified is non Readable.
  456. * Hence we need to move to the next column,
  457. * This means we start at the 1st instnace.
  458. */
  459. (*vindex)++ ;
  460. goto StartSearchAt;
  461. /* End Table case */
  462. }
  463. /* end of variable specified case */
  464. }
  465. StartSearchAt:
  466. /*
  467. * We have a start variable in *vindex.
  468. * At this point we are moving to the next column in case of a Table
  469. * Hence if we can't find an NextInstance ( empty Table), move to the
  470. * next class.
  471. */
  472. status = FAILURE;
  473. while ( *vindex <= class_info[ *cindex ].max_index) {
  474. tmpAccess = class_info[ *cindex ].variable[ *vindex ].access_mode ;
  475. if ( ( tmpAccess == NSM_READ_ONLY ) || (tmpAccess == NSM_READ_WRITE) ) {
  476. status = SUCCESS;
  477. break;
  478. } else {
  479. (*vindex)++;
  480. }
  481. }
  482. if ( status == SUCCESS) {
  483. /*
  484. * we hava a valid variable, get the instance
  485. */
  486. SNMP_oidfree ( &VarBind->name ) ;
  487. SNMP_oidcpy ( &VarBind->name, class_info[ *cindex ].variable[*vindex ].oid );
  488. if ( class_info[ *cindex ].table == NON_TABLE) {
  489. instance->ids[ 0 ] = 0 ;
  490. instance->idLength = 1 ;
  491. SNMP_oidappend ( &VarBind->name, instance );
  492. return SUCCESS ;
  493. } else {
  494. status = ( *class_info[ *cindex ].FindNextInstance )
  495. ( (ObjectIdentifier *)&(VarBind->name) ,
  496. (ObjectIdentifier *)instance ) ;
  497. if (status == SNMP_ERRORSTATUS_NOERROR) {
  498. SNMP_oidappend ( &VarBind->name, instance );
  499. return SUCCESS ;
  500. }
  501. }
  502. }
  503. /*
  504. * Come here to move on to the next class
  505. */
  506. BumpClass:
  507. {
  508. (*cindex)++ ;
  509. if ( *cindex >= CLASS_TABLE_MAX)
  510. return FAILURE ;
  511. SNMP_oidfree( &VarBind->name );
  512. SNMP_oidcpy ( &VarBind->name, class_info[ *cindex ].oid );
  513. status = ResolveGetNext( VarBind, cindex, vindex, instance) ;
  514. return status ;
  515. }
  516. // This oughtn't to happen
  517. return FAILURE ;
  518. } /* end of ResolveGetNext() */
  519. #ifndef TRAPS
  520. //
  521. // If there are no traps, TrapInit() is still needed.
  522. // If there are traps, all this code appears in
  523. // generated file trap.c
  524. //
  525. UINT number_of_traps = 0 ;
  526. trap_t
  527. trap_info[] = {
  528. { NULL, 0, 0, 0, NULL }
  529. } ;
  530. extern
  531. trap_t trap_info[] ;
  532. extern
  533. UINT number_of_traps ;
  534. extern HANDLE hEnabledTraps ;
  535. extern HANDLE hTrapQMutex ;
  536. /*
  537. * TrapInit
  538. *
  539. * This routine initializes the trap handle.
  540. *
  541. * Arguments:
  542. *
  543. * hPollForTrapEvent handle for traps - this is used to coordinate
  544. * between the Extendible Agent and this Extension
  545. * Agent.
  546. * - NULL indicates no traps
  547. * - value from CreateEvent() indicates traps
  548. * are implemented and the Extendible agent
  549. * must poll for them
  550. *
  551. * Return Code:
  552. *
  553. * SUCCESS Successful initialization
  554. * FAILURE Unable to initialize
  555. *
  556. |=========================================================================
  557. | There are no Traps associated with the HostMIB. Consequently this
  558. | routine is taken over and used to create a handle to a timer rather
  559. | than an event.
  560. |
  561. | We want to be entered at "SnmpExtensionTrap()" (in "HOSTMIB.C") on
  562. | a periodic interval. When entered, we won't really do any trap processing,
  563. | instead we'll refresh the cached information associated with SNMP
  564. | attribute "hrProcessorLoad" (in "HRPROCES.C") thru a call to function
  565. | "hrProcessLoad_Refresh()" (also in "HRPROCES.C").
  566. |
  567. | So the contents of this standard function is replaced. (Note that the
  568. | "hTrapQMutex" is no longer created).
  569. */
  570. VOID
  571. TrapInit( IN OUT HANDLE *hPollForTrapEvent )
  572. {
  573. #if 0
  574. // The default value for traps is NULL indicating NO traps.
  575. *hPollForTrapEvent = NULL ;
  576. hTrapQMutex = NULL ;
  577. // Call to CreateEvent uses the default security descriptor (therefore
  578. // the handle is not inheritable), flags auto reset (no call to ResetEvent()
  579. // required), flags no signal to be sent at the initial state, and does
  580. // not specify a name for this event.
  581. //
  582. // If the CreateEvent() fails the value returned is NULL so traps
  583. // are not enabled. Otherwise the setting of this event with will cause
  584. // the Extendible Agent to call this Extension Agent's SnmpExtensionTrap
  585. // routine to collect any traps.
  586. *hPollForTrapEvent = CreateEvent( NULL , // Address of security attrib
  587. FALSE , // Flag for manual-reset event
  588. FALSE , // Flag for initial state
  589. NULL ) ; // Address of event-object name
  590. //
  591. // Save the handle in a global variable for use later in setting a trap.
  592. //
  593. hEnabledTraps = *hPollForTrapEvent ;
  594. //
  595. // Create Mutex for assuring single thread access to enque/dequeue on trap_q
  596. hTrapQMutex = CreateMutex( NULL, // Address of security attrib
  597. FALSE, // Mutex is not initially owned
  598. NULL ) ; // Mutex is unnamed
  599. return ;
  600. #endif
  601. /*
  602. |========================
  603. | Special HostMIB code:
  604. */
  605. LARGE_INTEGER due_time; /* When the timer first goes off */
  606. LONG period; /* Frequency: every minute */
  607. BOOL waitable; /* Status from SetWaitable() */
  608. *hPollForTrapEvent = NULL ;
  609. /* Attempt the creation of a waitable timer . . . */
  610. *hPollForTrapEvent = CreateWaitableTimer(NULL, // Security
  611. FALSE, // = Auto-resetting
  612. NULL // = No name
  613. );
  614. /*
  615. | Set a negative due time to mean "relative": We want it to go off
  616. | in 30 seconds. Ticks are 100 ns or 1/10th of a millionth of a second.
  617. |
  618. */
  619. due_time.QuadPart = 10000000 * (-30);
  620. /*
  621. | Set the period in milliseconds to 1 minute.
  622. */
  623. period = 1000 * 60;
  624. /* If we actually managed to create it, start it */
  625. if (*hPollForTrapEvent != NULL) {
  626. waitable =
  627. SetWaitableTimer(*hPollForTrapEvent, // Handle to timer
  628. &due_time, // "Due Time" to go off
  629. period, // Length of period in ms.
  630. NULL, // no completion routine
  631. NULL, // no arg to comp. routine
  632. FALSE // no power-resume in NT
  633. );
  634. }
  635. } /* end of TrapInit() */
  636. #endif /* #ifndef TRAPS */