//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1997. // // File: lht.cxx // // Contents: Context handle management for servers // // Classes: // // Functions: // // History: 1-31-97 RichardW Created // //---------------------------------------------------------------------------- #include #include "sht.hxx" #include "lht.hxx" // // Due to the high number of connections for servers, the client context list // for a particular session could grow into the thousands. At that stage, a // linear list that is searched to validate a handle is prohibitively expensive. // // Thus, the faster, if more expensive to set up and add handle package // HP_INITIALIZE_FN LhtInitialize ; HP_CREATE_FN LhtCreate ; HP_DELETE_FN LhtDelete ; HP_ADD_HANDLE_FN LhtAddHandle ; HP_DELETE_HANDLE_FN LhtDeleteHandle ; HP_VALIDATE_HANDLE_FN LhtValidateHandle ; HP_REF_HANDLE_FN LhtRefHandle ; HP_DEREF_HANDLE_KEY_FN LhtDerefHandleKey ; HP_GET_HANDLE_CONTEXT_FN LhtGetHandleContext ; HP_RELEASE_CONTEXT_FN LhtReleaseContext ; HANDLE_PACKAGE LargeHandlePackage = { sizeof( LARGE_HANDLE_TABLE ), LhtInitialize, LhtCreate, LhtDelete, LhtAddHandle, LhtDeleteHandle, LhtValidateHandle, LhtRefHandle, LhtDerefHandleKey, LhtGetHandleContext, LhtReleaseContext }; ULONG LhtFastMem ; ULONG LhtShiftValues[] = { 4, 12, 16, 20 }; #define IndexFromHandle( Level, Handle ) \ ( ( ((PSecHandle) Handle)->dwUpper >> LhtShiftValues[ Level ] ) & HANDLE_TABLE_MASK ) #define LhtLockTable( t ) \ if ( (((PLARGE_HANDLE_TABLE) t)->Flags & LHT_NO_SERIALIZE ) == 0 ) \ { \ RtlEnterCriticalSection( &((PLARGE_HANDLE_TABLE)t)->Lock ); \ } #define LhtUnlockTable( t ) \ if ( (((PLARGE_HANDLE_TABLE) t)->Flags & LHT_NO_SERIALIZE ) == 0 ) \ { \ RtlLeaveCriticalSection( &((PLARGE_HANDLE_TABLE)t)->Lock ); \ } #define LHT_ACTION_ADDREF 0 #define LHT_ACTION_DELREF 1 #define LHT_ACTION_FORCEDEL 2 #define LHT_ACTION_VALIDATE 3 #define LHT_ACTION_ADDHANDLE 4 #define LHT_ACTION_DELHANDLE 5 #define LHT_ACTION_MASK 0x0000FFFF #define LHT_ACTION_LOCKED 0x00010000 #define LHTP_DEREF_NOT_DEL 0x10000000 #define LHTP_HANDLE_CHECKED 0x20000000 //+--------------------------------------------------------------------------- // // Function: LhtInitialize // // Synopsis: Initializes the LHT handle package // // Arguments: (none) // // History: 2-03-97 RichardW Created // // Notes: // //---------------------------------------------------------------------------- BOOL LhtInitialize( VOID ) { return TRUE ; } //+--------------------------------------------------------------------------- // // Function: LhtCreate // // Synopsis: Creates a large handle table. The table is referenced through // the returned pointer // // Arguments: [Flags] -- Flags as defined by handle.hxx // // History: 2-03-97 RichardW Created // // Notes: // //---------------------------------------------------------------------------- PVOID LhtCreate( IN ULONG Flags, IN PVOID HandleTable, IN PHP_ENUM_CALLBACK_FN Callback ) { PLARGE_HANDLE_TABLE Table ; ULONG i; if ( HandleTable ) { Table = (PLARGE_HANDLE_TABLE) HandleTable ; } else { Table = (PLARGE_HANDLE_TABLE) LsapAllocatePrivateHeap( sizeof( LARGE_HANDLE_TABLE ) ); } if ( Table ) { Table->Tag = LHT_TAG ; Table->Flags = 0 ; Table->Flags = (Flags & HANDLE_PACKAGE_GENERAL_FLAGS); if ( Flags & HANDLE_PACKAGE_CALLBACK_ON_DELETE ) { Table->DeleteCallback = Callback ; } else { Table->DeleteCallback = NULL ; } if ( HandleTable ) { Table->Flags |= LHT_NO_FREE ; } Table->Depth = 0 ; if ( ( Flags & LHT_NO_SERIALIZE ) == 0 ) { NTSTATUS Status = RtlInitializeCriticalSection( &Table->Lock ); if (!NT_SUCCESS(Status)) { if ( !HandleTable ) { LsapFreePrivateHeap( Table ); } Table = NULL ; } } } if ( Table ) { for ( i = 0 ; i < HANDLE_TABLE_SIZE ; i++ ) { SmallHandlePackage.Create( Flags | HANDLE_PACKAGE_NO_SERIALIZE, & Table->Lists[i], Callback ); } } return Table ; } //+--------------------------------------------------------------------------- // // Function: LhtpDeleteTable // // Synopsis: Delete table worker function // // Arguments: [Table] -- // [Callback] -- // // History: 4-15-97 RichardW Created // // Notes: // //---------------------------------------------------------------------------- VOID LhtpDeleteTable( PLARGE_HANDLE_TABLE Table, PHP_ENUM_CALLBACK_FN Callback ) { ULONG Index ; PSEC_HANDLE_ENTRY Entry ; PLIST_ENTRY Scan ; LhtLockTable( Table ); for ( Index = 0 ; Index < HANDLE_TABLE_SIZE ; Index++ ) { if ( Table->Lists[Index].Flags & LHT_SUB_TABLE ) { LhtpDeleteTable( (PLARGE_HANDLE_TABLE) Table->Lists[Index].List.Flink, Callback ); } else { SmallHandlePackage.Delete( &Table->Lists[ Index ], Callback ); } } LhtUnlockTable( Table ); if ( (Table->Flags & LHT_NO_SERIALIZE) == 0 ) { RtlDeleteCriticalSection( &Table->Lock ); } if ( ( Table->Flags & LHT_NO_FREE ) == 0 ) { LsapFreePrivateHeap( Table ); } } //+--------------------------------------------------------------------------- // // Function: LhtDelete // // Synopsis: Delete a table // // Arguments: [HandleTable] -- // [Callback] -- // // History: 4-15-97 RichardW Created // // Notes: // //---------------------------------------------------------------------------- BOOL LhtDelete( PVOID HandleTable, PHP_ENUM_CALLBACK_FN Callback ) { PLARGE_HANDLE_TABLE Table ; Table = (PLARGE_HANDLE_TABLE) HandleTable ; LhtLockTable( Table ); Table->Flags |= LHT_DELETE_PENDING ; LhtpDeleteTable( Table, Callback ); return TRUE ; } //+--------------------------------------------------------------------------- // // Function: LhtpFindHandle // // Synopsis: Worker function that grovels a handle table // // Arguments: [HandleTable] -- Table to scan // [Handle] -- handle to search for // [Action] -- action to take on the handle record // // History: 2-03-97 RichardW Created // // Notes: // //---------------------------------------------------------------------------- PSEC_HANDLE_ENTRY LhtpFindHandle( PVOID HandleTable, PSecHandle Handle, ULONG Action, PBOOL Removed, PVOID * FinalTable OPTIONAL ) { PLARGE_HANDLE_TABLE Table ; PSEC_HANDLE_ENTRY Entry ; PLIST_ENTRY Scan ; ULONG Index ; BOOL Locked ; Table = (PLARGE_HANDLE_TABLE) HandleTable ; LhtLockTable( Table ); Entry = NULL ; while ( TRUE ) { Index = (ULONG) IndexFromHandle( Table->Depth, Handle ); if ( Table->Lists[ Index ].Flags & LHT_SUB_TABLE ) { Table = (PLARGE_HANDLE_TABLE) Table->Lists[ Index ].List.Flink ; continue; } Entry = ShtpFindHandle( &Table->Lists[ Index ], Handle, Action, Removed ); if ( FinalTable ) { *FinalTable = &Table->Lists[ Index ] ; } break; } Table = (PLARGE_HANDLE_TABLE) HandleTable ; LhtUnlockTable( Table ); return Entry ; } //+--------------------------------------------------------------------------- // // Function: LhtpConvertSmallToLarge // // Synopsis: Worker to convert small tables to large // // Arguments: [Small] -- // [Large] -- // // History: 7-08-97 RichardW Created // // Notes: // //---------------------------------------------------------------------------- BOOL LhtpConvertSmallToLarge( PSMALL_HANDLE_TABLE Small, PLARGE_HANDLE_TABLE Large ) { ULONG NewIndex ; PSEC_HANDLE_ENTRY Entry ; while ( Entry = ShtpPopHandle( Small ) ) { NewIndex = (ULONG) IndexFromHandle( Large->Depth, &(Entry->Handle) ); ShtpInsertHandle( &Large->Lists[ NewIndex ], Entry ); } return TRUE ; } //+--------------------------------------------------------------------------- // // Function: LhtpExpandTable // // Synopsis: Expands the given index into its own table // // Effects: New table associated with given index // // Arguments: [Table] -- Source table // [Index] -- Source index // // Requires: Table must be write-locked // // History: 1-31-97 RichardW Created // // Notes: // //---------------------------------------------------------------------------- BOOL LhtpExpandTable( PLARGE_HANDLE_TABLE Table, ULONG Index ) { PLARGE_HANDLE_TABLE NewTable ; PLIST_ENTRY List; ULONG NewFlags ; NewFlags = HANDLE_PACKAGE_NO_SERIALIZE ; if ( Table->DeleteCallback ) { NewFlags |= HANDLE_PACKAGE_CALLBACK_ON_DELETE ; } NewTable = (PLARGE_HANDLE_TABLE) LhtCreate( NewFlags | LHT_CHILD, NULL, Table->DeleteCallback ); if ( !NewTable ) { return FALSE ; } NewTable->Depth = Table->Depth + 1 ; NewTable->Parent = Table ; NewTable->IndexOfParent = Index ; LhtpConvertSmallToLarge( &Table->Lists[ Index ], NewTable ); Table->Lists[ Index ].List.Flink = (PLIST_ENTRY) NewTable ; Table->Lists[ Index ].Flags = LHT_SUB_TABLE ; return TRUE ; } //+--------------------------------------------------------------------------- // // Function: LhtConvertSmallToLarge // // Synopsis: Converts a small handle table to a large one // // Arguments: [Small] -- // // History: 7-08-97 RichardW Created // // Notes: // //---------------------------------------------------------------------------- PVOID LhtConvertSmallToLarge( PVOID Small ) { PLARGE_HANDLE_TABLE Large ; PSMALL_HANDLE_TABLE SmallTable = (PSMALL_HANDLE_TABLE) Small ; PULONG Tag ; Tag = (PULONG) Small ; if ( *Tag == LHT_TAG ) { return Small ; } if ( *Tag != SHT_TAG ) { return NULL ; } Large = (PLARGE_HANDLE_TABLE) LhtCreate( (SmallTable->DeleteCallback ? HANDLE_PACKAGE_CALLBACK_ON_DELETE : 0), NULL, SmallTable->DeleteCallback ); if ( Large ) { LhtpConvertSmallToLarge( SmallTable, Large ); ShtDelete( Small, NULL ); return Large ; } return NULL ; } //+--------------------------------------------------------------------------- // // Function: LhtAddHandle // // Synopsis: Add a handle to a handle table // // Arguments: [HandleTable] -- Table to add the handle to // [Handle] -- Handle to add // // History: 2-03-97 RichardW Created // // Notes: // //---------------------------------------------------------------------------- BOOL LhtAddHandle( PVOID HandleTable, PSecHandle Handle, PVOID Context, ULONG Flags ) { PSEC_HANDLE_ENTRY Entry ; PLARGE_HANDLE_TABLE Table ; ULONG Index ; Table = (PLARGE_HANDLE_TABLE) HandleTable ; LhtLockTable( Table ); Entry = LhtpFindHandle( HandleTable, Handle, LHT_ACTION_ADDHANDLE, NULL, NULL ); if ( Entry ) { LhtUnlockTable( Table ); return TRUE ; } // // No entry, need to insert one. // while ( TRUE ) { Index = (ULONG) IndexFromHandle( Table->Depth, Handle ); if ( Table->Lists[ Index ].Flags & LHT_SUB_TABLE ) { Table = (PLARGE_HANDLE_TABLE) Table->Lists[ Index ].List.Flink ; continue; } if(SmallHandlePackage.AddHandle( &Table->Lists[ Index ], Handle, Context, Flags )) { if ( Table->Lists[ Index ].Count > HANDLE_SPLIT_THRESHOLD ) { LhtpExpandTable( Table, Index ); } break; } LhtUnlockTable( (PLARGE_HANDLE_TABLE)HandleTable ); return FALSE; } Table = (PLARGE_HANDLE_TABLE) HandleTable ; Table->Count++; LhtUnlockTable( Table ); return TRUE ; } //+--------------------------------------------------------------------------- // // Function: LhtDeleteHandle // // Synopsis: Delete a handle from the table // // Arguments: [HandleTable] -- Table // [Handle] -- Handle to delete // [Force] -- Force delete, even if handle is not ref'd to zero // // History: 2-03-97 RichardW Created // // Notes: // //---------------------------------------------------------------------------- BOOL LhtDeleteHandle( PVOID HandleTable, PSecHandle Handle, ULONG Options ) { PSEC_HANDLE_ENTRY Entry ; PLARGE_HANDLE_TABLE Table ; BOOL Removed; ULONG Action ; if ( Options & DELHANDLE_FORCE ) { Action = LHT_ACTION_FORCEDEL ; } else if ( Options & LHTP_DEREF_NOT_DEL ) { Action = LHT_ACTION_DELREF | LHTP_HANDLE_CHECKED ; } else { Action = LHT_ACTION_DELHANDLE ; } Entry = LhtpFindHandle( HandleTable, Handle, Action, &Removed, NULL ); if ( Entry ) { if ( Removed ) { Table = (PLARGE_HANDLE_TABLE) HandleTable ; LhtLockTable( Table ); Table->Count--; LhtUnlockTable( Table ); if ( (Table->DeleteCallback) && ((Options & DELHANDLE_NO_CALLBACK) == 0 ) && ((Entry->Flags & SEC_HANDLE_FLAG_NO_CALLBACK ) == 0 ) ) { Table->DeleteCallback( &Entry->Handle, Entry->Context, Entry->HandleIssuedCount // Entry->RefCount ); } if ( ( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING ) == 0 ) { LsapFreePrivateHeap( Entry ); } } return TRUE ; } return FALSE ; } //+--------------------------------------------------------------------------- // // Function: LhtValidateHandle // // Synopsis: Validate that a handle is within the table // // Arguments: [HandleTable] -- // [Handle] -- // // History: 2-03-97 RichardW Created // // Notes: // //---------------------------------------------------------------------------- BOOL LhtValidateHandle( PVOID HandleTable, PSecHandle Handle, BOOL Deref ) { PSEC_HANDLE_ENTRY Entry ; PLARGE_HANDLE_TABLE Table ; BOOL Removed ; Entry = LhtpFindHandle( HandleTable, Handle, (Deref ? LHT_ACTION_DELHANDLE : LHT_ACTION_VALIDATE), &Removed, NULL ); if ( Entry ) { if ( Removed ) { Table = (PLARGE_HANDLE_TABLE) HandleTable ; LhtLockTable( Table ); Table->Count--; LhtUnlockTable( Table ); if ( ( Table->DeleteCallback ) && ( ( Entry->Flags & SEC_HANDLE_FLAG_NO_CALLBACK) == 0 ) ) { Table->DeleteCallback( &Entry->Handle, Entry->Context, Entry->HandleIssuedCount // Entry->RefCount ); } if ( ( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING ) == 0 ) { LsapFreePrivateHeap( Entry ); } } return TRUE ; } else { return FALSE ; } } PVOID LhtRefHandle( PVOID HandleTable, PSecHandle Handle ) { PSEC_HANDLE_ENTRY Entry ; Entry = LhtpFindHandle( HandleTable, Handle, LHT_ACTION_ADDREF, NULL, NULL ); return Entry ; } VOID LhtDerefHandleKey( PVOID HandleTable, PVOID HandleKey ) { PSEC_HANDLE_ENTRY Entry = (PSEC_HANDLE_ENTRY) HandleKey ; LhtDeleteHandle( HandleTable, &Entry->Handle, LHTP_DEREF_NOT_DEL ); } PVOID LhtGetHandleContext( PVOID HandleTable, PSecHandle Handle ) { PSEC_HANDLE_ENTRY Entry ; Entry = LhtpFindHandle( HandleTable, Handle, LHT_ACTION_ADDREF, NULL, NULL ); if ( Entry ) { return Entry->Context ; } else { return NULL ; } } BOOL LhtReleaseContext( PVOID HandleTable, PSecHandle Handle ) { PSEC_HANDLE_ENTRY Entry ; PLARGE_HANDLE_TABLE Table ; BOOL Removed; Entry = LhtpFindHandle( HandleTable, Handle, LHT_ACTION_DELREF, &Removed, NULL ); if ( Entry ) { if ( Removed ) { Table = (PLARGE_HANDLE_TABLE) HandleTable ; LhtLockTable( Table ); Table->Count--; LhtUnlockTable( Table ); if ( ( Table->DeleteCallback ) && ( ( Entry->Flags & SEC_HANDLE_FLAG_NO_CALLBACK ) == 0 ) ) { Table->DeleteCallback( &Entry->Handle, Entry->Context, Entry->RefCount ); } if ( ( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING ) == 0 ) { LsapFreePrivateHeap( Entry ); } } return TRUE ; } return FALSE ; }