blob: c68a892e74fcd7d256cb23011b67b74fde0508d7 [file] [log] [blame]
Jon Medhurstaaf37a32013-06-11 12:10:56 +01001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2010-2015. All rights reserved.
Jon Medhurstaaf37a32013-06-11 12:10:56 +01003 *
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
Jon Medhurst15ce78d2014-04-10 09:02:02 +01009#include <arpa/inet.h>
10#include <fcntl.h>
11#include <pthread.h>
12#include <sys/mman.h>
13#include <sys/mount.h>
14#include <sys/prctl.h>
15#include <sys/resource.h>
16#include <sys/socket.h>
17#include <sys/stat.h>
18#include <sys/syscall.h>
Jon Medhurstaaf37a32013-06-11 12:10:56 +010019#include <sys/wait.h>
20#include <unistd.h>
Jon Medhurst15ce78d2014-04-10 09:02:02 +010021
Jon Medhurstb1d07442015-05-08 12:04:18 +010022#include "AnnotateListener.h"
Jon Medhurst96b56152014-10-30 18:01:15 +000023#include "CCNDriver.h"
Jon Medhurstaaf37a32013-06-11 12:10:56 +010024#include "Child.h"
Jon Medhurste31266f2014-08-04 15:47:44 +010025#include "EventsXML.h"
Jon Medhurst15ce78d2014-04-10 09:02:02 +010026#include "Logging.h"
Jon Medhurste31266f2014-08-04 15:47:44 +010027#include "Monitor.h"
Jon Medhurst15ce78d2014-04-10 09:02:02 +010028#include "OlySocket.h"
29#include "OlyUtility.h"
30#include "SessionData.h"
Jon Medhurst96b56152014-10-30 18:01:15 +000031#include "Setup.h"
Jon Medhurstaaf37a32013-06-11 12:10:56 +010032
33extern Child* child;
34static int shutdownFilesystem();
35static pthread_mutex_t numSessions_mutex;
Jon Medhurst15ce78d2014-04-10 09:02:02 +010036static OlyServerSocket* sock = NULL;
Jon Medhurste31266f2014-08-04 15:47:44 +010037static Monitor monitor;
38static int numSessions = 0;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010039static bool driverRunningAtStart = false;
40static bool driverMountedAtStart = false;
41
42struct cmdline_t {
Jon Medhurst96b56152014-10-30 18:01:15 +000043 char *module;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010044 int port;
Jon Medhurst96b56152014-10-30 18:01:15 +000045 bool update;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010046};
47
Jon Medhurstd3698592013-10-10 16:48:56 +010048#define DEFAULT_PORT 8080
49
Jon Medhurstaaf37a32013-06-11 12:10:56 +010050void cleanUp() {
51 if (shutdownFilesystem() == -1) {
52 logg->logMessage("Error shutting down gator filesystem");
53 }
Jon Medhurstd3698592013-10-10 16:48:56 +010054 delete sock;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010055 delete util;
56 delete logg;
57}
58
59// CTRL C Signal Handler
60static void handler(int signum) {
61 logg->logMessage("Received signal %d, gator daemon exiting", signum);
62
63 // Case 1: both child and parent receive the signal
64 if (numSessions > 0) {
65 // Arbitrary sleep of 1 second to give time for the child to exit;
66 // if something bad happens, continue the shutdown process regardless
67 sleep(1);
68 }
69
70 // Case 2: only the parent received the signal
71 if (numSessions > 0) {
72 // Kill child threads - the first signal exits gracefully
73 logg->logMessage("Killing process group as %d child was running when signal was received", numSessions);
74 kill(0, SIGINT);
75
76 // Give time for the child to exit
77 sleep(1);
78
79 if (numSessions > 0) {
80 // The second signal force kills the child
81 logg->logMessage("Force kill the child");
82 kill(0, SIGINT);
83 // Again, sleep for 1 second
84 sleep(1);
85
86 if (numSessions > 0) {
87 // Something bad has really happened; the child is not exiting and therefore may hold the /dev/gator resource open
88 printf("Unable to kill the gatord child process, thus gator.ko may still be loaded.\n");
89 }
90 }
91 }
92
93 cleanUp();
94 exit(0);
95}
96
97// Child exit Signal Handler
Jon Medhurst34d97692013-12-19 09:23:06 +000098static void child_exit(int) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010099 int status;
100 int pid = wait(&status);
101 if (pid != -1) {
102 pthread_mutex_lock(&numSessions_mutex);
103 numSessions--;
104 pthread_mutex_unlock(&numSessions_mutex);
105 logg->logMessage("Child process %d exited with status %d", pid, status);
106 }
107}
108
Jon Medhurste31266f2014-08-04 15:47:44 +0100109static const int UDP_REQ_PORT = 30001;
Jon Medhurstd3698592013-10-10 16:48:56 +0100110
111typedef struct {
112 char rviHeader[8];
113 uint32_t messageID;
114 uint8_t ethernetAddress[8];
115 uint32_t ethernetType;
116 uint32_t dhcp;
117 char dhcpName[40];
118 uint32_t ipAddress;
119 uint32_t defaultGateway;
120 uint32_t subnetMask;
Jon Medhurste31266f2014-08-04 15:47:44 +0100121 uint32_t activeConnections;
Jon Medhurstd3698592013-10-10 16:48:56 +0100122} RVIConfigureInfo;
123
124static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 };
125
Jon Medhurste31266f2014-08-04 15:47:44 +0100126class UdpListener {
127public:
Jon Medhurst96b56152014-10-30 18:01:15 +0000128 UdpListener() : mDstAns(), mReq(-1) {}
Jon Medhurstd3698592013-10-10 16:48:56 +0100129
Jon Medhurste31266f2014-08-04 15:47:44 +0100130 void setup(int port) {
131 mReq = udpPort(UDP_REQ_PORT);
Jon Medhurstd3698592013-10-10 16:48:56 +0100132
Jon Medhurste31266f2014-08-04 15:47:44 +0100133 // Format the answer buffer
134 memset(&mDstAns, 0, sizeof(mDstAns));
135 memcpy(mDstAns.rviHeader, "STR_ANS ", sizeof(mDstAns.rviHeader));
136 if (gethostname(mDstAns.dhcpName, sizeof(mDstAns.dhcpName) - 1) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100137 logg->logError("gethostname failed");
Jon Medhurste31266f2014-08-04 15:47:44 +0100138 handleException();
139 }
140 // Subvert the defaultGateway field for the port number
141 if (port != DEFAULT_PORT) {
142 mDstAns.defaultGateway = port;
143 }
144 // Subvert the subnetMask field for the protocol version
145 mDstAns.subnetMask = PROTOCOL_VERSION;
146 }
147
148 int getReq() const {
149 return mReq;
150 }
151
152 void handle() {
Jon Medhurstd3698592013-10-10 16:48:56 +0100153 char buf[128];
Jon Medhurst34d97692013-12-19 09:23:06 +0000154 struct sockaddr_in6 sockaddr;
Jon Medhurstd3698592013-10-10 16:48:56 +0100155 socklen_t addrlen;
156 int read;
157 addrlen = sizeof(sockaddr);
Jon Medhurste31266f2014-08-04 15:47:44 +0100158 read = recvfrom(mReq, &buf, sizeof(buf), 0, (struct sockaddr *)&sockaddr, &addrlen);
Jon Medhurstd3698592013-10-10 16:48:56 +0100159 if (read < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100160 logg->logError("recvfrom failed");
Jon Medhurstd3698592013-10-10 16:48:56 +0100161 handleException();
162 } else if ((read == 12) && (memcmp(buf, DST_REQ, sizeof(DST_REQ)) == 0)) {
Jon Medhurst96b56152014-10-30 18:01:15 +0000163 // Don't care if sendto fails - gatord shouldn't exit because of it and Streamline will retry
164 sendto(mReq, &mDstAns, sizeof(mDstAns), 0, (struct sockaddr *)&sockaddr, addrlen);
Jon Medhurstd3698592013-10-10 16:48:56 +0100165 }
166 }
Jon Medhurste31266f2014-08-04 15:47:44 +0100167
168 void close() {
169 ::close(mReq);
Jon Medhurste31266f2014-08-04 15:47:44 +0100170 }
171
172private:
173 int udpPort(int port) {
174 int s;
175 struct sockaddr_in6 sockaddr;
176 int on;
177 int family = AF_INET6;
178
Jon Medhurst96b56152014-10-30 18:01:15 +0000179 s = socket_cloexec(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
Jon Medhurste31266f2014-08-04 15:47:44 +0100180 if (s == -1) {
181 family = AF_INET;
Jon Medhurst96b56152014-10-30 18:01:15 +0000182 s = socket_cloexec(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Jon Medhurste31266f2014-08-04 15:47:44 +0100183 if (s == -1) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100184 logg->logError("socket failed");
Jon Medhurste31266f2014-08-04 15:47:44 +0100185 handleException();
186 }
187 }
188
189 on = 1;
190 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100191 logg->logError("setsockopt REUSEADDR failed");
Jon Medhurste31266f2014-08-04 15:47:44 +0100192 handleException();
193 }
194
Jon Medhurstb1d07442015-05-08 12:04:18 +0100195 // Listen on both IPv4 and IPv6
196 on = 0;
197 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) != 0) {
198 logg->logMessage("setsockopt IPV6_V6ONLY failed");
199 }
200
Jon Medhurste31266f2014-08-04 15:47:44 +0100201 memset((void*)&sockaddr, 0, sizeof(sockaddr));
202 sockaddr.sin6_family = family;
203 sockaddr.sin6_port = htons(port);
204 sockaddr.sin6_addr = in6addr_any;
205 if (bind(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100206 logg->logError("socket failed");
Jon Medhurste31266f2014-08-04 15:47:44 +0100207 handleException();
208 }
209
210 return s;
211 }
212
213 RVIConfigureInfo mDstAns;
214 int mReq;
Jon Medhurste31266f2014-08-04 15:47:44 +0100215};
216
217static UdpListener udpListener;
Jon Medhurstd3698592013-10-10 16:48:56 +0100218
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100219// retval: -1 = failure; 0 = was already mounted; 1 = successfully mounted
220static int mountGatorFS() {
221 // If already mounted,
222 if (access("/dev/gator/buffer", F_OK) == 0) {
223 return 0;
224 }
225
226 // else, mount the filesystem
227 mkdir("/dev/gator", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
228 if (mount("nodev", "/dev/gator", "gatorfs", 0, NULL) != 0) {
229 return -1;
230 } else {
231 return 1;
232 }
233}
234
235static bool init_module (const char * const location) {
236 bool ret(false);
Jon Medhurst96b56152014-10-30 18:01:15 +0000237 const int fd = open(location, O_RDONLY | O_CLOEXEC);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100238 if (fd >= 0) {
239 struct stat st;
240 if (fstat(fd, &st) == 0) {
241 void * const p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
242 if (p != MAP_FAILED) {
Jon Medhurste31266f2014-08-04 15:47:44 +0100243 if (syscall(__NR_init_module, p, (unsigned long)st.st_size, "") == 0) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100244 ret = true;
245 }
246 munmap(p, st.st_size);
247 }
248 }
249 close(fd);
250 }
251
252 return ret;
253}
254
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100255static bool setupFilesystem(char* module) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100256 if (module) {
257 // unmount and rmmod if the module was specified on the commandline, i.e. ensure that the specified module is indeed running
258 shutdownFilesystem();
259
260 // if still mounted
261 if (access("/dev/gator/buffer", F_OK) == 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100262 logg->logError("Unable to remove the running gator.ko. Manually remove the module or use the running module by not specifying one on the commandline");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100263 handleException();
264 }
265 }
266
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100267 const int retval = mountGatorFS();
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100268 if (retval == 1) {
269 logg->logMessage("Driver already running at startup");
270 driverRunningAtStart = true;
271 } else if (retval == 0) {
272 logg->logMessage("Driver already mounted at startup");
273 driverRunningAtStart = driverMountedAtStart = true;
274 } else {
275 char command[256]; // arbitrarily large amount
276 char location[256]; // arbitrarily large amount
277
278 if (module) {
279 strncpy(location, module, sizeof(location));
280 } else {
281 // Is the driver co-located in the same directory?
282 if (util->getApplicationFullPath(location, sizeof(location)) != 0) { // allow some buffer space
283 logg->logMessage("Unable to determine the full path of gatord, the cwd will be used");
284 }
285 strncat(location, "gator.ko", sizeof(location) - strlen(location) - 1);
286 }
287
288 if (access(location, F_OK) == -1) {
Jon Medhurste31266f2014-08-04 15:47:44 +0100289 if (module == NULL) {
290 // The gator kernel is not already loaded and unable to locate gator.ko in the default location
291 return false;
292 } else {
293 // gator location specified on the command line but it was not found
Jon Medhurstb1d07442015-05-08 12:04:18 +0100294 logg->logError("gator module not found at %s", location);
Jon Medhurste31266f2014-08-04 15:47:44 +0100295 handleException();
296 }
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100297 }
298
299 // Load driver
300 bool success = init_module(location);
301 if (!success) {
302 logg->logMessage("init_module failed, trying insmod");
303 snprintf(command, sizeof(command), "insmod %s >/dev/null 2>&1", location);
304 if (system(command) != 0) {
305 logg->logMessage("Unable to load gator.ko driver with command: %s", command);
Jon Medhurstb1d07442015-05-08 12:04:18 +0100306 logg->logError("Unable to load (insmod) gator.ko driver:\n >>> gator.ko must be built against the current kernel version & configuration\n >>> See dmesg for more details");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100307 handleException();
308 }
309 }
310
311 if (mountGatorFS() == -1) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100312 logg->logError("Unable to mount the gator filesystem needed for profiling.");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100313 handleException();
314 }
315 }
316
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100317 return true;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100318}
319
320static int shutdownFilesystem() {
321 if (driverMountedAtStart == false) {
322 umount("/dev/gator");
323 }
324 if (driverRunningAtStart == false) {
325 if (syscall(__NR_delete_module, "gator", O_NONBLOCK) != 0) {
326 logg->logMessage("delete_module failed, trying rmmod");
327 if (system("rmmod gator >/dev/null 2>&1") != 0) {
328 return -1;
329 }
330 }
331 }
332
333 return 0; // success
334}
335
Jon Medhurstb1d07442015-05-08 12:04:18 +0100336static const char OPTSTRING[] = "hvVudap:s:c:e:E:m:o:";
Jon Medhurst96b56152014-10-30 18:01:15 +0000337
338static bool hasDebugFlag(int argc, char** argv) {
339 int c;
340
341 optind = 1;
342 while ((c = getopt(argc, argv, OPTSTRING)) != -1) {
343 if (c == 'd') {
344 return true;
345 }
346 }
347
348 return false;
349}
350
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100351static struct cmdline_t parseCommandLine(int argc, char** argv) {
352 struct cmdline_t cmdline;
Jon Medhurstd3698592013-10-10 16:48:56 +0100353 cmdline.port = DEFAULT_PORT;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100354 cmdline.module = NULL;
Jon Medhurst96b56152014-10-30 18:01:15 +0000355 cmdline.update = false;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100356 char version_string[256]; // arbitrary length to hold the version information
357 int c;
358
359 // build the version string
360 if (PROTOCOL_VERSION < PROTOCOL_DEV) {
Jon Medhurstd3698592013-10-10 16:48:56 +0100361 snprintf(version_string, sizeof(version_string), "Streamline gatord version %d (DS-5 v5.%d)", PROTOCOL_VERSION, PROTOCOL_VERSION);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100362 } else {
363 snprintf(version_string, sizeof(version_string), "Streamline gatord development version %d", PROTOCOL_VERSION);
364 }
365
Jon Medhurst96b56152014-10-30 18:01:15 +0000366 optind = 1;
367 while ((c = getopt(argc, argv, OPTSTRING)) != -1) {
368 switch (c) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100369 case 'c':
370 gSessionData->mConfigurationXMLPath = optarg;
371 break;
Jon Medhurst96b56152014-10-30 18:01:15 +0000372 case 'd':
373 // Already handled
374 break;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100375 case 'e':
376 gSessionData->mEventsXMLPath = optarg;
377 break;
Jon Medhurstb1d07442015-05-08 12:04:18 +0100378 case 'E':
379 gSessionData->mEventsXMLAppend = optarg;
380 break;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100381 case 'm':
382 cmdline.module = optarg;
383 break;
384 case 'p':
385 cmdline.port = strtol(optarg, NULL, 10);
Jon Medhurstb1d07442015-05-08 12:04:18 +0100386 if ((cmdline.port == 8082) || (cmdline.port == 8083)) {
387 logg->logError("Gator can't use port %i, as it already uses ports 8082 and 8083 for annotations. Please select a different port.", cmdline.port);
388 handleException();
389 }
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100390 break;
391 case 's':
392 gSessionData->mSessionXMLPath = optarg;
393 break;
394 case 'o':
395 gSessionData->mTargetPath = optarg;
396 break;
Jon Medhurst96b56152014-10-30 18:01:15 +0000397 case 'u':
398 cmdline.update = true;
399 break;
400 case 'a':
401 gSessionData->mAllowCommands = true;
402 break;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100403 case 'h':
404 case '?':
Jon Medhurstb1d07442015-05-08 12:04:18 +0100405 logg->logError(
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100406 "%s. All parameters are optional:\n"
Jon Medhurstb1d07442015-05-08 12:04:18 +0100407 "-c config_xml path and filename of the configuration XML to use\n"
408 "-e events_xml path and filename of the events XML to use\n"
409 "-E events_xml path and filename of events XML to append\n"
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100410 "-h this help page\n"
411 "-m module path and filename of gator.ko\n"
412 "-p port_number port upon which the server listens; default is 8080\n"
Jon Medhurst96b56152014-10-30 18:01:15 +0000413 "-s session_xml path and filename of a session.xml used for local capture\n"
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100414 "-o apc_dir path and name of the output for a local capture\n"
415 "-v version information\n"
Jon Medhurst96b56152014-10-30 18:01:15 +0000416 "-d enable debug messages\n"
Jon Medhurstb1d07442015-05-08 12:04:18 +0100417 "-a allow the user to issue a command from Streamline"
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100418 , version_string);
419 handleException();
420 break;
421 case 'v':
Jon Medhurstb1d07442015-05-08 12:04:18 +0100422 logg->logError("%s", version_string);
423 handleException();
424 break;
425 case 'V':
426 logg->logError("%s\nSRC_MD5: %s", version_string, gSrcMd5);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100427 handleException();
428 break;
429 }
430 }
431
432 // Error checking
Jon Medhurstd3698592013-10-10 16:48:56 +0100433 if (cmdline.port != DEFAULT_PORT && gSessionData->mSessionXMLPath != NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100434 logg->logError("Only a port or a session xml can be specified, not both");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100435 handleException();
436 }
437
438 if (gSessionData->mTargetPath != NULL && gSessionData->mSessionXMLPath == NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100439 logg->logError("Missing -s command line option required for a local capture.");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100440 handleException();
441 }
442
443 if (optind < argc) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100444 logg->logError("Unknown argument: %s. Use '-h' for help.", argv[optind]);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100445 handleException();
446 }
447
448 return cmdline;
449}
450
Jon Medhurstb1d07442015-05-08 12:04:18 +0100451static AnnotateListener annotateListener;
452
Jon Medhurst96b56152014-10-30 18:01:15 +0000453static void handleClient() {
Jon Medhurste31266f2014-08-04 15:47:44 +0100454 OlySocket client(sock->acceptConnection());
455
456 int pid = fork();
457 if (pid < 0) {
458 // Error
Jon Medhurstb1d07442015-05-08 12:04:18 +0100459 logg->logError("Fork process failed. Please power cycle the target device if this error persists.");
Jon Medhurste31266f2014-08-04 15:47:44 +0100460 } else if (pid == 0) {
461 // Child
462 sock->closeServerSocket();
463 udpListener.close();
464 monitor.close();
Jon Medhurstb1d07442015-05-08 12:04:18 +0100465 annotateListener.close();
Jon Medhurste31266f2014-08-04 15:47:44 +0100466 child = new Child(&client, numSessions + 1);
467 child->run();
468 delete child;
469 exit(0);
470 } else {
471 // Parent
472 client.closeSocket();
473
474 pthread_mutex_lock(&numSessions_mutex);
475 numSessions++;
476 pthread_mutex_unlock(&numSessions_mutex);
477
478 // Maximum number of connections is 2
479 int wait = 0;
480 while (numSessions > 1) {
481 // Throttle until one of the children exits before continuing to accept another socket connection
482 logg->logMessage("%d sessions active!", numSessions);
483 if (wait++ >= 10) { // Wait no more than 10 seconds
484 // Kill last created child
485 kill(pid, SIGALRM);
486 break;
487 }
488 sleep(1);
489 }
490 }
491}
492
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100493// Gator data flow: collector -> collector fifo -> sender
Jon Medhurst34d97692013-12-19 09:23:06 +0000494int main(int argc, char** argv) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100495 // Ensure proper signal handling by making gatord the process group leader
496 // e.g. it may not be the group leader when launched as 'sudo gatord'
497 setsid();
498
Jon Medhurst96b56152014-10-30 18:01:15 +0000499 // Set up global thread-safe logging
500 logg = new Logging(hasDebugFlag(argc, argv));
501 // Global data class
502 gSessionData = new SessionData();
503 // Set up global utility class
504 util = new OlyUtility();
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100505
506 // Initialize drivers
Jon Medhurst96b56152014-10-30 18:01:15 +0000507 new CCNDriver();
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100508
509 prctl(PR_SET_NAME, (unsigned long)&"gatord-main", 0, 0, 0);
510 pthread_mutex_init(&numSessions_mutex, NULL);
511
512 signal(SIGINT, handler);
513 signal(SIGTERM, handler);
514 signal(SIGABRT, handler);
515
516 // Set to high priority
517 if (setpriority(PRIO_PROCESS, syscall(__NR_gettid), -19) == -1) {
518 logg->logMessage("setpriority() failed");
519 }
520
521 // Parse the command line parameters
522 struct cmdline_t cmdline = parseCommandLine(argc, argv);
523
Jon Medhurst96b56152014-10-30 18:01:15 +0000524 if (cmdline.update) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100525 update(argv[0]);
526 cmdline.update = false;
527 gSessionData->mAllowCommands = true;
Jon Medhurst96b56152014-10-30 18:01:15 +0000528 }
529
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100530 // Verify root permissions
531 uid_t euid = geteuid();
532 if (euid) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100533 logg->logError("gatord must be launched with root privileges");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100534 handleException();
535 }
536
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100537 // Call before setting up the SIGCHLD handler, as system() spawns child processes
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100538 if (!setupFilesystem(cmdline.module)) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100539 logg->logMessage("Unable to set up gatorfs, trying perf");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100540 if (!gSessionData->perf.setup()) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100541 logg->logError(
Jon Medhurste31266f2014-08-04 15:47:44 +0100542 "Unable to locate gator.ko driver:\n"
543 " >>> gator.ko should be co-located with gatord in the same directory\n"
544 " >>> OR insmod gator.ko prior to launching gatord\n"
545 " >>> OR specify the location of gator.ko on the command line\n"
Jon Medhurst96b56152014-10-30 18:01:15 +0000546 " >>> OR run Linux 3.4 or later with perf (CONFIG_PERF_EVENTS and CONFIG_HW_PERF_EVENTS) and tracing (CONFIG_TRACING and CONFIG_CONTEXT_SWITCH_TRACER) support to collect data via userspace only");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100547 handleException();
548 }
549 }
550
Jon Medhurste31266f2014-08-04 15:47:44 +0100551 {
552 EventsXML eventsXML;
553 mxml_node_t *xml = eventsXML.getTree();
Jon Medhurst96b56152014-10-30 18:01:15 +0000554 // Initialize all drivers
555 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
556 driver->readEvents(xml);
557 }
Jon Medhurste31266f2014-08-04 15:47:44 +0100558 mxmlDelete(xml);
559 }
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100560
561 // Handle child exit codes
562 signal(SIGCHLD, child_exit);
563
564 // Ignore the SIGPIPE signal so that any send to a broken socket will return an error code instead of asserting a signal
565 // Handling the error at the send function call is much easier than trying to do anything intelligent in the sig handler
566 signal(SIGPIPE, SIG_IGN);
567
568 // If the command line argument is a session xml file, no need to open a socket
569 if (gSessionData->mSessionXMLPath) {
570 child = new Child();
571 child->run();
572 delete child;
573 } else {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100574 annotateListener.setup();
575 int pipefd[2];
576 if (pipe_cloexec(pipefd) != 0) {
577 logg->logError("Unable to set up annotate pipe");
578 handleException();
579 }
580 gSessionData->mAnnotateStart = pipefd[1];
Jon Medhurste31266f2014-08-04 15:47:44 +0100581 sock = new OlyServerSocket(cmdline.port);
582 udpListener.setup(cmdline.port);
Jon Medhurst96b56152014-10-30 18:01:15 +0000583 if (!monitor.init() ||
584 !monitor.add(sock->getFd()) ||
585 !monitor.add(udpListener.getReq()) ||
Jon Medhurstb1d07442015-05-08 12:04:18 +0100586 !monitor.add(annotateListener.getSockFd()) ||
587 !monitor.add(annotateListener.getUdsFd()) ||
588 !monitor.add(pipefd[0]) ||
Jon Medhurst96b56152014-10-30 18:01:15 +0000589 false) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100590 logg->logError("Monitor setup failed");
Jon Medhurstd3698592013-10-10 16:48:56 +0100591 handleException();
592 }
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100593 // Forever loop, can be exited via a signal or exception
594 while (1) {
Jon Medhurste31266f2014-08-04 15:47:44 +0100595 struct epoll_event events[2];
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100596 logg->logMessage("Waiting on connection...");
Jon Medhurste31266f2014-08-04 15:47:44 +0100597 int ready = monitor.wait(events, ARRAY_LENGTH(events), -1);
598 if (ready < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100599 logg->logError("Monitor::wait failed");
Jon Medhurste31266f2014-08-04 15:47:44 +0100600 handleException();
601 }
602 for (int i = 0; i < ready; ++i) {
603 if (events[i].data.fd == sock->getFd()) {
604 handleClient();
605 } else if (events[i].data.fd == udpListener.getReq()) {
606 udpListener.handle();
Jon Medhurstb1d07442015-05-08 12:04:18 +0100607 } else if (events[i].data.fd == annotateListener.getSockFd()) {
608 annotateListener.handleSock();
609 } else if (events[i].data.fd == annotateListener.getUdsFd()) {
610 annotateListener.handleUds();
611 } else if (events[i].data.fd == pipefd[0]) {
612 uint64_t val;
613 if (read(pipefd[0], &val, sizeof(val)) != sizeof(val)) {
614 logg->logMessage("Reading annotate pipe failed");
615 }
616 annotateListener.signal();
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100617 }
618 }
619 }
620 }
621
622 cleanUp();
623 return 0;
624}