#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "main.h" #include "server.h" #include "client.cpp" #include "util.h" using namespace std::chrono_literals; const uint16_t max_clients = config->getInt("net", "max_clients", 255); const uint16_t cport = config->getInt("net", "control_port", 21); struct pollfd fds[65535]; struct clientfd { Client* client; bool close = false; } fdc[65535]; bool run = true, compress_array = false; void runClient(struct clientfd* cfd) { char inbuf[BUFFERSIZE]; //printf("[d] C(%i) Initialized\n", cfd->client->control_sock); // Loop as long as it is a valid file descriptor. try { //while (fcntl(cfd->client->control_sock, F_GETFD) != -1) { while (true) { if (cfd->client == nullptr) { break; } int rc = recv(cfd->client->control_sock, inbuf, sizeof(inbuf), 0); if (rc < 0) { logger->print(LOGLEVEL_WARNING, "C(%i) Recieved empty packet", cfd->client->control_sock); if (errno != EWOULDBLOCK) { perror("recv() failed"); break; } continue; } if (rc == 0 || cfd->client == nullptr) { //printf("[d] C(%i) closed\n", cfd->client->control_sock); break; } std::string lin(inbuf); int len = lin.find("\r\n", 0); int cmdend = lin.find(" ", 0); if (cmdend >= len || cmdend == std::string::npos) cmdend = len; std::string cmd = toUpper(lin.substr(0, cmdend)); std::string args = ""; if (len > cmdend) args = lin.substr(cmdend+1, len-cmdend-1); logger->print(LOGLEVEL_DEBUG, "C(%i) >> '%s' '%s'", cfd->client->control_sock, cmd.c_str(), args.c_str()); if (cfd->client->receive(cmd, args) < 0) break; inbuf[0] = '\0'; } } catch (...) { logger->print(LOGLEVEL_ERROR, "C(%i) Caught error!", cfd->client->control_sock); } cfd->close = true; } int main(int argc , char *argv[]) { logger = new Logger(config->getValue("logging", "file", "digftp.log").c_str()); logger->setLevel(config->getInt("logging", "level", 0)); std::string authType = config->getValue("main", "auth_engine", "plain"); auth = getAuthByName(authType); auth->setOptions(config->get(authType)); int opt = 1, master_socket = -1, newsock = -1, nfds = 1, current_size = 0; struct sockaddr_in ctrl_address; if ((master_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket() failed"); exit(-1); } if (setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) { perror("setsockopt() failed"); close(master_socket); exit(-1); } if (ioctl(master_socket, FIONBIO, (char *)&opt) < 0) { perror("ioctl() failed"); close(master_socket); exit(-1); } ctrl_address.sin_family = AF_INET; ctrl_address.sin_addr.s_addr = INADDR_ANY; ctrl_address.sin_port = htons(cport); if (bind(master_socket, (struct sockaddr *)&ctrl_address, sizeof(ctrl_address))<0 < 0) { perror("bind() failed"); close(master_socket); exit(-1); } if (listen(master_socket, 3) < 0) { perror("listen() failed"); close(master_socket); exit(-1); } memset(fds, 0, sizeof(fds)); memset(fdc, 0, sizeof(fdc)); fds[0].fd = master_socket; fds[0].events = POLLIN; logger->print(LOGLEVEL_INFO, "Server started."); while (run) { int pc = poll(fds, nfds, -1); if (pc < 0) { perror("poll() failed"); break; } if (pc == 0) { perror("poll() timed out\n"); break; } current_size = nfds; for (int i = 0; i < current_size; i++) { if(fds[i].revents == 0) continue; if(fds[i].revents != POLLIN) { logger->print(LOGLEVEL_ERROR, "C(%i) Error! revents = %d", fds[i].fd, fds[i].revents); goto conn_close; } if (fds[i].fd == master_socket) { do { newsock = accept(master_socket, NULL, NULL); if (newsock < 0) { if (errno != EWOULDBLOCK) { perror("accept() failed"); run = false; } break; } logger->print(LOGLEVEL_DEBUG, "C(%i) Accepted client", newsock); fds[nfds].fd = newsock; fds[nfds].events = POLLIN; fdc[nfds].close = false; fdc[nfds].client = new Client(newsock); fdc[nfds].client->thread = std::thread(runClient, &fdc[nfds]); nfds++; } while (newsock != -1); } else { if (fdc[i].close) { conn_close: logger->print(LOGLEVEL_DEBUG, "C(%i) Deleting client...", fds[i].fd); close(fds[i].fd); fds[i].fd = -1; if (fdc[i].client->thread.joinable()) fdc[i].client->thread.detach(); fdc[i].client = nullptr; fdc[i].close = false; compress_array = true; } else { fds[i].revents = 0; } } } if (compress_array) { compress_array = false; for (int i = 0; i < nfds; i++) { if (fds[i].fd == -1) { for(int j = i; j < nfds; j++) { if (fds[j].fd == -1) { logger->print(LOGLEVEL_DEBUG, "Compressing: %i(fd:%i) <= %i(fd:%i)", j, fds[j].fd, j+1, fds[j+1].fd); fds[j].fd = fds[j+1].fd; fds[j].revents = fds[j+1].revents; fds[j+1].fd = -1; logger->print(LOGLEVEL_DEBUG, "Reinitialized fds of %i", j+1); fdc[j].client = fdc[j+1].client; fdc[j].close = fdc[j+1].close; fdc[j+1] = {}; logger->print(LOGLEVEL_DEBUG, "[d] Reinitialized fdc of %i", j+1); } } i--; nfds--; } } } } logger->close(); return 0; }