d13cf1d2568c5746fe4b3c031ddb9f952d69298a
[android-sdk/arm-ds5-gator.git] / daemon / StreamlineSetup.cpp
1 /**
2  * Copyright (C) ARM Limited 2011-2012. 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 <dirent.h>
13 #include <sys/types.h>
14 #include <arpa/inet.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include "Sender.h"
18 #include "Logging.h"
19 #include "OlyUtility.h"
20 #include "SessionData.h"
21 #include "CapturedXML.h"
22 #include "StreamlineSetup.h"
23 #include "ConfigurationXML.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_SESSION       = "session";
34 static const char* VALUE_CAPTURED      = "captured";
35 static const char* VALUE_DEFAULTS      = "defaults";
37 StreamlineSetup::StreamlineSetup(OlySocket* s) {
38         bool ready = false;
39         char* data = NULL;
40         int type;
42         mSocket = s;
43         mSessionXML = NULL;
45         // Receive commands from Streamline (master)
46         while (!ready) {
47                 // receive command over socket
48                 gSessionData->mWaitingOnCommand = true;
49                 data = readCommand(&type);
51                 // parse and handle data
52                 switch (type) {
53                         case COMMAND_REQUEST_XML:
54                                 handleRequest(data);
55                                 break;
56                         case COMMAND_DELIVER_XML:
57                                 handleDeliver(data);
58                                 break;
59                         case COMMAND_APC_START:
60                                 logg->logMessage("Received apc start request");
61                                 ready = true;
62                                 break;
63                         case COMMAND_APC_STOP:
64                                 logg->logMessage("Received apc stop request before apc start request");
65                                 exit(0);
66                                 break;
67                         case COMMAND_DISCONNECT:
68                                 logg->logMessage("Received disconnect command");
69                                 exit(0);
70                                 break;
71                         case COMMAND_PING:
72                                 logg->logMessage("Received ping command");
73                                 sendData(NULL, 0, RESPONSE_ACK);
74                                 break;
75                         default:
76                                 logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type);
77                                 handleException();
78                 }
80                 free(data);
81         }
83         if (gSessionData->mCounterOverflow) {
84                 logg->logError(__FILE__, __LINE__, "Exceeded maximum number of %d performance counters", MAX_PERFORMANCE_COUNTERS);
85                 handleException();
86         }
87 }
89 StreamlineSetup::~StreamlineSetup() {
90         if (mSessionXML) {
91                 free(mSessionXML);
92         }
93 }
95 char* StreamlineSetup::readCommand(int* command) {
96         char type;
97         char* data;
98         int response, length;
100         // receive type
101         response = mSocket->receiveNBytes(&type, sizeof(type));
103         // After receiving a single byte, we are no longer waiting on a command
104         gSessionData->mWaitingOnCommand = false;
106         if (response < 0) {
107                 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
108                 handleException();
109         }
111         // receive length
112         response = mSocket->receiveNBytes((char*)&length, sizeof(length));
113         if (response < 0) {
114                 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
115                 handleException();
116         }
118         // add artificial limit
119         if ((length < 0) || length > 1024 * 1024) {
120                 logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length);
121                 handleException();
122         }
124         // allocate memory to contain the xml file, size of zero returns a zero size object
125         data = (char*)calloc(length + 1, 1);
126         if (data == NULL) {
127                 logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml");
128                 handleException();
129         }
131         // receive data
132         response = mSocket->receiveNBytes(data, length);
133         if (response < 0) {
134                 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
135                 handleException();
136         }
138         // null terminate the data for string parsing
139         if (length > 0) {
140                 data[length] = 0;
141         }
143         *command = type;
144         return data;
147 void StreamlineSetup::handleRequest(char* xml) {
148         mxml_node_t *tree, *node;
149         const char * attr = NULL;
151         tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK);
152         node = mxmlFindElement(tree, tree, TAG_REQUEST, ATTR_TYPE, NULL, MXML_DESCEND_FIRST);
153         if (node) {
154                 attr = mxmlElementGetAttr(node, ATTR_TYPE);
155         }
156         if (attr && strcmp(attr, VALUE_EVENTS) == 0) {
157                 sendEvents();
158                 logg->logMessage("Sent events xml response");
159         } else if (attr && strcmp(attr, VALUE_CONFIGURATION) == 0) {
160                 sendConfiguration();
161                 logg->logMessage("Sent configuration xml response");
162         } else if (attr && strcmp(attr, VALUE_COUNTERS) == 0) {
163                 sendCounters();
164                 logg->logMessage("Sent counters xml response");
165         } else if (attr && strcmp(attr, VALUE_SESSION) == 0) {
166                 sendData(mSessionXML, strlen(mSessionXML), RESPONSE_XML);
167                 logg->logMessage("Sent session xml response");
168         } else if (attr && strcmp(attr, VALUE_CAPTURED) == 0) {
169                 CapturedXML capturedXML;
170                 char* capturedText = capturedXML.getXML(false);
171                 sendData(capturedText, strlen(capturedText), RESPONSE_XML);
172                 free(capturedText);
173                 logg->logMessage("Sent captured xml response");
174         } else if (attr && strcmp(attr, VALUE_DEFAULTS) == 0) {
175                 sendDefaults();
176                 logg->logMessage("Sent default configuration xml response");
177         } else {
178                 char error[] = "Unknown request";
179                 sendData(error, strlen(error), RESPONSE_NAK);
180                 logg->logMessage("Received unknown request:\n%s", xml);
181         }
183         mxmlDelete(tree);
186 void StreamlineSetup::handleDeliver(char* xml) {
187         mxml_node_t *tree;
189         // Determine xml type
190         tree = mxmlLoadString(NULL, xml, MXML_NO_CALLBACK);
191         if (mxmlFindElement(tree, tree, TAG_SESSION, NULL, NULL, MXML_DESCEND_FIRST)) {
192                 // Session XML
193                 gSessionData->parseSessionXML(xml);
195                 // Save xml
196                 mSessionXML = strdup(xml);
197                 if (mSessionXML == NULL) {
198                         logg->logError(__FILE__, __LINE__, "malloc failed for size %d", strlen(xml) + 1);
199                         handleException();
200                 }
201                 sendData(NULL, 0, RESPONSE_ACK);
202                 logg->logMessage("Received session xml");
203         } else if (mxmlFindElement(tree, tree, TAG_CONFIGURATIONS, NULL, NULL, MXML_DESCEND_FIRST)) {
204                 // Configuration XML
205                 writeConfiguration(xml);
206                 sendData(NULL, 0, RESPONSE_ACK);
207                 logg->logMessage("Received configuration xml");
208         } else {
209                 // Unknown XML
210                 logg->logMessage("Received unknown XML delivery type");
211                 sendData(NULL, 0, RESPONSE_NAK);
212         }
214         mxmlDelete(tree);
217 void StreamlineSetup::sendData(const char* data, int length, int type) {
218         mSocket->send((char*)&type, 1);
219         mSocket->send((char*)&length, sizeof(length));
220         mSocket->send((char*)data, length);
223 void StreamlineSetup::sendEvents() {
224 #include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len
225         char* path = (char*)malloc(PATH_MAX);;
226         char* buffer;
227         unsigned int size = 0;
229         if (gSessionData->mEventsXMLPath) {
230                 strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
231         } else {
232                 util->getApplicationFullPath(path, PATH_MAX);
233                 strncat(path, "events.xml", PATH_MAX - strlen(path) - 1);
234         }
235         buffer = util->readFromDisk(path, &size);
236         if (buffer == NULL) {
237                 logg->logMessage("Unable to locate events.xml, using default");
238                 buffer = (char*)events_xml;
239                 size = events_xml_len;
240         }
242         sendData(buffer, size, RESPONSE_XML);
243         if (buffer != (char*)events_xml) {
244                 free(buffer);
245         }
246         free(path);
249 void StreamlineSetup::sendConfiguration() {
250         ConfigurationXML xml;
252         const char* string = xml.getConfigurationXML();
253         sendData(string, strlen(string), RESPONSE_XML);
256 void StreamlineSetup::sendDefaults() {
257         // Send the config built into the binary
258         const char* xml;
259         unsigned int size;
260         ConfigurationXML::getDefaultConfigurationXml(xml, size);
262         // Artificial size restriction
263         if (size > 1024*1024) {
264                 logg->logError(__FILE__, __LINE__, "Corrupt default configuration file");
265                 handleException();
266         }
268         sendData(xml, size, RESPONSE_XML);
271 #include <dirent.h>
272 void StreamlineSetup::sendCounters() {
273         struct dirent *ent;
274         mxml_node_t *xml;
275         mxml_node_t *counters;
276         mxml_node_t *counter;
278         // counters.xml is simply a file listing of /dev/gator/events
279         DIR* dir = opendir("/dev/gator/events");
280         if (dir == NULL) {
281                 logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events");
282                 handleException();
283         }
285         xml = mxmlNewXML("1.0");
286         counters = mxmlNewElement(xml, "counters");
287         while ((ent = readdir(dir)) != NULL) {
288                 // skip hidden files, current dir, and parent dir
289                 if (ent->d_name[0] == '.')
290                         continue;
291                 counter = mxmlNewElement(counters, "counter");
292                 mxmlElementSetAttr(counter, "name", ent->d_name);
293         }
294         closedir (dir);
296         char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
297         sendString(string, RESPONSE_XML);
299         free(string);
300         mxmlDelete(xml);
303 void StreamlineSetup::writeConfiguration(char* xml) {
304         char* path = (char*)malloc(PATH_MAX);
306         if (gSessionData->mConfigurationXMLPath) {
307                 strncpy(path, gSessionData->mConfigurationXMLPath, PATH_MAX);
308         } else {
309                 util->getApplicationFullPath(path, PATH_MAX);
310                 strncat(path, "configuration.xml", PATH_MAX - strlen(path) - 1);
311         }
313         if (util->writeToDisk(path, xml) < 0) {
314                 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify write permissions to this path.", path);
315                 handleException();
316         }
318         // Re-populate gSessionData with the configuration, as it has now changed
319         new ConfigurationXML();
320         free(path);
322         if (gSessionData->mCounterOverflow) {
323                 logg->logError(__FILE__, __LINE__, "Exceeded maximum number of %d performance counters", MAX_PERFORMANCE_COUNTERS);
324                 handleException();
325         }