blob: e37f2712cd04d40ce6f7e42d31d5a047733c3e69 [file] [log] [blame]
Jon Medhurstaaf37a32013-06-11 12:10:56 +01001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2011-2015. All rights reserved.
Jon Medhurstaaf37a32013-06-11 12:10:56 +01003 *
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.
7 */
8
Jon Medhurstaaf37a32013-06-11 12:10:56 +01009#include "StreamlineSetup.h"
Jon Medhurst15ce78d2014-04-10 09:02:02 +010010
11#include "Buffer.h"
12#include "CapturedXML.h"
Jon Medhurstaaf37a32013-06-11 12:10:56 +010013#include "ConfigurationXML.h"
14#include "Driver.h"
15#include "EventsXML.h"
Jon Medhurst15ce78d2014-04-10 09:02:02 +010016#include "Logging.h"
17#include "OlySocket.h"
18#include "OlyUtility.h"
19#include "Sender.h"
20#include "SessionData.h"
Jon Medhurstaaf37a32013-06-11 12:10:56 +010021
22static const char* TAG_SESSION = "session";
23static const char* TAG_REQUEST = "request";
24static const char* TAG_CONFIGURATIONS = "configurations";
25
26static const char* ATTR_TYPE = "type";
27static const char* VALUE_EVENTS = "events";
28static const char* VALUE_CONFIGURATION = "configuration";
29static const char* VALUE_COUNTERS = "counters";
30static const char* VALUE_CAPTURED = "captured";
31static const char* VALUE_DEFAULTS = "defaults";
32
33StreamlineSetup::StreamlineSetup(OlySocket* s) {
34 bool ready = false;
35 char* data = NULL;
36 int type;
37
38 mSocket = s;
39
40 // Receive commands from Streamline (master)
41 while (!ready) {
42 // receive command over socket
43 gSessionData->mWaitingOnCommand = true;
44 data = readCommand(&type);
45
46 // parse and handle data
47 switch (type) {
48 case COMMAND_REQUEST_XML:
49 handleRequest(data);
50 break;
51 case COMMAND_DELIVER_XML:
52 handleDeliver(data);
53 break;
54 case COMMAND_APC_START:
55 logg->logMessage("Received apc start request");
56 ready = true;
57 break;
58 case COMMAND_APC_STOP:
59 logg->logMessage("Received apc stop request before apc start request");
60 exit(0);
61 break;
62 case COMMAND_DISCONNECT:
63 logg->logMessage("Received disconnect command");
64 exit(0);
65 break;
66 case COMMAND_PING:
67 logg->logMessage("Received ping command");
68 sendData(NULL, 0, RESPONSE_ACK);
69 break;
70 default:
Jon Medhurstb1d07442015-05-08 12:04:18 +010071 logg->logError("Target error: Unknown command type, %d", type);
Jon Medhurstaaf37a32013-06-11 12:10:56 +010072 handleException();
73 }
74
75 free(data);
76 }
77
78 if (gSessionData->mCounterOverflow > 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010079 logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
Jon Medhurstaaf37a32013-06-11 12:10:56 +010080 handleException();
81 }
82}
83
84StreamlineSetup::~StreamlineSetup() {
85}
86
87char* StreamlineSetup::readCommand(int* command) {
88 unsigned char header[5];
89 char* data;
90 int response;
91
92 // receive type and length
93 response = mSocket->receiveNBytes((char*)&header, sizeof(header));
94
95 // After receiving a single byte, we are no longer waiting on a command
96 gSessionData->mWaitingOnCommand = false;
97
98 if (response < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010099 logg->logError("Target error: Unexpected socket disconnect");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100100 handleException();
101 }
102
103 const char type = header[0];
104 const int length = (header[1] << 0) | (header[2] << 8) | (header[3] << 16) | (header[4] << 24);
105
106 // add artificial limit
107 if ((length < 0) || length > 1024 * 1024) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100108 logg->logError("Target error: Invalid length received, %d", length);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100109 handleException();
110 }
111
112 // allocate memory to contain the xml file, size of zero returns a zero size object
113 data = (char*)calloc(length + 1, 1);
114 if (data == NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100115 logg->logError("Unable to allocate memory for xml");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100116 handleException();
117 }
118
119 // receive data
120 response = mSocket->receiveNBytes(data, length);
121 if (response < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100122 logg->logError("Target error: Unexpected socket disconnect");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100123 handleException();
124 }
125
126 // null terminate the data for string parsing
127 if (length > 0) {
128 data[length] = 0;
129 }
130
131 *command = type;
132 return data;
133}
134
135void StreamlineSetup::handleRequest(char* xml) {
136 mxml_node_t *tree, *node;
137 const char * attr = NULL;
138
139 tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK);
140 node = mxmlFindElement(tree, tree, TAG_REQUEST, ATTR_TYPE, NULL, MXML_DESCEND_FIRST);
141 if (node) {
142 attr = mxmlElementGetAttr(node, ATTR_TYPE);
143 }
144 if (attr && strcmp(attr, VALUE_EVENTS) == 0) {
145 sendEvents();
146 logg->logMessage("Sent events xml response");
147 } else if (attr && strcmp(attr, VALUE_CONFIGURATION) == 0) {
148 sendConfiguration();
149 logg->logMessage("Sent configuration xml response");
150 } else if (attr && strcmp(attr, VALUE_COUNTERS) == 0) {
151 sendCounters();
152 logg->logMessage("Sent counters xml response");
153 } else if (attr && strcmp(attr, VALUE_CAPTURED) == 0) {
154 CapturedXML capturedXML;
155 char* capturedText = capturedXML.getXML(false);
156 sendData(capturedText, strlen(capturedText), RESPONSE_XML);
157 free(capturedText);
158 logg->logMessage("Sent captured xml response");
159 } else if (attr && strcmp(attr, VALUE_DEFAULTS) == 0) {
160 sendDefaults();
161 logg->logMessage("Sent default configuration xml response");
162 } else {
163 char error[] = "Unknown request";
164 sendData(error, strlen(error), RESPONSE_NAK);
165 logg->logMessage("Received unknown request:\n%s", xml);
166 }
167
168 mxmlDelete(tree);
169}
170
171void StreamlineSetup::handleDeliver(char* xml) {
172 mxml_node_t *tree;
173
174 // Determine xml type
175 tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK);
176 if (mxmlFindElement(tree, tree, TAG_SESSION, NULL, NULL, MXML_DESCEND_FIRST)) {
177 // Session XML
178 gSessionData->parseSessionXML(xml);
179 sendData(NULL, 0, RESPONSE_ACK);
180 logg->logMessage("Received session xml");
181 } else if (mxmlFindElement(tree, tree, TAG_CONFIGURATIONS, NULL, NULL, MXML_DESCEND_FIRST)) {
182 // Configuration XML
183 writeConfiguration(xml);
184 sendData(NULL, 0, RESPONSE_ACK);
185 logg->logMessage("Received configuration xml");
186 } else {
187 // Unknown XML
188 logg->logMessage("Received unknown XML delivery type");
189 sendData(NULL, 0, RESPONSE_NAK);
190 }
191
192 mxmlDelete(tree);
193}
194
195void StreamlineSetup::sendData(const char* data, uint32_t length, char type) {
196 unsigned char header[5];
197 header[0] = type;
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100198 Buffer::writeLEInt(header + 1, length);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100199 mSocket->send((char*)&header, sizeof(header));
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100200 mSocket->send((const char*)data, length);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100201}
202
203void StreamlineSetup::sendEvents() {
204 EventsXML eventsXML;
205 char* string = eventsXML.getXML();
206 sendString(string, RESPONSE_XML);
207 free(string);
208}
209
210void StreamlineSetup::sendConfiguration() {
211 ConfigurationXML xml;
212
213 const char* string = xml.getConfigurationXML();
214 sendData(string, strlen(string), RESPONSE_XML);
215}
216
217void StreamlineSetup::sendDefaults() {
218 // Send the config built into the binary
219 const char* xml;
220 unsigned int size;
221 ConfigurationXML::getDefaultConfigurationXml(xml, size);
222
223 // Artificial size restriction
224 if (size > 1024*1024) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100225 logg->logError("Corrupt default configuration file");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100226 handleException();
227 }
228
229 sendData(xml, size, RESPONSE_XML);
230}
231
232void StreamlineSetup::sendCounters() {
233 mxml_node_t *xml;
234 mxml_node_t *counters;
235
236 xml = mxmlNewXML("1.0");
237 counters = mxmlNewElement(xml, "counters");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100238 int count = 0;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100239 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100240 count += driver->writeCounters(counters);
241 }
242
243 if (count == 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100244 logg->logError("No counters found, this could be because /dev/gator/events can not be read or because perf is not working correctly");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100245 handleException();
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100246 }
247
248 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
249 sendString(string, RESPONSE_XML);
250
251 free(string);
252 mxmlDelete(xml);
253}
254
255void StreamlineSetup::writeConfiguration(char* xml) {
256 char path[PATH_MAX];
257
Jon Medhurstd3698592013-10-10 16:48:56 +0100258 ConfigurationXML::getPath(path);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100259
260 if (util->writeToDisk(path, xml) < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100261 logg->logError("Error writing %s\nPlease verify write permissions to this path.", path);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100262 handleException();
263 }
264
265 // Re-populate gSessionData with the configuration, as it has now changed
266 { ConfigurationXML configuration; }
267
268 if (gSessionData->mCounterOverflow > 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100269 logg->logError("Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100270 handleException();
271 }
272}