diff --git a/.gitignore b/.gitignore index f1c28a6..83d4a71 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ server .vscode rough.cpp client -rough \ No newline at end of file +rough +.DS_Store \ No newline at end of file diff --git a/client.cpp b/client.cpp index 1b4d71b..232d3c0 100644 --- a/client.cpp +++ b/client.cpp @@ -1,15 +1,17 @@ #include #include #include -#include // For exit() -#include // For close() -#include // For inet_pton and other network functions +#include +#include +#include #include #include #include #include #include +#define DIRECTORY_PATH "/Users/rajkumar/Desktop/Snap-Sync/tmp/" + using namespace std; // FNV-1a hash function @@ -25,164 +27,182 @@ size_t fnv1a_hash(const string& str) { return hash; } -// Function to send a file to the server -bool send_file(int socket, const string& filepath) { - ifstream file(filepath, ios::binary); - if (!file) { - perror("Error opening file"); - return false; - } - - // Get the file size - file.seekg(0, ios::end); - size_t filesize = file.tellg(); - file.seekg(0, ios::beg); - - // Send the filename - string filename = filepath.substr(filepath.find_last_of("/") + 1); - if (send(socket, filename.c_str(), filename.size() + 1, 0) == -1) { // include null terminator - perror("Error sending filename to server"); - file.close(); - return false; - } - - // Send the file size - if (send(socket, &filesize, sizeof(filesize), 0) == -1) { - perror("Error sending file size to server"); - file.close(); - return false; - } +class Client { + int client_socket; + struct sockaddr_in server_addr; - // Send the file data - char buffer[1024]; - while (file.read(buffer, sizeof(buffer))) { - if (send(socket, buffer, sizeof(buffer), 0) == -1) { - perror("Error sending file data to server"); - file.close(); - return false; - } - } - if (file.gcount() > 0) { - if (send(socket, buffer, file.gcount(), 0) == -1) { - perror("Error sending remaining file data to server"); - file.close(); - return false; + public: + Client(const string& ip_address, int port) { + create_socket(); + setup_server_address(ip_address, port); + connect_to_server(); } - } - - file.close(); - return true; -} - -int main() { - // Create a socket - int client_socket = socket(AF_INET, SOCK_STREAM, 0); - if (client_socket == -1) { - perror("Error creating socket"); - exit(EXIT_FAILURE); - } - // Set up server address - struct sockaddr_in server_addr; - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(6969); + ~Client() { + close(client_socket); + } - if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) { - perror("Invalid address/ Address not supported"); - close(client_socket); - exit(EXIT_FAILURE); - } + void run() { + authenticate(); + send_files_in_directory(DIRECTORY_PATH); + } - if (connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { - perror("Error connecting to server"); - close(client_socket); - exit(EXIT_FAILURE); - } + private: + void create_socket() { + if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + perror("Error creating socket"); + exit(EXIT_FAILURE); + } + } - char token[1024]; - if (recv(client_socket, token, sizeof(token), 0) == -1) { - perror("Error receiving token from server"); - close(client_socket); - exit(EXIT_FAILURE); - } + void setup_server_address(const string& ip_address, int port) { + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + if (inet_pton(AF_INET, ip_address.c_str(), &server_addr.sin_addr) <= 0) { + perror("Invalid address/ Address not supported"); + close(client_socket); + exit(EXIT_FAILURE); + } + } - cout << "\nToken received from the server: " << token << endl; + void connect_to_server() { + if (connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { + perror("Error connecting to server"); + close(client_socket); + exit(EXIT_FAILURE); + } + } - string token_string = string(token); - string token_hash = to_string(fnv1a_hash(token_string)); + void authenticate() { + char token[1024]; + if (recv(client_socket, token, sizeof(token), 0) == -1) { + perror("Error receiving token from server"); + exit(EXIT_FAILURE); + } - if (send(client_socket, token_hash.c_str(), token_hash.size() + 1, 0) == -1) { // include null terminator - perror("Error sending hash to server"); - close(client_socket); - exit(EXIT_FAILURE); - } + cout << "\nToken received from the server: " << token << endl; - cout << "\nHash sent to the server\n"; - cout << "\nWaiting for the server to authenticate...\n"; + string token_string(token); + string token_hash = to_string(fnv1a_hash(token_string)); - char auth_status[1024] = {0}; - if (recv(client_socket, auth_status, sizeof(auth_status), 0) == -1) { - perror("Error receiving authentication status from server"); - close(client_socket); - exit(EXIT_FAILURE); - } + if (send(client_socket, token_hash.c_str(), token_hash.size() + 1, 0) == -1) { // include null terminator + perror("Error sending hash to server"); + exit(EXIT_FAILURE); + } - cout << auth_status << endl; + cout << "\nHash sent to the server\n"; + cout << "\nWaiting for the server to authenticate...\n"; - char signal[1024] = {0}; - if (recv(client_socket, signal, sizeof(signal), 0) == -1) { - perror("Error receiving start signal from server"); - close(client_socket); - exit(EXIT_FAILURE); - } + char auth_status[1024] = {0}; + if (recv(client_socket, auth_status, sizeof(auth_status), 0) == -1) { + perror("Error receiving authentication status from server"); + exit(EXIT_FAILURE); + } - cout << "Server signal: " << signal << endl; + cout << auth_status << endl; - DIR* dir; - struct dirent* ent; - if ((dir = opendir("test_data")) == NULL) { - perror("Error opening directory"); - close(client_socket); - exit(EXIT_FAILURE); - } + char signal[1024] = {0}; + if (recv(client_socket, signal, sizeof(signal), 0) == -1) { + perror("Error receiving start signal from server"); + exit(EXIT_FAILURE); + } - while ((ent = readdir(dir)) != NULL) { - if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { - continue; + cout << "Server signal: " << signal << endl; } - string filepath = "test_data/" + string(ent->d_name); - if (!send_file(client_socket, filepath)) { - closedir(dir); - close(client_socket); - exit(EXIT_FAILURE); + bool send_file(const string& filepath) { + ifstream file(filepath, ios::binary); + if (!file) { + perror("Error opening file"); + return false; + } + + // Get the file size + file.seekg(0, ios::end); + size_t filesize = file.tellg(); + file.seekg(0, ios::beg); + + // Send the filename + string filename = filepath.substr(filepath.find_last_of("/") + 1); + if (send(client_socket, filename.c_str(), filename.size() + 1, 0) == -1) { // include null terminator + perror("Error sending filename to server"); + file.close(); + return false; + } + + // Send the file size + if (send(client_socket, &filesize, sizeof(filesize), 0) == -1) { + perror("Error sending file size to server"); + file.close(); + return false; + } + + // Send the file data + char buffer[1024]; + while (file.read(buffer, sizeof(buffer))) { + if (send(client_socket, buffer, sizeof(buffer), 0) == -1) { + perror("Error sending file data to server"); + file.close(); + return false; + } + } + if (file.gcount() > 0) { + if (send(client_socket, buffer, file.gcount(), 0) == -1) { + perror("Error sending remaining file data to server"); + file.close(); + return false; + } + } + + file.close(); + return true; } - cout << "\nFile sent to the server: " << filepath << endl; + void send_files_in_directory(const string& directory_path) { + DIR* dir; + struct dirent* ent; + if ((dir = opendir(directory_path.c_str())) == NULL) { + perror("Error opening directory"); + exit(EXIT_FAILURE); + } + + while ((ent = readdir(dir)) != NULL) { + if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { + continue; + } + + string filepath = directory_path + string(ent->d_name); + if (!send_file(filepath)) { + closedir(dir); + exit(EXIT_FAILURE); + } + + cout << "\nFile sent to the server: " << filepath << endl; + + // Wait for confirmation from the server before sending the next file + char confirmation[1024]; + if (recv(client_socket, confirmation, sizeof(confirmation), 0) == -1) { + perror("Error receiving confirmation from server"); + closedir(dir); + exit(EXIT_FAILURE); + } + cout << "Server confirmation: " << confirmation << endl; + } + + // Send end signal to indicate all files have been sent + string end_signal = "end_of_files"; + if (send(client_socket, end_signal.c_str(), end_signal.size() + 1, 0) == -1) { // include null terminator + perror("Error sending end signal to server"); + exit(EXIT_FAILURE); + } + cout << "\nAll files sent to the server\n"; - // Wait for confirmation from the server before sending the next file - char confirmation[1024]; - if (recv(client_socket, confirmation, sizeof(confirmation), 0) == -1) { - perror("Error receiving confirmation from server"); closedir(dir); - close(client_socket); - exit(EXIT_FAILURE); } - cout << "Server confirmation: " << confirmation << endl; - } - - // Send end signal to indicate all files have been sent - string end_signal = "end_of_files"; - if (send(client_socket, end_signal.c_str(), end_signal.size() + 1, 0) == -1) { // include null terminator - perror("Error sending end signal to server"); - close(client_socket); - exit(EXIT_FAILURE); - } - cout << "\nAll files sent to the server\n"; - - closedir(dir); - close(client_socket); +}; +int main() { + Client client("127.0.0.1", 6969); + client.run(); return 0; } - diff --git a/server.cpp b/server.cpp index 30b1127..c7f0af6 100644 --- a/server.cpp +++ b/server.cpp @@ -1,241 +1,263 @@ #include #include -#include +#include #include -#include // For close() and gethostname() -#include // For inet_ntoa +#include +#include #include #include -#include // For getaddrinfo() +#include #include -#include // For mkdir -#include -#include -#include +#include +#include +#include -using namespace std; - -struct HostInfo { - string hostname; - string ip_addresses; -}; +#define TOKEN_LENGTH 256 -HostInfo getHostAndIP() { - HostInfo info; - char hostbuffer[256]; - if (gethostname(hostbuffer, sizeof(hostbuffer)) == -1) { - perror("Error getting hostname"); - exit(EXIT_FAILURE); - } - info.hostname = hostbuffer; - - struct hostent *host_entry = gethostbyname(hostbuffer); - if (host_entry == nullptr) { - herror("Error getting host by name"); - exit(EXIT_FAILURE); - } - - struct in_addr **addr_list = (struct in_addr **)host_entry->h_addr_list; - for (int i = 0; addr_list[i] != NULL; i++) { - info.ip_addresses += inet_ntoa(*addr_list[i]); - if (addr_list[i + 1] != NULL) { - info.ip_addresses += " "; - } - } - return info; -} +using namespace std; -bool authenticateClient(const string& receivedHash, const string& expectedHash) { - return receivedHash == expectedHash; -} +class Server { + int PORT; + int server_socket; + int client_socket; + struct sockaddr_in address; + int address_length; + + public: + Server(int port = 6969) : PORT(port) { + create_socket(); + setup_address(); + bind_socket(); + listen_for_connections(); + register_signal_handler(); + } -string generateRandomString(size_t length) { - const string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]{}|;:',.<>?/~`"; - random_device rd; - mt19937 generator(rd()); - uniform_int_distribution<> distribution(0, characters.size() - 1); - - string randomString; - for (size_t i = 0; i < length; ++i) { - randomString += characters[distribution(generator)]; - } - return randomString; -} + ~Server() { + close(server_socket); + } -size_t fnv1a_hash(const string& str) { - const size_t FNV_offset_basis = 14695981039346656037ULL; - const size_t FNV_prime = 1099511628211ULL; + void run() { + while (true) { + accept_connection(); + handle_client(); + } + } - size_t hash = FNV_offset_basis; - for (char c : str) { - hash ^= static_cast(c); - hash *= FNV_prime; - } - return hash; -} + private: + void create_socket() { + if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + perror("[ERROR] : Socket creation failed"); + exit(EXIT_FAILURE); + } + cout << "[LOG] : Socket created successfully.\n"; + } -bool createFolder(const string& folderName) { - if (mkdir(folderName.c_str(), 0755) == -1) { - perror("Error creating folder"); - return false; - } - return true; -} + void setup_address() { + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(PORT); + address_length = sizeof(address); + } -void handleClient(int client_socket) { - // Send random string to client - string token = generateRandomString(255); - cout << "Token: " << token << '\n'; - if (send(client_socket, token.c_str(), token.size() + 1, 0) == -1) { // include null terminator - perror("Error sending token to client"); - close(client_socket); - return; - } - cout << "Token sent to client\nWaiting for client to send hash\n"; - - // Hash the token and wait for the client to send the hash - string expectedHash = to_string(fnv1a_hash(token)); - char receivedHash[1024] = {0}; - if (recv(client_socket, receivedHash, sizeof(receivedHash), 0) == -1) { - perror("Error receiving hash from client"); - close(client_socket); - return; - } - cout << "Hash received from client\nChecking hash...\n"; - - string receivedHashString = string(receivedHash); - - cout << "Received hash: " << receivedHashString << endl; - cout << "Expected hash: " << expectedHash << endl; - - if (authenticateClient(receivedHashString, expectedHash)) { - cout << "Hash verified!\n"; - string successMessage = "Authentication successful\n"; - if (send(client_socket, successMessage.c_str(), successMessage.size() + 1, 0) == -1) { // include null terminator - perror("Error sending success message to client"); - close(client_socket); - return; + void bind_socket() { + if (bind(server_socket, (struct sockaddr *)&address, sizeof(address)) < 0) { + perror("[ERROR] : Bind failed"); + exit(EXIT_FAILURE); + } + cout << "[LOG] : Bind successful.\n"; } - // Create folder with today's date - time_t now = time(0); - tm *ltm = localtime(&now); - string folderName = to_string(1900 + ltm->tm_year) + "-" + to_string(1 + ltm->tm_mon) + "-" + to_string(ltm->tm_mday); - if (createFolder(folderName)) { - cout << "Folder created successfully\n"; - } else { - cout << "Error creating folder\n"; - close(client_socket); - return; + void listen_for_connections() { + if (listen(server_socket, 3) < 0) { + perror("[ERROR] : Listen failed"); + exit(EXIT_FAILURE); + } + cout << "[LOG] : Listening for connections (Max queue: 3)\n"; } - string signal = "start"; - if (send(client_socket, signal.c_str(), signal.size() + 1, 0) == -1) { // include null terminator - perror("Error sending signal to client"); + void accept_connection() { + if ((client_socket = accept(server_socket, (struct sockaddr *)&address, (socklen_t*)&address_length)) < 0) { + perror("[ERROR] : Accept failed"); + exit(EXIT_FAILURE); + } + cout << "[LOG] : Connection accepted from client.\n"; } - // Loop to receive multiple files - while (true) { - // Receive file metadata - char filename[1024] = {0}; - if (recv(client_socket, filename, sizeof(filename), 0) == -1) { - perror("Error receiving filename from client"); + void handle_client() { + flush_socket_buffer(client_socket); + + string token = generate_random_string(TOKEN_LENGTH); + cout << "Token: " << token << '\n'; + + if (send(client_socket, token.c_str(), token.size() + 1, 0) == -1) { + perror("[ERROR] : Sending token to client failed"); close(client_socket); return; } - if (strcmp(filename, "end_of_files") == 0) { - break; // End of file transmission - } - cout << "File name: " << filename << endl; + cout << "[LOG] : Token sent to client. Waiting for hash...\n"; + + flush_socket_buffer(client_socket); - // Receive file size - size_t filesize; - if (recv(client_socket, &filesize, sizeof(filesize), 0) == -1) { - perror("Error receiving file size from client"); + string expected_hash = to_string(fnv1a_hash(token)); + char received_hash[1024] = {0}; + if (recv(client_socket, received_hash, sizeof(received_hash), 0) == -1) { + perror("[ERROR] : Receiving hash from client failed"); close(client_socket); return; } - cout << "File size: " << filesize << " bytes" << endl; + cout << "[LOG] : Hash received from client. Checking hash...\n"; - string filepath = folderName + "/" + string(filename); - ofstream file(filepath, ios::binary); - if (!file) { - perror("Error opening file for writing"); - close(client_socket); - return; + if (authenticate_client(string(received_hash), expected_hash)) { + cout << "[LOG] : Hash verified!\n"; + send_message("Authentication successful\n"); + + string folder_name = create_timestamped_folder(); + if (!folder_name.empty()) { + cout << "[LOG] : Folder created successfully.\n"; + send_message("start"); + + receive_files(folder_name); + } else { + cout << "[ERROR] : Folder creation failed.\n"; + } + } else { + cout << "[LOG] : Hash verification failed!\n"; } - // Receive file data in chunks + close(client_socket); + } + + void flush_socket_buffer(int socket) { char buffer[1024]; - size_t bytes_received = 0; - while (bytes_received < filesize) { - ssize_t n = recv(client_socket, buffer, sizeof(buffer), 0); - if (n == -1) { - perror("Error receiving file from client"); - close(client_socket); - return; + int bytes_available = 0; + + if (ioctl(socket, FIONREAD, &bytes_available) == -1) { + perror("[ERROR] : Checking socket buffer failed"); + return; + } + + while (bytes_available > 0) { + ssize_t bytes_received = recv(socket, buffer, sizeof(buffer), 0); + if (bytes_received <= 0) { + break; } - file.write(buffer, n); - bytes_received += n; + bytes_available -= bytes_received; } + } - cout << "File received and saved to " << filepath << endl; + string generate_random_string(size_t length) { + const string characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]{}|;:',.<>?/~`"; + random_device rd; + mt19937 generator(rd()); + uniform_int_distribution<> distribution(0, characters.size() - 1); - // Inform client that the file has been received - string fileReceived = "File received: "; - if (send(client_socket, fileReceived.c_str(), fileReceived.size() + 1, 0) == -1) { // include null terminator - perror("Error sending file received message to client"); - close(client_socket); - return; + string random_string; + for (size_t i = 0; i < length; ++i) { + random_string += characters[distribution(generator)]; } + return random_string; } - cout << "All files received.\n"; - } else { - cout << "Hash verification failed!\n"; - } + size_t fnv1a_hash(const string& str) { + const size_t FNV_offset_basis = 14695981039346656037ULL; + const size_t FNV_prime = 1099511628211ULL; - close(client_socket); -} + size_t hash = FNV_offset_basis; + for (char c : str) { + hash ^= static_cast(c); + hash *= FNV_prime; + } + return hash; + } + + bool authenticate_client(const string& received_hash, const string& expected_hash) { + return received_hash == expected_hash; + } + + bool create_folder(const string& folder_name) { + if (mkdir(folder_name.c_str(), 0755) == -1) { + perror("[ERROR] : Creating folder failed"); + return false; + } + return true; + } + + string create_timestamped_folder() { + time_t now = time(0); + tm *ltm = localtime(&now); + string folder_name = to_string(1900 + ltm->tm_year) + "-" + + to_string(1 + ltm->tm_mon) + "-" + + to_string(ltm->tm_mday) + "_" + + to_string(ltm->tm_hour) + "-" + + to_string(ltm->tm_min) + "-" + + to_string(ltm->tm_sec); + return create_folder(folder_name) ? folder_name : ""; + } + + void receive_files(const string& folder_name) { + while (true) { + flush_socket_buffer(client_socket); + + char filename[1024] = {0}; + if (recv(client_socket, filename, sizeof(filename), 0) == -1) { + perror("[ERROR] : Receiving filename from client failed"); + return; + } + if (strcmp(filename, "end_of_files") == 0) { + break; + } + cout << "[LOG] : Receiving file: " << filename << endl; + + size_t filesize; + if (recv(client_socket, &filesize, sizeof(filesize), 0) == -1) { + perror("[ERROR] : Receiving file size from client failed"); + return; + } + cout << "[LOG] : File size: " << filesize << " bytes\n"; + + string filepath = folder_name + "/" + string(filename); + ofstream file(filepath, ios::binary); + if (!file) { + perror("[ERROR] : Opening file for writing failed"); + return; + } + + char buffer[1024]; + size_t bytes_received = 0; + while (bytes_received < filesize) { + ssize_t n = recv(client_socket, buffer, min(sizeof(buffer), filesize - bytes_received), 0); + if (n == -1) { + perror("[ERROR] : Receiving file data from client failed"); + return; + } + file.write(buffer, n); + bytes_received += n; + } + + cout << "[LOG] : File received and saved to " << filepath << endl; + send_message("File received: " + string(filename)); + } + cout << "[LOG] : All files received.\n"; + } + + void send_message(const string& message) { + if (send(client_socket, message.c_str(), message.size() + 1, 0) == -1) { + perror("[ERROR] : Sending message to client failed"); + } + } + + static void signal_handler(int signum) { + cout << "\nInterrupt signal (" << signum << ") received. Shutting down...\n"; + exit(signum); + } + + void register_signal_handler() { + signal(SIGINT, signal_handler); + } +}; int main() { - int server_socket = socket(AF_INET, SOCK_STREAM, 0); - if (server_socket == -1) { - perror("Error creating socket"); - exit(EXIT_FAILURE); - } - - struct sockaddr_in server_addr; - server_addr.sin_family = AF_INET; - server_addr.sin_addr.s_addr = INADDR_ANY; - server_addr.sin_port = htons(6969); - - if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { - perror("Error binding socket"); - close(server_socket); - exit(EXIT_FAILURE); - } - - if (listen(server_socket, 3) == -1) { - perror("Error listening on port 6969"); - close(server_socket); - exit(EXIT_FAILURE); - } - - cout << "Listening on port 6969\n"; - - while (true) { - int client_socket = accept(server_socket, NULL, NULL); - if (client_socket == -1) { - perror("Client socket setup error"); - continue; - } - - cout << "Connection accepted from client\n"; - handleClient(client_socket); - } - - close(server_socket); + Server server(6969); + server.run(); return 0; } -