CNdasEventMonitor::~CNdasEventMonitor() { if (INVALID_HANDLE_VALUE != m_hHeartbeatMonitorTimer) { BOOL fSuccess = ::CloseHandle(m_hHeartbeatMonitorTimer); if (!fSuccess) { DPWarningEx(_FT("Failed to close Heartbeat Monitor Timer Handle: ")); } } if (NULL != m_hLogDeviceSetChangeEvent) { BOOL fSuccess = ::CloseHandle(m_hLogDeviceSetChangeEvent); if (!fSuccess) { DPWarningEx(_FT("Failed to close Logical device set change event: ")); } } }
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; }
BOOL GetLocalLpxAddressList( IN DWORD cbBuffer, OUT LPSOCKET_ADDRESS_LIST lpBuffer, OUT LPDWORD pcbBytesReturned) { SOCKET sock = ::WSASocket( AF_LPX, SOCK_STREAM, IPPROTO_LPXTCP, NULL, 0, 0); if (INVALID_SOCKET == sock) { DPErrorEx(_FT("Socket creation failed: ")); return FALSE; } BOOL fSuccess = GetLocalLpxAddressList( sock, cbBuffer, lpBuffer, pcbBytesReturned); // // Close socket may shadow last error // int iWSALastError = ::WSAGetLastError(); INT iResult = ::closesocket(sock); if (0 != iResult) { DPWarningEx(_FT("Closing a socket failed: ")); } ::WSASetLastError(iWSALastError); return fSuccess; }
DWORD CNdasEventPublisher::OnTaskStart() { _ASSERTE(NULL != m_hSemQueue && "Don't forget to call initialize()."); // Queue Semaphore, Terminating Thread, Pipe Instances(MAX...) HANDLE hWaitHandles[2 + MAX_NDAS_EVENT_PIPE_INSTANCES]; hWaitHandles[0] = m_hTaskTerminateEvent; hWaitHandles[1] = m_hSemQueue; // // initial pipe instance // m_PipeData.clear(); BOOL fSuccess = AcceptNewConnection(); if (!fSuccess) { DPErrorEx(_T("Creating a first pipe instance failed: ")); return -1; } BOOL bTerminate(FALSE); while (FALSE == bTerminate) { DWORD dwWaitHandles = 2 + m_PipeData.size(); for (DWORD i = 0; i < m_PipeData.size(); ++i) { hWaitHandles[i + 2] = m_PipeData[i]->overlapped.hEvent; } DWORD dwWaitResult = ::WaitForMultipleObjects( dwWaitHandles, hWaitHandles, FALSE, m_dwPeriod); if (dwWaitResult == WAIT_OBJECT_0) { // // Terminate Thread // bTerminate = TRUE; } else if (dwWaitResult == WAIT_OBJECT_0 + 1) { // // Event Message is queued // while (TRUE) { m_queueLock.Lock(); bool bEmpty = m_EventMessageQueue.empty(); if (bEmpty) { m_queueLock.Unlock(); break; } NDAS_EVENT_MESSAGE message = m_EventMessageQueue.front(); m_EventMessageQueue.pop(); m_queueLock.Unlock(); Publish(&message); } } else if (dwWaitResult >= WAIT_OBJECT_0 + 2 && dwWaitResult < WAIT_OBJECT_0 + 2 + m_PipeData.size()) { DWORD dwPipe = dwWaitResult - WAIT_OBJECT_0 - 2; DPInfo(_FT("Event Client %d\n"), dwPipe); CLIENT_DATA* pCurClientData = m_PipeData[dwPipe]; DPInfo(_FT("Connected: %d\n"), pCurClientData->bConnected); fSuccess = ::ResetEvent(pCurClientData->overlapped.hEvent); _ASSERT(fSuccess); if (!pCurClientData->bConnected) { // // create another instance // fSuccess = AcceptNewConnection(); if (!fSuccess) { DPWarningEx(_FT("Creating another pipe instance failed: ")); DPWarning(_FT("No more event subscribers can be accepted.\n")); } // AcceptNewConnection will invalidate pCurClientData; pCurClientData = m_PipeData.at(dwPipe); // // Accepting connection // pCurClientData->bConnected = TRUE; fSuccess = ::ResetEvent(pCurClientData->overlapped.hEvent); _ASSERT(fSuccess); // // Send a version event for connected client // fSuccess = SendVersionInfo( pCurClientData->hPipe, &pCurClientData->overlapped); // // Any failure will disconnect the client // if (!fSuccess && ERROR_IO_PENDING != ::GetLastError()) { ClientDataVector::iterator itr = m_PipeData.begin(); CleanupConnection(pCurClientData); while (itr != m_PipeData.end()) { if ((CLIENT_DATA*)*itr == pCurClientData) { m_PipeData.erase(itr); break; } ++itr; } DPInfo(_FT("Accepted removed event subscriber.\n")); } else { DPInfo(_FT("Accepted new event subscriber.\n")); } } else { } // ignore other status } else if (WAIT_TIMEOUT == dwWaitResult) { NDAS_EVENT_MESSAGE msg = {0}; msg.EventType = NDAS_EVENT_TYPE_PERIODIC; Publish(&msg); } else { // // Error // } } // // TODO: Add cleanup // DWORD nPipeData = m_PipeData.size(); ClientDataVector::iterator itr = m_PipeData.begin(); while (itr != m_PipeData.end()) { CleanupConnection(*itr); ++itr; } m_PipeData.clear(); _tprintf(TEXT("Terminating Publisher Thread...\n")); return 0; }
void CNdasEventPublisher::Publish(const PNDAS_EVENT_MESSAGE pMessage) { DPInfo(_FT("Publishing Event: %s\n"), NdasEventTypeString(pMessage->EventType)); // // sent the message to the connected pipes // for (ClientDataVector::iterator itr = m_PipeData.begin(); itr != m_PipeData.end();) // // do not forward the iterator here when erasing some // elements // itr2 = v.erase(itr); // itr2 has a forwarded iterator from itr // { CLIENT_DATA* pClientData = *itr; if (pClientData->bConnected) { DWORD cbWritten; BOOL fSuccess = ::WriteFile( pClientData->hPipe, pMessage, sizeof(NDAS_EVENT_MESSAGE), &cbWritten, &pClientData->overlapped); if (!fSuccess && ERROR_IO_PENDING != ::GetLastError()) { DPErrorEx(_FT("Writing to a pipe failed: ")); DPInfo(_FT("Detaching an event subscriber.\n")); CleanupConnection(pClientData); // // erasing an element will automatically // forward the vector // (actually, itr remains the same, but the itr is // a next elemen) itr = m_PipeData.erase(itr); // // create another instance // fSuccess = AcceptNewConnection(); if (!fSuccess) { DPWarningEx(_FT("Creating another pipe instance failed: ")); DPWarning(_FT("No more event subscribers can be accepted.\n")); } } else { // // forward the iterator if we did erase // DPInfo(_FT("Event written to a pipe %p.\n"), (*itr)->hPipe); ++itr; } } else { // // forward the iterator if not connected // ++itr; } } }
////////////////////////////////////////////////////////////////////////// // // NdasDiInstallService // ////////////////////////////////////////////////////////////////////////// // // start type SERVICE_DEMAND_START, SERVICE_BOOT_START, // NDASDI_API BOOL WINAPI NdasDiInstallServiceSCH( SC_HANDLE schSCManager, LPCTSTR ServiceName, LPCTSTR DisplayName, LPCTSTR Description, DWORD DesiredAccess, DWORD ServiceType, DWORD StartType, DWORD ErrorControl, LPCTSTR BinaryPathName, LPCTSTR LoadOrderGroup, LPDWORD lpdwTagId, LPCTSTR Dependencies, LPCTSTR AccountName, LPCTSTR Password) { DPInfo(_FT("Creating a service %s(DisplayName: %s, Descr: %s) ") _T("Access %d, %s, %s, %s, ") _T("Path %s, LoadOrderGroup %s, Dep %s, Account %s, Pwd %s\n"), ServiceName, (NULL == DisplayName) ? ServiceName : DisplayName, Description, DesiredAccess, pServiceTypeString(ServiceType), pServiceStartTypeString(StartType), pServiceErrorControlString(ErrorControl), BinaryPathName, (LoadOrderGroup == NULL) ? _T("(none)") : LoadOrderGroup, (Dependencies == NULL) ? _T("(none)") : Dependencies, (AccountName == NULL) ? _T("LocalSystem") : AccountName, (Password == NULL) ? _T("(none)") : _T("(set)")); // // NOTE: This creates an entry for a standalone driver. If this // is modified for use with a driver that requires a Tag, // Group, and/or Dependencies, it may be necessary to // query the registry for existing driver information // (in order to determine a unique Tag, etc.). // AutoSCHandle schService = CreateService( schSCManager, ServiceName, (NULL == DisplayName) ? ServiceName : DisplayName, DesiredAccess, ServiceType, StartType, ErrorControl, BinaryPathName, LoadOrderGroup, lpdwTagId, Dependencies, AccountName, Password); if (NULL == (SC_HANDLE) schService) { DPErrorEx(_FT("Creating a service %s failed: "), ServiceName); return FALSE; } if (NULL != Description) { SERVICE_DESCRIPTION svcDesc; svcDesc.lpDescription = (LPTSTR) Description; BOOL fSuccess = ChangeServiceConfig2( schService, SERVICE_CONFIG_DESCRIPTION, &svcDesc); if (!fSuccess) { DPWarningEx(_FT("Setting a service description failed: ")); } } DPInfo(_FT("Service %s created successfully.\n"), ServiceName); return TRUE; }
BOOL CNdasIXBcast::BroadcastStatus() { BUSENUM_QUERY_INFORMATION BusEnumQuery; BUSENUM_INFORMATION BusEnumInformation; CNdasLogicalDeviceManager* pLdm = pGetNdasLogicalDeviceManager(); CNdasLogicalDeviceCollection coll; pLdm->Lock(); pLdm->GetItems(coll); pLdm->Unlock(); for (CNdasLogicalDeviceCollection::const_iterator itr = coll.begin(); itr != coll.end(); ++itr) { CNdasLogicalDevice* pLogDevice = *itr; if (NDAS_LOGICALDEVICE_STATUS_MOUNTED != pLogDevice->GetStatus()) { continue; } CONST NDAS_SCSI_LOCATION& location = pLogDevice->GetNdasScsiLocation(); BusEnumQuery.InfoClass = INFORMATION_PDO; BusEnumQuery.Size = sizeof(BUSENUM_QUERY_INFORMATION); BusEnumQuery.SlotNo = location.SlotNo; BOOL fSuccess = LsBusCtlQueryInformation( &BusEnumQuery, sizeof(BUSENUM_QUERY_INFORMATION), &BusEnumInformation, sizeof(BUSENUM_INFORMATION)); if (!fSuccess) { DPErrorEx(_FT("LanscsiQueryInformation failed at slot %d: "), location.SlotNo); continue; } // // Broadcast a primary write access status // if (ND_ACCESS_ISRW(BusEnumInformation.PdoInfo.GrantedAccess)) { const DWORD cbBuffer = sizeof(LSINFOX_HEADER) + sizeof(LSINFOX_PRIMARY_UPDATE); BYTE lpbBuffer[cbBuffer] = {0}; PLSINFOX_HEADER pixHeader = reinterpret_cast<PLSINFOX_HEADER>(lpbBuffer); PLSINFOX_DATA pixData = reinterpret_cast<PLSINFOX_DATA>(lpbBuffer + sizeof(LSINFOX_HEADER)); // // CAUTION: InfoExchange Protocol uses little-endian (Intel) // // // Header // UCHAR ixProtocolName[4] = INFOX_DATAGRAM_PROTOCOL; ::CopyMemory(pixHeader->Protocol, ixProtocolName, 4); pixHeader->LSInfoXMajorVersion = INFOX_DATAGRAM_MAJVER; pixHeader->LSInfoXMinorVersion = INFOX_DATAGRAM_MINVER; pixHeader->OsMajorType = OSTYPE_WINDOWS; DWORD dwOSMajorVersion, dwOSMinorVersion; pGetOSVersion(&dwOSMajorVersion, &dwOSMinorVersion); USHORT usLfsOsMinorType = pInfoXGetOSType(dwOSMajorVersion, dwOSMinorVersion); pixHeader->OsMinorType = usLfsOsMinorType; pixHeader->Type = LSINFOX_PRIMARY_UPDATE_MESSAGE; pixHeader->MessageSize = cbBuffer; // // Data // // primary node is dependent to each interface pixData->Update.PrimaryNode; pixData->Update.PrimaryPort = LPXRP_LFS_PRIMARY; pixData->Update.SWMajorVersion = NDASIX_VERSION_MAJOR; // TODO: Change these values pixData->Update.SWMinorVersion = NDASIX_VERSION_MINOR; pixData->Update.SWBuildNumber = NDASIX_VERSION_BUILD; pixData->Update.NDFSCompatVersion = m_NDFSVersion.wMajor; pixData->Update.NDFSVersion = m_NDFSVersion.wMinor; // // NetDisk Node is a property of each unit device // pixData->Update.NetDiskNode; // // We have fixed the port // (CNdasDevice does not store Port Number internally) // Do not try to retrieve from GetRemoteLpxAddress() // pixData->Update.NetDiskPort = NDAS_DEVICE_LPX_PORT; // // Unit Disk Number is a property of each unit device // pixData->Update.UnitDiskNo; // // pLogDevice->GetStatus() // for (DWORD n = 0; n < pLogDevice->GetUnitDeviceCount(); ++n) { // // Actually, we should traverse the real entry // from the device registrar. // However, here we do the shortcut for using NDAS device id // and fixed NetDiskPort, etc. // NDAS_UNITDEVICE_ID unitDeviceId = pLogDevice->GetUnitDeviceID(n); _ASSERTE(sizeof(pixData->Update.NetDiskNode) == sizeof(unitDeviceId.DeviceId)); ::CopyMemory( pixData->Update.NetDiskNode, unitDeviceId.DeviceId.Node, sizeof(pixData->Update.NetDiskNode)); pixData->Update.UnitDiskNo = unitDeviceId.UnitNo; // // Broadcast the data to every interface // for (DWORD i = 0; i < MAX_SOCKETLPX_INTERFACE; ++i) { if (INVALID_SOCKET != (SOCKET) m_senders[i]) { // // Fill the Primary Node (LPX Address Node) // LPX_ADDRESS localLpxAddress = m_senders[i].GetBoundAddr()->LpxAddress; _ASSERTE(sizeof(pixData->Update.PrimaryNode) == sizeof(localLpxAddress.Node)); ::CopyMemory( pixData->Update.PrimaryNode, localLpxAddress.Node, sizeof(pixData->Update.PrimaryNode)); // // Send the data // DWORD cbSent = 0; BOOL fSuccess = m_senders[i].SendToSync( &NDASIX_BCAST_ADDR, cbBuffer, lpbBuffer, 0, &cbSent); if (!fSuccess) { DPWarningEx(_FT("Sending a packet failed: ")); } } // end if } // for each local LPX address } // for each unit device } // if the logical device has a primary write access. } // for each logical device return TRUE; }
DWORD CNdasEventSubscriber:: Run() { _ASSERTE(NULL != m_hDataEvent); _ASSERTE(INVALID_HANDLE_VALUE != m_hThread); _ASSERTE(NULL != m_hThreadStopEvent); // Why? // _ASSERTE(m_hThread == ::GetCurrentThread()); OVERLAPPED ov = {0}; ov.hEvent = m_hDataEvent; BOOL bStopThread = FALSE; HANDLE hPipe = WaitServer(bStopThread); while (!bStopThread) { NDAS_EVENT_MESSAGE message = {0}; DWORD cbMessage = sizeof(NDAS_EVENT_MESSAGE); DWORD cbRead(0); BOOL fRead = ::ReadFile( hPipe, &message, cbMessage, &cbRead, &ov); if (!fRead && ERROR_IO_PENDING != ::GetLastError()) { // failure! DPErrorEx(_FT("ReadFile failed: ")); ::CloseHandle(hPipe); hPipe = WaitServer(bStopThread); continue; } if (fRead) { ::SetEvent(m_hDataEvent); } HANDLE hWaitHandles[2] = { m_hThreadStopEvent, m_hDataEvent }; DWORD dwWaitResult = ::WaitForMultipleObjects( 2, hWaitHandles, FALSE, INFINITE); if (WAIT_OBJECT_0 == dwWaitResult) { // // Thread stop event // bStopThread = TRUE; } else if (WAIT_OBJECT_0 + 1 == dwWaitResult) { DWORD cbRead(0); BOOL fData = ::GetOverlappedResult(hPipe, &ov, &cbRead, TRUE); NDAS_EVENT_INFO eventInfo = {0}; eventInfo.EventType = message.EventType; switch (eventInfo.EventType) { case NDAS_EVENT_TYPE_DEVICE_STATUS_CHANGED: case NDAS_EVENT_TYPE_DEVICE_PROPERTY_CHANGED: eventInfo.DeviceInfo = message.DeviceEventInfo; break; case NDAS_EVENT_TYPE_UNITDEVICE_PROPERTY_CHANGED: eventInfo.UnitDeviceInfo = message.UnitDeviceEventInfo; break; case NDAS_EVENT_TYPE_LOGICALDEVICE_STATUS_CHANGED: case NDAS_EVENT_TYPE_LOGICALDEVICE_DISCONNECTED: //case NDAS_EVENT_TYPE_LOGICALDEVICE_RECONNECTING: //case NDAS_EVENT_TYPE_LOGICALDEVICE_RECONNECTED: //case NDAS_EVENT_TYPE_LOGICALDEVICE_EMERGENCY: case NDAS_EVENT_TYPE_LOGICALDEVICE_ALARMED: eventInfo.LogicalDeviceInfo = message.LogicalDeviceEventInfo; break; case NDAS_EVENT_TYPE_LOGICALDEVICE_ENTRY_CHANGED: case NDAS_EVENT_TYPE_DEVICE_ENTRY_CHANGED: case NDAS_EVENT_TYPE_TERMINATING: break; case NDAS_EVENT_TYPE_SURRENDER_REQUEST: eventInfo.SurrenderRequestInfo = message.SurrenderRequestInfo; break; case NDAS_EVENT_TYPE_PERIODIC: default: break; } if (NDAS_EVENT_TYPE_PERIODIC != message.EventType) { CallEventProc(::GetLastError(), &eventInfo); } } else { DPWarningEx(_FT("Wait failed: ")); } } if (INVALID_HANDLE_VALUE != hPipe) { ::CloseHandle(hPipe); } 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; }