diff --git a/include/box_utils.h b/include/box_utils.h index f232787..6364499 100644 --- a/include/box_utils.h +++ b/include/box_utils.h @@ -6,5 +6,7 @@ int insert_into_box(box_entry_t *entries, char* path, time_t global_time, time_t box_entry_t* read_box(char *path); int write_box(char *path, box_entry_t *entries); void print_box(box_entry_t* head); +box_entry_t* find_in_box(box_entry_t *box_entry, char *name); +void create_or_update(box_entry_t *box_entry, char *name, size_t size, time_t local_time, time_t server_time); #endif diff --git a/include/communication_utils.h b/include/communication_utils.h index c628bcf..d831985 100644 --- a/include/communication_utils.h +++ b/include/communication_utils.h @@ -32,8 +32,10 @@ typedef struct BoxEntry { } box_entry_t; -void send_file(int socket, const char* path, message_type_t type); +void send_file(int socket, const char* path, message_type_t type, time_t mod_time); message_info_t receive_message_info(int socket); void receive_file(int socket, const char* new_path, size_t size); +void send_message_info(int socket, message_type_t type, const char* path, size_t size, time_t mod_time); +message_info_t receive_message_info(int socket); #endif diff --git a/include/server.h b/include/server.h index 7ff6773..bdd879b 100644 --- a/include/server.h +++ b/include/server.h @@ -17,6 +17,6 @@ server_t get_server(int socket); void register_client(server_t* server); void add_client(int socket, int* client_array, int* client_num); void handle_file_request(int socket, message_info_t info); -void handle_client_message(int socket); +void handle_client_message(int socket, server_t* server); #endif diff --git a/src/box_utils.c b/src/box_utils.c index 432cdce..91977db 100644 --- a/src/box_utils.c +++ b/src/box_utils.c @@ -69,7 +69,47 @@ int write_box(char *path, box_entry_t *entries) void print_box(box_entry_t* head) { while(head->next != NULL) { - printf("%s\n", head->path); + printf("%s %d %d\n", head->path, head->global_timestamp, head->local_timestamp); head = head->next; } -} \ No newline at end of file +} + + +box_entry_t* find_in_box(box_entry_t *box_entry, char *name) +{ + box_entry_t *it; + + it = box_entry; + + while(it->next != NULL) { + if(strcmp(it->path, name) == 0) { + return it; + } + it = it->next; + } + + return NULL; +} + + +void create_or_update(box_entry_t *box_entry, char *name, size_t size, time_t local_time, time_t server_time) +{ + box_entry_t *entry; + + entry = find_in_box(box_entry, name); + + + if(entry == NULL) { + insert_into_box(box_entry, name, server_time, local_time, -1); + } else { + strcpy(entry->path, name); + + if(local_time != 0) { + entry->local_timestamp = local_time; + } + + if(server_time != 0) { + entry->global_timestamp = server_time; + } + } +} diff --git a/src/client.c b/src/client.c index b34c432..c0a24cd 100644 --- a/src/client.c +++ b/src/client.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -12,7 +13,7 @@ #include "box_utils.h" #define SERVER_BOX_FILENAME ".server_box" #define LOCAL_BOX_FILENAME ".box" -#define SYNC_TIME 10 +#define SYNC_TIME 1 typedef struct dirent dirent_t; typedef struct stat stat_t; @@ -42,8 +43,6 @@ int file_exists(char* filename) - - void print_files_list(file_t *head) { while(head->next != NULL) { @@ -78,7 +77,7 @@ file_t* get_local_files_list(char* name) // returns: number of entries, -1 on er sprintf(entry_path, "%s/%s", name, ent->d_name); stat(entry_path, &entry_stat); - if(S_ISREG(entry_stat.st_mode)) { + if(S_ISREG(entry_stat.st_mode) && ent->d_name[0] != '.') { file_it->size = (int) entry_stat.st_size; file_it->path = strdup(entry_path); file_it->is_directory = -1; @@ -115,15 +114,18 @@ stack_t* detect_local_changes(file_t *local_files, box_entry_t* box_entries) files_it = local_files; + + while(files_it->next != NULL) { box_it = box_entries; is_found = -1; while(box_it->next != NULL) { if(strcmp(files_it->path, box_it->path) == 0) { + is_found = 1; + if(files_it->modification_time > box_it->local_timestamp) { message = create_info_message(CLIENT_FILE, files_it->path, files_it->modification_time, (size_t)files_it->size); - is_found = 1; push(stack, message); break; } @@ -155,6 +157,7 @@ stack_t* detect_local_changes(file_t *local_files, box_entry_t* box_entries) } if(is_found < 0) { + printf("Box entry is not found in the files\n"); message = create_info_message(FILE_REMOVAL, box_it->path, time(NULL), 0); push(stack, message); } @@ -173,92 +176,132 @@ int push_local_changes(stack_t* changes) while((message = (message_info_t *) pop(changes)) != NULL) { switch(message->message_type) { case CLIENT_FILE: - send_file(socket_fd, message->name, message->message_type); -// create_or_update(local_box, message->name, message->); + printf("CLIENT_FILE, sending file to server, filename: %s\n", message->name); + send_file(socket_fd, message->name, message->message_type, message->modification_time); + create_or_update(local_box, message->name, message->size, message->modification_time, message->modification_time); break; case FILE_REMOVAL: - printf("FILE REMOVAL; LET'S PRETEND IT'S REMOVED. TODO :-)\n"); + //printf("FILE REMOVAL; LET'S PRETEND IT'S REMOVED. TODO :-)\n"); + break; + default: + //printf("I have no idea what is happening he;)\n"); + break; + } + } + + + return 0; +} + + +stack_t *detect_server_changes(box_entry_t* local_box_entries, box_entry_t* server_box_entries) +{ + stack_t *stack; + box_entry_t *local_it, *server_it; + message_info_t *message; + + stack = init_stack(); + + server_it = server_box_entries; + + while(server_it->next != NULL) { + local_it = find_in_box(local_box_entries, server_it->path); + if(local_it == NULL || server_it->global_timestamp > local_it->global_timestamp) { + message = create_info_message(FILE_REQUEST, server_it->path, server_it->global_timestamp, 0); + push(stack, message); + } + server_it = server_it->next; + } + + return stack; +} + + +int apply_server_changes(stack_t *changes) +{ + message_info_t *message, received_message; + struct stat st; + + while((message = (message_info_t *) pop(changes)) != NULL) { + switch(message->message_type) { + case FILE_REQUEST: + printf("FILE REQUEST, requesting file: %s\n", message->name); + send_message_info(socket_fd, FILE_REQUEST, message->name, 0, 0); + received_message = receive_message_info(socket_fd); + + if(received_message.message_type == SERVER_FILE) { + receive_file(socket_fd, received_message.name, received_message.size); + stat(received_message.name, &st); + create_or_update(local_box, received_message.name, received_message.size, st.st_mtime, received_message.modification_time); + printf("Updated box\n"); + } else if(received_message.message_type == SERVER_BOX) { + printf("Hey server, you fucked up\n"); + } break; default: - printf("I have no idea what is happening he;)\n"); + printf("I have no idea what is happening here - \n"); break; } } + return 0; } +box_entry_t* receive_server_box(int socket_fd) +{ + message_info_t message_info; + + message_info = receive_message_info(socket_fd); + + if(!message_info.message_type == SERVER_BOX) { + printf("Message box expected\n"); + exit(EXIT_FAILURE); + } + + receive_file(socket_fd, SERVER_BOX_FILENAME, message_info.size); + + return read_box(SERVER_BOX_FILENAME); +} + +void* pull_changes(void *parameters) +{ + stack_t *changes; + + int i; + i = 0; + while(1) { + server_box = receive_server_box(socket_fd); + changes = detect_server_changes(local_box, server_box); + apply_server_changes(changes); + write_box(LOCAL_BOX_FILENAME, local_box); + + + } + + return NULL; +} -// -// -//int detect_server_changes(box_entry_t* local_box_entries, box_entry_t* server_box_entries, queue_t* changes) -//{ -// return -1; -//} -// -// -//int apply_server_changes(queue_t *changes) -//{ -// return -1; -//} - - - - - - -// -//box_entry_t* receive_server_box(int socket_fd) -//{ -// box_entry_t *box_entries; -// message_info_t message_info; -// -// message_info = receive_message_info(socket_fd); -// -// if(!message_info.message_type == MESSAGE_BOX) { -// printf("Message box expected\n"); -// exit(EXIT_FAILURE); -// } -// -// receive_file(socket_fd, SERVER_BOX_FILENAME, message_info.size); -// -// box_entries = malloc(message_info.size); -// -// if(read_box(SERVER_BOX_FILENAME, box_entries) < 0) { -// perror("reading server box failed\n"); -// return NULL; -// } -// -// return box_entries; -//} -// - -//void* pull_changes(void *parameters) -//{ -// while(1) { -// receive_server_box(socket_fd); -// -// -// } -// -// return NULL; -//} -// void* track_directory(void *parameters) { stack_t *changes; file_t *local_files; + int i; + i = 0; while(1) { - // acquire lock + // acquire lock] local_files = get_local_files_list("."); changes = detect_local_changes(local_files, local_box); + push_local_changes(changes); + write_box(LOCAL_BOX_FILENAME, local_box); // release lock + i += 1; sleep(SYNC_TIME); } @@ -266,28 +309,58 @@ void* track_directory(void *parameters) } +void init() +{ + int fd; + file_t *local_files; + stack_t *changes; + + server_box = receive_server_box(socket_fd); + + if(file_exists(LOCAL_BOX_FILENAME) != 0) { + fd = creat(LOCAL_BOX_FILENAME, 0666); + close(fd); + } + + local_box = read_box(LOCAL_BOX_FILENAME); + + // pull + changes = detect_server_changes(local_box, server_box); + apply_server_changes(changes); + write_box(LOCAL_BOX_FILENAME, local_box); + + // push + local_files = get_local_files_list("."); + changes = detect_local_changes(local_files, local_box); + push_local_changes(changes); + write_box(LOCAL_BOX_FILENAME, local_box); +} + + int main(int argc, char *argv[]) { -// pthread_t tracker_id, listener_id; -// -// socket_fd = get_client_socket(argv[1], atoi(argv[2])); -// server_box = receive_server_box(socket_fd); -// -// -// if(pthread_create(&tracker_id, NULL, &track_directory, NULL) < 0) { -// perror("pthread_create failed"); -// return EXIT_FAILURE; -// } -// -// if(pthread_create(&listener_id, NULL, &pull_changes, NULL) < 0) { -// perror("pthread_create failed"); -// return EXIT_FAILURE; -// } -// -// if(pthread_join(tracker_id, NULL) < 0) { perror("pthread_join failed"); return EXIT_FAILURE; } -// if(pthread_join(listener_id, NULL) < 0) { perror("pthread_join failed"); return EXIT_FAILURE; } -// -// return EXIT_SUCCESS; + pthread_t tracker_id, listener_id; + + chdir(argv[3]); + + socket_fd = get_client_socket(argv[1], atoi(argv[2])); + + init(); + + if(pthread_create(&tracker_id, NULL, &track_directory, NULL) < 0) { + perror("pthread_create failed"); + return EXIT_FAILURE; + } + + if(pthread_create(&listener_id, NULL, &pull_changes, NULL) < 0) { + perror("pthread_create failed"); + return EXIT_FAILURE; + } + + if(pthread_join(tracker_id, NULL) < 0) { perror("pthread_join failed"); return EXIT_FAILURE; } + if(pthread_join(listener_id, NULL) < 0) { perror("pthread_join failed"); return EXIT_FAILURE; } + + return EXIT_SUCCESS; } diff --git a/src/communication_utils.c b/src/communication_utils.c index 15ce5bd..97f2c65 100644 --- a/src/communication_utils.c +++ b/src/communication_utils.c @@ -5,15 +5,18 @@ #include #include #include +#include #include "communication_utils.h" +#define HISTORY_DIR "history" -void send_message_info(int socket, message_type_t type, const char* path, size_t size) +void send_message_info(int socket, message_type_t type, const char* path, size_t size, time_t mod_time) { message_info_t info; info.message_type = type; strncpy(info.name, path, MAX_PATHLEN); info.size = size; + info.modification_time = mod_time; if(write(socket, &info, sizeof(message_info_t)) < sizeof(info)) { @@ -27,15 +30,18 @@ void send_file_data(int socket, int fd, size_t size) { off_t offset = 0; int remain_data = size; - int sent_bytes; + int sent_bytes, len; + char buffer[BUFSIZ]; - while (((sent_bytes = sendfile(socket, fd, &offset, BUFSIZ)) > 0) && (remain_data > 0)) + while ((remain_data > 0) && ((len = read(fd, buffer, BUFSIZ)) > 0)) { - remain_data -= sent_bytes; + int num = write(socket, buffer, len); + remain_data -= len; } + } -void send_file(int socket, const char* path, message_type_t type){ +void send_file(int socket, const char* path, message_type_t type, time_t mod_time){ int fd; struct stat file_stat; @@ -51,8 +57,9 @@ void send_file(int socket, const char* path, message_type_t type){ exit(EXIT_FAILURE); } - send_message_info(socket, type, path, file_stat.st_size); + send_message_info(socket, type, path, file_stat.st_size, mod_time); send_file_data(socket, fd, file_stat.st_size); + close(fd); } message_info_t receive_message_info(int socket){ @@ -73,10 +80,36 @@ void receive_file(int socket, const char* new_path, size_t size){ int remain_data = size; file = fopen(new_path, "w"); - while (((len = read(socket, buffer, BUFSIZ)) > 0) && (remain_data > 0)) + while ((remain_data > 0) && ((len = read(socket, buffer, BUFSIZ)) > 0)) { - fwrite(buffer, sizeof(char), len, file); + int num =fwrite(buffer, sizeof(char), len, file); remain_data -= len; } fclose(file); } + + +void receive_file_history(int socket, const char* new_path, size_t size, time_t timestamp){ + int len; + FILE *file, *file_history; + char buffer[BUFSIZ]; + int remain_data = size; + char history_path[MAX_PATHLEN+50]=HISTORY_DIR; + char timestamp_s[15]=""; + sprintf(timestamp_s, "%d", (int)timestamp); + + strcat(history_path, "/"); + strcat(history_path, &new_path[2]); + strcat(history_path, "$"); + strcat(history_path, timestamp_s); + file = fopen(new_path, "w"); + file_history = fopen(history_path, "w"); + while ((remain_data > 0) && ((len = read(socket, buffer, BUFSIZ)) > 0)) + { + int num=fwrite(buffer, sizeof(char), len, file); + fwrite(buffer, sizeof(char), len, file_history); + remain_data -= len; + } + fclose(file); + fclose(file_history); + } \ No newline at end of file diff --git a/src/server.c b/src/server.c index b687e18..0fdc078 100644 --- a/src/server.c +++ b/src/server.c @@ -1,21 +1,24 @@ #include +#include +#include +#include +#include #include "server.h" #include "communication_utils.h" +#include "box_utils.h" #include "socket_utils.h" -#define SERVER_BOX_FILENAME ".server_box" -#define LOCAL_BOX_FILENAME ".box" +#define SERVER_BOX_FILENAME ".origin_server_box" +#define HISTORY_DIR "history" -int main(){ - struct sockaddr addr; - server_t server; - socklen_t len; +int max(int a, int b) { + return a > b ? a : b; +} - int socket = init_server_socket(9000); - server=get_server(socket); - run(server); - return EXIT_SUCCESS; +int file_exists(char* filename) +{ + return access(filename, F_OK); } @@ -38,7 +41,7 @@ void run(server_t server){ register_client(&server); } else{ - handle_client_message(fd); + handle_client_message(fd, &server); } } } @@ -60,11 +63,22 @@ server_t get_server(int socket){ void register_client(server_t* server){ int client_fd; client_fd = accept(server->socket, NULL, 0); + + printf("Registering new client, fd: %d \n", client_fd); + if(client_fd<0){ perror("accept error"); exit(EXIT_FAILURE); } + + server->highest_fd = max(server->highest_fd, client_fd); + FD_SET(client_fd, &server->server_fd_set); + add_client(client_fd, server->client_array, &server->client_num); + + printf("Sending server box to client\n"); + + send_file(client_fd, SERVER_BOX_FILENAME, SERVER_BOX, 0); } void add_client(int socket, int* client_array, int* client_num){ @@ -77,24 +91,101 @@ void add_client(int socket, int* client_array, int* client_num){ } void handle_file_request(int socket, message_info_t info){ - send_file(socket, info.name, SERVER_FILE); + box_entry_t *entries, *entry; + + entries = read_box(SERVER_BOX_FILENAME); + entry = find_in_box(entries, info.name); + if(entry==NULL){ + printf("Error finding file %s\n", info.name); + exit(0); + } + + send_file(socket, info.name, SERVER_FILE, entry->global_timestamp); } -void handle_client_file(int socket, message_info_t info){ +void broadcast_box(int sender_socket_fd, server_t *server) +{ + int i; + + for(i=0; iclient_num; i+=1) { + if(sender_socket_fd != server->client_array[i]) { + printf("Brodacasting box to FD: %d \n", server->client_array[i]); + send_file(server->client_array[i], SERVER_BOX_FILENAME, SERVER_BOX, 0); + } + } +} + + +void handle_client_file(int socket, message_info_t *info, server_t *server){ box_entry_t* head; + + receive_file_history(socket, info->name, info->size, info->modification_time); + head = read_box(SERVER_BOX_FILENAME); + create_or_update(head, info->name, info->size, info->modification_time, info->modification_time); + // broadcast + + write_box(SERVER_BOX_FILENAME, head); + + broadcast_box(socket, server); } -void handle_client_message(int socket){ +void handle_client_message(int socket, server_t *server){ + ssize_t read_bytes; message_info_t info; - read(socket, &info, sizeof(info)); + + read_bytes = read(socket, &info, sizeof(info)); + switch(info.message_type){ case FILE_REQUEST: + printf("Received FILE_REQUEST %s\n", info.name); handle_file_request(socket, info); + break; case CLIENT_FILE: - handle_client_file(socket, info); + printf("Received CLIENT_FILE %s from %d\n", info.name, socket); + handle_client_file(socket, &info, server); + break; default: break; } +} + + + +void init() +{ + int fd; + + if(file_exists(SERVER_BOX_FILENAME) != 0) { + fd = creat(SERVER_BOX_FILENAME, 0666); + close(fd); + } +} + + +int main(int argc, char *argv[]){ + struct sockaddr addr; + server_t server; + socklen_t len; + + if(argc!=2){ + printf("invalid number of arguments"); + exit(0); + } + + struct stat st = {0}; + if (stat(HISTORY_DIR, &st) == -1) { + mkdir(HISTORY_DIR, 0755); + } + + chdir("./server_"); + + init(); + + int socket = init_server_socket(atoi(argv[1])); + server=get_server(socket); + run(server); + + return EXIT_SUCCESS; } \ No newline at end of file