2 * Copyright (C) ARM Limited 2011-2013. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
12 #include <arpa/inet.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
17 #include "OlyUtility.h"
18 #include "SessionData.h"
19 #include "CapturedXML.h"
20 #include "StreamlineSetup.h"
21 #include "ConfigurationXML.h"
23 #include "EventsXML.h"
25 static const char* TAG_SESSION = "session";
26 static const char* TAG_REQUEST = "request";
27 static const char* TAG_CONFIGURATIONS = "configurations";
29 static const char* ATTR_TYPE = "type";
30 static const char* VALUE_EVENTS = "events";
31 static const char* VALUE_CONFIGURATION = "configuration";
32 static const char* VALUE_COUNTERS = "counters";
33 static const char* VALUE_CAPTURED = "captured";
34 static const char* VALUE_DEFAULTS = "defaults";
36 StreamlineSetup::StreamlineSetup(OlySocket* s) {
43 // Receive commands from Streamline (master)
45 // receive command over socket
46 gSessionData->mWaitingOnCommand = true;
47 data = readCommand(&type);
49 // parse and handle data
51 case COMMAND_REQUEST_XML:
54 case COMMAND_DELIVER_XML:
57 case COMMAND_APC_START:
58 logg->logMessage("Received apc start request");
61 case COMMAND_APC_STOP:
62 logg->logMessage("Received apc stop request before apc start request");
65 case COMMAND_DISCONNECT:
66 logg->logMessage("Received disconnect command");
70 logg->logMessage("Received ping command");
71 sendData(NULL, 0, RESPONSE_ACK);
74 logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type);
81 if (gSessionData->mCounterOverflow > 0) {
82 logg->logError(__FILE__, __LINE__, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
87 StreamlineSetup::~StreamlineSetup() {
90 char* StreamlineSetup::readCommand(int* command) {
91 unsigned char header[5];
95 // receive type and length
96 response = mSocket->receiveNBytes((char*)&header, sizeof(header));
98 // After receiving a single byte, we are no longer waiting on a command
99 gSessionData->mWaitingOnCommand = false;
102 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
106 const char type = header[0];
107 const int length = (header[1] << 0) | (header[2] << 8) | (header[3] << 16) | (header[4] << 24);
109 // add artificial limit
110 if ((length < 0) || length > 1024 * 1024) {
111 logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length);
115 // allocate memory to contain the xml file, size of zero returns a zero size object
116 data = (char*)calloc(length + 1, 1);
118 logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml");
123 response = mSocket->receiveNBytes(data, length);
125 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
129 // null terminate the data for string parsing
138 void StreamlineSetup::handleRequest(char* xml) {
139 mxml_node_t *tree, *node;
140 const char * attr = NULL;
142 tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK);
143 node = mxmlFindElement(tree, tree, TAG_REQUEST, ATTR_TYPE, NULL, MXML_DESCEND_FIRST);
145 attr = mxmlElementGetAttr(node, ATTR_TYPE);
147 if (attr && strcmp(attr, VALUE_EVENTS) == 0) {
149 logg->logMessage("Sent events xml response");
150 } else if (attr && strcmp(attr, VALUE_CONFIGURATION) == 0) {
152 logg->logMessage("Sent configuration xml response");
153 } else if (attr && strcmp(attr, VALUE_COUNTERS) == 0) {
155 logg->logMessage("Sent counters xml response");
156 } else if (attr && strcmp(attr, VALUE_CAPTURED) == 0) {
157 CapturedXML capturedXML;
158 char* capturedText = capturedXML.getXML(false);
159 sendData(capturedText, strlen(capturedText), RESPONSE_XML);
161 logg->logMessage("Sent captured xml response");
162 } else if (attr && strcmp(attr, VALUE_DEFAULTS) == 0) {
164 logg->logMessage("Sent default configuration xml response");
166 char error[] = "Unknown request";
167 sendData(error, strlen(error), RESPONSE_NAK);
168 logg->logMessage("Received unknown request:\n%s", xml);
174 void StreamlineSetup::handleDeliver(char* xml) {
177 // Determine xml type
178 tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK);
179 if (mxmlFindElement(tree, tree, TAG_SESSION, NULL, NULL, MXML_DESCEND_FIRST)) {
181 gSessionData->parseSessionXML(xml);
182 sendData(NULL, 0, RESPONSE_ACK);
183 logg->logMessage("Received session xml");
184 } else if (mxmlFindElement(tree, tree, TAG_CONFIGURATIONS, NULL, NULL, MXML_DESCEND_FIRST)) {
186 writeConfiguration(xml);
187 sendData(NULL, 0, RESPONSE_ACK);
188 logg->logMessage("Received configuration xml");
191 logg->logMessage("Received unknown XML delivery type");
192 sendData(NULL, 0, RESPONSE_NAK);
198 void StreamlineSetup::sendData(const char* data, uint32_t length, char type) {
199 unsigned char header[5];
201 header[1] = (length >> 0) & 0xff;
202 header[2] = (length >> 8) & 0xff;
203 header[3] = (length >> 16) & 0xff;
204 header[4] = (length >> 24) & 0xff;
205 mSocket->send((char*)&header, sizeof(header));
206 mSocket->send((char*)data, length);
209 void StreamlineSetup::sendEvents() {
211 char* string = eventsXML.getXML();
212 sendString(string, RESPONSE_XML);
216 void StreamlineSetup::sendConfiguration() {
217 ConfigurationXML xml;
219 const char* string = xml.getConfigurationXML();
220 sendData(string, strlen(string), RESPONSE_XML);
223 void StreamlineSetup::sendDefaults() {
224 // Send the config built into the binary
227 ConfigurationXML::getDefaultConfigurationXml(xml, size);
229 // Artificial size restriction
230 if (size > 1024*1024) {
231 logg->logError(__FILE__, __LINE__, "Corrupt default configuration file");
235 sendData(xml, size, RESPONSE_XML);
238 void StreamlineSetup::sendCounters() {
240 mxml_node_t *counters;
242 xml = mxmlNewXML("1.0");
243 counters = mxmlNewElement(xml, "counters");
244 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
245 driver->writeCounters(counters);
248 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
249 sendString(string, RESPONSE_XML);
255 void StreamlineSetup::writeConfiguration(char* xml) {
258 ConfigurationXML::getPath(path);
260 if (util->writeToDisk(path, xml) < 0) {
261 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify write permissions to this path.", path);
265 // Re-populate gSessionData with the configuration, as it has now changed
266 { ConfigurationXML configuration; }
268 if (gSessionData->mCounterOverflow > 0) {
269 logg->logError(__FILE__, __LINE__, "Only %i performance counters counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);