gator: Version 5.14
[android-sdk/arm-ds5-gator.git] / daemon / StreamlineSetup.cpp
1 /**
2  * Copyright (C) ARM Limited 2011-2013. 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  */
9 #include <string.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <arpa/inet.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include "Sender.h"
16 #include "Logging.h"
17 #include "OlyUtility.h"
18 #include "SessionData.h"
19 #include "CapturedXML.h"
20 #include "StreamlineSetup.h"
21 #include "ConfigurationXML.h"
22 #include "Driver.h"
24 static const char* TAG_SESSION = "session";
25 static const char* TAG_REQUEST = "request";
26 static const char* TAG_CONFIGURATIONS = "configurations";
28 static const char* ATTR_TYPE           = "type";
29 static const char* VALUE_EVENTS        = "events";
30 static const char* VALUE_CONFIGURATION = "configuration";
31 static const char* VALUE_COUNTERS      = "counters";
32 static const char* VALUE_CAPTURED      = "captured";
33 static const char* VALUE_DEFAULTS      = "defaults";
35 StreamlineSetup::StreamlineSetup(OlySocket* s) {
36         bool ready = false;
37         char* data = NULL;
38         int type;
40         mSocket = s;
42         // Receive commands from Streamline (master)
43         while (!ready) {
44                 // receive command over socket
45                 gSessionData->mWaitingOnCommand = true;
46                 data = readCommand(&type);
48                 // parse and handle data
49                 switch (type) {
50                         case COMMAND_REQUEST_XML:
51                                 handleRequest(data);
52                                 break;
53                         case COMMAND_DELIVER_XML:
54                                 handleDeliver(data);
55                                 break;
56                         case COMMAND_APC_START:
57                                 logg->logMessage("Received apc start request");
58                                 ready = true;
59                                 break;
60                         case COMMAND_APC_STOP:
61                                 logg->logMessage("Received apc stop request before apc start request");
62                                 exit(0);
63                                 break;
64                         case COMMAND_DISCONNECT:
65                                 logg->logMessage("Received disconnect command");
66                                 exit(0);
67                                 break;
68                         case COMMAND_PING:
69                                 logg->logMessage("Received ping command");
70                                 sendData(NULL, 0, RESPONSE_ACK);
71                                 break;
72                         default:
73                                 logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type);
74                                 handleException();
75                 }
77                 free(data);
78         }
80         if (gSessionData->mCounterOverflow) {
81                 logg->logError(__FILE__, __LINE__, "Exceeded maximum number of %d performance counters", MAX_PERFORMANCE_COUNTERS);
82                 handleException();
83         }
84 }
86 StreamlineSetup::~StreamlineSetup() {
87 }
89 char* StreamlineSetup::readCommand(int* command) {
90         char type;
91         char* data;
92         int response, length;
94         // receive type
95         response = mSocket->receiveNBytes(&type, sizeof(type));
97         // After receiving a single byte, we are no longer waiting on a command
98         gSessionData->mWaitingOnCommand = false;
100         if (response < 0) {
101                 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
102                 handleException();
103         }
105         // receive length
106         response = mSocket->receiveNBytes((char*)&length, sizeof(length));
107         if (response < 0) {
108                 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
109                 handleException();
110         }
112         // add artificial limit
113         if ((length < 0) || length > 1024 * 1024) {
114                 logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length);
115                 handleException();
116         }
118         // allocate memory to contain the xml file, size of zero returns a zero size object
119         data = (char*)calloc(length + 1, 1);
120         if (data == NULL) {
121                 logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml");
122                 handleException();
123         }
125         // receive data
126         response = mSocket->receiveNBytes(data, length);
127         if (response < 0) {
128                 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
129                 handleException();
130         }
132         // null terminate the data for string parsing
133         if (length > 0) {
134                 data[length] = 0;
135         }
137         *command = type;
138         return data;
141 void StreamlineSetup::handleRequest(char* xml) {
142         mxml_node_t *tree, *node;
143         const char * attr = NULL;
145         tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK);
146         node = mxmlFindElement(tree, tree, TAG_REQUEST, ATTR_TYPE, NULL, MXML_DESCEND_FIRST);
147         if (node) {
148                 attr = mxmlElementGetAttr(node, ATTR_TYPE);
149         }
150         if (attr && strcmp(attr, VALUE_EVENTS) == 0) {
151                 sendEvents();
152                 logg->logMessage("Sent events xml response");
153         } else if (attr && strcmp(attr, VALUE_CONFIGURATION) == 0) {
154                 sendConfiguration();
155                 logg->logMessage("Sent configuration xml response");
156         } else if (attr && strcmp(attr, VALUE_COUNTERS) == 0) {
157                 sendCounters();
158                 logg->logMessage("Sent counters xml response");
159         } else if (attr && strcmp(attr, VALUE_CAPTURED) == 0) {
160                 CapturedXML capturedXML;
161                 char* capturedText = capturedXML.getXML(false);
162                 sendData(capturedText, strlen(capturedText), RESPONSE_XML);
163                 free(capturedText);
164                 logg->logMessage("Sent captured xml response");
165         } else if (attr && strcmp(attr, VALUE_DEFAULTS) == 0) {
166                 sendDefaults();
167                 logg->logMessage("Sent default configuration xml response");
168         } else {
169                 char error[] = "Unknown request";
170                 sendData(error, strlen(error), RESPONSE_NAK);
171                 logg->logMessage("Received unknown request:\n%s", xml);
172         }
174         mxmlDelete(tree);
177 void StreamlineSetup::handleDeliver(char* xml) {
178         mxml_node_t *tree;
180         // Determine xml type
181         tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK);
182         if (mxmlFindElement(tree, tree, TAG_SESSION, NULL, NULL, MXML_DESCEND_FIRST)) {
183                 // Session XML
184                 gSessionData->parseSessionXML(xml);
185                 sendData(NULL, 0, RESPONSE_ACK);
186                 logg->logMessage("Received session xml");
187         } else if (mxmlFindElement(tree, tree, TAG_CONFIGURATIONS, NULL, NULL, MXML_DESCEND_FIRST)) {
188                 // Configuration XML
189                 writeConfiguration(xml);
190                 sendData(NULL, 0, RESPONSE_ACK);
191                 logg->logMessage("Received configuration xml");
192         } else {
193                 // Unknown XML
194                 logg->logMessage("Received unknown XML delivery type");
195                 sendData(NULL, 0, RESPONSE_NAK);
196         }
198         mxmlDelete(tree);
201 void StreamlineSetup::sendData(const char* data, int length, int type) {
202         mSocket->send((char*)&type, 1);
203         mSocket->send((char*)&length, sizeof(length));
204         mSocket->send((char*)data, length);
207 void StreamlineSetup::sendEvents() {
208 #include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len
209         char path[PATH_MAX];
210         mxml_node_t *xml;
211         FILE *fl;
213         // Avoid unused variable warning
214         (void)events_xml_len;
216         // Load the provided or default events xml
217         if (gSessionData->mEventsXMLPath) {
218                 strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
219         } else {
220                 util->getApplicationFullPath(path, PATH_MAX);
221                 strncat(path, "events.xml", PATH_MAX - strlen(path) - 1);
222         }
223         fl = fopen(path, "r");
224         if (fl) {
225                 xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
226                 fclose(fl);
227         } else {
228                 logg->logMessage("Unable to locate events.xml, using default");
229                 xml = mxmlLoadString(NULL, (char *)events_xml, MXML_NO_CALLBACK);
230         }
232         // Add dynamic events from the drivers
233         mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
234         if (!events) {
235                 logg->logMessage("Unable to find <events> node in the events.xml");
236                 handleException();
237         }
238         for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
239                 driver->writeEvents(events);
240         }
242         char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
243         sendString(string, RESPONSE_XML);
244         free(string);
245         mxmlDelete(xml);
248 void StreamlineSetup::sendConfiguration() {
249         ConfigurationXML xml;
251         const char* string = xml.getConfigurationXML();
252         sendData(string, strlen(string), RESPONSE_XML);
255 void StreamlineSetup::sendDefaults() {
256         // Send the config built into the binary
257         const char* xml;
258         unsigned int size;
259         ConfigurationXML::getDefaultConfigurationXml(xml, size);
261         // Artificial size restriction
262         if (size > 1024*1024) {
263                 logg->logError(__FILE__, __LINE__, "Corrupt default configuration file");
264                 handleException();
265         }
267         sendData(xml, size, RESPONSE_XML);
270 void StreamlineSetup::sendCounters() {
271         mxml_node_t *xml;
272         mxml_node_t *counters;
274         xml = mxmlNewXML("1.0");
275         counters = mxmlNewElement(xml, "counters");
276         for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
277                 driver->writeCounters(counters);
278         }
280         char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
281         sendString(string, RESPONSE_XML);
283         free(string);
284         mxmlDelete(xml);
287 void StreamlineSetup::writeConfiguration(char* xml) {
288         char path[PATH_MAX];
290         if (gSessionData->mConfigurationXMLPath) {
291                 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX);
292         } else {
293                 util->getApplicationFullPath(path, PATH_MAX);
294                 strncat(path, "configuration.xml", PATH_MAX - strlen(path) - 1);
295         }
297         if (util->writeToDisk(path, xml) < 0) {
298                 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify write permissions to this path.", path);
299                 handleException();
300         }
302         // Re-populate gSessionData with the configuration, as it has now changed
303         { ConfigurationXML configuration; }
305         if (gSessionData->mCounterOverflow) {
306                 logg->logError(__FILE__, __LINE__, "Exceeded maximum number of %d performance counters", MAX_PERFORMANCE_COUNTERS);
307                 handleException();
308         }