| // |
| // Copyright (c) Microsoft. All rights reserved. |
| // Licensed under the MIT license. See LICENSE file in the project root for full license information. |
| // |
| |
| /*++ |
| |
| |
| |
| Module Name: |
| |
| shmobjectmgr.cpp |
| |
| Abstract: |
| Shared memory based object manager |
| |
| |
| |
| --*/ |
| |
| #include "shmobjectmanager.hpp" |
| #include "shmobject.hpp" |
| #include "pal/cs.hpp" |
| #include "pal/thread.hpp" |
| #include "pal/procobj.hpp" |
| #include "pal/dbgmsg.h" |
| |
| SET_DEFAULT_DEBUG_CHANNEL(PAL); |
| |
| #include "pal/corunix.inl" |
| |
| using namespace CorUnix; |
| |
| IPalObjectManager * CorUnix::g_pObjectManager; |
| |
| static |
| PAL_ERROR |
| CheckObjectTypeAndRights( |
| IPalObject *pobj, |
| CAllowedObjectTypes *paot, |
| DWORD dwRightsGranted, |
| DWORD dwRightsRequired |
| ); |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::Initialize |
| |
| Performs (possibly failing) startup tasks for the object manager |
| |
| Parameters: |
| None |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::Initialize( |
| void |
| ) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| |
| ENTRY("CSharedMemoryObjectManager::Initialize (this=%p)\n", this); |
| |
| InitializeListHead(&m_leNamedObjects); |
| InitializeListHead(&m_leAnonymousObjects); |
| |
| InternalInitializeCriticalSection(&m_csListLock); |
| m_fListLockInitialized = TRUE; |
| |
| palError = m_HandleManager.Initialize(); |
| |
| LOGEXIT("CSharedMemoryObjectManager::Initialize returns %d", palError); |
| |
| return palError; |
| } |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::Shutdown |
| |
| Cleans up the object manager. This routine will call cleanup routines |
| for all objects referenced by this process. After this routine is called |
| no attempt should be made to access an IPalObject. |
| |
| Parameters: |
| pthr -- thread data for calling thread |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::Shutdown( |
| CPalThread *pthr |
| ) |
| { |
| PLIST_ENTRY ple; |
| CSharedMemoryObject *pshmobj; |
| |
| _ASSERTE(NULL != pthr); |
| |
| ENTRY("CSharedMemoryObjectManager::Shutdown (this=%p, pthr=%p)\n", |
| this, |
| pthr |
| ); |
| |
| InternalEnterCriticalSection(pthr, &m_csListLock); |
| SHMLock(); |
| |
| while (!IsListEmpty(&m_leAnonymousObjects)) |
| { |
| ple = RemoveTailList(&m_leAnonymousObjects); |
| pshmobj = CSharedMemoryObject::GetObjectFromListLink(ple); |
| pshmobj->CleanupForProcessShutdown(pthr); |
| } |
| |
| while (!IsListEmpty(&m_leNamedObjects)) |
| { |
| ple = RemoveTailList(&m_leNamedObjects); |
| pshmobj = CSharedMemoryObject::GetObjectFromListLink(ple); |
| pshmobj->CleanupForProcessShutdown(pthr); |
| } |
| |
| SHMRelease(); |
| InternalLeaveCriticalSection(pthr, &m_csListLock); |
| |
| LOGEXIT("CSharedMemoryObjectManager::Shutdown returns %d\n", NO_ERROR); |
| |
| return NO_ERROR; |
| } |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::AllocateObject |
| |
| Allocates a new object instance of the specified type. |
| |
| Parameters: |
| pthr -- thread data for calling thread |
| pot -- type of object to allocate |
| poa -- attributes (name and SD) of object to allocate |
| ppobjNew -- on success, receives a reference to the new object |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::AllocateObject( |
| CPalThread *pthr, |
| CObjectType *pot, |
| CObjectAttributes *poa, |
| IPalObject **ppobjNew // OUT |
| ) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| CSharedMemoryObject *pshmobj = NULL; |
| |
| _ASSERTE(NULL != pthr); |
| _ASSERTE(NULL != pot); |
| _ASSERTE(NULL != poa); |
| _ASSERTE(NULL != ppobjNew); |
| |
| ENTRY("CSharedMemoryObjectManager::AllocateObject " |
| "(this=%p, pthr=%p, pot=%p, poa=%p, ppobjNew=%p)\n", |
| this, |
| pthr, |
| pot, |
| poa, |
| ppobjNew |
| ); |
| |
| if (CObjectType::WaitableObject == pot->GetSynchronizationSupport()) |
| { |
| pshmobj = InternalNew<CSharedMemoryWaitableObject>(pot, &m_csListLock); |
| } |
| else |
| { |
| pshmobj = InternalNew<CSharedMemoryObject>(pot, &m_csListLock); |
| } |
| |
| if (NULL != pshmobj) |
| { |
| palError = pshmobj->Initialize(pthr, poa); |
| if (NO_ERROR == palError) |
| { |
| *ppobjNew = static_cast<IPalObject*>(pshmobj); |
| } |
| } |
| else |
| { |
| ERROR("Unable to allocate pshmobj\n"); |
| palError = ERROR_OUTOFMEMORY; |
| } |
| |
| LOGEXIT("CSharedMemoryObjectManager::AllocateObject returns %d\n", palError); |
| return palError; |
| } |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::RegisterObject |
| |
| Registers a newly-allocated object instance. If the object to be registered |
| has a name, and a previously registered object has the same name the new |
| object will not be registered. |
| |
| Distinguished return values: |
| ERROR_ALREADY_EXISTS -- an object of a compatible type was already registered |
| with the specified name |
| ERROR_INVALID_HANDLE -- an object of an incompatible type was already |
| registered with the specified name |
| |
| Parameters: |
| pthr -- thread data for calling thread |
| pobjToRegister -- the object instance to register. This routine will always |
| call ReleaseReference on this instance |
| paot -- object types that are compatible with the new object instance |
| dwRightsRequested -- requested access rights for the returned handle (ignored) |
| pHandle -- on success, receives a handle to the registered object |
| ppobjRegistered -- on success, receives a reference to the registered object |
| instance. |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::RegisterObject( |
| CPalThread *pthr, |
| IPalObject *pobjToRegister, |
| CAllowedObjectTypes *paot, |
| DWORD dwRightsRequested, |
| HANDLE *pHandle, // OUT |
| IPalObject **ppobjRegistered // OUT |
| ) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| CSharedMemoryObject *pshmobj = static_cast<CSharedMemoryObject*>(pobjToRegister); |
| SHMObjData *psmodNew = NULL; |
| CObjectAttributes *poa; |
| CObjectType *potObj; |
| IPalObject *pobjExisting; |
| BOOL fInherit = FALSE; |
| BOOL fShared = FALSE; |
| |
| _ASSERTE(NULL != pthr); |
| _ASSERTE(NULL != pobjToRegister); |
| _ASSERTE(NULL != paot); |
| _ASSERTE(NULL != pHandle); |
| _ASSERTE(NULL != ppobjRegistered); |
| |
| ENTRY("CSharedMemoryObjectManager::RegisterObject " |
| "(this=%p, pthr=%p, pobjToRegister=%p, paot=%p, " |
| "dwRightsRequested=%d, pHandle=%p, ppobjRegistered=%p)\n", |
| this, |
| pthr, |
| pobjToRegister, |
| paot, |
| dwRightsRequested, |
| pHandle, |
| ppobjRegistered |
| ); |
| |
| poa = pobjToRegister->GetObjectAttributes(); |
| _ASSERTE(NULL != poa); |
| |
| if (NULL != poa->pSecurityAttributes) |
| { |
| fInherit = poa->pSecurityAttributes->bInheritHandle; |
| } |
| |
| potObj = pobjToRegister->GetObjectType(); |
| fShared = (SharedObject == pshmobj->GetObjectDomain()); |
| |
| InternalEnterCriticalSection(pthr, &m_csListLock); |
| |
| if (fShared) |
| { |
| // |
| // We only need to acquire the shared memory lock if this |
| // object is actually shared. |
| // |
| |
| SHMLock(); |
| } |
| |
| if (0 != poa->sObjectName.GetStringLength()) |
| { |
| SHMPTR shmObjectListHead = SHMNULL; |
| |
| // |
| // The object must be shared |
| // |
| |
| _ASSERTE(fShared); |
| |
| // |
| // Check if an object by this name alredy exists |
| // |
| |
| palError = LocateObject( |
| pthr, |
| &poa->sObjectName, |
| paot, |
| &pobjExisting |
| ); |
| |
| if (NO_ERROR == palError) |
| { |
| // |
| // Obtain a new handle to the existing object |
| // |
| |
| palError = ObtainHandleForObject( |
| pthr, |
| pobjExisting, |
| dwRightsRequested, |
| fInherit, |
| NULL, |
| pHandle |
| ); |
| |
| if (NO_ERROR == palError) |
| { |
| // |
| // Transfer object reference to out param |
| // |
| |
| *ppobjRegistered = pobjExisting; |
| palError = ERROR_ALREADY_EXISTS; |
| } |
| else |
| { |
| pobjExisting->ReleaseReference(pthr); |
| } |
| |
| goto RegisterObjectExit; |
| } |
| else if (ERROR_INVALID_NAME != palError) |
| { |
| // |
| // Something different than an object not found error |
| // occurred. This is most likely due to a type conflict. |
| // |
| |
| goto RegisterObjectExit; |
| } |
| |
| // |
| // Insert the object on the named object lists |
| // |
| |
| InsertTailList(&m_leNamedObjects, pshmobj->GetObjectListLink()); |
| |
| psmodNew = SHMPTR_TO_TYPED_PTR(SHMObjData, pshmobj->GetShmObjData()); |
| if (NULL == psmodNew) |
| { |
| ASSERT("Failure to map shared object data\n"); |
| palError = ERROR_INTERNAL_ERROR; |
| goto RegisterObjectExit; |
| } |
| |
| shmObjectListHead = SHMGetInfo(SIID_NAMED_OBJECTS); |
| if (SHMNULL != shmObjectListHead) |
| { |
| SHMObjData *psmodListHead; |
| |
| psmodListHead = SHMPTR_TO_TYPED_PTR(SHMObjData, shmObjectListHead); |
| if (NULL != psmodListHead) |
| { |
| psmodNew->shmNextObj = shmObjectListHead; |
| psmodListHead->shmPrevObj = pshmobj->GetShmObjData(); |
| } |
| else |
| { |
| ASSERT("Failure to map shared object data\n"); |
| palError = ERROR_INTERNAL_ERROR; |
| goto RegisterObjectExit; |
| } |
| } |
| |
| psmodNew->fAddedToList = TRUE; |
| |
| if (!SHMSetInfo(SIID_NAMED_OBJECTS, pshmobj->GetShmObjData())) |
| { |
| ASSERT("Failed to set shared named object list head\n"); |
| palError = ERROR_INTERNAL_ERROR; |
| goto RegisterObjectExit; |
| } |
| } |
| else |
| { |
| // |
| // Place the object on the anonymous object list |
| // |
| |
| InsertTailList(&m_leAnonymousObjects, pshmobj->GetObjectListLink()); |
| } |
| |
| // |
| // Hoist the object's immutable data (if any) into shared memory if |
| // the object is shared |
| // |
| |
| if (fShared && 0 != potObj->GetImmutableDataSize()) |
| { |
| VOID *pvImmutableData; |
| SHMObjData *psmod; |
| |
| palError = pobjToRegister->GetImmutableData(&pvImmutableData); |
| if (NO_ERROR != palError) |
| { |
| ASSERT("Failure to obtain object immutable data\n"); |
| goto RegisterObjectExit; |
| } |
| |
| psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, pshmobj->GetShmObjData()); |
| if (NULL != psmod) |
| { |
| VOID *pvSharedImmutableData = |
| SHMPTR_TO_TYPED_PTR(VOID, psmod->shmObjImmutableData); |
| |
| if (NULL != pvSharedImmutableData) |
| { |
| CopyMemory( |
| pvSharedImmutableData, |
| pvImmutableData, |
| potObj->GetImmutableDataSize() |
| ); |
| } |
| else |
| { |
| ASSERT("Failure to map psmod->shmObjImmutableData\n"); |
| palError = ERROR_INTERNAL_ERROR; |
| goto RegisterObjectExit; |
| } |
| } |
| else |
| { |
| ASSERT("Failure to map pshmobj->GetShmObjData()\n"); |
| palError = ERROR_INTERNAL_ERROR; |
| goto RegisterObjectExit; |
| } |
| } |
| |
| // |
| // Obtain a handle for the new object |
| // |
| |
| palError = ObtainHandleForObject( |
| pthr, |
| pobjToRegister, |
| dwRightsRequested, |
| fInherit, |
| NULL, |
| pHandle |
| ); |
| |
| if (NO_ERROR == palError) |
| { |
| // |
| // Transfer pobjToRegister reference to out param |
| // |
| |
| *ppobjRegistered = pobjToRegister; |
| pobjToRegister = NULL; |
| } |
| |
| RegisterObjectExit: |
| |
| if (fShared) |
| { |
| SHMRelease(); |
| } |
| |
| InternalLeaveCriticalSection(pthr, &m_csListLock); |
| |
| if (NULL != pobjToRegister) |
| { |
| pobjToRegister->ReleaseReference(pthr); |
| } |
| |
| LOGEXIT("CSharedMemoryObjectManager::RegisterObject return %d\n", palError); |
| |
| return palError; |
| } |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::LocateObject |
| |
| Search for a previously registered object with a give name and type |
| |
| Distinguished return values: |
| ERROR_INVALID_NAME -- no object with the specified name was previously |
| registered |
| ERROR_INVALID_HANDLE -- an object with the specified name was previously |
| registered, but its type is not compatible |
| |
| Parameters: |
| pthr -- thread data for calling thread |
| psObjectToLocate -- the name of the object to locate |
| paot -- acceptable types for the object |
| ppobj -- on success, receives a reference to the object instance |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::LocateObject( |
| CPalThread *pthr, |
| CPalString *psObjectToLocate, |
| CAllowedObjectTypes *paot, |
| IPalObject **ppobj // OUT |
| ) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| IPalObject *pobjExisting = NULL; |
| SHMPTR shmSharedObjectData = SHMNULL; |
| SHMPTR shmObjectListEntry = SHMNULL; |
| SHMObjData *psmod = NULL; |
| LPWSTR pwsz = NULL; |
| |
| _ASSERTE(NULL != pthr); |
| _ASSERTE(NULL != psObjectToLocate); |
| _ASSERTE(NULL != psObjectToLocate->GetString()); |
| _ASSERTE(PAL_wcslen(psObjectToLocate->GetString()) == psObjectToLocate->GetStringLength()); |
| _ASSERTE(NULL != ppobj); |
| |
| ENTRY("CSharedMemoryObjectManager::LocateObject " |
| "(this=%p, pthr=%p, psObjectToLocate=%p, paot=%p, " |
| "ppobj=%p)\n", |
| this, |
| pthr, |
| psObjectToLocate, |
| paot, |
| ppobj |
| ); |
| |
| TRACE("Searching for object name %S\n", psObjectToLocate->GetString()); |
| |
| InternalEnterCriticalSection(pthr, &m_csListLock); |
| |
| // |
| // Search the local named object list for this object |
| // |
| |
| for (PLIST_ENTRY ple = m_leNamedObjects.Flink; |
| ple != &m_leNamedObjects; |
| ple = ple->Flink) |
| { |
| CObjectAttributes *poa; |
| CSharedMemoryObject *pshmobj = |
| CSharedMemoryObject::GetObjectFromListLink(ple); |
| |
| poa = pshmobj->GetObjectAttributes(); |
| _ASSERTE(NULL != poa); |
| |
| if (poa->sObjectName.GetStringLength() != psObjectToLocate->GetStringLength()) |
| { |
| continue; |
| } |
| |
| if (0 != PAL_wcscmp(poa->sObjectName.GetString(), psObjectToLocate->GetString())) |
| { |
| continue; |
| } |
| |
| // |
| // This object has the name we're looking for |
| // |
| |
| pobjExisting = static_cast<IPalObject*>(pshmobj); |
| break; |
| } |
| |
| if (NULL != pobjExisting) |
| { |
| // |
| // Validate the located object's type |
| // |
| |
| if (paot->IsTypeAllowed( |
| pobjExisting->GetObjectType()->GetId() |
| )) |
| { |
| TRACE("Local object exists with compatible type\n"); |
| |
| // |
| // Add a reference to the found object |
| // |
| |
| pobjExisting->AddReference(); |
| *ppobj = pobjExisting; |
| } |
| else |
| { |
| TRACE("Local object exists w/ incompatible type\n"); |
| palError = ERROR_INVALID_HANDLE; |
| } |
| |
| goto LocateObjectExit; |
| } |
| |
| // |
| // Search the shared memory named object list for a matching object |
| // |
| |
| SHMLock(); |
| |
| shmObjectListEntry = SHMGetInfo(SIID_NAMED_OBJECTS); |
| while (SHMNULL != shmObjectListEntry) |
| { |
| psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, shmObjectListEntry); |
| if (NULL != psmod) |
| { |
| if (psmod->dwNameLength == psObjectToLocate->GetStringLength()) |
| { |
| pwsz = SHMPTR_TO_TYPED_PTR(WCHAR, psmod->shmObjName); |
| if (NULL != pwsz) |
| { |
| if (0 == PAL_wcscmp(pwsz, psObjectToLocate->GetString())) |
| { |
| // |
| // This is the object we were looking for. |
| // |
| |
| shmSharedObjectData = shmObjectListEntry; |
| break; |
| } |
| } |
| else |
| { |
| ASSERT("Unable to map psmod->shmObjName\n"); |
| break; |
| } |
| } |
| |
| shmObjectListEntry = psmod->shmNextObj; |
| } |
| else |
| { |
| ASSERT("Unable to map shmObjectListEntry\n"); |
| break; |
| } |
| } |
| |
| if (SHMNULL != shmSharedObjectData) |
| { |
| CSharedMemoryObject *pshmobj = NULL; |
| CObjectAttributes oa(pwsz, NULL); |
| |
| // |
| // Check if the type is allowed |
| // |
| |
| if (!paot->IsTypeAllowed(psmod->eTypeId)) |
| { |
| TRACE("Remote object exists w/ incompatible type\n"); |
| palError = ERROR_INVALID_HANDLE; |
| goto LocateObjectExitSHMRelease; |
| } |
| |
| // |
| // Get the local instance of the CObjectType |
| // |
| |
| CObjectType *pot = CObjectType::GetObjectTypeById(psmod->eTypeId); |
| if (NULL == pot) |
| { |
| ASSERT("Invalid object type ID in shared memory info\n"); |
| goto LocateObjectExitSHMRelease; |
| } |
| |
| TRACE("Remote object exists compatible type -- importing\n"); |
| |
| // |
| // Create the local state for the shared object |
| // |
| |
| palError = ImportSharedObjectIntoProcess( |
| pthr, |
| pot, |
| &oa, |
| shmSharedObjectData, |
| psmod, |
| TRUE, |
| &pshmobj |
| ); |
| |
| if (NO_ERROR == palError) |
| { |
| *ppobj = static_cast<IPalObject*>(pshmobj); |
| } |
| else |
| { |
| ERROR("Failure initializing object from shared data\n"); |
| goto LocateObjectExitSHMRelease; |
| } |
| |
| } |
| else |
| { |
| // |
| // The object was not found |
| // |
| |
| palError = ERROR_INVALID_NAME; |
| } |
| |
| LocateObjectExitSHMRelease: |
| |
| SHMRelease(); |
| |
| LocateObjectExit: |
| |
| InternalLeaveCriticalSection(pthr, &m_csListLock); |
| |
| LOGEXIT("CSharedMemoryObjectManager::LocateObject returns %d\n", palError); |
| |
| return palError; |
| } |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::ObtainHandleForObject |
| |
| Allocated a new handle for an object |
| |
| Parameters: |
| pthr -- thread data for calling thread |
| pobj -- the object to allocate a handle for |
| dwRightsRequired -- the access rights to grant the handle; currently ignored |
| fInheritHandle -- true if the handle is inheritable; ignored for all but file |
| objects that represent pipes |
| pProcessForHandle -- the process the handle is to be used from; currently |
| must be NULL |
| pNewHandle -- on success, receives the newly allocated handle |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::ObtainHandleForObject( |
| CPalThread *pthr, |
| IPalObject *pobj, |
| DWORD dwRightsRequested, |
| bool fInheritHandle, |
| IPalProcess *pProcessForHandle, // IN, OPTIONAL |
| HANDLE *pNewHandle // OUT |
| ) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| |
| _ASSERTE(NULL != pthr); |
| _ASSERTE(NULL != pobj); |
| _ASSERTE(NULL != pNewHandle); |
| |
| ENTRY("CSharedMemoryObjectManager::ObtainHandleForObject " |
| "(this=%p, pthr=%p, pobj=%p, dwRightsRequested=%d, " |
| "fInheritHandle=%p, pProcessForHandle=%p, pNewHandle=%p)\n", |
| this, |
| pthr, |
| pobj, |
| dwRightsRequested, |
| fInheritHandle, |
| pProcessForHandle, |
| pNewHandle |
| ); |
| |
| if (NULL != pProcessForHandle) |
| { |
| // |
| // Not yet supported |
| // |
| |
| ASSERT("Caller to ObtainHandleForObject provided a process\n"); |
| return ERROR_CALL_NOT_IMPLEMENTED; |
| } |
| |
| palError = m_HandleManager.AllocateHandle( |
| pthr, |
| pobj, |
| dwRightsRequested, |
| fInheritHandle, |
| pNewHandle |
| ); |
| |
| LOGEXIT("CSharedMemoryObjectManager::ObtainHandleForObject return %d\n", palError); |
| |
| return palError; |
| } |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::RevokeHandle |
| |
| Removes a handle from the process's handle table, which in turn releases |
| the handle's reference on the object instance it refers to |
| |
| Parameters: |
| pthr -- thread data for calling thread |
| hHandleToRevoke -- the handle to revoke |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::RevokeHandle( |
| CPalThread *pthr, |
| HANDLE hHandleToRevoke |
| ) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| |
| _ASSERTE(NULL != pthr); |
| |
| ENTRY("CSharedMemoryObjectManager::RevokeHandle " |
| "(this=%p, pthr=%p, hHandleToRevoke=%p)\n", |
| this, |
| pthr, |
| hHandleToRevoke |
| ); |
| |
| palError = m_HandleManager.FreeHandle(pthr, hHandleToRevoke); |
| |
| LOGEXIT("CSharedMemoryObjectManager::RevokeHandle returns %d\n", palError); |
| |
| return palError; |
| } |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::ReferenceObjectByHandle |
| |
| Returns a referenced object instance that a handle refers to |
| |
| Parameters: |
| pthr -- thread data for calling thread |
| hHandleToReference -- the handle to reference |
| paot -- acceptable types for the underlying object |
| dwRightsRequired -- the access rights that the handle must have been |
| granted; currently ignored |
| ppobj -- on success, receives a reference to the object instance |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::ReferenceObjectByHandle( |
| CPalThread *pthr, |
| HANDLE hHandleToReference, |
| CAllowedObjectTypes *paot, |
| DWORD dwRightsRequired, |
| IPalObject **ppobj // OUT |
| ) |
| { |
| PAL_ERROR palError; |
| DWORD dwRightsGranted; |
| IPalObject *pobj; |
| |
| _ASSERTE(NULL != pthr); |
| _ASSERTE(NULL != paot); |
| _ASSERTE(NULL != ppobj); |
| |
| ENTRY("CSharedMemoryObjectManager::ReferenceObjectByHandle " |
| "(this=%p, pthr=%p, hHandleToReference=%p, paot=%p, " |
| "dwRightsRequired=%d, ppobj=%p)\n", |
| this, |
| pthr, |
| hHandleToReference, |
| paot, |
| dwRightsRequired, |
| ppobj |
| ); |
| |
| palError = m_HandleManager.GetObjectFromHandle( |
| pthr, |
| hHandleToReference, |
| &dwRightsGranted, |
| &pobj |
| ); |
| |
| if (NO_ERROR == palError) |
| { |
| palError = CheckObjectTypeAndRights( |
| pobj, |
| paot, |
| dwRightsGranted, |
| dwRightsRequired |
| ); |
| |
| if (NO_ERROR == palError) |
| { |
| // |
| // Transfer object reference to out parameter |
| // |
| |
| *ppobj = pobj; |
| } |
| else |
| { |
| pobj->ReleaseReference(pthr); |
| } |
| } |
| |
| LOGEXIT("CSharedMemoryObjectManager::ReferenceObjectByHandle returns %d\n", |
| palError |
| ); |
| |
| return palError; |
| } |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::ReferenceObjectByHandleArray |
| |
| Returns the referenced object instances that an array of handles |
| refer to. |
| |
| Parameters: |
| pthr -- thread data for calling thread |
| rgHandlesToReference -- the array of handles to reference |
| dwHandleCount -- the number of handles in the arrayu |
| paot -- acceptable types for the underlying objects |
| dwRightsRequired -- the access rights that the handles must have been |
| granted; currently ignored |
| rgpobjs -- on success, receives references to the object instances; will |
| be empty on failures |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::ReferenceMultipleObjectsByHandleArray( |
| CPalThread *pthr, |
| HANDLE rghHandlesToReference[], |
| DWORD dwHandleCount, |
| CAllowedObjectTypes *paot, |
| DWORD dwRightsRequired, |
| IPalObject *rgpobjs[] // OUT (caller allocated) |
| ) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| IPalObject *pobj = NULL; |
| DWORD dwRightsGranted; |
| DWORD dw; |
| |
| _ASSERTE(NULL != pthr); |
| _ASSERTE(NULL != rghHandlesToReference); |
| _ASSERTE(0 < dwHandleCount); |
| _ASSERTE(NULL != paot); |
| _ASSERTE(NULL != rgpobjs); |
| |
| ENTRY("CSharedMemoryObjectManager::ReferenceMultipleObjectsByHandleArray " |
| "(this=%p, pthr=%p, rghHandlesToReference=%p, dwHandleCount=%d, " |
| "pAllowedTyped=%d, dwRightsRequired=%d, rgpobjs=%p)\n", |
| this, |
| pthr, |
| rghHandlesToReference, |
| dwHandleCount, |
| paot, |
| dwRightsRequired, |
| rgpobjs |
| ); |
| |
| m_HandleManager.Lock(pthr); |
| |
| for (dw = 0; dw < dwHandleCount; dw += 1) |
| { |
| palError = m_HandleManager.GetObjectFromHandle( |
| pthr, |
| rghHandlesToReference[dw], |
| &dwRightsGranted, |
| &pobj |
| ); |
| |
| if (NO_ERROR == palError) |
| { |
| palError = CheckObjectTypeAndRights( |
| pobj, |
| paot, |
| dwRightsGranted, |
| dwRightsRequired |
| ); |
| |
| if (NO_ERROR == palError) |
| { |
| // |
| // Transfer reference to out array |
| // |
| |
| rgpobjs[dw] = pobj; |
| pobj = NULL; |
| } |
| } |
| |
| if (NO_ERROR != palError) |
| { |
| break; |
| } |
| } |
| |
| // |
| // The handle manager lock must be released before releasing |
| // any object references, as ReleaseReference will acquire |
| // the object manager list lock (which needs to be acquired before |
| // the handle manager lock) |
| // |
| |
| m_HandleManager.Unlock(pthr); |
| |
| if (NO_ERROR != palError) |
| { |
| // |
| // dw's current value is the failing index, so we want |
| // to free from dw - 1. |
| // |
| |
| while (dw > 0) |
| { |
| rgpobjs[--dw]->ReleaseReference(pthr); |
| } |
| |
| if (NULL != pobj) |
| { |
| pobj->ReleaseReference(pthr); |
| } |
| } |
| |
| LOGEXIT("CSharedMemoryObjectManager::ReferenceMultipleObjectsByHandleArray" |
| " returns %d\n", |
| palError |
| ); |
| |
| return palError; |
| } |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::ReferenceObjectByForeignHandle |
| |
| Returns a referenced object instance that a handle belongin to |
| another process refers to; currently unimplemented |
| |
| Parameters: |
| pthr -- thread data for calling thread |
| hForeignHandle -- the handle to reference |
| pForeignProcess -- the process that hForeignHandle belongs to |
| paot -- acceptable types for the underlying object |
| dwRightsRequired -- the access rights that the handle must have been |
| granted; currently ignored |
| ppobj -- on success, receives a reference to the object instance |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::ReferenceObjectByForeignHandle( |
| CPalThread *pthr, |
| HANDLE hForeignHandle, |
| IPalProcess *pForeignProcess, |
| CAllowedObjectTypes *paot, |
| DWORD dwRightsRequired, |
| IPalObject **ppobj // OUT |
| ) |
| { |
| // |
| // Not implemented for basic shared memory object manager -- |
| // requires an IPC channel. (For the shared memory object manager |
| // PAL_LocalHandleToRemote and PAL_RemoteHandleToLocal must still |
| // be used...) |
| // |
| |
| ASSERT("ReferenceObjectByForeignHandle not yet supported\n"); |
| return ERROR_CALL_NOT_IMPLEMENTED; |
| } |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::ImportSharedObjectIntoProcess |
| |
| Takes an object's shared memory data and from it creates the |
| necessary in-process structures for the object |
| |
| Parameters: |
| pthr -- thread data for calling thread |
| pot -- the object's type |
| poa -- attributes for the object |
| shmSharedObjectData -- the shared memory pointer for the object's shared |
| data |
| psmod -- the shared memory data for the object, mapped into this process's |
| address space |
| fAddRefSharedData -- if TRUE, we need to add to the shared data reference |
| count |
| ppshmobj -- on success, receives a pointer to the newly created local |
| object instance |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::ImportSharedObjectIntoProcess( |
| CPalThread *pthr, |
| CObjectType *pot, |
| CObjectAttributes *poa, |
| SHMPTR shmSharedObjectData, |
| SHMObjData *psmod, |
| bool fAddRefSharedData, |
| CSharedMemoryObject **ppshmobj |
| ) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| CSharedMemoryObject *pshmobj; |
| PLIST_ENTRY pleObjectList; |
| |
| _ASSERTE(NULL != pthr); |
| _ASSERTE(NULL != pot); |
| _ASSERTE(NULL != poa); |
| _ASSERTE(SHMNULL != shmSharedObjectData); |
| _ASSERTE(NULL != psmod); |
| _ASSERTE(NULL != ppshmobj); |
| |
| ENTRY("CSharedMemoryObjectManager::ImportSharedObjectIntoProcess(pthr=%p, " |
| "pot=%p, poa=%p, shmSharedObjectData=%p, psmod=%p, fAddRefSharedData=%d, " |
| "ppshmobj=%p)\n", |
| pthr, |
| pot, |
| poa, |
| shmSharedObjectData, |
| psmod, |
| fAddRefSharedData, |
| ppshmobj |
| ); |
| |
| if (CObjectType::WaitableObject == pot->GetSynchronizationSupport()) |
| { |
| pshmobj = InternalNew<CSharedMemoryWaitableObject>(pot, |
| &m_csListLock, |
| shmSharedObjectData, |
| psmod, |
| fAddRefSharedData); |
| } |
| else |
| { |
| pshmobj = InternalNew<CSharedMemoryObject>(pot, |
| &m_csListLock, |
| shmSharedObjectData, |
| psmod, |
| fAddRefSharedData); |
| } |
| |
| if (NULL != pshmobj) |
| { |
| palError = pshmobj->InitializeFromExistingSharedData(pthr, poa); |
| if (NO_ERROR == palError) |
| { |
| if (0 != psmod->dwNameLength) |
| { |
| pleObjectList = &m_leNamedObjects; |
| } |
| else |
| { |
| pleObjectList = &m_leAnonymousObjects; |
| } |
| |
| InsertTailList(pleObjectList, pshmobj->GetObjectListLink()); |
| } |
| else |
| { |
| goto ImportSharedObjectIntoProcessExit; |
| } |
| } |
| else |
| { |
| ERROR("Unable to alllocate new object\n"); |
| palError = ERROR_OUTOFMEMORY; |
| goto ImportSharedObjectIntoProcessExit; |
| } |
| |
| *ppshmobj = pshmobj; |
| |
| ImportSharedObjectIntoProcessExit: |
| |
| LOGEXIT("CSharedMemoryObjectManager::ImportSharedObjectIntoProcess returns %d\n", palError); |
| |
| return palError; |
| } |
| |
| static PalObjectTypeId RemotableObjectTypes[] = |
| {otiManualResetEvent, otiAutoResetEvent, otiMutex, otiProcess}; |
| |
| static CAllowedObjectTypes aotRemotable PAL_GLOBAL ( |
| RemotableObjectTypes, |
| sizeof(RemotableObjectTypes) / sizeof(RemotableObjectTypes[0]) |
| ); |
| |
| /*++ |
| Function: |
| PAL_LocalHandleToRemote |
| |
| Returns a "remote handle" that may be passed to another process. |
| |
| Parameters: |
| hLocal -- the handle to generate a "remote handle" for |
| --*/ |
| |
| PALIMPORT |
| RHANDLE |
| PALAPI |
| PAL_LocalHandleToRemote(IN HANDLE hLocal) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| CPalThread *pthr; |
| IPalObject *pobj = NULL; |
| CSharedMemoryObject *pshmobj; |
| SHMObjData *psmod = NULL; |
| RHANDLE hRemote = reinterpret_cast<RHANDLE>(INVALID_HANDLE_VALUE); |
| |
| PERF_ENTRY(PAL_LocalHandleToRemote); |
| ENTRY("PAL_LocalHandleToRemote( hLocal=0x%lx )\n", hLocal); |
| |
| pthr = InternalGetCurrentThread(); |
| |
| if (!HandleIsSpecial(hLocal)) |
| { |
| palError = g_pObjectManager->ReferenceObjectByHandle( |
| pthr, |
| hLocal, |
| &aotRemotable, |
| 0, |
| &pobj |
| ); |
| |
| if (NO_ERROR != palError) |
| { |
| goto PAL_LocalHandleToRemoteExitNoLockRelease; |
| } |
| } |
| else if (hPseudoCurrentProcess == hLocal) |
| { |
| pobj = g_pobjProcess; |
| pobj->AddReference(); |
| } |
| else |
| { |
| ASSERT("Invalid special handle type passed to PAL_LocalHandleToRemote\n"); |
| palError = ERROR_INVALID_HANDLE; |
| goto PAL_LocalHandleToRemoteExitNoLockRelease; |
| } |
| |
| pshmobj = static_cast<CSharedMemoryObject*>(pobj); |
| |
| // |
| // Make sure that the object is shared |
| // |
| |
| palError = pshmobj->EnsureObjectIsShared(pthr); |
| if (NO_ERROR != palError) |
| { |
| ERROR("Failure %d promoting object\n", palError); |
| goto PAL_LocalHandleToRemoteExitNoLockRelease; |
| } |
| |
| SHMLock(); |
| |
| psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, pshmobj->GetShmObjData()); |
| if (NULL != psmod) |
| { |
| // |
| // Bump up the process ref count by 1. The receiving process will not |
| // increase the ref count when it converts the remote handle to |
| // local. |
| // |
| |
| psmod->lProcessRefCount += 1; |
| |
| // |
| // The remote handle is simply the SHMPTR for the SHMObjData |
| // |
| |
| hRemote = reinterpret_cast<RHANDLE>(pshmobj->GetShmObjData()); |
| } |
| else |
| { |
| ASSERT("Unable to map shared object data\n"); |
| palError = ERROR_INTERNAL_ERROR; |
| goto PAL_LocalHandleToRemoteExit; |
| } |
| |
| PAL_LocalHandleToRemoteExit: |
| |
| SHMRelease(); |
| |
| PAL_LocalHandleToRemoteExitNoLockRelease: |
| |
| if (NULL != pobj) |
| { |
| pobj->ReleaseReference(pthr); |
| } |
| |
| if (NO_ERROR != palError) |
| { |
| pthr->SetLastError(palError); |
| } |
| |
| LOGEXIT("PAL_LocalHandleToRemote returns RHANDLE 0x%lx\n", hRemote); |
| PERF_EXIT(PAL_LocalHandleToRemote); |
| return hRemote; |
| } |
| |
| /*++ |
| Function: |
| CSharedMemoryObjectManager::ConvertRemoteHandleToLocal |
| |
| Given a "remote handle" creates a local handle that refers |
| to the desired object. (Unlike PAL_RemoteHandleToLocal this method |
| needs to access internal object manager state, so it's a member function.) |
| |
| Parameters: |
| pthr -- thread data for calling thread |
| rhRemote -- the remote handle |
| phLocal -- on success, receives the local handle |
| --*/ |
| |
| PAL_ERROR |
| CSharedMemoryObjectManager::ConvertRemoteHandleToLocal( |
| CPalThread *pthr, |
| RHANDLE rhRemote, |
| HANDLE *phLocal |
| ) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| SHMObjData *psmod; |
| CSharedMemoryObject *pshmobj = NULL; |
| PLIST_ENTRY pleObjectList; |
| |
| _ASSERTE(NULL != pthr); |
| _ASSERTE(NULL != phLocal); |
| |
| ENTRY("CSharedMemoryObjectManager::ConvertRemoteHandleToLocal " |
| "(this=%p, pthr=%p, rhRemote=%p, phLocal=%p)\n", |
| this, |
| pthr, |
| rhRemote, |
| phLocal |
| ); |
| |
| if (rhRemote == NULL || rhRemote == INVALID_HANDLE_VALUE) |
| { |
| palError = ERROR_INVALID_HANDLE; |
| goto ConvertRemoteHandleToLocalExitNoLockRelease; |
| } |
| |
| InternalEnterCriticalSection(pthr, &m_csListLock); |
| SHMLock(); |
| |
| // |
| // The remote handle is really a shared memory pointer to the |
| // SHMObjData for the object. |
| // |
| |
| psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, reinterpret_cast<SHMPTR>(rhRemote)); |
| if (NULL == psmod) |
| { |
| ERROR("Invalid remote handle\n"); |
| palError = ERROR_INVALID_HANDLE; |
| goto ConvertRemoteHandleToLocalExit; |
| } |
| |
| // |
| // Check to see if a local reference for this object already |
| // exists |
| // |
| |
| if (0 != psmod->dwNameLength) |
| { |
| pleObjectList = &m_leNamedObjects; |
| } |
| else |
| { |
| pleObjectList = &m_leAnonymousObjects; |
| } |
| |
| for (PLIST_ENTRY ple = pleObjectList->Flink; |
| ple != pleObjectList; |
| ple = ple->Flink) |
| { |
| pshmobj = CSharedMemoryObject::GetObjectFromListLink(ple); |
| |
| if (SharedObject == pshmobj->GetObjectDomain() |
| && reinterpret_cast<SHMPTR>(rhRemote) == pshmobj->GetShmObjData()) |
| { |
| TRACE("Object for remote handle already present in this process\n"); |
| |
| // |
| // PAL_LocalHandleToRemote bumped up the process refcount on the |
| // object. Since this process already had a reference to the object |
| // we need to decrement that reference now... |
| // |
| |
| psmod->lProcessRefCount -= 1; |
| _ASSERTE(0 < psmod->lProcessRefCount); |
| |
| // |
| // We also need to add a reference to the object (since ReleaseReference |
| // gets called below) |
| // |
| |
| pshmobj->AddReference(); |
| |
| break; |
| } |
| |
| pshmobj = NULL; |
| } |
| |
| if (NULL == pshmobj) |
| { |
| CObjectType *pot; |
| CObjectAttributes oa; |
| |
| // |
| // Get the local instance of the CObjectType |
| // |
| |
| pot = CObjectType::GetObjectTypeById(psmod->eTypeId); |
| if (NULL == pot) |
| { |
| ASSERT("Invalid object type ID in shared memory info\n"); |
| goto ConvertRemoteHandleToLocalExit; |
| } |
| |
| // |
| // Create the local state for the shared object |
| // |
| |
| palError = ImportSharedObjectIntoProcess( |
| pthr, |
| pot, |
| &oa, |
| reinterpret_cast<SHMPTR>(rhRemote), |
| psmod, |
| FALSE, |
| &pshmobj |
| ); |
| |
| if (NO_ERROR != palError) |
| { |
| goto ConvertRemoteHandleToLocalExit; |
| } |
| } |
| |
| // |
| // Finally, allocate a local handle for the object |
| // |
| |
| palError = ObtainHandleForObject( |
| pthr, |
| pshmobj, |
| 0, |
| FALSE, |
| NULL, |
| phLocal |
| ); |
| |
| ConvertRemoteHandleToLocalExit: |
| |
| SHMRelease(); |
| InternalLeaveCriticalSection(pthr, &m_csListLock); |
| |
| ConvertRemoteHandleToLocalExitNoLockRelease: |
| |
| if (NULL != pshmobj) |
| { |
| pshmobj->ReleaseReference(pthr); |
| } |
| |
| LOGEXIT("CSharedMemoryObjectManager::ConvertRemoteHandleToLocal returns %d\n", palError); |
| |
| return palError; |
| } |
| |
| /*++ |
| Function: |
| PAL_RemoteHandleToLocal |
| |
| Given a "remote handle", return a local handle that refers to the |
| specified process. Calls |
| SharedMemoryObjectManager::ConvertRemoteHandleToLocal to do the actual |
| work |
| |
| Parameters: |
| rhRemote -- the "remote handle" to convert to a local handle |
| --*/ |
| |
| PALIMPORT |
| HANDLE |
| PALAPI |
| PAL_RemoteHandleToLocal(IN RHANDLE rhRemote) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| CPalThread *pthr; |
| HANDLE hLocal = INVALID_HANDLE_VALUE; |
| |
| PERF_ENTRY(PAL_RemoteHandleToLocal); |
| ENTRY("PAL_RemoteHandleToLocal( hRemote=0x%lx )\n", rhRemote); |
| |
| pthr = InternalGetCurrentThread(); |
| |
| palError = static_cast<CSharedMemoryObjectManager*>(g_pObjectManager)->ConvertRemoteHandleToLocal( |
| pthr, |
| rhRemote, |
| &hLocal |
| ); |
| |
| if (NO_ERROR != palError) |
| { |
| pthr->SetLastError(palError); |
| } |
| |
| LOGEXIT("PAL_RemoteHandleToLocal returns HANDLE 0x%lx\n", hLocal); |
| PERF_EXIT(PAL_RemoteHandleToLocal); |
| return hLocal; |
| } |
| |
| /*++ |
| Function: |
| CheckObjectTypeAndRights |
| |
| Helper routine that determines if: |
| 1) An object instance is of a specified type |
| 2) A set of granted access rights satisfies the required access rights |
| (currently ignored) |
| |
| Parameters: |
| pobj -- the object instance whose type is to be checked |
| paot -- the acceptable type for the object instance |
| dwRightsGranted -- the granted access rights (ignored) |
| dwRightsRequired -- the required access rights (ignored) |
| --*/ |
| |
| static |
| PAL_ERROR |
| CheckObjectTypeAndRights( |
| IPalObject *pobj, |
| CAllowedObjectTypes *paot, |
| DWORD dwRightsGranted, |
| DWORD dwRightsRequired |
| ) |
| { |
| PAL_ERROR palError = NO_ERROR; |
| |
| _ASSERTE(NULL != pobj); |
| _ASSERTE(NULL != paot); |
| |
| ENTRY("CheckObjectTypeAndRights (pobj=%p, paot=%p, " |
| "dwRightsGranted=%d, dwRightsRequired=%d)\n", |
| pobj, |
| paot, |
| dwRightsGranted, |
| dwRightsRequired |
| ); |
| |
| if (paot->IsTypeAllowed(pobj->GetObjectType()->GetId())) |
| { |
| #ifdef ENFORCE_OBJECT_ACCESS_RIGHTS |
| |
| // |
| // This is where the access right check would occur if Win32 object |
| // security were supported. |
| // |
| |
| if ((dwRightsRequired & dwRightsGranted) != dwRightsRequired) |
| { |
| palError = ERROR_ACCESS_DENIED; |
| } |
| #endif |
| } |
| else |
| { |
| palError = ERROR_INVALID_HANDLE; |
| } |
| |
| LOGEXIT("CheckObjectTypeAndRights returns %d\n", palError); |
| |
| return palError; |
| } |
| |
| |