#include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __SWITCH__ #include #include namespace fs = std::filesystem; #else namespace fs = std::__fs::filesystem; #endif #define PORT 8080 #define BUFFER_SIZE 1024 #define MULTICAST_PORT 8081 #define MULTICAST_GROUP "239.0.0.1" // Multicast group IP struct ThreadArgs { char **filenames; int file_count; int sock; fs::path directory; }; bool receiveAck(int sock) { char ack[4] = {0}; int bytes_received = read(sock, ack, 3); return bytes_received > 0 && std::string(ack) == "ACK"; } // Отправка строки с учетом её длины void send_string(int sock, const std::string &str) { size_t length = str.size(); send(sock, &length, sizeof(length), 0); send(sock, str.c_str(), length, 0); } void *send_files_thread(void *args) { ThreadArgs *thread_args = static_cast(args); char **filenames = thread_args->filenames; int file_count = thread_args->file_count; int sock = thread_args->sock; fs::path cwd = thread_args->directory; delete thread_args; char buffer[BUFFER_SIZE]; // Send the directory length std::cout << Logger::INFO << "cwd.filename is: " << cwd.filename().c_str() << std::endl; // Get the parent directory std::string dirname = cwd.parent_path().filename(); uint32_t directory_len = dirname.size(); send(sock, &directory_len, sizeof(directory_len), 0); // Send the dirname send(sock, dirname.c_str(), directory_len, 0); for (int i = 0; i < file_count; ++i) { std::string path = filenames[i]; std::size_t found = path.find_last_of("/\\"); std::string filename = path.substr(found+1); std::ifstream infile(path, std::ios::binary | std::ios::ate); if (!infile.is_open()) { std::cout << Logger::ERROR << "File not found: " << filename.c_str() << std::endl; return nullptr; } // Get the size of the file std::streamsize file_size = infile.tellg(); infile.seekg(0, std::ios::beg); // Send the filename length uint32_t filename_len = filename.size(); std::cout << Logger::INFO << "Send filename length: " << filename_len << std::endl; send(sock, &filename_len, sizeof(filename_len), 0); // Send the filename std::cout << Logger::INFO << "Send file name: " << filename.c_str() << std::endl; send(sock, filename.c_str(), filename_len, 0); // Send the file size std::cout << Logger::INFO << "Send file size: " << file_size << std::endl; send(sock, &file_size, sizeof(file_size), 0); char buffer[BUFFER_SIZE]; // Send the file data while (file_size > 0) { infile.read(buffer, BUFFER_SIZE); send(sock, buffer, infile.gcount(), 0); file_size -= infile.gcount(); std::cout << Logger::INFO << "wait for ACK" << std::endl; // Wait for acknowledgment after each chunk if (!receiveAck(sock)) { std::cout << Logger::ERROR << "Failed to receive acknowledgment" << std::endl;; } } send(sock, 0, 0, 0); std::cout << Logger::INFO << "File sent successfully: " << filename.c_str() << std::endl; infile.close(); } close(sock); pthread_exit(nullptr); } int find_server(char *server_ip) { std::cout << Logger::INFO << "Init find_server" << std::endl;; int sockfd; struct sockaddr_in multicast_addr; std::cout << Logger::INFO << "Create socket" << std::endl; if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { std::cout << Logger::ERROR << "Socket creation error" << std::endl; return -1; } memset(&multicast_addr, 0, sizeof(multicast_addr)); multicast_addr.sin_family = AF_INET; multicast_addr.sin_port = htons(MULTICAST_PORT); multicast_addr.sin_addr.s_addr = inet_addr(MULTICAST_GROUP); std::cout << Logger::INFO << "Send DISCOVER_SERVER" << std::endl; const char *multicast_message = "DISCOVER_SERVER"; if (sendto(sockfd, multicast_message, strlen(multicast_message), 0, (struct sockaddr *)&multicast_addr, sizeof(multicast_addr)) < 0) { std::cout << Logger::ERROR << "sendto failed" << std::endl; close(sockfd); return -1; } else { std::cout << Logger::INFO << "send multicast message success" << std::endl; } struct sockaddr_in cliaddr; socklen_t len = sizeof(cliaddr); char buffer[BUFFER_SIZE]; ssize_t n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&cliaddr, &len); std::cout << Logger::INFO << "recvfrom n: %i" << n << std::endl; if (n < 0) { std::cout << Logger::ERROR << "recvfrom failed" << std::endl; close(sockfd); return -1; } std::cout << Logger::INFO << "buffer: " << buffer << std::endl; buffer[n] = '\0'; if (strcmp(buffer, "SERVER_HERE") == 0) { std::cout << Logger::INFO << "Server found" << std::endl; inet_ntop(AF_INET, &cliaddr.sin_addr, server_ip, INET_ADDRSTRLEN); } else { std::cout << Logger::ERROR << "Unable to find server, close socket" << std::endl;; close(sockfd); return -1; } close(sockfd); return 0; } int transfer_files(fs::path directory, char **filenames, int file_count) { std::cout << Logger::INFO << "Init transfer_files" << std::endl; char server_ip[INET_ADDRSTRLEN]; if (find_server(server_ip) != 0) { std::cout << Logger::ERROR << "Failed to find server" << std::endl; return -1; } int sock = 0; struct sockaddr_in serv_addr; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { std::cout << Logger::ERROR << "Socket creation error" << std::endl; return -1; } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); if (inet_pton(AF_INET, server_ip, &serv_addr.sin_addr) <= 0) { std::cout << Logger::ERROR << "Invalid address / Address not supported" << std::endl; return -1; } if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { std::cout << Logger::ERROR << "Connection failed" << std::endl; return -1; } pthread_t file_thread; ThreadArgs *thread_args = new ThreadArgs{filenames, file_count, sock, directory}; if (pthread_create(&file_thread, nullptr, send_files_thread, (void *)thread_args) < 0) { std::cout << Logger::ERROR << "Thread creation failed" << std::endl; close(sock); delete thread_args; return -1; } else { std::cout << Logger::INFO << "Wait for file_thread" << std::endl; pthread_join(file_thread, nullptr); } return 0; } #ifndef __SWITCH__ // for desktop int main(int argc, char *argv[]) { if (argc < 2) { std::cerr << "Usage: " << argv[0] << " ..." << std::endl; return 1; } char **filenames = const_cast(&argv[1]); int file_count = argc - 1; transfer_files(filenames, file_count); return 0; } #endif