// // status check event handler // to reconcile the status // // to be connected status, broadcast packet // should be received within MAX_ALLOWED_HEARTBEAT_INTERVAL // // returns TRUE to detach from the monitor // FALSE otherwise. // BOOL CNdasDevice::OnStatusCheck() { ximeta::CAutoLock autolock(this); // // Only when the device is connected! // if (NDAS_DEVICE_STATUS_CONNECTED != m_status) { // _ASSERTE(FALSE && "OnStatusCheck should be called when connected!"); DBGPRT_WARN(_FT("OnStatusCheck is called on connected. Detaching.\n")); // Detach from the monitor return TRUE; } DWORD dwCurrentTick = ::GetTickCount(); DWORD dwElapsed = dwCurrentTick - m_dwLastHeartbeatTick; if (dwElapsed > MAX_ALLOWED_HEARTBEAT_INTERVAL) { // // When just a single unit device is mounted, // status will not be changed to DISCONNECTED! // if (IsAnyUnitDevicesMounted()) { return FALSE; } // // Do not disconnect the device when the debugger is attached // if (!NdasServiceConfig::Get(nscDisconnectOnDebug) && ::IsDebuggerPresent()) { return FALSE; } BOOL fSuccess = DestroyAllUnitDevices(); if (!fSuccess) { return FALSE; } ChangeStatus(NDAS_DEVICE_STATUS_DISCONNECTED); return TRUE; } return FALSE; }
VOID CNdasLogicalDevice::OnDeviceStatusFailure() { ximeta::CAutoLock autolock(this); DBGPRT_WARN(_FT("Logical device %s instance does not exist anymore.\n"), ToString()); SetStatus(NDAS_LOGICALDEVICE_STATUS_UNMOUNTED); // // Detach from the event monitor // CNdasEventMonitor* pEventMon = pGetNdasEventMonitor(); pEventMon->Detach(this); }
BOOL CNdasLogicalDeviceManager::UnregisterNdasScsiLocation( CONST NDAS_SCSI_LOCATION& location) { ximeta::CAutoLock autolock(this); LocationMap::size_type nErased = m_NdasScsiLocationMap.erase(location); if (1 != nErased) { DBGPRT_WARN( _FT("NdasScsiLocation not registered at %s"), CNdasScsiLocation(location).ToString()); } _ASSERTE(1 == nErased); return (1 == nErased); }
BOOL CNdasDevice::CreateUnitDevice(DWORD dwUnitNo) { _ASSERTE(dwUnitNo < MAX_NDAS_UNITDEVICE_COUNT); if (dwUnitNo >= MAX_NDAS_UNITDEVICE_COUNT) { return FALSE; } _ASSERTE(NULL == m_pUnitDevices[dwUnitNo]); if (!m_fUnitDevicePresent[dwUnitNo]) { DBGPRT_WARN(_FT("HWINFO does not contain unit %d.\n"), dwUnitNo); return FALSE; } DWORD dwMaxFailure = NdasServiceConfig::Get(nscUnitDeviceIdentifyRetryMax); DWORD dwInterval = NdasServiceConfig::Get(nscUnitDeviceIdentifyRetryGap); for (DWORD i = 0; i < dwMaxFailure; ++i) { CNdasUnitDeviceCreator udCreator(*this, dwUnitNo); CNdasUnitDevice* pUnitDevice = udCreator.CreateUnitDevice(); // CreateUnitDevice already called AddRef if (NULL != pUnitDevice) { m_pUnitDevices[dwUnitNo] = pUnitDevice; pUnitDevice->RegisterToLDM(); return TRUE; } ::Sleep(dwInterval); DBGPRT_ERR_EX(_FT("Creating a unit device instance failed (%d out of %d): "), i, dwMaxFailure); } return FALSE; }
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) { DBGPRT_ERR_EX(_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; DBGPRT_INFO(_FT("Event Client %d\n"), dwPipe); CLIENT_DATA* pCurClientData = m_PipeData[dwPipe]; DBGPRT_INFO(_FT("Connected: %d\n"), pCurClientData->bConnected); fSuccess = ::ResetEvent(pCurClientData->overlapped.hEvent); _ASSERT(fSuccess); if (!pCurClientData->bConnected) { // // create another instance // fSuccess = AcceptNewConnection(); if (!fSuccess) { DBGPRT_WARN_EX(_FT("Creating another pipe instance failed: ")); DBGPRT_WARN(_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; } DBGPRT_INFO(_FT("Accepted removed event subscriber.\n")); } else { DBGPRT_INFO(_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) { DBGPRT_INFO(_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()) { DBGPRT_ERR_EX(_FT("Writing to a pipe failed: ")); DBGPRT_INFO(_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) { DBGPRT_WARN_EX(_FT("Creating another pipe instance failed: ")); DBGPRT_WARN(_FT("No more event subscribers can be accepted.\n")); } } else { // // forward the iterator if we did erase // DBGPRT_INFO(_FT("Event written to a pipe %p.\n"), (*itr)->hPipe); ++itr; } } else { // // forward the iterator if not connected // ++itr; } } }
BOOL CNdasDevice::CreateUnitDevice(DWORD dwUnitNo) { _ASSERTE(dwUnitNo < MAX_NDAS_UNITDEVICE_COUNT); if (dwUnitNo >= MAX_NDAS_UNITDEVICE_COUNT) { return FALSE; } _ASSERTE(NULL == m_pUnitDevices[dwUnitNo]); if (!m_fUnitDevicePresent[dwUnitNo]) { DBGPRT_WARN(_FT("HWINFO does not contain unit %d.\n"), dwUnitNo); return FALSE; } static const DWORD UNITDEVICE_IDENTIFY_FAILURE_RETRY_DEFAULT = 4; static const DWORD UNITDEVICE_IDENTIFY_INTERVAL_DEFAULT = 2500; DWORD dwMaxFailure = UNITDEVICE_IDENTIFY_FAILURE_RETRY_DEFAULT; BOOL fSuccess = _NdasSystemCfg.GetValueEx( _T("ndassvc"), _T("MaxUnitDeviceIdentifyFailure"), &dwMaxFailure); if (!fSuccess || 0 == dwMaxFailure) { dwMaxFailure = UNITDEVICE_IDENTIFY_FAILURE_RETRY_DEFAULT; } DWORD dwInterval = UNITDEVICE_IDENTIFY_INTERVAL_DEFAULT; fSuccess = _NdasSystemCfg.GetValueEx( _T("ndassvc"), _T("UnitDeviceIdentifyFailureRetryInterval"), &dwInterval); if (!fSuccess || dwInterval > 300000) { dwInterval = UNITDEVICE_IDENTIFY_INTERVAL_DEFAULT; } for (DWORD i = 0; i < dwMaxFailure; ++i) { CNdasUnitDeviceCreator udCreator(*this, dwUnitNo); CNdasUnitDevice* pUnitDevice = udCreator.CreateUnitDevice(); // CreateUnitDevice already called AddRef if (NULL != pUnitDevice) { m_pUnitDevices[dwUnitNo] = pUnitDevice; pUnitDevice->RegisterToLDM(); return TRUE; } ::Sleep(dwInterval); DBGPRT_ERR_EX(_FT("Creating a unit device instance failed (%d out of %d): "), i, dwMaxFailure); } return FALSE; }
VOID CNdasIXServer::OnReceive(CLpxDatagramSocket& sock) { SOCKADDR_LPX remoteAddr; DWORD cbReceived; BYTE* pPacket = NULL; DWORD dwRecvFlags; BOOL fSuccess = sock.GetRecvFromResult( &remoteAddr, &cbReceived, (BYTE**)&pPacket, &dwRecvFlags); // // Sanity Check // CONST LSINFOX_HEADER* pHeader = reinterpret_cast<CONST LSINFOX_HEADER*>(pPacket); UCHAR ProtocolName[4] = INFOX_DATAGRAM_PROTOCOL; if (pHeader->Protocol[0] != ProtocolName[0] || pHeader->Protocol[1] != ProtocolName[1] || pHeader->Protocol[2] != ProtocolName[2] || pHeader->Protocol[3] != ProtocolName[3]) { DBGPRT_WARN(_FT("Invalid INFOX packet: protocol %c%c%c%c\n"), pHeader->Protocol[0], pHeader->Protocol[1], pHeader->Protocol[2], pHeader->Protocol[3]); return; } if (pHeader->MessageSize != cbReceived) { DBGPRT_WARN( _FT("Invalid packet size: Received %d bytes, Claimed %d bytes\n"), cbReceived, pHeader->MessageSize); return; } CONST LSINFOX_DATA* pData = reinterpret_cast<CONST LSINFOX_DATA*>(pPacket + sizeof(LSINFOX_HEADER)); switch (LSINFOX_TYPE_MAJTYPE & pHeader->Type) { case LSINFOX_PRIMARY_UPDATE_MESSAGE: { CONST LSINFOX_PRIMARY_UPDATE* pPrimaryUpdateData = reinterpret_cast<const LSINFOX_PRIMARY_UPDATE*>(pData); OnIXPrimaryUpdate(sock,&remoteAddr,pPrimaryUpdateData); return; } case LSINFOX_PRIMARY_USAGE_MESSAGE: { CONST LSINFOX_NDASDEV_USAGE_REQUEST* pUsageRequest = reinterpret_cast<const LSINFOX_NDASDEV_USAGE_REQUEST*>(pData); OnIXUsageRequest(sock,&remoteAddr,pUsageRequest); return; } default: return; } }
VOID CNdasIXBcast::ResetBind() { BOOL fSuccess = FALSE; if (NULL != m_lpSocketAddressList) { ::LocalFree(m_lpSocketAddressList); m_lpSocketAddressList = NULL; } while (NULL == m_lpSocketAddressList) { m_lpSocketAddressList = pCreateLocalLpxAddressList(); if (NULL == m_lpSocketAddressList) { DBGPRT_WARN_EX(_FT("Getting local lpx address list failed. Retry in 5 sec: ")); // try to get address list again in 5 sec // we should terminate this routine at a task terminate event DWORD dwWaitResult = ::WaitForSingleObject(m_hTaskTerminateEvent, 5000); if (WAIT_OBJECT_0 == dwWaitResult) { return; } } } fSuccess = m_sockAddrChangeNotifier.Reset(); // _ASSERTE(fSuccess); if (!fSuccess) { DBGPRT_WARN(_FT("Resetting sockAddrChangeNotifier failed: ")); } DWORD nLocalAddrs = min((DWORD)m_lpSocketAddressList->iAddressCount, m_nSenders); for (DWORD i = 0; i < m_nSenders; ++i) { if (INVALID_SOCKET != (SOCKET)m_senders[i]) { m_senders[i].Close(); } } for (DWORD i = 0; i < nLocalAddrs && i < m_nSenders; ++i) { PSOCKADDR_LPX pSockAddr = (PSOCKADDR_LPX) m_lpSocketAddressList->Address[i].lpSockaddr; pSockAddr->LpxAddress.Port = 0; fSuccess = m_senders[i].Create(); if (!fSuccess) { DBGPRT_ERR_EX(_FT("Creating a socket failed: ")); continue; } // // This is a broadcast socket // BOOL bBroadcast = TRUE; fSuccess = m_senders[i].SetSockOpt( SO_BROADCAST, (CONST BYTE*)&bBroadcast, sizeof(BOOL)); if (!fSuccess) { DBGPRT_ERR_EX(_FT("Setting a sock option to broadcast failed: ")); (VOID) m_senders[i].Close(); continue; } fSuccess = m_senders[i].Bind(pSockAddr); if (!fSuccess) { DBGPRT_ERR_EX(_FT("Binding a sock %d to %s failed: "), i, CSockLpxAddr(pSockAddr).ToString()); (VOID) m_senders[i].Close(); continue; } } }
void CNdasDeviceHeartbeatListener::OnReceive(CLpxDatagramSocket& sock) { SOCKADDR_LPX remoteAddr; DWORD cbReceived; PNDAS_DEVICE_HEARTBEAT pData = NULL; DWORD dwRecvFlags; BOOL fSuccess = sock.GetRecvFromResult( &remoteAddr, &cbReceived, (BYTE**)&pData, &dwRecvFlags); if (!fSuccess) { DBGPRT_ERR_EX(_FT("Heartbeat Packet Receive failed: ")); return; } DBGPRT_NOISE(_FT("Received Heartbeat Packet (%d bytes) ") _T("from %s at %s: ") _T("Receive Flag %08X\n"), cbReceived, CSockLpxAddr(remoteAddr).ToString(), CSockLpxAddr(sock.GetBoundAddr()).ToString(), dwRecvFlags); fSuccess = IsValidHeartbeat(cbReceived, (LPCVOID) pData); if (!fSuccess) { DBGPRT_WARN(_FT("Invalid packet received!\n")); return; } const NDAS_DEVICE_HEARTBEAT* pHeartbeat = reinterpret_cast<const NDAS_DEVICE_HEARTBEAT*>(pData); NDAS_DEVICE_HEARTBEAT_INFO eventData = {0}; ::CopyMemory( eventData.DeviceAddress.Node, remoteAddr.LpxAddress.Node, sizeof(remoteAddr.LpxAddress.Node)); C_ASSERT( sizeof(eventData.DeviceAddress.Node) == sizeof(remoteAddr.LpxAddress.Node)); ::CopyMemory( eventData.LocalAddress.Node, sock.GetBoundAddr()->LpxAddress.Node, sizeof(remoteAddr.LpxAddress.Node)); C_ASSERT( sizeof(eventData.LocalAddress.Node) == sizeof(remoteAddr.LpxAddress.Node)); eventData.Timestamp = ::GetTickCount(); eventData.Type = pHeartbeat->Type; eventData.Version = pHeartbeat->Version; __raise this->OnHeartbeat(eventData); }