Exemplo n.º 1
0
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;
}
Exemplo n.º 2
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;
}