diff options
Diffstat (limited to 'daemon/main.cpp')
-rw-r--r-- | daemon/main.cpp | 260 |
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 @@ | |||
33 | extern Child* child; | 31 | extern Child* child; |
34 | static int shutdownFilesystem(); | 32 | static int shutdownFilesystem(); |
35 | static pthread_mutex_t numSessions_mutex; | 33 | static pthread_mutex_t numSessions_mutex; |
36 | static OlyServerSocket* sock = NULL; | ||
37 | static Monitor monitor; | ||
38 | static int numSessions = 0; | 34 | static int numSessions = 0; |
35 | static OlyServerSocket* sock = NULL; | ||
39 | static bool driverRunningAtStart = false; | 36 | static bool driverRunningAtStart = false; |
40 | static bool driverMountedAtStart = false; | 37 | static bool driverMountedAtStart = false; |
41 | 38 | ||
@@ -105,8 +102,42 @@ static void child_exit(int) { | |||
105 | } | 102 | } |
106 | } | 103 | } |
107 | 104 | ||
108 | static const int UDP_ANS_PORT = 30000; | 105 | static int udpPort(int port) { |
109 | static 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 | ||
111 | typedef struct { | 142 | typedef 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 | ||
124 | static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 }; | 155 | static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 }; |
125 | 156 | ||
126 | class UdpListener { | 157 | static void* answerThread(void* pVoid) { |
127 | public: | 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 | |||
176 | private: | ||
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 | |||
216 | static 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 |
219 | static int mountGatorFS() { | 198 | static 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 | ||
410 | void 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 |
450 | int main(int argc, char** argv) { | 384 | int 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 | } |