diff --git a/src/client.cpp b/src/client.cpp index 922da93..53fd0c1 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "server.h" #include "filer.cpp" @@ -25,6 +26,7 @@ public: * 2 - Waiting for data */ int state = 0; + std::thread thread; Client(int &_sock) { control_sock = _sock; @@ -37,7 +39,7 @@ public: return -1; } else if (state > 0) { if (cmd == "SYST") { - submit(215, "UNIX"); + submit(215, "UNIX Type: L8"); } else if (cmd == "PWD") { submit(257, "'"+filer->cwd.string()+"'"); } else if (cmd == "CWD") { @@ -69,7 +71,76 @@ public: sscanf(argstr.c_str(), "%c", &(filer->type)); submit(226, "OK"); } else if (cmd == "PASV") { - submit(502, "Command not implemented"); + if ((data_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("pasv socket() failed"); + return -1; + } + + if (setsockopt(data_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, (char *)&opt, sizeof(opt)) < 0) { + perror("pasv setsockopt() failed"); + close(data_fd); + return -1; + } + + uint16_t dataport; + uint8_t netaddr[4]; + uint8_t netport[2]; + socklen_t datalen = sizeof(data_address); + + data_address.sin_family = AF_INET; + data_address.sin_addr.s_addr = INADDR_ANY; + data_address.sin_port = 0; + + if (bind(data_fd, (struct sockaddr *)&data_address, sizeof(data_address)) < 0) { + perror("pasv bind() failed"); + close(data_fd); + return -1; + } + + if (listen(data_fd, 3) < 0) { + perror("pasv listen() failed"); + close(data_fd); + return -1; + } + + if (getsockname(data_fd, (struct sockaddr *)&data_address, &datalen) == 0) { + //memcpy(&netaddr[0], &data_address.sin_addr, 4); + netaddr[0] = 127; + netaddr[1] = netaddr[2] = 0; + netaddr[3] = 1; + dataport = ntohs(data_address.sin_port); + memcpy(&netport[0], &dataport, 2); + printf("[i] D(%i) PASV initialized: %u.%u.%u.%u:%u\n", data_fd, netaddr[0], netaddr[1], netaddr[2], netaddr[3], dataport); + } else { + perror("pasv getpeername() failed"); + close(data_fd); + return -1; + } + + char* pasvok; + asprintf( + &pasvok, + "Entering Passive Mode (%u,%u,%u,%u,%u,%u)", + netaddr[0], + netaddr[1], + netaddr[2], + netaddr[3], + netport[1], + netport[0] + ); + + submit(227, std::string(pasvok)); + free(pasvok); + + if ((data_sock = accept(data_fd, NULL, NULL)) >= 0) { + printf("[i] D(%i) PASV accepted: %i\n", data_fd, data_sock); + state = 2; + //submit(200, "OK"); + } else { + perror("accept() failed"); + submit(425, "Unknown Error"); + data_close(); + } } else if (cmd == "PORT") { data_sock = socket(AF_INET, SOCK_STREAM, 0); @@ -79,16 +150,15 @@ public: sscanf(argstr.c_str(), "%d,%d,%d,%d,%d,%d", &act_ip[0], &act_ip[1], &act_ip[2], &act_ip[3], (int*)&act_port[0], (int*)&act_port[1]); sprintf(ip_decimal, "%d.%d.%d.%d", act_ip[0], act_ip[1], act_ip[2], act_ip[3]); port_dec = act_port[0]*256+act_port[1]; - printf("[d] D(%i) Initialized data transport: %s:%d\n", control_sock, ip_decimal, port_dec); + printf("[d] D(%i) PORT initialized: %s:%d\n", control_sock, ip_decimal, port_dec); data_address.sin_family = AF_INET; data_address.sin_addr.s_addr = inet_addr(ip_decimal); data_address.sin_port = htons(port_dec); if (connect(data_sock, (struct sockaddr *)&data_address, sizeof(data_address)) != 0) { - close(data_sock); - data_sock = 0; submit(425, "Unknown Error"); + data_close(); } else { state = 2; submit(200, "OK"); @@ -152,9 +222,7 @@ public: } submit(226, "OK"); } - if (data_close() != 0) { - printf("[!] Data Sock returned %i instead of 0! Not closed!!!\n", data_sock); - } + data_close(); } else { submit(502, "Command not implemented"); } @@ -205,17 +273,22 @@ public: } int data_close() { + if (data_sock <= 0) return 0; printf("[d] D(%i) Closing...\n", data_sock); close(data_sock); - data_sock = 0; + data_sock = -1; + close(data_fd); + data_fd = -1; state = 1; - return data_sock; // Should be 0 if successful. + return 0; } private: std::string name; Filer* filer = new Filer(); + const int opt = 1; + int data_fd; int data_sock; struct sockaddr_in data_address; }; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 341eb8d..d15cbda 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,7 +28,6 @@ using namespace std::chrono_literals; struct pollfd fds[MAXCLIENTS]; struct clientfd { Client* client; - std::thread thread; bool close = false; } fdc[MAXCLIENTS]; @@ -38,6 +37,7 @@ 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) { printf("[d] C(%i) Attempting read...\n", cfd->client->control_sock); int rc = recv(cfd->client->control_sock, inbuf, sizeof(inbuf), 0); @@ -67,9 +67,12 @@ void runClient(struct clientfd* cfd) { if (cfd->client->receive(cmd, args) < 0) break; inbuf[0] = '\0'; } + } catch (...) { + printf("[!] C(%i) Caught error!\n", cfd->client->control_sock); + } + cfd->client->thread.detach(); printf("[d] C(%i) Marking for deletion...\n", cfd->client->control_sock); cfd->close = true; - cfd->thread.detach(); } int main(int argc , char *argv[]) { @@ -79,10 +82,9 @@ int main(int argc , char *argv[]) { nfds = 1, current_size = 0; - char inbuf[BUFFERSIZE]; struct sockaddr_in ctrl_address; - if ((master_socket = socket(AF_INET , SOCK_STREAM , 0)) < 0) { + if ((master_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket() failed"); exit(-1); } @@ -137,8 +139,6 @@ int main(int argc , char *argv[]) { current_size = nfds; for (int i = 0; i < current_size; i++) { - inbuf[0] = '\0'; - if(fds[i].revents == 0) continue; @@ -158,56 +158,22 @@ int main(int argc , char *argv[]) { break; } - printf("[d] C(%i) Accepted client%i\n", newsock); - // If we assign thead if it is still attached, - // we suffer greatly, and by we I mean me. - if (fdc[nfds].thread.joinable()) { - printf("[!] C(%i) Thread still joinable! Detaching...\n", newsock); - // Pray the thread will end itself. - fdc[nfds].thread.detach(); - } + printf("[d] C(%i) Accepted client\n", newsock); fds[nfds].fd = newsock; fds[nfds].events = POLLIN; + fdc[nfds].close = false; fdc[nfds].client = new Client(newsock); - fdc[nfds].thread = std::thread(runClient, &fdc[nfds]); + fdc[nfds].client->thread = std::thread(runClient, &fdc[nfds]); nfds++; } while (newsock != -1); } else { - /* - int rc = recv(fds[i].fd, inbuf, sizeof(inbuf), 0); - if (rc < 0) { - if (errno != EWOULDBLOCK) { - perror("recv() failed"); - fdc[i].close = true; - } - continue; - } - - if (rc == 0 || fdc[i].client == nullptr) { - printf("[d] (%i) closed\n", fds[i].fd); - fdc[i].close = true; - } - - 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); - - printf("[d] (%i) >> '%s' '%s'\n", fds[i].fd, cmd.c_str(), args.c_str()); - - if (fdc[i].client->receive(cmd, args) < 0) fdc[i].close = true; - inbuf[0] = '\0'; - */ - if (fdc[i].close) { conn_close: printf("[d] C(%i) Deleting client...\n", fds[i].fd); close(fds[i].fd); fds[i].fd = -1; - if (fdc[i].thread.joinable()) fdc[i].thread.detach(); + if (fdc[i].client->thread.joinable()) + fdc[i].client->thread.detach(); fdc[i].client = nullptr; fdc[i].close = false; compress_array = true; @@ -217,18 +183,19 @@ int main(int argc , char *argv[]) { if (compress_array) { compress_array = false; - printf("[d] Compressing...\n"); for (int i = 0; i < nfds; i++) { if (fds[i].fd == -1) { for(int j = i; j < nfds; j++) { - printf("[d] Compressing: id %i to fd %i\n", j, fds[j+1].fd); - fds[j].fd = fds[j+1].fd; + if (fds[j].fd == -1) { + printf("[d] Compressing: %i(fd:%i) <= %i(fd:%i)\n", j, fds[j].fd, j+1, fds[j+1].fd); + fds[j].fd = fds[j+1].fd; + fdc[j].client = fdc[j+1].client; + } } i--; nfds--; } } - printf("[d] Compressing complete!\n"); } } return 0;