#include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __SWITCH__ #include #include #endif #define PORT 8080 #define BUFFER_SIZE 1024 #define MULTICAST_PORT 8081 #define MULTICAST_GROUP "239.0.0.1" // Multicast group IP namespace fs = std::filesystem; using path = fs::path; class Logger { public: inline static const std::string INFO = "[INFO]"; inline static const std::string DEBUG = "[DEBUG]"; inline static const std::string ERROR = "[ERROR]"; inline static const std::string WARN = "[WARN]"; }; struct ThreadArgs { int sock; fs::path directory; }; bool receiveAck(int sock) { char ack[4] = {0}; int bytes_received = read(sock, ack, 3); std::cout << "receiveAck bytes_received: " << bytes_received << std::endl; 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 sendFile(int sock, const fs::path &base_path, const fs::path &filepath) { std::ifstream infile(filepath, std::ios::binary | std::ios::ate); if (!infile.is_open()) { std::cerr << "File not found: " << filepath << std::endl; return; } // std::string relative_path = fs::relative(filepath, base_path).string(); uint32_t filename_len = filepath.string().size(); std::cout << "send filepath length: " << filename_len << std::endl; if (send(sock, &filename_len, sizeof(filename_len), 0) == -1) { std::cerr << "Failed to send filename length" << std::endl; } std::cout << "send filepath: " << filepath.string() << std::endl; // Send the filename if (send(sock, filepath.c_str(), filename_len, 0) == -1) { // Send the filename length std::cerr << "Failed to send filename" << std::endl; } // Get the size of the file std::streamsize file_size = infile.tellg(); infile.seekg(0, std::ios::beg); char buffer[BUFFER_SIZE]; std::cout << "send filesize: " << file_size << std::endl; // Send the file size if (send(sock, &file_size, sizeof(file_size), 0) == -1) { std::cerr << "Failed to send file size" << std::endl; } while (file_size > 0) { infile.read(buffer, BUFFER_SIZE); ssize_t bytes_sent = send(sock, buffer, infile.gcount(), 0); if (bytes_sent == -1) { std::cerr << "Failed to send file data" << std::endl; pthread_exit(nullptr); } file_size -= bytes_sent; // Wait for acknowledgment after each chunk if (!receiveAck(sock)) { std::cerr << "Failed to receive acknowledgment" << std::endl; pthread_exit(nullptr); } } std::cout << "File sent successfully: " << filepath << std::endl; infile.close(); } void *send_files_thread(void *args) { ThreadArgs *thread_args = static_cast(args); int sock = thread_args->sock; fs::path cwd = thread_args->directory; delete thread_args; std::cout << "cwd is: " << cwd << std::endl; char buffer[BUFFER_SIZE]; for (const auto &entry : fs::recursive_directory_iterator(cwd)) { path path = entry.path(); std::cout << "path is " << path << std::endl; if (fs::is_regular_file(path)) { std::cout << "regular file | path is: " << path << std::endl; sendFile(sock, path.parent_path(), path); } } 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) { 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{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 < 1) { std::cerr << "Usage: " << argv[0] << " " << std::endl; return 1; } fs::path directory = fs::path(argv[1]); std::cout << "directory is " << directory << std::endl; transfer_files(directory); return 0; } #endif