BOOL CNdasDeviceRegistrar::Unregister(const NDAS_DEVICE_ID& DeviceId) { ximeta::CAutoLock autolock(this); CNdasDeviceId cdevid(DeviceId); DPInfo(_FT("Unregister device %s\n"), (LPCTSTR)cdevid); DeviceIdMap::iterator itrId = m_deviceIdMap.find(DeviceId); if (m_deviceIdMap.end() == itrId) { // TODO: ::SetLastError(NDAS_ERROR_DEVICE_NOT_FOUND); // TODO: Make more specific error code ::SetLastError(NDASHLPSVC_ERROR_DEVICE_ENTRY_NOT_FOUND); } PCNdasDevice pDevice = itrId->second; if (pDevice->GetStatus() != NDAS_DEVICE_STATUS_DISABLED) { // TODO: ::SetLastError(NDAS_ERROR_CANNOT_UNREGISTER_ENABLED_DEVICE); // TODO: Make more specific error code ::SetLastError(NDASHLPSVC_ERROR_CANNOT_UNREGISTER_ENABLED_DEVICE); return FALSE; } DWORD dwSlotNo = pDevice->GetSlotNo(); _ASSERT(0 != dwSlotNo); DeviceSlotMap::iterator itrSlot = m_deviceSlotMap.find(dwSlotNo); m_deviceIdMap.erase(itrId); m_deviceSlotMap.erase(itrSlot); m_pbSlotOccupied[dwSlotNo] = FALSE; pDevice->Release(); TCHAR szContainer[30]; HRESULT hr = ::StringCchPrintf(szContainer, 30, TEXT("Devices\\%04d"), dwSlotNo); _ASSERT(SUCCEEDED(hr)); BOOL fSuccess = _NdasSystemCfg.DeleteContainer(szContainer, TRUE); if (!fSuccess) { DPWarningEx( _FT("Deleting registration entry from the registry failed at %s.\n"), szContainer); } CNdasInstanceManager* pInstMan = CNdasInstanceManager::Instance(); _ASSERTE(NULL != pInstMan); CNdasEventPublisher* pEventPublisher = pInstMan->GetEventPublisher(); _ASSERTE(NULL != pEventPublisher); (void) pEventPublisher->DeviceEntryChanged(); return TRUE; }
VOID CNdasEventMonitor:: Attach(const PCNdasDevice pDevice) { ximeta::CAutoLock autolock(this); DPInfo(_FT("Attaching device %s to the monitor\n"), CNdasDeviceId(pDevice->GetDeviceId()).ToString()); std::pair<PCNdasDeviceSet::iterator,bool> ins = m_hbMonDevices.insert(pDevice); }
VOID CNdasEventMonitor:: Detach(const PCNdasDevice pDevice) { ximeta::CAutoLock autolock(this); _ASSERTE(!m_bIterating && "You must not call Detach from OnStatusCheck" && "Return TRUE to detach during OnStatusCheck instead!"); DPInfo(_FT("Detaching device %s from the monitor\n"), CNdasDeviceId(pDevice->GetDeviceId()).ToString()); m_hbMonDevices.erase(pDevice); }
DWORD CNdasEventMonitor::OnTaskStart() { BOOL bTerminateThread(FALSE); // 15 sec = 10,000,000 nanosec // negative value means relative time LARGE_INTEGER liDueTime; liDueTime.QuadPart = - 10 * 1000 * 1000; BOOL fSuccess = ::SetWaitableTimer( m_hHeartbeatMonitorTimer, &liDueTime, HEARTBEAT_MONITOR_INTERVAL, NULL, NULL, FALSE); if (!fSuccess) { DPErrorEx(_FT("Setting waitable timer failed: ")); } do { // // Lock against m_vLogDevice set change // this->Lock(); DWORD dwLogDevices = m_vLogDevices.size(); DWORD dwHandles = 3 + 2 * dwLogDevices; HANDLE* hWaitingHandles = new HANDLE[dwHandles]; hWaitingHandles[0] = m_hTaskTerminateEvent; hWaitingHandles[1] = m_hLogDeviceSetChangeEvent; hWaitingHandles[2] = m_hHeartbeatMonitorTimer; PCNdasLogicalDeviceVector::const_iterator itr = m_vLogDevices.begin(); for (DWORD i = 3; itr != m_vLogDevices.end(); ++itr, ++i) { PCNdasLogicalDevice pLogDevice = *itr; hWaitingHandles[i] = pLogDevice->GetDisconnectEvent(); hWaitingHandles[dwLogDevices + i] = pLogDevice->GetAlarmEvent(); } this->Unlock(); fSuccess = ::ResetEvent(m_hLogDeviceSetChangeEvent); _ASSERTE(fSuccess); BOOL bResetLogDeviceSet(FALSE); do { DWORD dwWaitResult = ::WaitForMultipleObjects( dwHandles, hWaitingHandles, FALSE, INFINITE); if (WAIT_OBJECT_0 == dwWaitResult) { // // Terminate Thread Event // bTerminateThread = TRUE; } else if (WAIT_OBJECT_0 + 1 == dwWaitResult) { // // LogicalDeviceSetChange Event // bResetLogDeviceSet = TRUE; } else if (WAIT_OBJECT_0 + 2 == dwWaitResult) { ximeta::CAutoLock autolock(this); // // Heartbeat Monitor Timer Event // PCNdasDeviceSet::const_iterator devitr = m_hbMonDevices.begin(); m_bIterating = TRUE; for (; devitr != m_hbMonDevices.end();) { PCNdasDevice pDevice = *devitr; BOOL fDetach = pDevice->OnStatusCheck(); if (fDetach) { devitr = m_hbMonDevices.erase(devitr); pDevice->Release(); } else { ++devitr; } } m_bIterating = FALSE; // // Check the logical devices // std::for_each( m_vLogDevices.begin(), m_vLogDevices.end(), NdasLogicalDeviceStatusCheck); } else if (WAIT_OBJECT_0 + 3 <= dwWaitResult && dwWaitResult < WAIT_OBJECT_0 + 3 + dwLogDevices) { // // Disconnect Event // DWORD n = dwWaitResult - (WAIT_OBJECT_0 + 3); BOOL fHandled = OnLogicalDeviceDisconnected(n); if (!fHandled) { fSuccess = ::ResetEvent(hWaitingHandles[dwWaitResult - WAIT_OBJECT_0]); _ASSERTE(fSuccess); } } else if (WAIT_OBJECT_0 + 3 + dwLogDevices <= dwWaitResult && dwWaitResult < WAIT_OBJECT_0 + 3 + 2 * dwLogDevices) { // // Alarm Event // DWORD n = dwWaitResult - (WAIT_OBJECT_0 + 3 + dwLogDevices); BOOL fHandled = OnLogicalDeviceAlarmed(n); if (!fHandled) { fSuccess = ::ResetEvent(hWaitingHandles[dwWaitResult - WAIT_OBJECT_0]); _ASSERTE(fSuccess); } } else { // _ASSERTE(FALSE); // Some handles may be already invalid. // LogicalDeviceSetChange Event // bResetLogDeviceSet = TRUE; DPErrorEx(_FT("Wait failed: ")); } } while (!bResetLogDeviceSet && !bTerminateThread); delete [] hWaitingHandles; } while (!bTerminateThread); fSuccess = ::CancelWaitableTimer(m_hHeartbeatMonitorTimer); if (!fSuccess) { DPErrorEx(_FT("Canceling waitable timer failed: ")); } return 0; }
DWORD CNdasEventMonitor:: OnTaskStart() { BOOL bTerminateThread(FALSE); // 15 sec = 10,000,000 nanosec // negative value means relative time LARGE_INTEGER liDueTime; liDueTime.QuadPart = - 10 * 1000 * 1000; BOOL fSuccess = ::SetWaitableTimer( m_hHeartbeatMonitorTimer, &liDueTime, HEARTBEAT_MONITOR_INTERVAL, NULL, NULL, FALSE); if (!fSuccess) { DPErrorEx(_FT("Setting waitable timer failed: ")); } do { // // Lock against m_vLogDevice set change // this->Lock(); DWORD dwLogDevices = m_vLogDevices.size(); DWORD dwHandles = 3 + 2 * dwLogDevices; HANDLE* hWaitingHandles = new HANDLE[dwHandles]; hWaitingHandles[0] = m_hTaskTerminateEvent; hWaitingHandles[1] = m_hLogDeviceSetChangeEvent; hWaitingHandles[2] = m_hHeartbeatMonitorTimer; PCNdasLogicalDeviceVector::const_iterator itr = m_vLogDevices.begin(); for (DWORD i = 3; itr != m_vLogDevices.end(); ++itr, ++i) { PCNdasLogicalDevice pLogDevice = *itr; hWaitingHandles[i] = pLogDevice->GetDisconnectEvent(); hWaitingHandles[dwLogDevices + i] = pLogDevice->GetAlarmEvent(); } this->Unlock(); BOOL fSuccess = ::ResetEvent(m_hLogDeviceSetChangeEvent); _ASSERTE(fSuccess); BOOL bResetLogDeviceSet(FALSE); do { DWORD dwWaitResult = ::WaitForMultipleObjects( dwHandles, hWaitingHandles, FALSE, INFINITE); if (WAIT_OBJECT_0 == dwWaitResult) { // // Terminate Thread Event // bTerminateThread = TRUE; } else if (WAIT_OBJECT_0 + 1 == dwWaitResult) { // // LogicalDeviceSetChange Event // bResetLogDeviceSet = TRUE; } else if (WAIT_OBJECT_0 + 2 == dwWaitResult) { // // Heartbeat Monitor Timer Event // ximeta::CAutoLock autolock(this); PCNdasDeviceSet::const_iterator itr = m_hbMonDevices.begin(); m_bIterating = TRUE; for (; itr != m_hbMonDevices.end();) { PCNdasDevice pDevice = *itr; BOOL bDetach = pDevice->OnStatusCheck(); if (bDetach) { DPInfo(_FT("Detaching device %s from the monitor\n"), CNdasDeviceId(pDevice->GetDeviceId()).ToString()); itr = m_hbMonDevices.erase(itr); } else { ++itr; } } m_bIterating = FALSE; } else if (WAIT_OBJECT_0 + 3 <= dwWaitResult && dwWaitResult < WAIT_OBJECT_0 + 3 + dwLogDevices) { // // Disconnect Event // DWORD n = dwWaitResult - (WAIT_OBJECT_0 + 3); PCNdasLogicalDevice pLogDevice = m_vLogDevices[n]; DPInfo(_FT("Disconnect Event from slot %d: %s\n"), pLogDevice->GetSlot(), pLogDevice->ToString()); // // Publish event here // // TODO: Publish event here // CNdasInstanceManager* pInstMan = CNdasInstanceManager::Instance(); _ASSERTE(NULL != pInstMan); CNdasEventPublisher* pEventPublisher = pInstMan->GetEventPublisher(); _ASSERTE(NULL != pEventPublisher); NDAS_LOGICALDEVICE_ID logicalDeviceId = {0}; logicalDeviceId.SlotNo = pLogDevice->GetSlot(); logicalDeviceId.TargetId = 0; logicalDeviceId.LUN = 0; (void) pEventPublisher->LogicalDeviceDisconnected(logicalDeviceId); BOOL fSuccess = ::ResetEvent(pLogDevice->GetDisconnectEvent()); _ASSERTE(fSuccess); // // Eject device // DPInfo(_FT("Ejecting disconnected logical device\n")); fSuccess = pLogDevice->Eject(); if (!fSuccess) { DPErrorEx(_FT("Eject failed: ")); DPError(_FT("Trying to unplug...\n")); fSuccess = pLogDevice->Unplug(); if (!fSuccess) { DPErrorEx(_FT("Unplugging failed: ")); } } } else if (WAIT_OBJECT_0 + 3 + dwLogDevices <= dwWaitResult && dwWaitResult < WAIT_OBJECT_0 + 3 + 2 * dwLogDevices) { // // Alarm Event // DWORD n = dwWaitResult - (WAIT_OBJECT_0 + 3 + dwLogDevices); PCNdasLogicalDevice pLogDevice = m_vLogDevices[n]; ULONG ulStatus; DPInfo(_FT("Alarm Event from slot %d: %s\n"), pLogDevice->GetSlot(), pLogDevice->ToString()); LsBusCtlQueryAlarmStatus(pLogDevice->GetSlot(), &ulStatus); CNdasInstanceManager* pInstMan = CNdasInstanceManager::Instance(); _ASSERTE(NULL != pInstMan); CNdasEventPublisher* pEventPublisher = pInstMan->GetEventPublisher(); _ASSERTE(NULL != pEventPublisher); switch (ulStatus) { case ALARM_STATUS_NORMAL: { DPInfo(_FT("Alarm Normal\n")); NDAS_LOGICALDEVICE_ID logicalDeviceId = {0}; logicalDeviceId.SlotNo = pLogDevice->GetSlot(); logicalDeviceId.TargetId = 0; logicalDeviceId.LUN = 0; (void) pEventPublisher-> LogicalDeviceReconnected(logicalDeviceId); } break; case ALARM_STATUS_START_RECONNECT: { DPInfo(_FT("Alarm Start Reconnect\n")); NDAS_LOGICALDEVICE_ID logicalDeviceId = {0}; logicalDeviceId.SlotNo = pLogDevice->GetSlot(); logicalDeviceId.TargetId = 0; logicalDeviceId.LUN = 0; (void) pEventPublisher-> LogicalDeviceReconnecting(logicalDeviceId); } break; case ALARM_STATUS_FAIL_RECONNECT: // obsolete DPInfo(_FT("Alarm Failed Reconnecting\n")); break; default: DPWarning(_FT("Unknown alarm status: %d\n"), ulStatus); } // // TODO: Publish event here // BOOL fSuccess = ::ResetEvent(pLogDevice->GetAlarmEvent()); _ASSERTE(fSuccess); } else { _ASSERTE(FALSE); DPErrorEx(_FT("Wait failed: ")); } } while (!bResetLogDeviceSet && !bTerminateThread); delete [] hWaitingHandles; } while (!bTerminateThread); fSuccess = ::CancelWaitableTimer(m_hHeartbeatMonitorTimer); if (!fSuccess) { DPErrorEx(_FT("Canceling waitable timer failed: ")); } return 0; }
PCNdasDevice CNdasDeviceRegistrar::Register(const NDAS_DEVICE_ID& DeviceId, DWORD dwSlotNo) { // // this will lock this class from here // and releases the lock when the function returns; // ximeta::CAutoLock autolock(this); DPInfo(_FT("Registering device %s at slot %d\n"), LPCTSTR(CNdasDeviceId(DeviceId)), dwSlotNo); // check slot number if (dwSlotNo < 1 || dwSlotNo > m_dwMaxSlotNo) { ::SetLastError(NDASHLPSVC_ERROR_INVALID_SLOT_NUMBER); return NULL; } // check and see if the slot is occupied if (m_pbSlotOccupied[dwSlotNo]) { ::SetLastError(NDASHLPSVC_ERROR_SLOT_ALREADY_OCCUPIED); return NULL; } // find an duplicate address if (NULL != Find(DeviceId)) { ::SetLastError(NDASHLPSVC_ERROR_DUPLICATE_DEVICE_ENTRY); return NULL; } // register PCNdasDevice pDevice = new CNdasDevice(dwSlotNo, DeviceId); if (NULL == pDevice) { // memory allocation failed // No need to set error here! return NULL; } pDevice->AddRef(); BOOL fSuccess = pDevice->Initialize(); if (!fSuccess) { // DebugPrintError((ERROR_T("Device initialization failed!"))); pDevice->Release(); return NULL; } m_pbSlotOccupied[dwSlotNo] = TRUE; bool insertResult; insertResult = m_deviceSlotMap.insert(DeviceSlotMap::value_type(dwSlotNo, pDevice)).second; _ASSERTE(insertResult == true); insertResult = m_deviceIdMap.insert(DeviceIdMap::value_type(DeviceId, pDevice)).second; _ASSERTE(insertResult == true); _ASSERTE(m_deviceSlotMap.size() == m_deviceIdMap.size()); TCHAR szContainer[30]; HRESULT hr = ::StringCchPrintf(szContainer, 30, TEXT("Devices\\%04d"), dwSlotNo); _ASSERT(SUCCEEDED(hr)); fSuccess = _NdasSystemCfg.SetSecureValueEx( szContainer, _T("DeviceId"), &DeviceId, sizeof(DeviceId)); if (!fSuccess) { DPWarningEx( _FT("Writing registration entry to the registry failed at %s.\n"), szContainer); } // // During bootstrapping, we do not publish this event // Bootstrapper will do this later. // if (!m_fBootstrapping) { CNdasEventPublisher* pEventPublisher = pGetNdasEventPublisher(); (VOID) pEventPublisher->DeviceEntryChanged(); } return pDevice; }
BOOL CNdasDeviceRegistrar::Bootstrap() { BOOL fSuccess = FALSE; BOOL fMigrated = FALSE; // // Set bootstrapping flag to prevent multiple events // for DeviceSetChange Events // m_fBootstrapping = TRUE; TCHAR szSubcontainer[30]; for (DWORD i = 0; i < MAX_SLOT_NUMBER; ++i) { HRESULT hr = ::StringCchPrintf(szSubcontainer, 30, TEXT("%s\\%04d"), CFG_CONTAINER, i); _ASSERTE(SUCCEEDED(hr) && "CFG_CONTAINER is too large???"); BOOL fAutoRegistered = FALSE; fSuccess = _NdasSystemCfg.GetValueEx( szSubcontainer, _T("AutoRegistered"), &fAutoRegistered); if (fSuccess && fAutoRegistered) { DBGPRT_WARN_EX(_FT("Deleting %s: "), szSubcontainer); // Auto registered devices are not persistent // it is an error to show up here. // We just ignore those entries fSuccess = _NdasSystemCfg.DeleteContainer(szSubcontainer, TRUE); if (!fSuccess) { DBGPRT_WARN_EX(_FT("Deleting %s failed: "), szSubcontainer); } continue; } NDAS_DEVICE_ID deviceId; fSuccess = _NdasSystemCfg.GetSecureValueEx( szSubcontainer, _T("DeviceID"), &deviceId, sizeof(deviceId)); // ignore read fault - tampered or not exists if (!fSuccess) { continue; } PCNdasDevice pDevice = Register(deviceId, i); // _ASSERTE(NULL != pDevice && "Failure of registration should not happed during bootstrap!"); // This may happen due to auto-register feature! if (NULL == pDevice) { continue; } ACCESS_MASK grantedAccess = GENERIC_READ; const DWORD cbBuffer = sizeof(ACCESS_MASK) + sizeof(NDAS_DEVICE_ID); BYTE pbBuffer[cbBuffer]; fSuccess = _NdasSystemCfg.GetSecureValueEx( szSubcontainer, _T("GrantedAccess"), pbBuffer, cbBuffer); if (fSuccess) { grantedAccess = *((ACCESS_MASK*)(pbBuffer)); } grantedAccess |= GENERIC_READ; // to prevent invalid access mask configuration // _ASSERTE(grantedAccess & GENERIC_READ); // invalid configuration? pDevice->SetGrantedAccess(grantedAccess); TCHAR szDeviceName[MAX_NDAS_DEVICE_NAME_LEN + 1]; fSuccess = _NdasSystemCfg.GetValueEx( szSubcontainer, _T("DeviceName"), szDeviceName, sizeof(TCHAR)*(MAX_NDAS_DEVICE_NAME_LEN + 1)); if (fSuccess) { pDevice->SetName(szDeviceName); } BOOL fEnabled = FALSE; fSuccess = _NdasSystemCfg.GetValueEx( szSubcontainer, _T("Enabled"), &fEnabled); if (fSuccess && fEnabled) { pDevice->Enable(fEnabled); } } // // Migration will be done only once // if there is no registered devices in the current configurations // and if the migration flag (Install\Migrate = 1) is set // if (m_deviceSlotMap.size() == 0) { fSuccess = _NdasSystemCfg.GetValueEx(_T("Install"), _T("Migrated"), &fMigrated); if (!fSuccess || !fMigrated) { fMigrated = TRUE; ImportLegacySettings(); _NdasSystemCfg.SetValueEx(_T("Install"), _T("Migrated"), fMigrated); } } // // Clear bootstrapping state // m_fBootstrapping = FALSE; return TRUE; }
BOOL CNdasDeviceRegistrar::ImportLegacyEntry(DWORD dwSlotNo, HKEY hEntryKey) { static CONST size_t CB_ADDR = sizeof(TCHAR) * 18; HRESULT hr = E_FAIL; TCHAR szAddrVal[CB_ADDR + 1]; DWORD cbAddrVal = sizeof(szAddrVal); DWORD dwValueType; LONG lResult = ::RegQueryValueEx( hEntryKey, _T("Address"), 0, &dwValueType, (LPBYTE)szAddrVal, &cbAddrVal); if (ERROR_SUCCESS != lResult) { // Ignore invalid values return FALSE; } if (cbAddrVal != CB_ADDR) { DBGPRT_ERR(_FT("Invalid Entry(A): %s, ignored\n"), szAddrVal); return FALSE; } // // 00:0B:D0:00:D4:2F to NDAS_DEVICE_ID // NDAS_DEVICE_ID deviceId = {0}; BOOL fSuccess = pConvertStringToDeviceId(szAddrVal, &deviceId); if (!fSuccess) { DBGPRT_ERR(_FT("Invalid Entry(D): %s, ignored\n"), szAddrVal); return FALSE; } DBGPRT_INFO(_FT("Importing an entry: %s\n"), CNdasDeviceId(deviceId).ToString()); TCHAR szNameVal[MAX_NDAS_DEVICE_NAME_LEN + 1] = {0}; DWORD cbNameVal = sizeof(szNameVal); lResult = ::RegQueryValueEx( hEntryKey, _T("Name"), 0, &dwValueType, (LPBYTE)szNameVal, &cbNameVal); if (ERROR_SUCCESS != lResult || _T('\0') == szNameVal[0]) { TCHAR szDefaultName[MAX_NDAS_DEVICE_NAME_LEN + 1] = {0}; fSuccess = _NdasSystemCfg.GetValueEx( _T("Devices"), _T("DefaultPrefix"), szDefaultName, sizeof(szDefaultName)); if (!fSuccess) { hr = ::StringCchCopy( szDefaultName, MAX_NDAS_DEVICE_NAME_LEN + 1, _T("NDAS Device ")); _ASSERTE(SUCCEEDED(hr)); } hr = ::StringCchPrintf( szNameVal, MAX_NDAS_DEVICE_NAME_LEN, _T("%s %d"), szDefaultName, dwSlotNo); } BYTE pbSerialKeyVal[9]; DWORD cbSerialKeyVal = sizeof(pbSerialKeyVal); lResult = ::RegQueryValueEx( hEntryKey, _T("SerialKey"), 0, &dwValueType, (LPBYTE)pbSerialKeyVal, &cbSerialKeyVal); if (ERROR_SUCCESS != lResult) { return FALSE; } if (cbSerialKeyVal != sizeof(pbSerialKeyVal)) { return FALSE; } ACCESS_MASK fAccessMode = GENERIC_READ; if (0xFF == pbSerialKeyVal[8]) { // Registered as RW fAccessMode |= GENERIC_WRITE; } else if (0x00 == pbSerialKeyVal[8]) { // Registered as RO } else { // Invalid value return FALSE; } PCNdasDevice pDevice = Register(deviceId, dwSlotNo); if (NULL == pDevice) { DBGPRT_ERR_EX(_FT("Failed to register %s at %d during import: "), CNdasDeviceId(deviceId).ToString(), dwSlotNo); return FALSE; } // Always enable this! pDevice->Enable(TRUE); pDevice->SetName(szNameVal); pDevice->SetGrantedAccess(fAccessMode); return TRUE; }