void mainloop(int socket) { uint8_t butts[2048]; int res, i; size_t rcvd; pid_t build; enum message_type msg_type; BuildRequest* msg; /* Allocate some handlers on the heap */ fd_list **subscriptions; /* Be super pessimistic about how many pids we might see */ #define ___MAX_PIDS pow(sizeof(pid_t), 8) subscriptions = malloc(sizeof(fd_list) * ___MAX_PIDS); memset(subscriptions, 0, ___MAX_PIDS); fd_list *new_sub; fd_list *sub_node; #undef ___MAX_PIDS /* Setup FD sets for monitoring */ fd_set fds; fd_set rfds, wfds, efds; FD_ZERO(&fds); FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(socket, &fds); /* Block SIGCHLD set setup signalfd for monitoring */ sigset_t signals; sigemptyset(&signals); sigaddset(&signals, SIGCHLD); /* Block sigchld */ sigprocmask(SIG_BLOCK, &signals, NULL); /* Setup a signalfd */ #ifdef __linux int sigfd = signalfd(-1, &signals, SFD_NONBLOCK | SFD_CLOEXEC); struct signalfd_siginfo child; size_t child_read; #elif __APPLE__ int sigfd = kqueue(); int kq_status; struct kevent ke, child; EV_SET(&ke, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); i = kevent(sigfd, &ke, 1, NULL, 0, NULL); if (i == -1) { warn("Couldn't set up sigfd\n"); return; } #endif /* Add sigfd to the main set */ FD_SET(sigfd, &fds); /* Structure to read children into */ pid_t child_pid; int child_status; while(1) { FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); memcpy(&rfds, &fds, sizeof(fd_set)); memcpy(&wfds, &fds, sizeof(fd_set)); memcpy(&efds, &fds, sizeof(fd_set)); res = select(FD_SETSIZE, &rfds, NULL, &efds, NULL); info("got %d fds\n", res); if (res == 0) { error("No fd's returned from select\n"); } else if (res == -1) { warn("select call interrupted"); break; // We probably saw a signal. Defer signals and do some stuff. } else { for (i = 0; i < FD_SETSIZE; ++i) { if (FD_ISSET(i, &efds)) { debug("%d has made a whoopsie\n", i); } if (!FD_ISSET(i, &rfds)) continue; if (i == socket) { accept_new_connection(socket, &fds); info("Accepted a new connection\n"); } else if (i == sigfd) { child_status = 0; #ifdef __linux child_read = read(sigfd, &child, sizeof(child)); switch(child_read) { case 0: case -1: warn("Couldn't read from signalfd"); continue; default: info("Recieved signal %d from %d\n", child.ssi_signo, child.ssi_pid); } if (child.ssi_signo == SIGCHLD) { child_pid = waitpid(child.ssi_pid, &child_status, 0); child_status = WEXITSTATUS(child_status); info("Child %d exited with status %d\n", child_pid, child_status); notify(subscriptions, child_pid, child_status); } #elif __APPLE__ kq_status = kevent(sigfd, NULL, 0, &child, 1, NULL); if (kq_status == -1) { warn("kevent read failed\n"); return; } info("Recieved signal %ld\n", child.ident); child_pid = wait(&child_status); child_status = WEXITSTATUS(child_status); info("Child %d exited with status %d\n", child_pid, child_status); notify(subscriptions, child_pid, child_status); #endif } else { // Check if the socket is still alive if (recv(i, butts, 1, MSG_PEEK) < 1) { close(i); FD_CLR(i, &fds); continue; } msg_type = load_message_type(i); switch(msg_type) { case MSG_ERROR: /* Connection is irreperably damaged */ error("Couldn't decode message type\n"); close(i); FD_CLR(i, &fds); break; case MSG_BUILD_REQUEST: msg = load_request(i); if (!msg) { info("Got a null request from %d\n", i); continue; } info("new payload\n"); info(" command : %s\n", msg->command); info(" workspace: %s\n", msg->workspace); info(" priority : %d\n", msg->priority); info("--\n"); if (init_worktree2(msg->workspace) != 0) { /* TODO: Actually bail out of this */ error("Couldn't create worktree %s\n", msg->workspace); } build = start_build(msg); info("Started a new build from %d with pid %d\n", i, build); build_request__free_unpacked(msg, NULL); /* Implicitly subscribe whoever kicked off the build */ new_sub = malloc(sizeof(fd_list)); new_sub->fd = i; new_sub->next = NULL; if (subscriptions[build] == NULL) { subscriptions[build] = new_sub; } else { sub_node = subscriptions[build]; while (sub_node != NULL) { sub_node = sub_node->next; } sub_node->next = new_sub; } /* TODO: Write out the pid + a nonce to the client. * TODO: Implement an implicit subscribe flag in the build request */ break; default: error("Unknown message type %d\n", msg_type); } } } } } }
void CServer::handle_request(const char *request) { const char *p; int cmd_len; int ok; logger->log(3, "Got request: %s", request); p = strchr(request,' '); if (p == 0) { p = request + strlen(request); } cmd_len = p - request; while (*p == ' ') { p++; } ok = 0; if (cmd_len == 0) { logger->log(2, "Empty request!"); return; } char *command = new char[cmd_len+1]; memcpy(command, request, cmd_len); command[cmd_len] = 0; try { if (strcmp(command, "SEARCH") == 0) { ok = 1; search_request(p); } if (strcmp(command, "COUNT") == 0) { ok = 1; count_request(); } if (strcmp(command, "DELETEHOST") == 0) { ok = 1; delete_request(p); } if (strcmp(command, "LOAD") == 0) { ok = 1; load_request(p); } if (strcmp(command, "STATUS") == 0) { ok = 1; status_request(); } if (strcmp(command, "HOSTINFO") == 0) { ok = 1; host_info_request(p); } if (strcmp(command, "HOSTSTAT") == 0) { ok = 1; host_stat_request(p); } if (strcmp(command, "CACHEINFO") == 0) { ok = 1; cache_info_request(); } if (strcmp(command, "UPDATEHOSTS") == 0) { ok = 1; update_hosts_request(p); } if (strcmp(command, "SERVERSTAT") == 0) { ok = 1; server_stat_request(); } if (strcmp(command, "DEBUG") == 0) { ok = 1; debug_request(p); } if (strcmp(command, "DUMP") == 0) { ok = 1; dump_state_request(); } if (strcmp(command, "FULLSCAN") == 0) { ok = 1; enable_full_request(p); } if (strcmp(command, "WORDORDER") == 0) { ok = 1; word_order_request(); } if (strcmp(command, "CLEARPAGECACHE") == 0) { ok = 1; clear_pagecache_request(); } if (strcmp(command, "CLEARQUERYCACHE") == 0) { ok = 1; clear_querycache_request(); } if (strcmp(command, "DUMPFILES") == 0) { ok = 1; dump_files_request(p); } if (strcmp(command, "DUMPINDEX") == 0) { ok = 1; dump_index_request(p); } if (!ok) { throw std::runtime_error(std::string("Unrecognized request: ") + request); } } catch (std::runtime_error &e) { logger->log(1, "Error: %s", e.what()); send_string("ERROR"); } delete[] command; m_request_count++; }