gator: Version 5.19
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / StreamlineSetup.cpp
1 /**
2  * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3  *
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
9 #include "StreamlineSetup.h"
10
11 #include "Buffer.h"
12 #include "CapturedXML.h"
13 #include "ConfigurationXML.h"
14 #include "Driver.h"
15 #include "EventsXML.h"
16 #include "Logging.h"
17 #include "OlySocket.h"
18 #include "OlyUtility.h"
19 #include "Sender.h"
20 #include "SessionData.h"
21
22 static const char* TAG_SESSION = "session";
23 static const char* TAG_REQUEST = "request";
24 static const char* TAG_CONFIGURATIONS = "configurations";
25
26 static const char* ATTR_TYPE           = "type";
27 static const char* VALUE_EVENTS        = "events";
28 static const char* VALUE_CONFIGURATION = "configuration";
29 static const char* VALUE_COUNTERS      = "counters";
30 static const char* VALUE_CAPTURED      = "captured";
31 static const char* VALUE_DEFAULTS      = "defaults";
32
33 StreamlineSetup::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:
71                                 logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type);
72                                 handleException();
73                 }
74
75                 free(data);
76         }
77
78         if (gSessionData->mCounterOverflow > 0) {
79                 logg->logError(__FILE__, __LINE__, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
80                 handleException();
81         }
82 }
83
84 StreamlineSetup::~StreamlineSetup() {
85 }
86
87 char* 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) {
99                 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
100                 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) {
108                 logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length);
109                 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) {
115                 logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml");
116                 handleException();
117         }
118
119         // receive data
120         response = mSocket->receiveNBytes(data, length);
121         if (response < 0) {
122                 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
123                 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
135 void 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
171 void 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
195 void StreamlineSetup::sendData(const char* data, uint32_t length, char type) {
196         unsigned char header[5];
197         header[0] = type;
198         Buffer::writeLEInt(header + 1, length);
199         mSocket->send((char*)&header, sizeof(header));
200         mSocket->send((const char*)data, length);
201 }
202
203 void StreamlineSetup::sendEvents() {
204         EventsXML eventsXML;
205         char* string = eventsXML.getXML();
206         sendString(string, RESPONSE_XML);
207         free(string);
208 }
209
210 void StreamlineSetup::sendConfiguration() {
211         ConfigurationXML xml;
212
213         const char* string = xml.getConfigurationXML();
214         sendData(string, strlen(string), RESPONSE_XML);
215 }
216
217 void 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) {
225                 logg->logError(__FILE__, __LINE__, "Corrupt default configuration file");
226                 handleException();
227         }
228
229         sendData(xml, size, RESPONSE_XML);
230 }
231
232 void StreamlineSetup::sendCounters() {
233         mxml_node_t *xml;
234         mxml_node_t *counters;
235
236         xml = mxmlNewXML("1.0");
237         counters = mxmlNewElement(xml, "counters");
238         int count = 0;
239         for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
240                 count += driver->writeCounters(counters);
241         }
242
243         if (count == 0) {
244                 logg->logError(__FILE__, __LINE__, "No counters found, this could be because /dev/gator/events can not be read or because perf is not working correctly");
245                 handleException();
246         }
247
248         char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
249         sendString(string, RESPONSE_XML);
250
251         free(string);
252         mxmlDelete(xml);
253 }
254
255 void StreamlineSetup::writeConfiguration(char* xml) {
256         char path[PATH_MAX];
257
258         ConfigurationXML::getPath(path);
259
260         if (util->writeToDisk(path, xml) < 0) {
261                 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify write permissions to this path.", path);
262                 handleException();
263         }
264
265         // Re-populate gSessionData with the configuration, as it has now changed
266         { ConfigurationXML configuration; }
267
268         if (gSessionData->mCounterOverflow > 0) {
269                 logg->logError(__FILE__, __LINE__, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow);
270                 handleException();
271         }
272 }