summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/main.cpp')
-rw-r--r--daemon/main.cpp260
1 files changed, 104 insertions, 156 deletions
diff --git a/daemon/main.cpp b/daemon/main.cpp
index 2998c70..1275aef 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -20,10 +20,8 @@
20#include <unistd.h> 20#include <unistd.h>
21 21
22#include "Child.h" 22#include "Child.h"
23#include "EventsXML.h"
24#include "KMod.h" 23#include "KMod.h"
25#include "Logging.h" 24#include "Logging.h"
26#include "Monitor.h"
27#include "OlySocket.h" 25#include "OlySocket.h"
28#include "OlyUtility.h" 26#include "OlyUtility.h"
29#include "SessionData.h" 27#include "SessionData.h"
@@ -33,9 +31,8 @@
33extern Child* child; 31extern Child* child;
34static int shutdownFilesystem(); 32static int shutdownFilesystem();
35static pthread_mutex_t numSessions_mutex; 33static pthread_mutex_t numSessions_mutex;
36static OlyServerSocket* sock = NULL;
37static Monitor monitor;
38static int numSessions = 0; 34static int numSessions = 0;
35static OlyServerSocket* sock = NULL;
39static bool driverRunningAtStart = false; 36static bool driverRunningAtStart = false;
40static bool driverMountedAtStart = false; 37static bool driverMountedAtStart = false;
41 38
@@ -105,8 +102,42 @@ static void child_exit(int) {
105 } 102 }
106} 103}
107 104
108static const int UDP_ANS_PORT = 30000; 105static int udpPort(int port) {
109static const int UDP_REQ_PORT = 30001; 106 int s;
107 struct sockaddr_in6 sockaddr;
108 int on;
109 int family = AF_INET6;
110
111 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
112 if (s == -1) {
113 family = AF_INET;
114 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
115 if (s == -1) {
116 logg->logError(__FILE__, __LINE__, "socket failed");
117 handleException();
118 }
119 }
120
121 on = 1;
122 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) {
123 logg->logError(__FILE__, __LINE__, "setsockopt failed");
124 handleException();
125 }
126
127 memset((void*)&sockaddr, 0, sizeof(sockaddr));
128 sockaddr.sin6_family = family;
129 sockaddr.sin6_port = htons(port);
130 sockaddr.sin6_addr = in6addr_any;
131 if (bind(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
132 logg->logError(__FILE__, __LINE__, "socket failed");
133 handleException();
134 }
135
136 return s;
137}
138
139#define UDP_ANS_PORT 30000
140#define UDP_REQ_PORT 30001
110 141
111typedef struct { 142typedef struct {
112 char rviHeader[8]; 143 char rviHeader[8];
@@ -118,102 +149,50 @@ typedef struct {
118 uint32_t ipAddress; 149 uint32_t ipAddress;
119 uint32_t defaultGateway; 150 uint32_t defaultGateway;
120 uint32_t subnetMask; 151 uint32_t subnetMask;
121 uint32_t activeConnections; 152 uint32_t activeConnections;
122} RVIConfigureInfo; 153} RVIConfigureInfo;
123 154
124static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 }; 155static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 };
125 156
126class UdpListener { 157static void* answerThread(void* pVoid) {
127public: 158 prctl(PR_SET_NAME, (unsigned long)&"gatord-discover", 0, 0, 0);
128 UdpListener() : mDstAns(), mReq(-1), mAns(-1) {} 159 const struct cmdline_t * const cmdline = (struct cmdline_t *)pVoid;
129 160 RVIConfigureInfo dstAns;
130 void setup(int port) { 161 int req = udpPort(UDP_REQ_PORT);
131 mReq = udpPort(UDP_REQ_PORT); 162 int ans = udpPort(UDP_ANS_PORT);
132 mAns = udpPort(UDP_ANS_PORT); 163
133 164 // Format the answer buffer
134 // Format the answer buffer 165 memset(&dstAns, 0, sizeof(dstAns));
135 memset(&mDstAns, 0, sizeof(mDstAns)); 166 memcpy(dstAns.rviHeader, "STR_ANS ", sizeof(dstAns.rviHeader));
136 memcpy(mDstAns.rviHeader, "STR_ANS ", sizeof(mDstAns.rviHeader)); 167 if (gethostname(dstAns.dhcpName, sizeof(dstAns.dhcpName) - 1) != 0) {
137 if (gethostname(mDstAns.dhcpName, sizeof(mDstAns.dhcpName) - 1) != 0) { 168 logg->logError(__FILE__, __LINE__, "gethostname failed");
138 logg->logError(__FILE__, __LINE__, "gethostname failed"); 169 handleException();
139 handleException();
140 }
141 // Subvert the defaultGateway field for the port number
142 if (port != DEFAULT_PORT) {
143 mDstAns.defaultGateway = port;
144 }
145 // Subvert the subnetMask field for the protocol version
146 mDstAns.subnetMask = PROTOCOL_VERSION;
147 } 170 }
148 171 // Subvert the defaultGateway field for the port number
149 int getReq() const { 172 if (cmdline->port != DEFAULT_PORT) {
150 return mReq; 173 dstAns.defaultGateway = cmdline->port;
151 } 174 }
175 // Subvert the subnetMask field for the protocol version
176 dstAns.subnetMask = PROTOCOL_VERSION;
152 177
153 void handle() { 178 for (;;) {
154 char buf[128]; 179 char buf[128];
155 struct sockaddr_in6 sockaddr; 180 struct sockaddr_in6 sockaddr;
156 socklen_t addrlen; 181 socklen_t addrlen;
157 int read; 182 int read;
158 addrlen = sizeof(sockaddr); 183 addrlen = sizeof(sockaddr);
159 read = recvfrom(mReq, &buf, sizeof(buf), 0, (struct sockaddr *)&sockaddr, &addrlen); 184 read = recvfrom(req, &buf, sizeof(buf), 0, (struct sockaddr *)&sockaddr, &addrlen);
160 if (read < 0) { 185 if (read < 0) {
161 logg->logError(__FILE__, __LINE__, "recvfrom failed"); 186 logg->logError(__FILE__, __LINE__, "recvfrom failed");
162 handleException(); 187 handleException();
163 } else if ((read == 12) && (memcmp(buf, DST_REQ, sizeof(DST_REQ)) == 0)) { 188 } else if ((read == 12) && (memcmp(buf, DST_REQ, sizeof(DST_REQ)) == 0)) {
164 if (sendto(mAns, &mDstAns, sizeof(mDstAns), 0, (struct sockaddr *)&sockaddr, addrlen) != sizeof(mDstAns)) { 189 if (sendto(ans, &dstAns, sizeof(dstAns), 0, (struct sockaddr *)&sockaddr, addrlen) != sizeof(dstAns)) {
165 logg->logError(__FILE__, __LINE__, "sendto failed"); 190 logg->logError(__FILE__, __LINE__, "sendto failed");
166 handleException(); 191 handleException();
167 } 192 }
168 } 193 }
169 } 194 }
170 195}
171 void close() {
172 ::close(mReq);
173 ::close(mAns);
174 }
175
176private:
177 int udpPort(int port) {
178 int s;
179 struct sockaddr_in6 sockaddr;
180 int on;
181 int family = AF_INET6;
182
183 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
184 if (s == -1) {
185 family = AF_INET;
186 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
187 if (s == -1) {
188 logg->logError(__FILE__, __LINE__, "socket failed");
189 handleException();
190 }
191 }
192
193 on = 1;
194 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) {
195 logg->logError(__FILE__, __LINE__, "setsockopt failed");
196 handleException();
197 }
198
199 memset((void*)&sockaddr, 0, sizeof(sockaddr));
200 sockaddr.sin6_family = family;
201 sockaddr.sin6_port = htons(port);
202 sockaddr.sin6_addr = in6addr_any;
203 if (bind(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
204 logg->logError(__FILE__, __LINE__, "socket failed");
205 handleException();
206 }
207
208 return s;
209 }
210
211 RVIConfigureInfo mDstAns;
212 int mReq;
213 int mAns;
214};
215
216static UdpListener udpListener;
217 196
218// retval: -1 = failure; 0 = was already mounted; 1 = successfully mounted 197// retval: -1 = failure; 0 = was already mounted; 1 = successfully mounted
219static int mountGatorFS() { 198static int mountGatorFS() {
@@ -239,7 +218,7 @@ static bool init_module (const char * const location) {
239 if (fstat(fd, &st) == 0) { 218 if (fstat(fd, &st) == 0) {
240 void * const p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 219 void * const p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
241 if (p != MAP_FAILED) { 220 if (p != MAP_FAILED) {
242 if (syscall(__NR_init_module, p, (unsigned long)st.st_size, "") == 0) { 221 if (syscall(__NR_init_module, p, st.st_size, "") == 0) {
243 ret = true; 222 ret = true;
244 } 223 }
245 munmap(p, st.st_size); 224 munmap(p, st.st_size);
@@ -285,14 +264,8 @@ static bool setupFilesystem(char* module) {
285 } 264 }
286 265
287 if (access(location, F_OK) == -1) { 266 if (access(location, F_OK) == -1) {
288 if (module == NULL) { 267 // The gator kernel is not already loaded and unable to locate gator.ko
289 // The gator kernel is not already loaded and unable to locate gator.ko in the default location 268 return false;
290 return false;
291 } else {
292 // gator location specified on the command line but it was not found
293 logg->logError(__FILE__, __LINE__, "gator module not found at %s", location);
294 handleException();
295 }
296 } 269 }
297 270
298 // Load driver 271 // Load driver
@@ -407,45 +380,6 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) {
407 return cmdline; 380 return cmdline;
408} 381}
409 382
410void handleClient() {
411 OlySocket client(sock->acceptConnection());
412
413 int pid = fork();
414 if (pid < 0) {
415 // Error
416 logg->logError(__FILE__, __LINE__, "Fork process failed. Please power cycle the target device if this error persists.");
417 } else if (pid == 0) {
418 // Child
419 sock->closeServerSocket();
420 udpListener.close();
421 monitor.close();
422 child = new Child(&client, numSessions + 1);
423 child->run();
424 delete child;
425 exit(0);
426 } else {
427 // Parent
428 client.closeSocket();
429
430 pthread_mutex_lock(&numSessions_mutex);
431 numSessions++;
432 pthread_mutex_unlock(&numSessions_mutex);
433
434 // Maximum number of connections is 2
435 int wait = 0;
436 while (numSessions > 1) {
437 // Throttle until one of the children exits before continuing to accept another socket connection
438 logg->logMessage("%d sessions active!", numSessions);
439 if (wait++ >= 10) { // Wait no more than 10 seconds
440 // Kill last created child
441 kill(pid, SIGALRM);
442 break;
443 }
444 sleep(1);
445 }
446 }
447}
448
449// Gator data flow: collector -> collector fifo -> sender 383// Gator data flow: collector -> collector fifo -> sender
450int main(int argc, char** argv) { 384int main(int argc, char** argv) {
451 // Ensure proper signal handling by making gatord the process group leader 385 // Ensure proper signal handling by making gatord the process group leader
@@ -486,23 +420,16 @@ int main(int argc, char** argv) {
486 logg->logMessage("Unable to setup gatorfs, trying perf"); 420 logg->logMessage("Unable to setup gatorfs, trying perf");
487 if (!gSessionData->perf.setup()) { 421 if (!gSessionData->perf.setup()) {
488 logg->logError(__FILE__, __LINE__, 422 logg->logError(__FILE__, __LINE__,
489 "Unable to locate gator.ko driver:\n" 423 "Unable to locate gator.ko driver:\n"
490 " >>> gator.ko should be co-located with gatord in the same directory\n" 424 " >>> gator.ko should be co-located with gatord in the same directory\n"
491 " >>> OR insmod gator.ko prior to launching gatord\n" 425 " >>> OR insmod gator.ko prior to launching gatord\n"
492 " >>> OR specify the location of gator.ko on the command line\n" 426 " >>> OR specify the location of gator.ko on the command line\n"
493 " >>> OR run Linux 3.4 or later with perf (CONFIG_PERF_EVENTS and CONFIG_HW_PERF_EVENTS) and tracing (CONFIG_TRACING) support to collect data via userspace only"); 427 " >>> OR run Linux 3.12 or later with perf support to collect data via userspace only");
494 handleException(); 428 handleException();
495 } 429 }
496 } 430 }
497 431
498 gSessionData->hwmon.setup(); 432 gSessionData->hwmon.setup();
499 {
500 EventsXML eventsXML;
501 mxml_node_t *xml = eventsXML.getTree();
502 gSessionData->fsDriver.setup(xml);
503 gSessionData->maliVideo.setup(xml);
504 mxmlDelete(xml);
505 }
506 433
507 // Handle child exit codes 434 // Handle child exit codes
508 signal(SIGCHLD, child_exit); 435 signal(SIGCHLD, child_exit);
@@ -517,26 +444,47 @@ int main(int argc, char** argv) {
517 child->run(); 444 child->run();
518 delete child; 445 delete child;
519 } else { 446 } else {
520 sock = new OlyServerSocket(cmdline.port); 447 pthread_t answerThreadID;
521 udpListener.setup(cmdline.port); 448 if (pthread_create(&answerThreadID, NULL, answerThread, &cmdline)) {
522 if (!monitor.init() || !monitor.add(sock->getFd()) || !monitor.add(udpListener.getReq())) { 449 logg->logError(__FILE__, __LINE__, "Failed to create answer thread");
523 logg->logError(__FILE__, __LINE__, "Monitor setup failed");
524 handleException(); 450 handleException();
525 } 451 }
452 sock = new OlyServerSocket(cmdline.port);
526 // Forever loop, can be exited via a signal or exception 453 // Forever loop, can be exited via a signal or exception
527 while (1) { 454 while (1) {
528 struct epoll_event events[2];
529 logg->logMessage("Waiting on connection..."); 455 logg->logMessage("Waiting on connection...");
530 int ready = monitor.wait(events, ARRAY_LENGTH(events), -1); 456 OlySocket client(sock->acceptConnection());
531 if (ready < 0) { 457
532 logg->logError(__FILE__, __LINE__, "Monitor::wait failed"); 458 int pid = fork();
533 handleException(); 459 if (pid < 0) {
534 } 460 // Error
535 for (int i = 0; i < ready; ++i) { 461 logg->logError(__FILE__, __LINE__, "Fork process failed. Please power cycle the target device if this error persists.");
536 if (events[i].data.fd == sock->getFd()) { 462 } else if (pid == 0) {
537 handleClient(); 463 // Child
538 } else if (events[i].data.fd == udpListener.getReq()) { 464 sock->closeServerSocket();
539 udpListener.handle(); 465 child = new Child(&client, numSessions + 1);
466 child->run();
467 delete child;
468 exit(0);
469 } else {
470 // Parent
471 client.closeSocket();
472
473 pthread_mutex_lock(&numSessions_mutex);
474 numSessions++;
475 pthread_mutex_unlock(&numSessions_mutex);
476
477 // Maximum number of connections is 2
478 int wait = 0;
479 while (numSessions > 1) {
480 // Throttle until one of the children exits before continuing to accept another socket connection
481 logg->logMessage("%d sessions active!", numSessions);
482 if (wait++ >= 10) { // Wait no more than 10 seconds
483 // Kill last created child
484 kill(pid, SIGALRM);
485 break;
486 }
487 sleep(1);
540 } 488 }
541 } 489 }
542 } 490 }