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; }
int UpdateDataItem(StatusType status, AeDRMDataItem *dataItem) { int ret = 0; AeGetCurrentTime(&dataItem->value.timeStamp); switch (status) { case STATUS_HD: { struct statfs buf; memset(&buf, 0, sizeof(buf)); if (statfs("/results", &buf) == 0) { double newPercentFull = 1.0 - (double)buf.f_bavail / (double)buf.f_blocks; double delta = newPercentFull - percentFull; if (delta < 0) delta = -delta; if (delta > 0.01) { percentFull = newPercentFull; dataItem->pName = "TS.HW.HD.ResultsFull"; dataItem->value.iType = AeDRMDataAnalog; dataItem->value.iQuality = AeDRMDataGood; dataItem->value.data.dAnalog = 100.0 * percentFull; ret = 1; } } } break; case STATUS_TASK: dataItem->pName = "TS.TASK"; dataItem->value.iType = AeDRMDataString; dataItem->value.iQuality = AeDRMDataGood; dataItem->value.data.pString = "Idle"; // MGD placeholder ret = 1; break; case STATUS_EVENT: // here we check the event log for new entries, and post any we find via our callback ret = 0; // the caller will try and post if this is non-zero, so always return 0, we handle posts via the callback here // eventLogCheck(EventPostCB, dataItem); break; case STATUS_VERSIONS: { // check to see if the package database has been modified, if so we need to update our version information struct stat buf; memset(&buf, 0, sizeof(buf)); stat("/var/lib/dpkg/status", &buf); if (buf.st_mtime != lastVersionModTime) { lastVersionModTime = buf.st_mtime; GenerateVersionInfo(); SendVersionInfo(dataItem); // no need to set ret to 1, we have already posted the data } } break; case STATUS_CONTACTINFO: { // check to see if the contact info has been modified and if so update Axeda const char* contactsFile = "ContactInfo.txt"; struct stat buf; memset(&buf, 0, sizeof(buf)); int retVal = stat(contactsFile, &buf); if (retVal != 0) { // no contactinfo.txt so call updateContactInfo.py script here. // dbreports calls updateContactInfo.py if the contact info changes. // TODO: depends on getContactInfo.py putting contactinfo.txt where we can find it // which is currently in the same directory as the location of the script itself // which happens to be where the RSM agent is running from // TODO: contactsFile is not locked during write so script called from dbreports // could overwrite it while we are reading/writing it here retVal = system("python updateContactInfo.py"); if (retVal == 0) { memset(&buf, 0, sizeof(buf)); retVal = stat("ContactInfo.txt", &buf); } } if (retVal == 0 && buf.st_mtime != lastContactInfoTime) { lastContactInfoTime = buf.st_mtime; SendContactInfo(dataItem, contactsFile); // no need to set ret to 1, we have already posted the data } } break; case STATUS_SERVICES: system("python status.py > TSServers.txt"); SendServersStatus(dataItem); break; case STATUS_FILESERVERS: system("python queryFileServers.py > TSFileServers.txt"); SendFileServerStatus(dataItem); break; case STATUS_NETWORK: if (0 == system("TSquery > TSnetwork.txt")) { SendNetworkStatus(dataItem, "TSnetwork.txt"); } break; case STATUS_EXPERIMENT: { // torrent server writes out the experiment metrics files at the end of analysis // (see TLScript.py) // if we see any experiment metrics files send them to DRM server // SendExperimentMetrics deletes the files when it is done with them. if (0 == system("ls -tr1 TSexperiment-*.txt > TSexperiments.txt")) { SendExperimentMetrics(dataItem, "TSexperiments.txt"); } } break; case STATUS_HARDWARE: { // Identifies the type of computer hardware the server is running on. // Dell T7500 or Dell T620 for example. // product_info.alt file is written during RSM_launch startup script execution SendHardwareName(dataItem, "product_info.alt"); // Records version of BIOS installed on server SendBiosVersion(dataItem, "product_info.alt"); } break; case STATUS_PGMS: // get the list of attached PGM's // MGD - for now, we will just do this when we start up, but might want to do once an hour or something in the future // MGD - the python script stops after finding the first valid, could change in the future if we want the entire list // - but the purpose initially was to allow Axeda to grab customer info from SAP using a serial number of a PGM // free old list if (agentInfo.numPGMs > 0) { int i; for(i=0;i<agentInfo.numPGMs;i++) free(agentInfo.pgmSerialNumberList[i]); free(agentInfo.pgmSerialNumberList); agentInfo.pgmSerialNumberList = NULL; } // build new list agentInfo.numPGMs = 0; agentInfo.pgmSerialNumberList = 0; system("python find_serial.py > PGM_list.txt"); FILE *fp = fopen("PGM_list.txt", "rb"); if (!fp) break; // count lines/PGMs agentInfo.numPGMs = 0; const int LF=10; int c; while ((c=fgetc(fp))!=EOF) agentInfo.numPGMs += (c==LF) ? 1 : 0; // one line per PGM serial number fseek(fp,0,SEEK_SET); agentInfo.pgmSerialNumberList = (char **)malloc(sizeof(char *)*agentInfo.numPGMs); // its a list of string pointers int i; for (i = 0; i < agentInfo.numPGMs; i++) { char serial[64], line[64]; if (fgets(line, sizeof(line), fp) == NULL) break; sscanf(line, "%s", serial); // gets rid of LF if (serial[0] != 0) { char *ptr = serial; if (serial[0] == 's' && serial[1] == 'n') ptr = ptr + 2; agentInfo.pgmSerialNumberList[i] = strdup(ptr); } // send list if (i == 0) { dataItem->pName = "TS.PGM.Default"; // MGD - in the future, we can specify each PGM by name if we wanted to, but the 'Default' PGM can still be hooked into for SAP lookups dataItem->value.iQuality = AeDRMDataGood; dataItem->value.iType = AeDRMDataString; dataItem->value.data.pString = agentInfo.pgmSerialNumberList[i]; AeDRMPostDataItem(iDeviceId, iServerId, AeDRMQueuePriorityNormal, dataItem); } char itemName[64]; sprintf(itemName, "TS.PGM.%d", i+1); dataItem->pName = itemName; dataItem->value.iQuality = AeDRMDataGood; dataItem->value.iType = AeDRMDataString; dataItem->value.data.pString = agentInfo.pgmSerialNumberList[i]; AeDRMPostDataItem(iDeviceId, iServerId, AeDRMQueuePriorityNormal, dataItem); } fclose(fp); // MGD - I'm leaving the ret code as 0 since I envision this code could send over multiple PGMs in the future, so I'm sending the one now break; } return ret; }