5662ee8c76ff8f092bc7a0925cbc8b9d4f78bc09
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 "XMLOut.h"
18 #include "Sender.h"
19 #include "Logging.h"
20 #include "XMLReader.h"
21 #include "RequestXML.h"
22 #include "OlyUtility.h"
23 #include "SessionData.h"
24 #include "CapturedXML.h"
25 #include "StreamlineSetup.h"
26 #include "ConfigurationXML.h"
28 extern void handleException();
30 static const char* TAG_SESSION = "session";
31 static const char* TAG_CONFIGURATIONS = "configurations";
33 StreamlineSetup::StreamlineSetup(OlySocket* s) {
34 bool ready = false;
35 char *data = NULL;
36 int type;
38 socket = s;
39 mSessionXML = NULL;
41 // Receive commands from Streamline (master)
42 while (!ready) {
43 // receive command over socket
44 gSessionData->mWaitingOnCommand = true;
45 data = readCommand(&type);
47 // parse and handle data
48 switch (type) {
49 case COMMAND_REQUEST_XML:
50 handleRequest(data);
51 break;
52 case COMMAND_DELIVER_XML:
53 handleDeliver(data);
54 break;
55 case COMMAND_APC_START:
56 logg->logMessage("Received apc start request");
57 ready = true;
58 break;
59 case COMMAND_APC_STOP:
60 logg->logMessage("Received apc stop request before apc start request");
61 exit(0);
62 break;
63 case COMMAND_DISCONNECT:
64 logg->logMessage("Received disconnect command");
65 exit(0);
66 break;
67 case COMMAND_PING:
68 logg->logMessage("Received ping command");
69 sendData(NULL, 0, RESPONSE_ACK);
70 break;
71 default:
72 logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type);
73 handleException();
74 }
76 delete(data);
77 }
78 }
80 StreamlineSetup::~StreamlineSetup() {
81 if (mSessionXML)
82 free(mSessionXML);
83 }
85 char* StreamlineSetup::readCommand(int* command) {
86 char type;
87 char* data;
88 int response, length;
90 // receive type
91 response = socket->receiveNBytes(&type, sizeof(type));
93 // After receiving a single byte, we are no longer waiting on a command
94 gSessionData->mWaitingOnCommand = false;
96 if (response < 0) {
97 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
98 handleException();
99 }
101 // receive length
102 response = socket->receiveNBytes((char*)&length, sizeof(length));
103 if (response < 0) {
104 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
105 handleException();
106 }
108 // add artificial limit
109 if ((length < 0) || length > 1024 * 1024) {
110 logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length);
111 handleException();
112 }
114 // allocate memory to contain the xml file, size of zero returns a zero size object
115 data = (char*)calloc(length + 1, 1);
116 if (data == NULL) {
117 logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml");
118 handleException();
119 }
121 // receive data
122 response = socket->receiveNBytes(data, length);
123 if (response < 0) {
124 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
125 handleException();
126 }
128 // null terminate the data for string parsing
129 if (length > 0) {
130 data[length] = 0;
131 }
133 *command = type;
134 return data;
135 }
137 void StreamlineSetup::handleRequest(char* xml) {
138 RequestXML request(xml);
140 if (request.parameters.protocol) {
141 sendProtocol();
142 logg->logMessage("Sent protocol xml response");
143 } else if (request.parameters.events) {
144 sendEvents();
145 logg->logMessage("Sent events xml response");
146 } else if (request.parameters.configuration) {
147 sendConfiguration();
148 logg->logMessage("Sent configuration xml response");
149 } else if (request.parameters.counters) {
150 sendCounters();
151 logg->logMessage("Sent counters xml response");
152 } else if (request.parameters.session) {
153 sendData(mSessionXML, strlen(mSessionXML), RESPONSE_XML);
154 logg->logMessage("Sent session xml response");
155 } else if (request.parameters.captured) {
156 CapturedXML capturedXML;
157 const char* capturedText = capturedXML.getXML();
158 sendData(capturedText, strlen(capturedText), RESPONSE_XML);
159 logg->logMessage("Sent captured xml response");
160 } else if (request.parameters.defaults) {
161 sendDefaults();
162 logg->logMessage("Sent default configuration xml response");
163 } else {
164 char error[] = "Unknown request";
165 sendData(error, strlen(error), RESPONSE_NAK);
166 logg->logMessage("Received unknown request:\n%s", xml);
167 }
168 }
170 typedef enum {UNKNOWN, SESSION_XML, CONFIGURATION_XML} delivery_type_t;
171 void StreamlineSetup::handleDeliver(char* xml) {
172 delivery_type_t type = UNKNOWN;
174 // Determine xml type
175 XMLReader reader(xml);
176 char * tag = reader.nextTag();
177 while(tag != 0) {
178 if (strcmp(tag, TAG_SESSION) == 0) {
179 type = SESSION_XML;
180 break;
181 } else if (strcmp(tag, TAG_CONFIGURATIONS) == 0) {
182 type = CONFIGURATION_XML;
183 break;
184 }
185 tag = reader.nextTag();
186 }
188 switch (type) {
189 case UNKNOWN:
190 logg->logMessage("Received unknown delivery type: %d", type);
191 sendData(NULL, 0, RESPONSE_NAK);
192 break;
193 case SESSION_XML:
194 // Parse the session xml
195 gSessionData->parseSessionXML(xml);
197 // Save xml
198 mSessionXML = strdup(xml);
199 if (mSessionXML == NULL) {
200 logg->logError(__FILE__, __LINE__, "malloc failed for size %d", strlen(xml) + 1);
201 handleException();
202 }
203 sendData(NULL, 0, RESPONSE_ACK);
204 logg->logMessage("Received session xml");
205 break;
206 case CONFIGURATION_XML:
207 writeConfiguration(xml);
208 sendData(NULL, 0, RESPONSE_ACK);
209 logg->logMessage("Received configuration xml");
210 break;
211 }
212 }
214 void StreamlineSetup::sendData(const char* data, int length, int type) {
215 socket->send((char*)&type, 1);
216 socket->send((char*)&length, sizeof(length));
217 socket->send((char*)data, length);
218 }
220 void StreamlineSetup::sendProtocol() {
221 XMLOut out;
222 out.xmlHeader();
224 out.startElement("protocol");
225 out.attributeInt("version", PROTOCOL_VERSION);
226 out.endElement("protocol");
228 sendString(out.getXmlString(), RESPONSE_XML);
229 }
231 void StreamlineSetup::sendEvents() {
232 #include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len
233 char* path = (char*)malloc(PATH_MAX);;
234 char* buffer;
235 unsigned int size = 0;
237 util->getApplicationFullPath(path, PATH_MAX);
238 strncat(path, "events.xml", PATH_MAX - strlen(path) - 1);
239 buffer = util->readFromDisk(path, &size);
240 if (buffer == NULL) {
241 logg->logMessage("Unable to locate events.xml, using default");
242 buffer = (char*)events_xml;
243 size = events_xml_len;
244 }
246 sendData(buffer, size, RESPONSE_XML);
247 if (buffer != (char*)events_xml) {
248 free(buffer);
249 }
250 free(path);
251 }
253 void StreamlineSetup::sendConfiguration() {
254 ConfigurationXML xml;
256 const char* string = xml.getConfigurationXML();
257 sendData(string, strlen(string), RESPONSE_XML);
258 }
260 void StreamlineSetup::sendDefaults() {
261 #include "configuration_xml.h" // defines and initializes char configuration_xml[] and int configuration_xml_len
262 // Send the config built into the binary
263 char* xml = (char*)configuration_xml;
264 unsigned int size = configuration_xml_len;
266 // Artificial size restriction
267 if (size > 1024*1024) {
268 logg->logError(__FILE__, __LINE__, "Corrupt default configuration file");
269 handleException();
270 }
272 sendData(xml, size, RESPONSE_XML);
273 }
275 #include <dirent.h>
276 void StreamlineSetup::sendCounters() {
277 XMLOut out;
278 struct dirent *ent;
280 // counters.xml is simply a file listing of /dev/gator/events
281 DIR* dir = opendir("/dev/gator/events");
282 if (dir == NULL) {
283 logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events");
284 handleException();
285 }
287 out.xmlHeader();
288 out.startElement("counters");
289 while ((ent = readdir(dir)) != NULL) {
290 // skip hidden files, current dir, and parent dir
291 if (ent->d_name[0] == '.')
292 continue;
293 out.startElement("counter");
294 out.attributeString("name", ent->d_name);
295 out.endElement("counter");
296 }
297 out.endElement("counters");
298 closedir (dir);
300 sendString(out.getXmlString(), RESPONSE_XML);
301 }
303 void StreamlineSetup::writeConfiguration(char* xml) {
304 char* path = (char*)malloc(PATH_MAX);
306 if (gSessionData->configurationXMLPath) {
307 strncpy(path, gSessionData->configurationXMLPath, 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);
321 }