BOOL CLpxStreamListener::Accept(SOCKET sockAccept, DWORD cbDataBuffer) { _ASSERTE(INVALID_SOCKET != m_sock); _ASSERTE(INVALID_SOCKET != sockAccept); BOOL fSuccess = FALSE; DWORD cbBufReq = (sizeof(SOCKADDR_LPX) + 16) * 2 + cbDataBuffer; fSuccess = AllocRecvBuf(cbBufReq); if (!fSuccess) { DBGPRT_ERR_EX(_FT("AllocRecvBuf failed: ")); return FALSE; } DWORD cbAcceptBuffer = m_wsaReceiveBuffer.len; PVOID pbAcceptBuffer = m_wsaReceiveBuffer.buf; ResetRecvOverlapped(); //---------------------------------------- // Load the AcceptEx function into memory using WSAIoctl. // The WSAIoctl function is an extension of the ioctlsocket() // function that can use overlapped I/O. The function's 3rd // through 6th parameters are input and output buffers where // we pass the pointer to our AcceptEx function. This is used // so that we can call the AcceptEx function directly, rather // than refer to the Mswsock.lib library. LPFN_ACCEPTEX lpfnAcceptEx = NULL; GUID GuidAcceptEx = WSAID_ACCEPTEX; DWORD cbRead; INT iResult = ::WSAIoctl(m_sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx), &lpfnAcceptEx, sizeof(lpfnAcceptEx), &cbRead, NULL, NULL); if (NULL == lpfnAcceptEx) { DBGPRT_ERR_EX(_FT("Cannot load AcceptEx function: ")); return FALSE; } DWORD cbReceived = 0; fSuccess = lpfnAcceptEx( m_sock, sockAccept, pbAcceptBuffer, cbDataBuffer, sizeof(SOCKADDR_LPX) + 16, sizeof(SOCKADDR_LPX) + 16, &cbReceived, &m_ovReceive); if (!fSuccess && ERROR_IO_PENDING != ::GetLastError()) { return FALSE; } iResult = ::setsockopt( sockAccept, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&m_sock, sizeof(m_sock)); if (0 != iResult) { DBGPRT_WARN_EX(_FT("Setting SO_UPDATE_ACCEPT_CONTEXT failed: ")); } if (fSuccess) { ::SetEvent(m_hReceivedEvent); return TRUE; } return TRUE; }
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; } } }
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 CNdasLogicalDevice::cpLocateRegContainer() { ximeta::CAutoLock autolock(this); // // Registry Container // HKLM\Software\NDAS\LogDevices\XXXXXXXX // BOOL fSuccess, fWriteData = TRUE; m_dwHashValue = cpGetHashValue(); while (TRUE) { HRESULT hr = ::StringCchPrintf( m_szRegContainer, 30, _T("LogDevices\\%08X"), m_dwHashValue); _ASSERTE(SUCCEEDED(hr)); NDAS_LOGICALDEVICE_GROUP ldGroup; DWORD cbData = 0; fSuccess = _NdasSystemCfg.GetSecureValueEx( m_szRegContainer, _T("Data"), &ldGroup, sizeof(ldGroup), &cbData); if (fSuccess && cbData == sizeof(ldGroup)) { if (0 != ::memcmp(&ldGroup, &m_logicalDeviceGroup, sizeof(ldGroup))) { // collision on hash value // increment the hash value and recalculate ++m_dwHashValue; continue; } else { fWriteData = FALSE; } } break; } if (fWriteData) { fSuccess = _NdasSystemCfg.SetSecureValueEx( m_szRegContainer, _T("Data"), &m_logicalDeviceGroup, sizeof(m_logicalDeviceGroup)); if (!fSuccess) { DBGPRT_WARN_EX(_FT("Writing LDData failed: ")); } } DBGPRT_INFO(_FT("Hash Value: %08X\n"), m_dwHashValue); DBGPRT_INFO(_FT("RegContainer: %s\n"), m_szRegContainer); }
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 CNdasIXServer::OnIXUsageRequest( CLpxDatagramSocket& sock, CONST SOCKADDR_LPX* pRemoteAddr, CONST LSINFOX_NDASDEV_USAGE_REQUEST* pData) { NDAS_UNITDEVICE_ID unitDeviceId = { { pData->NetDiskNode[0], pData->NetDiskNode[1], pData->NetDiskNode[2], pData->NetDiskNode[3], pData->NetDiskNode[4], pData->NetDiskNode[5] }, pData->UnitDiskNo }; DPNoise(_FT("LSINFOX_PRIMARY_USAGE_MESSAGE: %02X:%02X:%02X:%02X:%02X:%02X@%d\n"), pData->NetDiskNode[0], pData->NetDiskNode[1], pData->NetDiskNode[2], pData->NetDiskNode[3], pData->NetDiskNode[4], pData->NetDiskNode[5], pData->UnitDiskNo); CNdasLogicalDevice* pLogDevice = pGetNdasLogicalDevice(unitDeviceId); if (NULL == pLogDevice) { // Discard message return; } switch (pLogDevice->GetStatus()) { case NDAS_LOGICALDEVICE_STATUS_MOUNTED: case NDAS_LOGICALDEVICE_STATUS_MOUNT_PENDING: case NDAS_LOGICALDEVICE_STATUS_UNMOUNT_PENDING: break; default: // // Otherwise, discard message // return; } ACCESS_MASK mountedAcces = pLogDevice->GetMountedAccess(); CONST DWORD cbPacket = sizeof(LSINFOX_HEADER) + sizeof(LSINFOX_NDASDEV_USAGE_REPLY) + MAX_HOSTNAME_LEN * sizeof(WCHAR); BYTE pbPacket[cbPacket] = {0}; PLSINFOX_HEADER pHeader = reinterpret_cast<PLSINFOX_HEADER>(pbPacket); PLSINFOX_NDASDEV_USAGE_REPLY pUsageReply = reinterpret_cast<PLSINFOX_NDASDEV_USAGE_REPLY>( pbPacket + sizeof(LSINFOX_HEADER)); // // Header // CONST BYTE NdasIxProtocolName[] = INFOX_DATAGRAM_PROTOCOL; ::CopyMemory( pHeader->Protocol, NdasIxProtocolName, sizeof(NdasIxProtocolName)); pHeader->LSInfoXMajorVersion = INFOX_DATAGRAM_MAJVER; pHeader->LSInfoXMinorVersion = INFOX_DATAGRAM_MINVER; pHeader->OsMajorType = OSTYPE_WINDOWS; DWORD dwOSMajorVersion, dwOSMinorVersion; pGetOSVersion(&dwOSMajorVersion, &dwOSMinorVersion); USHORT usLfsOsMinorType = pInfoXGetOSType(dwOSMajorVersion, dwOSMinorVersion); pHeader->OsMinorType = usLfsOsMinorType; pHeader->Type = LSINFOX_PRIMARY_UPDATE_MESSAGE | LSINFOX_TYPE_REPLY; pHeader->MessageSize = cbPacket; // // Body // LPX_ADDRESS localLpxAddress = sock.GetBoundAddr()->LpxAddress; pUsageReply->HostLanAddr.AddressType = LSNODE_ADDRTYPE_ETHER; pUsageReply->HostLanAddr.AddressLen = LPXADDR_NODE_LENGTH; ::CopyMemory( pUsageReply->HostLanAddr.Address, localLpxAddress.Node, LPXADDR_NODE_LENGTH); WCHAR wszHostName[MAX_HOSTNAME_LEN] = {0}; USHORT hostNameType = LSNODENAME_DNSFULLYQ; DWORD cchHostName = MAX_HOSTNAME_LEN; BOOL fSuccess = ::GetComputerNameExW( ComputerNameDnsFullyQualified, wszHostName, &cchHostName); if (!fSuccess) { hostNameType = LSNODENAME_NETBOIS; cchHostName = MAX_HOSTNAME_LEN; fSuccess = ::GetComputerNameExW( ComputerNameNetBIOS, wszHostName, &cchHostName); } if (!fSuccess) { hostNameType = LSNODENAME_UNKNOWN; cchHostName = 0; } pUsageReply->HostNameType = hostNameType; pUsageReply->HostNameLength = cchHostName; ::CopyMemory( pUsageReply->HostName, wszHostName, cchHostName * sizeof(WCHAR)); // // LPX Address.Node is an adapter address. // const DWORD cbAdapterAddress = 6; BYTE pAdapterAddress[cbAdapterAddress] = {0}; ::CopyMemory(pAdapterAddress, localLpxAddress.Node, 6); DWORD cbIpAddress = 14; // TODO: why is this 14? BYTE pPrimaryIpAddress[14] = {0}; fSuccess = pGetAdapterPrimaryIpAddress( cbAdapterAddress, pAdapterAddress, &cbIpAddress, pPrimaryIpAddress); fSuccess = FALSE; if (!fSuccess) { DBGPRT_WARN_EX(_FT("Failed to get primary ip address of %s: "), CSockLpxAddr(sock.GetBoundAddr()).ToString()); pUsageReply->HostWanAddr.AddressLen = 0; pUsageReply->HostWanAddr.AddressType = LSNODE_ADDRTYPE_IP; ::ZeroMemory(pUsageReply->HostWanAddr.Address, LSNODE_ADDR_LENGTH); } else { pUsageReply->HostWanAddr.AddressLen = (USHORT) cbIpAddress; pUsageReply->HostWanAddr.AddressType = LSNODE_ADDRTYPE_IP; _ASSERTE(cbIpAddress <= LSNODE_ADDR_LENGTH); ::CopyMemory( pUsageReply->HostWanAddr.Address, pPrimaryIpAddress, cbIpAddress); } // // Software Versions, status, etc // if (mountedAcces & GENERIC_READ) { pUsageReply->AccessRight |= LSSESSION_ACCESS_READ; } if (mountedAcces & GENERIC_WRITE) { pUsageReply->AccessRight |= LSSESSION_ACCESS_WRITE; } pUsageReply->NetDiskPort = NDAS_DEVICE_LPX_PORT; pUsageReply->UnitDiskNo = unitDeviceId.UnitNo; pUsageReply->UsageID = 0; pUsageReply->SWMajorVersion = NDASIX_VERSION_MAJOR; pUsageReply->SWMinorVersion = NDASIX_VERSION_MINOR; pUsageReply->SWBuildNumber = NDASIX_VERSION_BUILD; pUsageReply->NDFSCompatVersion = m_NDFSVersion.wMajor; pUsageReply->NDFSVersion = m_NDFSVersion.wMinor; DWORD cbSent = 0; fSuccess = sock.SendToSync(pRemoteAddr, cbPacket, pbPacket, 0, &cbSent); if (!fSuccess) { DBGPRT_ERR_EX(_FT("Failed to send a reply (%d bytes): "), cbPacket); return; } return; }
BOOL CNdasLogicalDevice::Recover() { BOOL fSuccess(FALSE); ximeta::CAutoLock autolock(this); DBGPRT_INFO(_FT("Recovering %s\n"), ToString()); switch(GetType()) { case NDAS_LOGICALDEVICE_TYPE_DISK_RAID1: case NDAS_LOGICALDEVICE_TYPE_DISK_RAID4: break; default: return FALSE; } if (m_status == NDAS_LOGICALDEVICE_STATUS_NOT_INITIALIZED) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_NOT_INITIALIZED); return FALSE; } if (m_status != NDAS_LOGICALDEVICE_STATUS_MOUNTED) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_LOGICALDEVICE_NOT_MOUNTED); return FALSE; } // Do not recover if any NDAS unit device is not alive DWORD ldSequence = 0; for(ldSequence = 0; ldSequence < m_logicalDeviceGroup.nUnitDevices; ldSequence++) { if(NDAS_UNITDEVICE_STATUS_MOUNTED != m_pUnitDevices[ldSequence]->GetStatus()) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_UNITDEVICE_NOT_MOUNTED); return FALSE; } } if(IsAnyUnitDevicesFault()) { ::SetLastError(NDASHLPSVC_ERROR_NDAS_UNITDEVICE_NOT_MOUNTED); return FALSE; } ULONG ulStatus; fSuccess = ::LsBusCtlQueryStatus( m_NdasScsiLocation.SlotNo, &ulStatus); if (!fSuccess) { DBGPRT_ERR_EX(_FT("Unable to get status")); return FALSE; } // Do not recover if NDAS logical device is not under emergency // Do not recover if NDAS logical device is already recovering if(!ADAPTERINFO_ISSTATUSFLAG(ulStatus, ADAPTERINFO_STATUSFLAG_MEMBER_FAULT)) { DBGPRT_ERR_EX(_FT("Not in emergency mode or already recovering")); return FALSE; } // // LsBusCtl is overhauled only to use SlotNo for RemoveTargetData // // // Remove target ejects the disk and the volume. // fSuccess = LsBusCtlRecoverTarget(m_NdasScsiLocation.SlotNo); if (!fSuccess) { DBGPRT_WARN_EX(_FT("LsBusCtlRemoveTarget failed: ")); } DBGPRT_INFO(_FT("Started recovering successfully at slot %s.\n"), CNdasScsiLocation(m_NdasScsiLocation).ToString()); return TRUE; }
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; }