8473f8fb3d6a100750d73bca8aa850d14d74c169
1 /**
2 * Copyright (C) ARM Limited 2011. 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 typedef long long int64_t;
10 typedef unsigned long long uint64_t;
11 #include <string.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <dirent.h>
15 #include <sys/types.h>
16 #include <arpa/inet.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include "XMLOut.h"
20 #include "Sender.h"
21 #include "Logging.h"
22 #include "XMLReader.h"
23 #include "RequestXML.h"
24 #include "OlyUtility.h"
25 #include "SessionData.h"
26 #include "CapturedXML.h"
27 #include "StreamlineSetup.h"
28 #include "ConfigurationXML.h"
30 extern void handleException();
32 static const char* TAG_SESSION = "session";
33 static const char* TAG_CONFIGURATIONS = "configurations";
35 StreamlineSetup::StreamlineSetup(OlySocket* s) {
36 bool ready = false;
37 char *data = NULL;
38 int type;
40 socket = s;
41 mSessionXML = NULL;
43 // Receive commands from Streamline (master)
44 while (!ready) {
45 // receive command over socket
46 gSessionData.mWaitingOnCommand = true;
47 data = readCommand(&type);
49 // parse and handle data
50 switch (type) {
51 case COMMAND_REQUEST_XML:
52 handleRequest(data);
53 break;
54 case COMMAND_DELIVER_XML:
55 handleDeliver(data);
56 break;
57 case COMMAND_APC_START:
58 logg->logMessage("Received apc start request");
59 ready = true;
60 break;
61 case COMMAND_APC_STOP:
62 // Clear error log so no text appears on console and exit
63 logg->logMessage("Received apc stop request before apc start request");
64 logg->logError(__FILE__, __LINE__, "");
65 handleException();
66 break;
67 case COMMAND_DISCONNECT:
68 // Clear error log so no text appears on console and exit
69 logg->logMessage("Received disconnect command");
70 logg->logError(__FILE__, __LINE__, "");
71 handleException();
72 break;
73 case COMMAND_PING:
74 logg->logMessage("Received ping command");
75 sendData(NULL, 0, RESPONSE_ACK);
76 break;
77 default:
78 logg->logError(__FILE__, __LINE__, "Target error: Unknown command type, %d", type);
79 handleException();
80 }
82 delete(data);
83 }
84 }
86 StreamlineSetup::~StreamlineSetup() {
87 if (mSessionXML)
88 free(mSessionXML);
89 }
91 char* StreamlineSetup::readCommand(int* command) {
92 char type;
93 char* data;
94 int response, length;
96 // receive type
97 response = socket->receiveNBytes(&type, sizeof(type));
99 // After receiving a single byte, we are no longer waiting on a command
100 gSessionData.mWaitingOnCommand = false;
102 if (response < 0) {
103 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
104 handleException();
105 }
107 // receive length
108 response = socket->receiveNBytes((char*)&length, sizeof(length));
109 if (response < 0) {
110 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
111 handleException();
112 }
114 // add artificial limit
115 if ((length < 0) || length > 1024 * 1024) {
116 logg->logError(__FILE__, __LINE__, "Target error: Invalid length received, %d", length);
117 handleException();
118 }
120 // allocate memory to contain the xml file, size of zero returns a zero size object
121 data = (char*)calloc(length + 1, 1);
122 if (data == NULL) {
123 logg->logError(__FILE__, __LINE__, "Unable to allocate memory for xml");
124 handleException();
125 }
127 // receive data
128 response = socket->receiveNBytes(data, length);
129 if (response < 0) {
130 logg->logError(__FILE__, __LINE__, "Target error: Unexpected socket disconnect");
131 handleException();
132 }
134 // null terminate the data for string parsing
135 if (length > 0) {
136 data[length] = 0;
137 }
139 *command = type;
140 return data;
141 }
143 void StreamlineSetup::handleRequest(char* xml) {
144 RequestXML request(xml);
146 if (request.parameters.protocol) {
147 sendProtocol();
148 logg->logMessage("Sent protocol xml response");
149 } else if (request.parameters.events) {
150 sendEvents();
151 logg->logMessage("Sent events xml response");
152 } else if (request.parameters.configuration) {
153 sendConfiguration();
154 logg->logMessage("Sent configuration xml response");
155 } else if (request.parameters.counters) {
156 sendCounters();
157 logg->logMessage("Sent counters xml response");
158 } else if (request.parameters.session) {
159 sendData(mSessionXML, strlen(mSessionXML), RESPONSE_XML);
160 logg->logMessage("Sent session xml response");
161 } else if (request.parameters.captured) {
162 CapturedXML capturedXML;
163 const char* capturedText = capturedXML.getXML();
164 sendData(capturedText, strlen(capturedText), RESPONSE_XML);
165 logg->logMessage("Sent captured xml response");
166 } else if (request.parameters.defaults) {
167 sendDefaults();
168 logg->logMessage("Sent default configuration xml response");
169 } else {
170 char error[] = "Unknown request";
171 sendData(error, strlen(error), RESPONSE_NAK);
172 logg->logMessage("Received unknown request:\n%s", xml);
173 }
174 }
176 typedef enum {UNKNOWN, SESSION_XML, CONFIGURATION_XML} delivery_type_t;
177 void StreamlineSetup::handleDeliver(char* xml) {
178 delivery_type_t type = UNKNOWN;
180 // Determine xml type
181 XMLReader reader(xml);
182 char * tag = reader.nextTag();
183 while(tag != 0) {
184 if (strcmp(tag, TAG_SESSION) == 0) {
185 type = SESSION_XML;
186 break;
187 } else if (strcmp(tag, TAG_CONFIGURATIONS) == 0) {
188 type = CONFIGURATION_XML;
189 break;
190 }
191 tag = reader.nextTag();
192 }
194 switch (type) {
195 case UNKNOWN:
196 logg->logMessage("Received unknown delivery type: %d", type);
197 sendData(NULL, 0, RESPONSE_NAK);
198 break;
199 case SESSION_XML:
200 // Parse the session xml
201 gSessionData.parseSessionXML(xml);
203 // Save xml
204 mSessionXML = strdup(xml);
205 if (mSessionXML == NULL) {
206 logg->logError(__FILE__, __LINE__, "malloc failed for size %d", strlen(xml) + 1);
207 handleException();
208 }
209 sendData(NULL, 0, RESPONSE_ACK);
210 logg->logMessage("Received session xml");
211 break;
212 case CONFIGURATION_XML:
213 writeConfiguration(xml);
214 sendData(NULL, 0, RESPONSE_ACK);
215 logg->logMessage("Received configuration xml");
216 break;
217 }
218 }
220 void StreamlineSetup::sendData(const char* data, int length, int type) {
221 socket->send((char*)&type, 1);
222 socket->send((char*)&length, sizeof(length));
223 socket->send((char*)data, length);
224 }
226 void StreamlineSetup::sendProtocol() {
227 XMLOut out;
228 out.xmlHeader();
230 out.startElement("protocol");
231 out.attributeInt("version", PROTOCOL_VERSION);
232 out.endElement("protocol");
234 sendString(out.getXmlString(), RESPONSE_XML);
235 }
237 void StreamlineSetup::sendEvents() {
238 #include "events_xml.h"
239 char path[PATH_MAX];
240 char * buffer;
241 unsigned int size = 0;
243 util->getApplicationFullPath(path, sizeof(path));
244 strncat(path, "events.xml", sizeof(path) - strlen(path) - 1);
245 buffer = util->readFromDisk(path, &size);
246 if (buffer == NULL) {
247 logg->logMessage("Unable to locate events.xml, using default");
248 buffer = (char*)events_xml;
249 size = events_xml_len;
250 }
252 sendData(buffer, size, RESPONSE_XML);
253 if (buffer != (char*)events_xml) {
254 free(buffer);
255 }
256 }
258 void StreamlineSetup::sendConfiguration() {
259 ConfigurationXML xml;
261 const char* string = xml.getConfigurationXML();
262 sendData(string, strlen(string), RESPONSE_XML);
263 }
265 void StreamlineSetup::sendDefaults() {
266 #include "configuration_xml.h"
267 // Send the config built into the binary
268 char* xml = (char*)configuration_xml;
269 unsigned int size = configuration_xml_len;
271 // Artificial size restriction
272 if (size > 1024*1024) {
273 logg->logError(__FILE__, __LINE__, "Corrupt default configuration file");
274 handleException();
275 }
277 sendData(xml, size, RESPONSE_XML);
278 }
280 #include <dirent.h>
281 void StreamlineSetup::sendCounters() {
282 XMLOut out;
283 struct dirent *ent;
285 // counters.xml is simply a file listing of /dev/gator/events
286 DIR* dir = opendir("/dev/gator/events");
287 if (dir == NULL) {
288 logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events");
289 handleException();
290 }
292 out.xmlHeader();
293 out.startElement("counters");
294 while ((ent = readdir(dir)) != NULL) {
295 // skip hidden files, current dir, and parent dir
296 if (ent->d_name[0] == '.')
297 continue;
298 out.startElement("counter");
299 out.attributeString("name", ent->d_name);
300 out.endElement("counter");
301 }
302 out.endElement("counters");
303 closedir (dir);
305 sendString(out.getXmlString(), RESPONSE_XML);
306 }
308 void StreamlineSetup::writeConfiguration(char* xml) {
309 char path[PATH_MAX];
311 util->getApplicationFullPath(path, sizeof(path));
312 strncat(path, "configuration.xml", sizeof(path) - strlen(path) - 1);
313 if (util->writeToDisk(path, xml) < 0) {
314 logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", path);
315 handleException();
316 }
318 new ConfigurationXML();
319 }