commit f7d7a53adee781c7bdcd246b5c9ce5c2a9b127ca Author: Hizenberg Date: Tue May 7 22:02:08 2024 +0530 RTM Project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f218f66 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*vsidx +*.opendb +.vs +out +CMakePresets.json \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9cd20d2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,28 @@ +# CMakeList.txt : CMake project for Routing_Table_Manager, include source and define +# project specific logic here. +# +cmake_minimum_required (VERSION 3.8) + +project(RTM VERSION 1.0.0 LANGUAGES C CXX) + +set(CMAKE_C_STANDARD 17) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS OFF) + +set(DLL_NAME Dll) +set(ML_NAME Mac_List) +set(RT_NAME Rounting_Table) +set(SM_NAME Sync_Message) + + +option( DLL_TESTING "if to check the integrity of doubly linked list library." OFF) + +add_subdirectory(DLL) +add_subdirectory(Mac-List) +add_subdirectory(Routing-Table) +add_subdirectory(Sync) +add_subdirectory(app) + + + +# TODO: Add tests and install targets if needed. diff --git a/DLL/CMakeLists.txt b/DLL/CMakeLists.txt new file mode 100644 index 0000000..d1572eb --- /dev/null +++ b/DLL/CMakeLists.txt @@ -0,0 +1,25 @@ +set( DLL_SOURCE + "dll.c") + +set( DLL_HEADER + "dll.h") + +set( TEST_EXE + "main.c") + +add_library( ${DLL_NAME} STATIC + ${DLL_SOURCE} + ${DLL_HEADER}) + +if( DLL_TESTING ) + add_executable( testDll + ${TEST_EXE}) + + target_include_directories( testDll PUBLIC + "./") +endif() + +target_include_directories( ${DLL_NAME} PUBLIC + "./" #for files on same path as this CMakeLists.txt file. + ) + diff --git a/DLL/dll.c b/DLL/dll.c new file mode 100644 index 0000000..accaa7c --- /dev/null +++ b/DLL/dll.c @@ -0,0 +1,71 @@ +#include +#include +#include "dll.h" + +/* +* Initialize an empty list in which the head +* and the tail are the same, i.e. they both +* point to dummy node. +*/ + +dll_t* init_dll() { + + dll_t* dll = calloc(1, sizeof(dll_t)); + dll_node_t* node = calloc(1, sizeof(dll_node_t)); + node->next = node; + node->prev = node; + dll->head = node; + dll->tail = node; + return dll; + +} + +/* +* Add new node with data to back of list. +*/ + +void append(dll_t* dll, void* data) { + + dll_node_t* head = dll->head; + dll_node_t* node = calloc(1, sizeof(dll_node_t)); + node->data = data; + node->next = dll->head; + node->prev = dll->tail; + dll->head->prev = node; + dll->tail->next = node; + dll->tail = node; + if (dll->head != head) { + printf("Head of the list is compromised.\n"); + } +} + +/* +* Delete a node from the lists. +*/ + +void del(dll_t* dll, dll_node_t* node) { + node->prev->next = node->next; + node->next->prev = node->prev; + if (node == dll->tail) { + // need to update the tail node if we're deleting it. + dll->tail = node->prev; + } + + free(node); +} + +/* +* Delete all nodes from the list. +*/ + +void deinit_dll(dll_t* dll) { + + dll_node_t* node = dll->head->next; + while (node != dll->head) { + dll_node_t* next = node->next; + del(dll, node); + node = next; + } + free(dll); + +} \ No newline at end of file diff --git a/DLL/dll.h b/DLL/dll.h new file mode 100644 index 0000000..a62779b --- /dev/null +++ b/DLL/dll.h @@ -0,0 +1,47 @@ +#ifndef DLL_H +#define DLL_H + +/* +* Data Structure definations for +* generic cicular doubly linked +* list. +*/ + +typedef struct dll_node_ { + + void* data; + struct dll_node_* next; + struct dll_node_* prev; + +}dll_node_t; + +typedef struct dll_ { + + dll_node_t* head; + dll_node_t* tail; + +}dll_t; + +/* +* DLL API'S +*/ + +dll_t* init_dll(); + +void append(dll_t* dll, void* data); + +void del(dll_t* dll, dll_node_t* node); + +void deinit_dll(dll_t* dll); + +#define ITERATE_DLL( dll, data_ptr, struct_type ) { \ + dll_node_t* c_ptr = dll->head->next; \ + while( c_ptr != dll->head ){ \ + struct_type* data_ptr = (struct_type* )c_ptr->data; \ + c_ptr = c_ptr->next; + +#define ITERATE_DLL_END() } + + + +#endif \ No newline at end of file diff --git a/DLL/main.c b/DLL/main.c new file mode 100644 index 0000000..f63403e --- /dev/null +++ b/DLL/main.c @@ -0,0 +1,65 @@ +#include +#include + +#include "dll.h" + +dll_node_t* find(dll_t* dll, int n) { + dll_node_t* node = dll->head->next; + while (node != dll->head) { + if (*((int*)node->data) == n) { + return node; + } + node = node->next; + } + return node; +} + +void print(dll_t* dll) { + printf("Printing...\n"); + dll_node_t* node = dll->head->next; + while (node != dll->head) { + printf("%i\n", *((int*)node->data)); + node = node->next; + } +} + +void reverse_print(dll_t* dll) { + printf("Reverse printing...\n"); + dll_node_t* node = dll->tail; + while (node != dll->head) { + printf("%i\n", *((int*)node->data)); + node = node->prev; + } +} + +int main() { + dll_t* dll = init_dll(); + int i; + for (i = 0; i < 5; i++) { + int* n = malloc(sizeof(int)); + *n = i; + append(dll, n); + } + + //print(dll); + reverse_print(dll); + + for (i = 0; i < 5; i++) { + if (find(dll, i) != dll->head) { + printf("Correct\n"); + } + } + + del(dll, find(dll, 3)); + del(dll, find(dll, 0)); + del(dll, find(dll, 4)); + + print(dll); + reverse_print(dll); + + deinit_dll(dll); + + print(dll); + reverse_print(dll); + exit(0); +} \ No newline at end of file diff --git a/Mac-List/CMakeLists.txt b/Mac-List/CMakeLists.txt new file mode 100644 index 0000000..91c4d05 --- /dev/null +++ b/Mac-List/CMakeLists.txt @@ -0,0 +1,16 @@ +set(MAC_LIST_SRC + "mac-list.c") + +set(MAC_LIST_HEADER + "mac-list.h") + +add_library( ${ML_NAME} STATIC + ${MAC_LIST_SRC} + ${MAC_LIST_HEADER}) + +target_include_directories( ${ML_NAME} PUBLIC + "./") + +target_link_libraries( ${ML_NAME} PUBLIC + ${DLL_NAME} + ${RT_NAME}) \ No newline at end of file diff --git a/Mac-List/mac-list.c b/Mac-List/mac-list.c new file mode 100644 index 0000000..776713a --- /dev/null +++ b/Mac-List/mac-list.c @@ -0,0 +1,54 @@ +#include +#include +#include + +#include "mac-list.h" +#include "dll.h" +#include "routing-table.h" + +extern int get_IP(const char* mac, char* ip); + +/* +* Display each row (entry) of a routing table. +*/ + +void display_mac_list(const dll_t* mac_list) { + + printf("Printing MAC list\n"); + + dll_node_t* node = mac_list->head->next; + while (node != mac_list->head) { + + mac_list_entry_t entry = *((mac_list_entry_t*) node->data); + printf("MAC: %s ", entry.mac); + + char ip[IP_ADDR_LEN]; + + if (get_IP(entry.mac, ip) != -1) { + printf("IP: %s", ip); + } + + putchar('\n'); + node = node->next; + } +} + +/* +* Look up entry in MAC list by MAC address. +*/ + +dll_node_t* find_mac(const dll_t* mac_list, const char* mac) { + + dll_node_t* node = mac_list->head->next; + + while (node != mac_list->head) { + mac_list_entry_t entry = *((mac_list_entry_t*)node->data); + if (!strcmp(entry.mac, mac)) { + break; + } + + node = node->next; + } + + return node; +} \ No newline at end of file diff --git a/Mac-List/mac-list.h b/Mac-List/mac-list.h new file mode 100644 index 0000000..e359430 --- /dev/null +++ b/Mac-List/mac-list.h @@ -0,0 +1,26 @@ +#ifndef MAC_LIST_H +#define MAC_LIST_H + +#define MAC_ADDR_LEN 18 + +typedef struct dll_ dll_t; +typedef struct dll_node_ dll_node_t; + +/* +* Data structure defination for MAC +* address list entry. +*/ +typedef struct mac_list_entry_ { + + char mac[MAC_ADDR_LEN]; + +}mac_list_entry_t; + +/* +* Public API's for MAC list functionality. +*/ + +void display_mac_list(const dll_t* mac_list); +dll_node_t* find_mac(const dll_t* mac_list, const char* mac); + +#endif \ No newline at end of file diff --git a/Routing-Table/CMakeLists.txt b/Routing-Table/CMakeLists.txt new file mode 100644 index 0000000..410e05f --- /dev/null +++ b/Routing-Table/CMakeLists.txt @@ -0,0 +1,17 @@ +set( RT_SRC + "routing-table.c") + +set( RT_HEADER + "routing-table.h") + + +add_library( ${RT_NAME} STATIC + ${RT_SRC} + ${RT_HEADER}) + +target_include_directories( ${RT_NAME} PUBLIC + "./" + ) + +target_link_libraries( ${RT_NAME} PUBLIC + ${DLL_NAME}) \ No newline at end of file diff --git a/Routing-Table/routing-table.c b/Routing-Table/routing-table.c new file mode 100644 index 0000000..92dcaf2 --- /dev/null +++ b/Routing-Table/routing-table.c @@ -0,0 +1,59 @@ +#include +#include +#include + +#include "routing-table.h" +#include "dll.h" + +/* +* Display each (entry) of a routing table. +*/ + +void display_routing_table(const dll_t* routing_table) { + + printf("Printing routing table.\n"); + + dll_node_t* node = routing_table->head->next; + while (node != routing_table->head) { + routing_table_entry_t entry = *((routing_table_entry_t*)node->data); + + printf("Destination IP: %s Mask: %u Gateway IP: %s OIF: %s\n", entry.dest, + entry.mask, entry.gw, entry.oif); + node = node->next; + } +} + +/* +* Look up entry in routing table by destination IP and subnet mask. +*/ + +dll_node_t* find_routing_table_entry(const dll_t* routing_table, const char* dest, + const unsigned short mask) { + + dll_node_t* node = routing_table->head->next; + while (node != routing_table->head) { + + routing_table_entry_t entry = *((routing_table_entry_t*)node->data); + if (!strcmp(entry.dest, dest) && entry.mask == mask) { + break; + } + + node = node->next; + } + + return node; +} + +/* +* Updates the entry whose destination IP is dest and subnet mask is mask. +*/ + +void update(dll_node_t* node, const char* gw, const char* oif) { + + routing_table_entry_t* entry = node->data; + memset(entry->gw, 0, IP_ADDR_LEN); + memset(entry->oif, 0, OIF_LEN); + memcpy(entry->gw, gw, strlen(gw)); + memcpy(entry->oif, oif, strlen(oif)); + +} \ No newline at end of file diff --git a/Routing-Table/routing-table.h b/Routing-Table/routing-table.h new file mode 100644 index 0000000..f9d417f --- /dev/null +++ b/Routing-Table/routing-table.h @@ -0,0 +1,31 @@ +#ifndef ROUTINGTABLE_H +#define ROUTINGTABLE_H + +#define IP_ADDR_LEN 26 +#define OIF_LEN 32 + +typedef struct dll_ dll_t; +typedef struct dll_node_ dll_node_t; + +/* +* Data structure defination for routing table entry +*/ +typedef struct routing_table_entry_ { + + char dest[IP_ADDR_LEN]; + unsigned short mask; + char gw[IP_ADDR_LEN]; + char oif[OIF_LEN]; + +}routing_table_entry_t; + +/* +* Public API's for routing table functionality +*/ + +void display_routing_table(const dll_t* routing_table); +dll_node_t* find_routing_table_entry(const dll_t* routing_table, const char* dest, + const unsigned short mask); +void update(dll_node_t* node, const char* gw, const char* oif); + +#endif \ No newline at end of file diff --git a/Sync/CMakeLists.txt b/Sync/CMakeLists.txt new file mode 100644 index 0000000..067ad0f --- /dev/null +++ b/Sync/CMakeLists.txt @@ -0,0 +1,15 @@ +set(SYNC_SRC + "sync.c") +set(SYNC_HEADER + "sync.h") + +add_library( ${SM_NAME} STATIC + ${SYNC_SRC} + ${SYNC_HEADER}) + +target_include_directories( ${SM_NAME} PUBLIC + "./") + +target_link_libraries( ${SM_NAME} PUBLIC + ${ML_NAME} + ${RT_NAME}) \ No newline at end of file diff --git a/Sync/sync.c b/Sync/sync.c new file mode 100644 index 0000000..3af602c --- /dev/null +++ b/Sync/sync.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include // for unlink +#include + +#include "dll.h" +#include "sync.h" + +/* +* Makes changes to a routing table or mac list based on the +* instructions encoded in sync_msg. +*/ + +void process_sync_mesg(dll_t* dll, sync_msg_t* sync_msg) { + + dll_node_t* node; + if (sync_msg->l_code == L3) { + node = find_routing_table_entry(dll, + sync_msg->msg_body.routing_table_entry.dest, + sync_msg->msg_body.routing_table_entry.mask); + + switch (sync_msg->op_code) { + case CREATE: + + if (node == dll->head) { + append(dll, &sync_msg->msg_body.routing_table_entry); + + node = find_routing_table_entry(dll, + sync_msg->msg_body.routing_table_entry.dest, + sync_msg->msg_body.routing_table_entry.mask); + + if (node != dll->head) { + routing_table_entry_t entry = *((routing_table_entry_t*)node->data); + + printf("Added Destination IP: %s mask: %u Gateway IP: %s OIF: %s\n", + entry.dest, + entry.mask, + entry.gw, + entry.oif); + } + } + break; + + case UPDATE: + + if (node != dll->head) { + update(node, + sync_msg->msg_body.routing_table_entry.gw, + sync_msg->msg_body.routing_table_entry.oif); + + node = find_routing_table_entry(dll, + sync_msg->msg_body.routing_table_entry.dest, + sync_msg->msg_body.routing_table_entry.mask); + + if (node != dll->head) { + routing_table_entry_t entry = *((routing_table_entry_t*)node->data); + + printf("Updated Destination IP: %s mask: %u Gateway IP: %s OIF: %s\n", + entry.dest, + entry.mask, + entry.gw, + entry.oif); + } + } + + break; + + case DELETE: + + if (node != dll->head) { + del(dll, node); + node = find_routing_table_entry(dll, + sync_msg->msg_body.routing_table_entry.dest, + sync_msg->msg_body.routing_table_entry.mask); + + if (node == dll->head) { + printf("Deleted Destination IP: %s mask: %u\n", + sync_msg->msg_body.routing_table_entry.dest, + sync_msg->msg_body.routing_table_entry.mask); + } + } + + break; + + default: + + break; + } + } + else { + node = find_mac(dll, + sync_msg->msg_body.mac_list_entry.mac); + + switch (sync_msg->op_code) { + + case CREATE: + + if (node == dll->head) { + append(dll, &sync_msg->msg_body.mac_list_entry); + node = find_mac(dll, + sync_msg->msg_body.mac_list_entry.mac); + + if (node != dll->head) { + mac_list_entry_t entry = *((mac_list_entry_t*)node->data); + printf("Added MAC: %s", entry.mac); + char ip[IP_ADDR_LEN]; + + if (get_IP(entry.mac, ip) != -1) { + printf("IP: %s", ip); + } + + putchar('\n'); + } + } + + break; + + case DELETE: + + if (node == dll->head) { + del(dll, node); + node = find_mac(dll, + sync_msg->msg_body.mac_list_entry.mac); + + if (node == dll->head) { + printf("Deleted: MAC: %s\n", + sync_msg->msg_body.mac_list_entry.mac); + unlink(sync_msg->msg_body.mac_list_entry.mac); + //deallocate shared memory region corresponding to this MAC key. + } + } + + break; + + default: + + break; + } + } +} \ No newline at end of file diff --git a/Sync/sync.h b/Sync/sync.h new file mode 100644 index 0000000..60290b9 --- /dev/null +++ b/Sync/sync.h @@ -0,0 +1,52 @@ +#ifndef SYNC_H +#define SYNC_H + +#include "routing-table.h" +#include "mac-list.h" + + +/* +* Synchronization protocol constants, structure, +* and API definitions. +*/ + +#define SOCKET_NAME "AdminNetworkSocket" + +#define WAIT 0 +#define RT 1 +#define ML 2 + +typedef struct dll_ dll_t; + +typedef enum { + + CREATE, + UPDATE, + DELETE, + NONE // indicate that all current updates from server have been processed +}OPCODE; + + +/* +* Specifies whether we're dealing with L3 (IP routing table) or L2 (MAC address list) +*/ + +typedef enum { + L3, + L2 +} LCODE; + +typedef struct sync_msg_ { + + OPCODE op_code; + LCODE l_code; + union { + routing_table_entry_t routing_table_entry; + mac_list_entry_t mac_list_entry; + }msg_body; +}sync_msg_t; + +void process_sync_mesg(dll_t* dll, sync_msg_t* sync_msg); +extern int get_IP(const char* mac, char* ip); + +#endif \ No newline at end of file diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt new file mode 100644 index 0000000..6b2565d --- /dev/null +++ b/app/CMakeLists.txt @@ -0,0 +1,36 @@ +set(CLIENT + "client.c") +set(SERVER + "server.c") +set(SHM_TABLE + "shm_ip.c") + + +add_executable( client + ${CLIENT} + ${SHM_TABLE}) +add_executable( server + ${SERVER} + ${SHM_TABLE}) + +#add_executable( dummy_server +# "dummy_server.c" +# ${SHM_TABLE}) + +target_link_libraries( client PUBLIC + ${DLL_NAME} + ${ML_NAME} + ${RT_NAME} + ${SM_NAME}) + +target_link_libraries( server PUBLIC + ${DLL_NAME} + ${ML_NAME} + ${RT_NAME} + ${SM_NAME}) + +#target_link_libraries( dummy_server PUBLIC +# ${DLL_NAME} +# ${ML_NAME} +# ${RT_NAME} +# ${SM_NAME}) \ No newline at end of file diff --git a/app/client.c b/app/client.c new file mode 100644 index 0000000..23f46ec --- /dev/null +++ b/app/client.c @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dll.h" +#include "mac-list.h" +#include "routing-table.h" +#include "sync.h" + +int data_socket; +int loop = 1; // indicates if server is still up and running +int disconnect = 1; // indicates to server that client wants to disconnect + +/* +* Client's copies of network data structures. +*/ +dll_t* routing_table; +dll_t* mac_list; + +/* Break out of main infinite loop and inform server of intent to disconnect */ + +void signal_handler(int signal_num) { + + if (signal_num == SIGINT) { + loop = 0; + write(data_socket, &disconnect, sizeof(int)); + close(data_socket); + deinit_dll(routing_table); + deinit_dll(mac_list); + exit(0); + } + else if (signal_num == SIGUSR1) { + deinit_dll(routing_table); + deinit_dll(mac_list); + + routing_table = init_dll(); + mac_list = init_dll(); + } + +} + +/* +* Optionally, display contents of a data +* structure (routing table or MAC list). +*/ +void display_ds(int synchronized) { + char c, flush; + + switch (synchronized) { + case RT: + + printf("Routing table is up to date. Would you like to see it?(y/n)\n"); + c = getchar(); + + scanf("%c", &flush); + if (c == 'y') { + display_routing_table(routing_table); + } + + break; + + case ML: + + printf("MAC list is up to date. Would you like to see it?(y/n)\n"); + c = getchar(); + scanf("%c", &flush); + if (c == 'y') { + display_mac_list(mac_list); + } + break; + + default: + + break; + } +} + +int main() { + + struct sockaddr_un addr; + + routing_table = init_dll(); + mac_list = init_dll(); + + data_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (data_socket == -1) { + perror("socket"); + exit(1); + } + + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1); + + if (connect(data_socket, (const struct sockaddr*)&addr, + sizeof(struct sockaddr_un)) == -1) { + fprintf(stderr, "The server is down.\n"); + exit(1); + } + + + pid_t pid = getpid(); + + write(data_socket, &pid, sizeof(pid_t)); // send server client's process id + + signal(SIGINT, signal_handler); // register signal handler. + signal(SIGUSR1, signal_handler); + /* + * Continously wait for updates to routing table and MAC list + * from the server regarding table contents and server state. + */ + + while (loop) { + int synchronized; + char ip[IP_ADDR_LEN]; + + sync_msg_t* sync_msg = calloc(1, sizeof(sync_msg_t)); + + memset(ip, 0, IP_ADDR_LEN); + + if (read(data_socket, sync_msg, sizeof(sync_msg_t)) == -1) { + perror("read"); + break; + } + + if (read(data_socket, &synchronized, sizeof(int)) == -1) { + perror("read"); + break; + } + + if (read(data_socket, &loop, sizeof(int)) == -1) { + perror("read"); + break; + } + + if (sync_msg->l_code == L3) { + process_sync_mesg(routing_table, sync_msg); + } + else { + process_sync_mesg(mac_list, sync_msg); + } + + display_ds(synchronized); + } + + exit(0); +} \ No newline at end of file diff --git a/app/dummy_server.c b/app/dummy_server.c new file mode 100644 index 0000000..9498b3b --- /dev/null +++ b/app/dummy_server.c @@ -0,0 +1,469 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dll.h" +#include "mac-list.h" +#include "routing-table.h" +#include "sync.h" + +#define MAX_CLIENTS 32 +#define OP_LEN 128 +#define MAX_MASK 32 + +extern int store_IP(const char* mac, const char* ip); + +int synchronized; // indicates if server has finished sending current updates +int connection_socket; // socket to establish connections with new clients +int loop = 1; // indicates if server is still running to clients + +/* Server's copies of network data structures */ +dll_t* routing_table; +dll_t* mac_list; + +/*An array of File descriptors which the server process is maintaining in order to talk with the connected clients. Master skt FD is also a member of this array*/ +int monitored_fd_set[MAX_CLIENTS]; +pid_t client_pid_set[MAX_CLIENTS]; // array of client process id's + +/*Remove all the FDs and client pid's, if any, from the the array*/ +void intitiaze_monitor_fd_and_client_pid_set() { + int i = 0; + for (; i < MAX_CLIENTS; i++) { + monitored_fd_set[i] = -1; + client_pid_set[i] = -1; + } +} + +/*Add a new FD to the monitored_fd_set array*/ +void add_to_monitored_fd_set(int skt_fd) { + int i = 0; + for (; i < MAX_CLIENTS; i++) { + if (monitored_fd_set[i] != -1) + continue; + monitored_fd_set[i] = skt_fd; + break; + } +} + +/*Add a new pid to the client_pid_set array*/ +void add_to_client_pid_set(int pid) { + int i = 0; + for (; i < MAX_CLIENTS; i++) { + if (client_pid_set[i] != -1) + continue; + client_pid_set[i] = pid; + break; + } +} + +/*Remove the FD from monitored_fd_set array*/ +void remove_from_monitored_fd_set(int skt_fd) { + int i = 0; + for (; i < MAX_CLIENTS; i++) { + if (monitored_fd_set[i] != skt_fd) + continue; + monitored_fd_set[i] = -1; + break; + } +} + +/*Remove the pid from client_pid_set array*/ +void remove_from_client_pid_set(int pid) { + int i = 0; + for (; i < MAX_CLIENTS; i++) { + if (monitored_fd_set[i] != pid) + continue; + client_pid_set[i] = -1; + break; + } +} + +/* Clone all the FDs in monitored_fd_set array into fd_set Data structure*/ +void refresh_fd_set(fd_set* fd_set_ptr) { + FD_ZERO(fd_set_ptr); + int i = 0; + for (; i < MAX_CLIENTS; i++) { + if (monitored_fd_set[i] != -1) { + FD_SET(monitored_fd_set[i], fd_set_ptr); + } + } +} + +/* Inform clients to flush their routing tables and mac lists*/ +void flush_clients() { + int i; + for (i = 0; i < MAX_CLIENTS; i++) { + int pid = client_pid_set[i]; + if (pid != -1) { + kill(pid, SIGUSR1); + } + } +} + +/* Helper function for isValidMask */ +int digits_only(const char* s) +{ + while (*s) { + if (isdigit(*s++) == 0) return 0; + } + + return 1; +} + +/* Checks if IP address is valid */ +int isValidIP(const char* addr) { + struct sockaddr_in sa; + return addr && inet_pton(AF_INET, addr, &(sa.sin_addr)) != 0; +} + + +/* Mask is valid if it is a string that can be converted to an integer within [0, 32] */ +int isValidMask(const char* mask) { + return digits_only(mask) && atoi(mask) <= 32; +} + +/* Checks if a given string represents a valid mac address in the format XX:XX:XX:XX:XX:XX, where each X represents a hexidecimal digit 0-9 or a-f */ +int isValidMAC(const char* addr) { + if (!addr) + return 0; + int i; + for (i = 0; i < MAC_ADDR_LEN - 1; i++) { + if (i % 3 != 2 && !isxdigit(addr[i])) + return 0; + if (i % 3 == 2 && addr[i] != ':') + return 0; + } + return addr[i] == '\0'; +} + +/*Get the numerical max value among all FDs which server is monitoring*/ +int get_max_fd() { + int i = 0; + int max = -1; + + for (; i < MAX_CLIENTS; i++) { + if (monitored_fd_set[i] > max) + max = monitored_fd_set[i]; + } + + return max; +} + +/* Parses a string command, in the format or with each field separated by a space, to create a sync message for clients, instructing them on how to update their copies of the routing table. The silent parameter indicates whether the server is actively inputting a command for MAC list via stdin or a client is replicating a command sent by the server. Returns 0 on success and -1 on any failure. */ +int create_sync_message(char* operation, sync_msg_t* sync_msg, int silent) { + char* token = strtok(operation, " "); + if (token) { + switch (token[0]) { + case 'C': + sync_msg->op_code = CREATE; + break; + case 'U': + sync_msg->op_code = UPDATE; + break; + case 'D': + sync_msg->op_code = DELETE; + break; + case 'S': + sync_msg->op_code = NONE; + display_routing_table(routing_table); + display_mac_list(mac_list); + return 0; + case 'F': + sync_msg->op_code = NONE; + + flush_clients(); + deinit_dll(routing_table); + deinit_dll(mac_list); + + routing_table = init_dll(); + mac_list = init_dll(); + return 0; + default: + fprintf(stderr, "Invalid operation: unknown op code\n"); + return -1; + } + } + else { + fprintf(stderr, "Invalid operation: missing op code\n"); + return -1; + } + + token = strtok(NULL, " "); + if (isValidIP(token)) { + sync_msg->l_code = L3; + memcpy(sync_msg->msg_body.routing_table_entry.dest, token, strlen(token)); + } + else if (isValidMAC(token)) { + sync_msg->l_code = L2; + memcpy(sync_msg->msg_body.mac_list_entry.mac, token, strlen(token)); + + if (!silent && sync_msg->op_code == CREATE) { + printf("Enter an IP address:\n"); + char ip[IP_ADDR_LEN]; + int ret = read(0, ip, IP_ADDR_LEN); + ip[strcspn(ip, "\r\n")] = 0; + + if (ret < 0 || store_IP(sync_msg->msg_body.mac_list_entry.mac, ip) == -1) { + fprintf(stderr, "Failed to store ip address\n"); + return -1; + } + } + return 0; + } + else { + fprintf(stderr, "Invalid operation: invalid or missing destination IP/MAC address\n"); + return -1; + } + + token = strtok(NULL, " "); + if (isValidMask(token)) { + sync_msg->msg_body.routing_table_entry.mask = atoi(token); + } + else { + fprintf(stderr, "Invalid operation: invalid or missing subnet mask/IP address\n"); + return -1; + } + + /* Only CREATE and UPDATE require a gw and oif*/ + if (sync_msg->op_code == CREATE || sync_msg->op_code == UPDATE) { + token = strtok(NULL, " "); + if (isValidIP(token)) { + memcpy(sync_msg->msg_body.routing_table_entry.gw, token, strlen(token)); + } + else { + fprintf(stderr, "Invalid operation: invalid or missing gateway IP\n"); + return -1; + } + + token = strtok(NULL, " "); + if (token) { + memcpy(sync_msg->msg_body.routing_table_entry.oif, token, strlen(token)); + } + else { + fprintf(stderr, "Invalid operation: missing OIF\n"); + return -1; + } + } + + return 0; +} + +/* Break out of main infinite loop and inform clients of shutdown to exit cleanly. */ +void signal_handler(int signal_num) +{ + if (signal_num == SIGINT) + { + int i, synchronized = WAIT, loop = 0; + sync_msg_t sync_msg; + sync_msg.op_code = NONE; + for (i = 2; i < MAX_CLIENTS; i++) { + int comm_socket_fd = monitored_fd_set[i]; + if (comm_socket_fd != -1) { + write(comm_socket_fd, &sync_msg, sizeof(sync_msg_t)); + write(comm_socket_fd, &synchronized, sizeof(int)); + write(comm_socket_fd, &loop, sizeof(int)); + } + } + + /* Clean up resources */ + deinit_dll(routing_table); + deinit_dll(mac_list); + close(connection_socket); + remove_from_monitored_fd_set(connection_socket); + unlink(SOCKET_NAME); + exit(0); + } +} + +/* Send newly client all necessary CREATE commands to replicate the server's copies of the current routing table or MAC list. */ +void update_new_client(int data_socket, LCODE l_code, char* op, sync_msg_t* sync_msg) { + dll_node_t* head = l_code == L3 ? routing_table->head : mac_list->head; + dll_node_t* curr = head->next; + + while (curr != head) { + routing_table_entry_t rt_entry = *((routing_table_entry_t*)curr->data); + mac_list_entry_t ml_entry = *((mac_list_entry_t*)curr->data); + + sync_msg->op_code = CREATE; + if (l_code == L3) { + sprintf(op, "C %s %u %s %s", rt_entry.dest, rt_entry.mask, rt_entry.gw, rt_entry.oif); + } + else { + sprintf(op, "C %s", ml_entry.mac); + } + + create_sync_message(op, sync_msg, 1); + + write(data_socket, sync_msg, sizeof(sync_msg_t)); + write(data_socket, &synchronized, sizeof(int)); + write(data_socket, &loop, sizeof(int)); + + curr = curr->next; + } + + /* Send dummy sync message to inform client that all current updates have been sent. */ + sync_msg->op_code = NONE; + write(data_socket, sync_msg, sizeof(sync_msg_t)); + synchronized = l_code == L3 ? RT : ML; + write(data_socket, &synchronized, sizeof(int)); + write(data_socket, &loop, sizeof(int)); +} + + +int main() { + struct sockaddr_un name; + int ret; + int data_socket; + fd_set readfds; + + routing_table = init_dll(); + mac_list = init_dll(); + + intitiaze_monitor_fd_and_client_pid_set(); + add_to_monitored_fd_set(0); + + unlink(SOCKET_NAME); //In case the program exited inadvertently on the last run, remove the socket. + + /* master socket for accepting connections from client */ + connection_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (connection_socket == -1) { + perror("socket"); + exit(1); + } + + /*initialize*/ + memset(&name, 0, sizeof(struct sockaddr_un)); + + /*Specify the socket Cridentials*/ + name.sun_family = AF_UNIX; + strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1); + + /* Bind socket to socket name.*/ + ret = bind(connection_socket, (const struct sockaddr*)&name, + sizeof(struct sockaddr_un)); + if (ret == -1) { + perror("bind"); + exit(1); + } + + /* Prepare for accepting connections. */ + ret = listen(connection_socket, 20); + if (ret == -1) { + perror("listen"); + exit(1); + } + + add_to_monitored_fd_set(connection_socket); + + signal(SIGINT, signal_handler); //register signal handlers + + /* The server continuously checks for new client connections, monitors existing connections (i.e. incoming messages and inactive connections, modifies the routing table or MAC list if need be, and broadcasts any changes to clients. */ + while (1) { + char op[OP_LEN]; + sync_msg_t* sync_msg = calloc(1, sizeof(sync_msg_t)); + synchronized = 0; + + refresh_fd_set(&readfds); /*Copy the entire monitored FDs to readfds*/ + + printf("Please select from the following options:\n"); + printf("1.CREATE \n"); + printf("2.UPDATE \n"); + printf("3.DELETE \n"); + printf("4.CREATE \n"); + printf("5.DELETE \n"); + printf("6.SHOW\n"); + printf("7.FLUSH\n"); + + select(get_max_fd() + 1, &readfds, NULL, NULL, NULL); /* Wait for incoming connections. */ + + /* New connection: send entire routing table and mac list states to newly connected client. */ + if (FD_ISSET(connection_socket, &readfds)) { + data_socket = accept(connection_socket, NULL, NULL); + if (data_socket == -1) { + perror("accept"); + exit(1); + } + + pid_t pid; + if (read(data_socket, &pid, sizeof(pid_t)) == -1) { + perror("read"); + exit(1); + } + + add_to_monitored_fd_set(data_socket); + add_to_client_pid_set(pid); + + + update_new_client(data_socket, L3, op, sync_msg); + update_new_client(data_socket, L2, op, sync_msg); + } + else if (FD_ISSET(0, &readfds)) { // server stdin + ret = read(0, op, OP_LEN - 1); + + op[strcspn(op, "\r\n")] = 0; // flush new line + if (ret == -1) { + perror("read"); + return 1; + } + op[ret] = 0; + + if (!create_sync_message(op, sync_msg, 0)) { + // update server's tables + if (sync_msg->l_code == L3) { + process_sync_mesg(routing_table, sync_msg); + synchronized = RT; + } + else { + process_sync_mesg(mac_list, sync_msg); + synchronized = ML; + } + + /* Notify existing clients of changes */ + int i, comm_socket_fd; + for (i = 2; i < MAX_CLIENTS; i++) { // start at 2 since 0 and 1 are for server's stdin and stdout + comm_socket_fd = monitored_fd_set[i]; + if (comm_socket_fd != -1) { + write(comm_socket_fd, sync_msg, sizeof(sync_msg_t)); + write(comm_socket_fd, &synchronized, sizeof(int)); + write(comm_socket_fd, &loop, sizeof(int)); + } + } + } + } + else { /* Check active status of clients */ + int i; + for (i = 2; i < MAX_CLIENTS; i++) { + if (FD_ISSET(monitored_fd_set[i], &readfds)) { + int done; + int comm_socket_fd = monitored_fd_set[i]; + + ret = read(comm_socket_fd, &done, sizeof(int)); + if (done == 1) { // this client is disconnecting + close(comm_socket_fd); + remove_from_monitored_fd_set(comm_socket_fd); + } + else if (ret == -1) { + perror("read"); + exit(1); + } + else { + printf("%i\n", done); + } + } + } + } + } + exit(0); +} \ No newline at end of file diff --git a/app/server.c b/app/server.c new file mode 100644 index 0000000..61d60cd --- /dev/null +++ b/app/server.c @@ -0,0 +1,619 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dll.h" +#include "mac-list.h" +#include "routing-table.h" +#include "sync.h" + +#define MAX_CLIENTS 32 +#define OP_LEN 128 +#define MAX_MASK 32 + +extern int store_IP(const char* mac, const char* ip); + +int synchronized; // indicates if server has finished sending current updates +int connection_socket; // socket to establish connections with new clients +int loop = 1; // indicates if server is still running to clients + + +/* +* Server's copies of network data structures +*/ + +dll_t* routing_table; +dll_t* mac_list; + +/* +* An array of File descriptors which the server process is maintaining in order +* to talk with connected clients. Master skt FD is also a member of this array. +*/ + +int monitored_fd_set[MAX_CLIENTS]; +pid_t client_pid_set[MAX_CLIENTS]; // array of client process id's. + +/* +* Remove all the FDs and client pid's, if any, from the array. +*/ + +void initialize_monitor_fd_and_client_pid_set() { + int i = 0; + + for (; i < MAX_CLIENTS; i++) { + monitored_fd_set[i] = -1; + client_pid_set[i] = -1; + } +} + +/* +* Add a new FD to the monitored_fd_set. +*/ + +void add_to_monitored_fd_set(int skt_fd) { + int i = 0; + for (; i < MAX_CLIENTS; i++) { + if (monitored_fd_set[i] != -1) + continue; + + monitored_fd_set[i] = skt_fd; + break; + } +} + +/* +* Add a new pid to the client_pid_set array +*/ + +void add_to_client_pid_set(pid_t pid) { + + int i = 0; + for (; i < MAX_CLIENTS; i++) { + if (client_pid_set[i] != -1) + continue; + client_pid_set[i] = pid; + break; + } +} + + +/*Remove the FD from monitored_fd_set array*/ +void remove_from_monitored_fd_set(int skt_fd) { + int i = 0; + for (; i < MAX_CLIENTS; i++) { + if (monitored_fd_set[i] != skt_fd) + continue; + monitored_fd_set[i] = -1; + break; + } +} + +/*Remove the pid from client_pid_set array*/ +void remove_from_client_pid_set(int pid) { + int i = 0; + for (; i < MAX_CLIENTS; i++) { + if (monitored_fd_set[i] != pid) + continue; + client_pid_set[i] = -1; + break; + } +} + +/* +* Clone all the fds in monitored_fd_set array into fd_set +* Data structure. +*/ +void refresh_fd_set(fd_set* fd_set_ptr) { + + FD_ZERO(fd_set_ptr); + int i = 0; + for (; i < MAX_CLIENTS; i++) { + if (monitored_fd_set[i] != -1) { + FD_SET(monitored_fd_set[i], fd_set_ptr); + } + } +} + +/* +* Inform clients to flush their routing tables and mac lists. +*/ + +void flush_clients() { + int i; + for (i = 0; i < MAX_CLIENTS; i++) { + int pid = client_pid_set[i]; + if (pid != -1) { + kill(pid, SIGUSR1); + } + } +} + +/* +* Helper function for isValidMask. +*/ +int digits_only(const char* s) { + + while (*s) { + if (isdigit(*s++) == 0)return 0; + } + + return 1; +} + +/* +* Checks if IP address is Valid. +*/ +int isValidIP(const char* addr) { + struct sockaddr_in sa; + return addr && inet_pton(AF_INET, addr, &(sa.sin_addr)) != 0; +} + +/* +* Mask is valid if it is a string that can be +* converted to an integer within [0,32]. +*/ + +int isValidMask(const char* mask) { + return digits_only(mask) && atoi(mask) <= 32; +} + +/* +* Check if a given string represents a valid mac address +* in the format XX:XX:XX:XX:XX:XX, where each X represents +* a hexadecimal digit 0-9 or a-f. +*/ +int isValidMAC(const char* addr) { + if (!addr) + return 0; + + int i; + for (i = 0; i < MAC_ADDR_LEN - 1; i++) { + if (i % 3 != 2 && !isdigit(addr[i])) { + return 0; + } + + if (i % 3 == 2 && addr[i] != ':') + return 0; + + } + + return addr[i] == '\0'; +} + + +/* +* Get the numerical max value among all fds which server +* is monitoring. +*/ + +int get_max_fd() { + int i = 0; + int max = -1; + + for (; i < MAX_CLIENTS; i++) { + if (monitored_fd_set[i] > max) + max = monitored_fd_set[i]; + } + + return max; +} + +/* +* Parses a string command, in the format +* or +* with each field seperated by a space, to create +* a sync message for clients, instructing them on +* how to update their copies of the routing table. +* The silent parameter indicates whether the server +* is actively inputting a command for MAC list via +* stdin or a client is replicating a command sent by +* the server. Returns 0 on success and -1 on any +* failure. +*/ + + +int create_sync_message(char* operation, sync_msg_t* sync_msg, int silent) { + + char* token = strtok(operation, " "); + + if (token) { + switch (token[0]) { + case 'C': + sync_msg->op_code = CREATE; + break; + + case 'U': + sync_msg->op_code = UPDATE; + break; + + case 'D': + sync_msg->op_code = DELETE; + break; + + case 'S': + sync_msg->op_code = NONE; + display_routing_table(routing_table); + display_mac_list(mac_list); + return 0; + + case 'F': + sync_msg->op_code = NONE; + + flush_clients(); + deinit_dll(routing_table); + deinit_dll(mac_list); + + routing_table = init_dll(); + mac_list = init_dll(); + return 0; + + default: + + fprintf(stderr, "Invalid operation: unknown op code\n"); + return -1; + } + } + else { + fprintf(stderr, "Invalid operation: missing op code\n"); + return -1; + } + + token = strtok(NULL, " "); + + if (isValidIP(token)) { + sync_msg->l_code = L3; + memcpy(sync_msg->msg_body.routing_table_entry.dest, token, strlen(token)); + } + else if (isValidMAC(token)) { + sync_msg->l_code = L2; + memcpy(sync_msg->msg_body.mac_list_entry.mac, token, strlen(token)); + + if (!silent && sync_msg->op_code == CREATE) { + + printf("Enter an IP address:\n"); + char ip[IP_ADDR_LEN]; + int ret = read(0, ip, IP_ADDR_LEN); + + ip[strcspn(ip, "\r\n")] = 0; + + if (ret < 0 || store_IP(sync_msg->msg_body.mac_list_entry.mac, ip) == -1) { + fprintf(stderr, "Failed to store ip address\n"); + return -1; + } + } + + return 0; + } + else { + fprintf(stderr, "Invalid operation: invalid or missing destination IP/MAC address\n"); + return -1; + } + + token = strtok(NULL, " "); + if (isValidMask(token)) { + sync_msg->msg_body.routing_table_entry.mask = atoi(token); + } + else { + fprintf(stderr, "Invalid operation: invalid or missing subnet mask/IP address\n"); + return -1; + } + + /* + * Only CREATE and UPDATE require a gw and oif. + */ + + if (sync_msg->op_code == CREATE || sync_msg->op_code == UPDATE) { + token = strtok(NULL, " "); + + if (isValidIP(token)) { + memcpy(sync_msg->msg_body.routing_table_entry.gw, token, strlen(token)); + } + else { + fprintf(stderr, "Invalid operation: invalid or missing gateway IP\n"); + return -1; + } + + token = strtok(NULL, " "); + if (token) { + memcpy(sync_msg->msg_body.routing_table_entry.oif, token, strlen(token)); + } + else { + fprintf(stderr, "Invalid operation: missing OIF\n"); + return -1; + } + } + + return 0; +} + +/* +* Break out of main infinite loop and inform clients of +* shutdown to exit clearly. +*/ + +void signal_handler(int signal_num) { + + if (signal_num == SIGINT) { + int i, synchronized = WAIT, loop = 0; + sync_msg_t sync_msg; + sync_msg.op_code = NONE; + + for (i = 2; i < MAX_CLIENTS; i++) { + int comm_socket_fd = monitored_fd_set[i]; + + if (comm_socket_fd != -1) { + write(comm_socket_fd, &sync_msg, sizeof(sync_msg_t)); + write(comm_socket_fd, &synchronized, sizeof(int)); + write(comm_socket_fd, &loop, sizeof(int)); + } + } + + /* + * Clean up resources. + */ + + int shm_fd; + mac_list_entry_t* entry; + + ITERATE_DLL(mac_list, entry, mac_list_entry_t) + + shm_fd = shm_open(entry->mac, + O_CREAT | O_RDONLY, + 0660); + + shm_unlink(entry->mac); + close(shm_fd); + ITERATE_DLL_END() + + deinit_dll(routing_table); + deinit_dll(mac_list); + close(connection_socket); + remove_from_monitored_fd_set(connection_socket); + unlink(SOCKET_NAME); + exit(0); + } +} + + +/* +* Send newly client all necessary CREATE commands to replicate +* the server's copies of the current routing table or MAC list. +*/ + +void update_new_client(int data_socket, LCODE l_code, char* op, sync_msg_t* sync_msg) { + + dll_node_t* head = l_code == L3 ? routing_table->head : mac_list->head; + dll_node_t* curr = head->next; + + while (curr != head) { + routing_table_entry_t rt_entry = *((routing_table_entry_t*)curr->data); + + mac_list_entry_t ml_entry = *((mac_list_entry_t*)curr->data); + + sync_msg->op_code = CREATE; + + if (l_code == L3) { + sprintf(op, "C %s %u %s %s", + rt_entry.dest, + rt_entry.mask, + rt_entry.gw, + rt_entry.oif); + } + else { + + sprintf(op, "C %s", ml_entry.mac); + } + + create_sync_message(op, sync_msg, 1); + + write(data_socket, sync_msg, sizeof(sync_msg_t)); + write(data_socket, &synchronized, sizeof(int)); + write(data_socket, &loop, sizeof(int)); + + curr = curr->next; + } + + /* + * Send dummy sync message to inform client that all + * current updates have been sent. + */ + + sync_msg->op_code = NONE; + write(data_socket, sync_msg, sizeof(sync_msg_t)); + synchronized = l_code == L3 ? RT : ML; + write(data_socket, &synchronized, sizeof(int)); + write(data_socket, &loop, sizeof(int)); +} + +int main() { + + struct sockaddr_un name; + int ret; + int data_socket; + fd_set readfds; + + routing_table = init_dll(); + mac_list = init_dll(); + + initialize_monitor_fd_and_client_pid_set(); + add_to_monitored_fd_set(0); + + unlink(SOCKET_NAME); //In case the program exited inadvertently on the last run, remove the socket. + + /* + * Master socket for accepting connections + * from client + */ + + connection_socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (connection_socket == -1) { + perror("socket"); + exit(1); + } + + /* + * Initialize + */ + + memset(&name, 0, sizeof(struct sockaddr_un)); + + /* + * Specify the socket Credentials + */ + name.sun_family = AF_UNIX; + strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1); + + /* + * Bind socket to socket name + */ + + ret = bind(connection_socket, (const struct sockaddr*) &name, + sizeof(struct sockaddr_un)); + + if (ret == -1) { + perror("bind"); + exit(1); + } + + /* + * Prepare for accepting connections. + */ + + ret = listen(connection_socket, 20); + if (ret == -1) { + perror("listen"); + exit(1); + } + + add_to_monitored_fd_set(connection_socket); + + signal(SIGINT, signal_handler); //register signal handler + + /* + * The server continuously checks for new clients connections, monitors + * existing connections (i.e. incoming messages and inactive connections, + * modifies the routing table or MAC list if need be, and broadcasts to + * clients. + */ + + while (1) { + char op[OP_LEN]; + sync_msg_t* sync_msg = calloc(1, sizeof(sync_msg_t)); + synchronized = 0; + + refresh_fd_set(&readfds); /*Copy the entire monitored FDs to readfds*/ + + printf("Please select from the following options:\n"); + printf("1.CREATE \n"); + printf("2.UPDATE \n"); + printf("3.DELETE \n"); + printf("4.CREATE \n"); + printf("5.DELETE \n"); + printf("6.SHOW\n"); + printf("7.FLUSH\n"); + + select(get_max_fd() + 1, &readfds, NULL, NULL, NULL); /* Wait for incoming connections*/ + + /* New Connection : send entire routing table and mac list states to newly connected clients*/ + if (FD_ISSET(connection_socket, &readfds)) { + data_socket = accept(connection_socket, NULL, NULL); + if (data_socket == -1) { + perror("accept"); + exit(1); + } + + pid_t pid; + if (read(data_socket, &pid, sizeof(pid_t)) == -1) { + perror("read"); + exit(1); + } + + add_to_monitored_fd_set(data_socket); + add_to_client_pid_set(pid); + + update_new_client(data_socket, L3, op, sync_msg); + update_new_client(data_socket, L2, op, sync_msg); + + } + else if (FD_ISSET(0, &readfds)) { // server stdin + + ret = read(0, op, OP_LEN - 1); + + op[strcspn(op, "\r\n")] = 0; //flush new line + + if (ret == -1) { + perror("read"); + return 1; + } + + op[ret] = 0; + + + if (!create_sync_message(op, sync_msg, 0)) { + //Update server's tables + + if (sync_msg->l_code == L3) { + process_sync_mesg(routing_table, sync_msg); + synchronized = RT; + } + else { + process_sync_mesg(mac_list, sync_msg); + synchronized = ML; + } + + // Notify existing clients of change. + int i, comm_socket_fd; + for (i = 2; i < MAX_CLIENTS; i++) { + //Start at 2 since 0 and 1 are for server's stdin and stdout + comm_socket_fd = monitored_fd_set[i]; + if (comm_socket_fd != -1) { + write(comm_socket_fd, sync_msg, sizeof(sync_msg_t)); + write(comm_socket_fd, &synchronized, sizeof(int)); + write(comm_socket_fd, &loop, sizeof(int)); + } + } + } + } + else { + /* + * Check active status of clients. + */ + + int i; + for (i = 2; i < MAX_CLIENTS; i++) { + if (FD_ISSET(monitored_fd_set[i], &readfds)) { + int done; + int comm_socket_fd = monitored_fd_set[i]; + + ret = read(comm_socket_fd, &done, sizeof(int)); + if (done == 1) { + //this client is disconnecting + close(comm_socket_fd); + remove_from_monitored_fd_set(comm_socket_fd); + } + else if (ret == -1) { + perror("read"); + exit(1); + } + else { + printf("%i\n", done); + } + } + } + } + } + + exit(0); +} \ No newline at end of file diff --git a/app/shm_ip.c b/app/shm_ip.c new file mode 100644 index 0000000..c5837a0 --- /dev/null +++ b/app/shm_ip.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "routing-table.h" + +/* +* Stores IP address in newly created shared memory region +* corresponding to its key, which is a MAC address. Returns +* the size of created shm on success otherwise -1 on failure. +*/ + +int store_IP(const char* mac, const char* ip) { + + size_t size = strlen(ip); // account for terminating null byte + + int shm_fd = shm_open(mac, O_CREAT | O_RDWR | O_TRUNC, 0660); + + if (shm_fd == -1) { + printf("Could not create shared memory for MAC %s - IP %s pair\n", + mac, + ip); + return -1; + } + + if (ftruncate(shm_fd, size) == -1) { + printf("Error on ftruncate to allocate size for IP %s\n", ip); + return -1; + } + + void* shm_reg = mmap(NULL, + size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + shm_fd, + 0); + + if (shm_reg == MAP_FAILED) { + printf("Mapping failed\n"); + return -1; + } + + memset(shm_reg, 0, size); + memcpy(shm_reg, ip, size); + + if (munmap(shm_reg, size) == -1) { + printf("Unmapping failed\n"); + return -1; + } + + close(shm_fd); + return size; +} + +/* +* Get the IP address corresponding to the MAC address +* from the shared region that the server created. +* Returns number of bytes on success else -1 on +* failure. +*/ + +int get_IP(const char* mac, char* ip) { + + int shm_fd = shm_open(mac, + O_CREAT | O_RDONLY, + 0660); + + if (shm_fd == -1) { + printf("Couldn't open shared memory for MAC %s - IP %s pair\n", + mac, + ip); + return -1; + } + + void* shm_reg = mmap(NULL, + IP_ADDR_LEN, + PROT_READ, + MAP_SHARED, + shm_fd, + 0); + + if (shm_reg == MAP_FAILED) { + printf("Mapping failed\n"); + return -1; + } + + memcpy(ip, shm_reg, IP_ADDR_LEN); + if (munmap(shm_reg, IP_ADDR_LEN) == -1) { + printf("Unmapping failed\n"); + return -1; + } + + close(shm_fd); + return strlen(ip); +} \ No newline at end of file