Files
NXST/source/client.cpp
2024-11-05 00:27:24 +03:00

249 lines
7.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <string>
#include <arpa/inet.h>
#include <cstring>
#include <fcntl.h>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <netinet/in.h>
#include <ostream>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef __SWITCH__
#include <client.hpp>
#include <switch.h>
#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<ThreadArgs *>(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] << " <path> " << std::endl;
return 1;
}
fs::path directory = fs::path(argv[1]);
std::cout << "directory is " << directory << std::endl;
transfer_files(directory);
return 0;
}
#endif