diff options
Diffstat (limited to 'daemon/main.cpp')
-rw-r--r-- | daemon/main.cpp | 260 |
1 files changed, 156 insertions, 104 deletions
diff --git a/daemon/main.cpp b/daemon/main.cpp index 1275aef..2998c70 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -20,8 +20,10 @@ #include <unistd.h> #include "Child.h" +#include "EventsXML.h" #include "KMod.h" #include "Logging.h" +#include "Monitor.h" #include "OlySocket.h" #include "OlyUtility.h" #include "SessionData.h" @@ -31,8 +33,9 @@ extern Child* child; static int shutdownFilesystem(); static pthread_mutex_t numSessions_mutex; -static int numSessions = 0; static OlyServerSocket* sock = NULL; +static Monitor monitor; +static int numSessions = 0; static bool driverRunningAtStart = false; static bool driverMountedAtStart = false; @@ -102,42 +105,8 @@ static void child_exit(int) { } } -static int udpPort(int port) { - int s; - struct sockaddr_in6 sockaddr; - int on; - int family = AF_INET6; - - s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); - if (s == -1) { - family = AF_INET; - s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (s == -1) { - logg->logError(__FILE__, __LINE__, "socket failed"); - handleException(); - } - } - - on = 1; - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) { - logg->logError(__FILE__, __LINE__, "setsockopt failed"); - handleException(); - } - - memset((void*)&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin6_family = family; - sockaddr.sin6_port = htons(port); - sockaddr.sin6_addr = in6addr_any; - if (bind(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { - logg->logError(__FILE__, __LINE__, "socket failed"); - handleException(); - } - - return s; -} - -#define UDP_ANS_PORT 30000 -#define UDP_REQ_PORT 30001 +static const int UDP_ANS_PORT = 30000; +static const int UDP_REQ_PORT = 30001; typedef struct { char rviHeader[8]; @@ -149,50 +118,102 @@ typedef struct { uint32_t ipAddress; uint32_t defaultGateway; uint32_t subnetMask; - uint32_t activeConnections; + uint32_t activeConnections; } RVIConfigureInfo; static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 }; -static void* answerThread(void* pVoid) { - prctl(PR_SET_NAME, (unsigned long)&"gatord-discover", 0, 0, 0); - const struct cmdline_t * const cmdline = (struct cmdline_t *)pVoid; - RVIConfigureInfo dstAns; - int req = udpPort(UDP_REQ_PORT); - int ans = udpPort(UDP_ANS_PORT); - - // Format the answer buffer - memset(&dstAns, 0, sizeof(dstAns)); - memcpy(dstAns.rviHeader, "STR_ANS ", sizeof(dstAns.rviHeader)); - if (gethostname(dstAns.dhcpName, sizeof(dstAns.dhcpName) - 1) != 0) { - logg->logError(__FILE__, __LINE__, "gethostname failed"); - handleException(); +class UdpListener { +public: + UdpListener() : mDstAns(), mReq(-1), mAns(-1) {} + + void setup(int port) { + mReq = udpPort(UDP_REQ_PORT); + mAns = udpPort(UDP_ANS_PORT); + + // Format the answer buffer + memset(&mDstAns, 0, sizeof(mDstAns)); + memcpy(mDstAns.rviHeader, "STR_ANS ", sizeof(mDstAns.rviHeader)); + if (gethostname(mDstAns.dhcpName, sizeof(mDstAns.dhcpName) - 1) != 0) { + logg->logError(__FILE__, __LINE__, "gethostname failed"); + handleException(); + } + // Subvert the defaultGateway field for the port number + if (port != DEFAULT_PORT) { + mDstAns.defaultGateway = port; + } + // Subvert the subnetMask field for the protocol version + mDstAns.subnetMask = PROTOCOL_VERSION; } - // Subvert the defaultGateway field for the port number - if (cmdline->port != DEFAULT_PORT) { - dstAns.defaultGateway = cmdline->port; + + int getReq() const { + return mReq; } - // Subvert the subnetMask field for the protocol version - dstAns.subnetMask = PROTOCOL_VERSION; - for (;;) { + void handle() { char buf[128]; struct sockaddr_in6 sockaddr; socklen_t addrlen; int read; addrlen = sizeof(sockaddr); - read = recvfrom(req, &buf, sizeof(buf), 0, (struct sockaddr *)&sockaddr, &addrlen); + read = recvfrom(mReq, &buf, sizeof(buf), 0, (struct sockaddr *)&sockaddr, &addrlen); if (read < 0) { logg->logError(__FILE__, __LINE__, "recvfrom failed"); handleException(); } else if ((read == 12) && (memcmp(buf, DST_REQ, sizeof(DST_REQ)) == 0)) { - if (sendto(ans, &dstAns, sizeof(dstAns), 0, (struct sockaddr *)&sockaddr, addrlen) != sizeof(dstAns)) { + if (sendto(mAns, &mDstAns, sizeof(mDstAns), 0, (struct sockaddr *)&sockaddr, addrlen) != sizeof(mDstAns)) { logg->logError(__FILE__, __LINE__, "sendto failed"); handleException(); } } } -} + + void close() { + ::close(mReq); + ::close(mAns); + } + +private: + int udpPort(int port) { + int s; + struct sockaddr_in6 sockaddr; + int on; + int family = AF_INET6; + + s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (s == -1) { + family = AF_INET; + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s == -1) { + logg->logError(__FILE__, __LINE__, "socket failed"); + handleException(); + } + } + + on = 1; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) { + logg->logError(__FILE__, __LINE__, "setsockopt failed"); + handleException(); + } + + memset((void*)&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_family = family; + sockaddr.sin6_port = htons(port); + sockaddr.sin6_addr = in6addr_any; + if (bind(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { + logg->logError(__FILE__, __LINE__, "socket failed"); + handleException(); + } + + return s; + } + + RVIConfigureInfo mDstAns; + int mReq; + int mAns; +}; + +static UdpListener udpListener; // retval: -1 = failure; 0 = was already mounted; 1 = successfully mounted static int mountGatorFS() { @@ -218,7 +239,7 @@ static bool init_module (const char * const location) { if (fstat(fd, &st) == 0) { void * const p = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (p != MAP_FAILED) { - if (syscall(__NR_init_module, p, st.st_size, "") == 0) { + if (syscall(__NR_init_module, p, (unsigned long)st.st_size, "") == 0) { ret = true; } munmap(p, st.st_size); @@ -264,8 +285,14 @@ static bool setupFilesystem(char* module) { } if (access(location, F_OK) == -1) { - // The gator kernel is not already loaded and unable to locate gator.ko - return false; + if (module == NULL) { + // The gator kernel is not already loaded and unable to locate gator.ko in the default location + return false; + } else { + // gator location specified on the command line but it was not found + logg->logError(__FILE__, __LINE__, "gator module not found at %s", location); + handleException(); + } } // Load driver @@ -380,6 +407,45 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) { return cmdline; } +void handleClient() { + OlySocket client(sock->acceptConnection()); + + int pid = fork(); + if (pid < 0) { + // Error + logg->logError(__FILE__, __LINE__, "Fork process failed. Please power cycle the target device if this error persists."); + } else if (pid == 0) { + // Child + sock->closeServerSocket(); + udpListener.close(); + monitor.close(); + child = new Child(&client, numSessions + 1); + child->run(); + delete child; + exit(0); + } else { + // Parent + client.closeSocket(); + + pthread_mutex_lock(&numSessions_mutex); + numSessions++; + pthread_mutex_unlock(&numSessions_mutex); + + // Maximum number of connections is 2 + int wait = 0; + while (numSessions > 1) { + // Throttle until one of the children exits before continuing to accept another socket connection + logg->logMessage("%d sessions active!", numSessions); + if (wait++ >= 10) { // Wait no more than 10 seconds + // Kill last created child + kill(pid, SIGALRM); + break; + } + sleep(1); + } + } +} + // Gator data flow: collector -> collector fifo -> sender int main(int argc, char** argv) { // Ensure proper signal handling by making gatord the process group leader @@ -420,16 +486,23 @@ int main(int argc, char** argv) { logg->logMessage("Unable to setup gatorfs, trying perf"); if (!gSessionData->perf.setup()) { logg->logError(__FILE__, __LINE__, - "Unable to locate gator.ko driver:\n" - " >>> gator.ko should be co-located with gatord in the same directory\n" - " >>> OR insmod gator.ko prior to launching gatord\n" - " >>> OR specify the location of gator.ko on the command line\n" - " >>> OR run Linux 3.12 or later with perf support to collect data via userspace only"); + "Unable to locate gator.ko driver:\n" + " >>> gator.ko should be co-located with gatord in the same directory\n" + " >>> OR insmod gator.ko prior to launching gatord\n" + " >>> OR specify the location of gator.ko on the command line\n" + " >>> 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"); handleException(); } } gSessionData->hwmon.setup(); + { + EventsXML eventsXML; + mxml_node_t *xml = eventsXML.getTree(); + gSessionData->fsDriver.setup(xml); + gSessionData->maliVideo.setup(xml); + mxmlDelete(xml); + } // Handle child exit codes signal(SIGCHLD, child_exit); @@ -444,47 +517,26 @@ int main(int argc, char** argv) { child->run(); delete child; } else { - pthread_t answerThreadID; - if (pthread_create(&answerThreadID, NULL, answerThread, &cmdline)) { - logg->logError(__FILE__, __LINE__, "Failed to create answer thread"); + sock = new OlyServerSocket(cmdline.port); + udpListener.setup(cmdline.port); + if (!monitor.init() || !monitor.add(sock->getFd()) || !monitor.add(udpListener.getReq())) { + logg->logError(__FILE__, __LINE__, "Monitor setup failed"); handleException(); } - sock = new OlyServerSocket(cmdline.port); // Forever loop, can be exited via a signal or exception while (1) { + struct epoll_event events[2]; logg->logMessage("Waiting on connection..."); - OlySocket client(sock->acceptConnection()); - - int pid = fork(); - if (pid < 0) { - // Error - logg->logError(__FILE__, __LINE__, "Fork process failed. Please power cycle the target device if this error persists."); - } else if (pid == 0) { - // Child - sock->closeServerSocket(); - child = new Child(&client, numSessions + 1); - child->run(); - delete child; - exit(0); - } else { - // Parent - client.closeSocket(); - - pthread_mutex_lock(&numSessions_mutex); - numSessions++; - pthread_mutex_unlock(&numSessions_mutex); - - // Maximum number of connections is 2 - int wait = 0; - while (numSessions > 1) { - // Throttle until one of the children exits before continuing to accept another socket connection - logg->logMessage("%d sessions active!", numSessions); - if (wait++ >= 10) { // Wait no more than 10 seconds - // Kill last created child - kill(pid, SIGALRM); - break; - } - sleep(1); + int ready = monitor.wait(events, ARRAY_LENGTH(events), -1); + if (ready < 0) { + logg->logError(__FILE__, __LINE__, "Monitor::wait failed"); + handleException(); + } + for (int i = 0; i < ready; ++i) { + if (events[i].data.fd == sock->getFd()) { + handleClient(); + } else if (events[i].data.fd == udpListener.getReq()) { + udpListener.handle(); } } } |