From 0ec3209cc6398c8ad0a4095ca6ce9b149655e9e4 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Wed, 3 Apr 2013 14:21:06 +0100 Subject: gator: Version 5.14 Signed-off-by: Jon Medhurst --- tools/gator/daemon/StreamlineSetup.cpp | 309 +++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 tools/gator/daemon/StreamlineSetup.cpp (limited to 'tools/gator/daemon/StreamlineSetup.cpp') diff --git a/tools/gator/daemon/StreamlineSetup.cpp b/tools/gator/daemon/StreamlineSetup.cpp new file mode 100644 index 00000000000..88c07a6224c --- /dev/null +++ b/tools/gator/daemon/StreamlineSetup.cpp @@ -0,0 +1,309 @@ +/** + * Copyright (C) ARM Limited 2011-2013. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include "Sender.h" +#include "Logging.h" +#include "OlyUtility.h" +#include "SessionData.h" +#include "CapturedXML.h" +#include "StreamlineSetup.h" +#include "ConfigurationXML.h" +#include "Driver.h" + +static const char* TAG_SESSION = "session"; +static const char* TAG_REQUEST = "request"; +static const char* TAG_CONFIGURATIONS = "configurations"; + +static const char* ATTR_TYPE = "type"; +static const char* VALUE_EVENTS = "events"; +static const char* VALUE_CONFIGURATION = "configuration"; +static const char* VALUE_COUNTERS = "counters"; +static const char* VALUE_CAPTURED = "captured"; +static const char* VALUE_DEFAULTS = "defaults"; + +StreamlineSetup::StreamlineSetup(OlySocket* s) { + bool ready = false; + char* data = NULL; + int type; + + mSocket = s; + + // Receive commands from Streamline (master) + while (!ready) { + // receive command over socket + gSessionData->mWaitingOnCommand = true; + data = readCommand(&type); + + // parse and handle data + switch (type) { + case COMMAND_REQUEST_XML: + handleRequest(data); + break; + case COMMAND_DELIVER_XML: + handleDeliver(data); + break; + case COMMAND_APC_START: + logg->logMessage("Received apc start request"); + ready = true; + break; + case COMMAND_APC_STOP: + logg->logMessage("Received apc stop request before apc start request"); + exit(0); + break; + case COMMAND_DISCONNECT: + logg->logMessage("Received disconnect command"); + exit(0); + break; + case COMMAND_PING: + logg->logMessage("Received ping command"); + sendData(NULL, 0, RESPONSE_ACK); + break; + default: + logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type); + handleException(); + } + + free(data); + } + + if (gSessionData->mCounterOverflow) { + logg->logError(__FILE__, __LINE__, "Exceeded maximum number of %d performance counters", MAX_PERFORMANCE_COUNTERS); + handleException(); + } +} + +StreamlineSetup::~StreamlineSetup() { +} + +char* StreamlineSetup::readCommand(int* command) { + char type; + char* data; + int response, length; + + // receive type + response = mSocket->receiveNBytes(&type, sizeof(type)); + + // After receiving a single byte, we are no longer waiting on a command + gSessionData->mWaitingOnCommand = false; + + if (response < 0) { + logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect"); + handleException(); + } + + // receive length + response = mSocket->receiveNBytes((char*)&length, sizeof(length)); + if (response < 0) { + logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect"); + handleException(); + } + + // add artificial limit + if ((length < 0) || length > 1024 * 1024) { + logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length); + handleException(); + } + + // allocate memory to contain the xml file, size of zero returns a zero size object + data = (char*)calloc(length + 1, 1); + if (data == NULL) { + logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml"); + handleException(); + } + + // receive data + response = mSocket->receiveNBytes(data, length); + if (response < 0) { + logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect"); + handleException(); + } + + // null terminate the data for string parsing + if (length > 0) { + data[length] = 0; + } + + *command = type; + return data; +} + +void StreamlineSetup::handleRequest(char* xml) { + mxml_node_t *tree, *node; + const char * attr = NULL; + + tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK); + node = mxmlFindElement(tree, tree, TAG_REQUEST, ATTR_TYPE, NULL, MXML_DESCEND_FIRST); + if (node) { + attr = mxmlElementGetAttr(node, ATTR_TYPE); + } + if (attr && strcmp(attr, VALUE_EVENTS) == 0) { + sendEvents(); + logg->logMessage("Sent events xml response"); + } else if (attr && strcmp(attr, VALUE_CONFIGURATION) == 0) { + sendConfiguration(); + logg->logMessage("Sent configuration xml response"); + } else if (attr && strcmp(attr, VALUE_COUNTERS) == 0) { + sendCounters(); + logg->logMessage("Sent counters xml response"); + } else if (attr && strcmp(attr, VALUE_CAPTURED) == 0) { + CapturedXML capturedXML; + char* capturedText = capturedXML.getXML(false); + sendData(capturedText, strlen(capturedText), RESPONSE_XML); + free(capturedText); + logg->logMessage("Sent captured xml response"); + } else if (attr && strcmp(attr, VALUE_DEFAULTS) == 0) { + sendDefaults(); + logg->logMessage("Sent default configuration xml response"); + } else { + char error[] = "Unknown request"; + sendData(error, strlen(error), RESPONSE_NAK); + logg->logMessage("Received unknown request:\n%s", xml); + } + + mxmlDelete(tree); +} + +void StreamlineSetup::handleDeliver(char* xml) { + mxml_node_t *tree; + + // Determine xml type + tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK); + if (mxmlFindElement(tree, tree, TAG_SESSION, NULL, NULL, MXML_DESCEND_FIRST)) { + // Session XML + gSessionData->parseSessionXML(xml); + sendData(NULL, 0, RESPONSE_ACK); + logg->logMessage("Received session xml"); + } else if (mxmlFindElement(tree, tree, TAG_CONFIGURATIONS, NULL, NULL, MXML_DESCEND_FIRST)) { + // Configuration XML + writeConfiguration(xml); + sendData(NULL, 0, RESPONSE_ACK); + logg->logMessage("Received configuration xml"); + } else { + // Unknown XML + logg->logMessage("Received unknown XML delivery type"); + sendData(NULL, 0, RESPONSE_NAK); + } + + mxmlDelete(tree); +} + +void StreamlineSetup::sendData(const char* data, int length, int type) { + mSocket->send((char*)&type, 1); + mSocket->send((char*)&length, sizeof(length)); + mSocket->send((char*)data, length); +} + +void StreamlineSetup::sendEvents() { +#include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len + char path[PATH_MAX]; + mxml_node_t *xml; + FILE *fl; + + // Avoid unused variable warning + (void)events_xml_len; + + // Load the provided or default events xml + if (gSessionData->mEventsXMLPath) { + strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX); + } else { + util->getApplicationFullPath(path, PATH_MAX); + strncat(path, "events.xml", PATH_MAX - strlen(path) - 1); + } + fl = fopen(path, "r"); + if (fl) { + xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK); + fclose(fl); + } else { + logg->logMessage("Unable to locate events.xml, using default"); + xml = mxmlLoadString(NULL, (char *)events_xml, MXML_NO_CALLBACK); + } + + // Add dynamic events from the drivers + mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND); + if (!events) { + logg->logMessage("Unable to find node in the events.xml"); + handleException(); + } + for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) { + driver->writeEvents(events); + } + + char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB); + sendString(string, RESPONSE_XML); + free(string); + mxmlDelete(xml); +} + +void StreamlineSetup::sendConfiguration() { + ConfigurationXML xml; + + const char* string = xml.getConfigurationXML(); + sendData(string, strlen(string), RESPONSE_XML); +} + +void StreamlineSetup::sendDefaults() { + // Send the config built into the binary + const char* xml; + unsigned int size; + ConfigurationXML::getDefaultConfigurationXml(xml, size); + + // Artificial size restriction + if (size > 1024*1024) { + logg->logError(__FILE__, __LINE__, "Corrupt default configuration file"); + handleException(); + } + + sendData(xml, size, RESPONSE_XML); +} + +void StreamlineSetup::sendCounters() { + mxml_node_t *xml; + mxml_node_t *counters; + + xml = mxmlNewXML("1.0"); + counters = mxmlNewElement(xml, "counters"); + for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) { + driver->writeCounters(counters); + } + + char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB); + sendString(string, RESPONSE_XML); + + free(string); + mxmlDelete(xml); +} + +void StreamlineSetup::writeConfiguration(char* xml) { + char path[PATH_MAX]; + + if (gSessionData->mConfigurationXMLPath) { + strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX); + } else { + util->getApplicationFullPath(path, PATH_MAX); + strncat(path, "configuration.xml", PATH_MAX - strlen(path) - 1); + } + + if (util->writeToDisk(path, xml) < 0) { + logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify write permissions to this path.", path); + handleException(); + } + + // Re-populate gSessionData with the configuration, as it has now changed + { ConfigurationXML configuration; } + + if (gSessionData->mCounterOverflow) { + logg->logError(__FILE__, __LINE__, "Exceeded maximum number of %d performance counters", MAX_PERFORMANCE_COUNTERS); + handleException(); + } +} -- cgit v1.2.3