diff options
Diffstat (limited to 'semestr-4/sieci/pracownia2')
28 files changed, 1670 insertions, 0 deletions
diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka.tar.xz b/semestr-4/sieci/pracownia2/franciszek_malinka.tar.xz Binary files differnew file mode 100644 index 0000000..ac3b1f7 --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka.tar.xz diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/config.h b/semestr-4/sieci/pracownia2/franciszek_malinka/config.h new file mode 100644 index 0000000..ee4eac0 --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/config.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define SERVER_PORT 54321 +#define TURN_LEN_S 20 + +#define INFINITY_DIST 16 +#define REACHABILITY_WAIT_TIME 3 + +#define DV_DATAGRAM_LEN 9 + +#define TURN_LEN_MS (1000 * TURN_LEN_S) +#define TURN_LEN_US (1000000 * TURN_LEN_S) + +#endif diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/dist_vector.c b/semestr-4/sieci/pracownia2/franciszek_malinka/dist_vector.c new file mode 100644 index 0000000..74ae82e --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/dist_vector.c @@ -0,0 +1,114 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include "dist_vector.h" +#include <stdio.h> +#include <time.h> +#include <string.h> + +bool is_connected_directly(struct vector_item item) { + return item.is_connected_directly; +} + +bool is_reachable(struct vector_item item) { + return (item.distance < INFINITY_DIST); +} + +void init_dv(list_t *dv, int n_cnt, struct network_addr *neighbours) { + for (int i = 0; i < n_cnt; i++) { + struct vector_item new_item; + new_item.network = neighbours[i]; + new_item.distance = INFINITY_DIST; + new_item.is_connected_directly = true; + insert(dv, &new_item, sizeof(new_item)); + } +} + +void update_dv_reachability(list_t *distance_vector) { + reset(distance_vector); + while (distance_vector->it != NULL) { + struct vector_item *current = (struct vector_item *)distance_vector->it->data; + if(++current->reachable > REACHABILITY_WAIT_TIME) { + if (current->distance >= INFINITY_DIST) { + if (!is_connected_directly(*current)) { + erase_it(distance_vector); + } + } else { + current->distance = INFINITY_DIST; + current->reachable = 0; + } + } + iterate(distance_vector); + } +} + +void update_dv_new_item(list_t *distance_vector, struct vector_item new_item) { + bool new_entry = true; + reset(distance_vector); + while (distance_vector->it != NULL) { + struct vector_item *current = (struct vector_item *)distance_vector->it->data; + + /* If the network is already in the distance vector, then we possibly want to change it: + * - if the new item has better distance than the previous one, then we just want to change it no matter what, + * - if the new item has the same via ip, then we want to check two things: + * - if new item has infinity dist, then we want to set infinity (if it wasn't set, then we want to change reachable to 0) + * - if new item has < inf dist, then we want to change reachable to 0 and set our dist accordingly. + * - else we ignore the entry. + */ + if (get_network_address(current->network).s_addr == get_network_address(new_item.network).s_addr) { + if (current->distance > new_item.distance) { + *current = new_item; + current->reachable = 0; + } else if(current->via_ip.s_addr == new_item.via_ip.s_addr) { + if (new_item.distance >= INFINITY_DIST) { + if (current->distance < INFINITY_DIST) { + current->distance = INFINITY_DIST; + current->reachable = 0; + } + } else { + current->distance = new_item.distance; + current->reachable = 0; + } + } + new_entry = false; + } + + iterate(distance_vector); + } + + if (new_entry && new_item.reachable < INFINITY_DIST) { + insert(distance_vector, &new_item, sizeof(new_item)); + } +} + +void print_dv(list_t *distance_vector) { + time_t rawtime; + struct tm * timeinfo; + + time ( &rawtime ); + timeinfo = localtime ( &rawtime ); + char t[100]; + strcpy(t, asctime(timeinfo)); + t[strlen(t) - 1] = 0; + printf("Distance vector [%s]:\n", t); + reset(distance_vector); + while (distance_vector->it != NULL) { + char addr[20], via_addr[20]; + struct vector_item current = *(struct vector_item *)distance_vector->it->data; + struct in_addr net_addr = get_network_address(current.network); + inet_ntop(AF_INET, &net_addr, addr, sizeof(addr)); + printf("%s/%d ", addr, current.network.netmask); + + if (is_reachable(current)) printf("distance %d ", current.distance); + else printf("unreachable "); + + inet_ntop(AF_INET, ¤t.via_ip, via_addr, sizeof(via_addr)); + if (is_connected_directly(current)) printf("connected directly\n"); + else printf("via %s\n", via_addr); + + iterate(distance_vector); + } + printf("\n"); +}
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/dist_vector.h b/semestr-4/sieci/pracownia2/franciszek_malinka/dist_vector.h new file mode 100644 index 0000000..14159b4 --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/dist_vector.h @@ -0,0 +1,36 @@ +#ifndef DIST_VECTOR_H +#define DIST_VECTOR_H + +#include "linked_list.h" +#include "network_addr.h" +#include "config.h" + +/* Item of the distance vector. + * If <<reachable>> is set to 0, then it means that the network is reachable. + * If <<reachable>> has positive value, then it indicates that the network was + * unreachable for <<reachable>> turns. + */ +struct vector_item { + struct network_addr network; + struct in_addr via_ip; + uint16_t distance; + uint8_t reachable; + bool is_connected_directly; +}; + +/* Initis distance vector with given neighbours array. */ +void init_dv(list_t *dv, int n_cnt, struct network_addr *neighbours); + +/* Returns true if given distance vector item is connected directly, false otherwise. */ +bool is_connected_directly(struct vector_item item); + +/* Updates the distance vector. */ +void update_dv_new_item(list_t *distance_vector, struct vector_item new_item); + +/* Updates reachabilities. */ +void update_dv_reachability(list_t *distance_vector); + +/* Print distance vector. */ +void print_dv(list_t *distance_vector); + +#endif
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/linked_list.c b/semestr-4/sieci/pracownia2/franciszek_malinka/linked_list.c new file mode 100644 index 0000000..16113ac --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/linked_list.c @@ -0,0 +1,79 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include "linked_list.h" +#include <stdlib.h> +#include <stdint.h> + +node_t *_next(node_t *node) { + return (node == NULL) ? NULL : node->next; +} + +void _insert(node_t **head, void *data, size_t data_size) { + node_t *new_node = (node_t *)malloc(sizeof(node_t)); + new_node->data = malloc(data_size); + for (int i = 0; i < data_size; i++) + *(uint8_t *)(new_node->data + i) = *(uint8_t *)(data + i); + new_node->next = *head; + *head = new_node; +} + +void _free_node(node_t *node) { + free(node->data); + free(node); +} + +void _erase(node_t **head) { + node_t *next_node = _next(*head); + _free_node(*head); + *head = next_node; +} + +void _free_list(node_t *head) { + if (head == NULL) return; + _free_list(head->next); + _free_node(head); +} + +list_t create_list() { + list_t ret; + ret.head = NULL; + ret.it = NULL; + return ret; +} + +void insert(list_t *list, void *data, size_t data_size) { + _insert(&list->head, data, data_size); +} + +void erase(list_t *list) { + _erase(&list->head); +} + +void erase_it(list_t *list) { + if(list->it == NULL) return; + if(list->prev_it == NULL) { + erase(list); + reset(list); + return; + } + list->prev_it->next = _next(list->it); + _free_node(list->it); + list->it = list->prev_it->next; +} + +void iterate(list_t *list) { + list->prev_it = list->it; + list->it = _next(list->it); +} + +void reset(list_t *list) { + list->prev_it = NULL; + list->it = list->head; +} + +void free_list(list_t *list) { + _free_list(list->head); +}
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/linked_list.h b/semestr-4/sieci/pracownia2/franciszek_malinka/linked_list.h new file mode 100644 index 0000000..1574b2f --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/linked_list.h @@ -0,0 +1,42 @@ +#ifndef LINKED_LIST_H +#define LINKED_LIST_H + +#include <stddef.h> + +typedef struct node { + void *data; + struct node *next; +} node_t; + + +typedef struct list_t { + node_t *head; + node_t *it; + node_t *prev_it; +} list_t; + +/* Creates an empty list. */ +list_t create_list(); + +/* Insert a new node in the begining of a list. */ +void insert(list_t *list, void *data, size_t data_size); + +/* Erases first node from the list. */ +void erase(list_t *list); + +/* Erases element under iterator and sets iterator to the next one. */ +void erase_it(list_t *list); + +/* Moves iterator one step. */ +void iterate(list_t *list); + +/* Resets the iterator. + * Should execute the function after if you want to itarate unless you didnt insert or erase anything from the list. + */ +void reset(list_t *list); + +/* Deletes the whole list. */ +void free_list(list_t *list); + + +#endif
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/makefile b/semestr-4/sieci/pracownia2/franciszek_malinka/makefile new file mode 100644 index 0000000..bf6a327 --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/makefile @@ -0,0 +1,34 @@ +CC := gcc +CFLAGS := -O2 -std=gnu17 -Wall -Wall -Wno-unused-result +TARGET := router +TEST := test +DEPS := config.h + +ODIR := obj +_OBJ := router.o utils.o linked_list.o network_addr.o dist_vector.o +OBJ := $(patsubst %,$(ODIR)/%,$(_OBJ)) + +_TEST_OBJ := test.o linked_list.o +TEST_OBJ := $(patsubst %,$(ODIR)/%,$(_TEST_OBJ)) + + +all: $(TARGET) +test: $(TEST) + +$(ODIR)/%.o: %.c $(DEPS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(TARGET): $(OBJ) + $(CC) -o $@ $^ $(CFLAGS) + +$(TEST): $(TEST_OBJ) + $(CC) -o $@ $^ $(CFLAGS) + +clean: + rm -rf $(TARGET) + rm -rf test + +distclean: + rm -rf $(TARGET) + rm -rf test + rm -rf $(ODIR)/*.o diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/network_addr.c b/semestr-4/sieci/pracownia2/franciszek_malinka/network_addr.c new file mode 100644 index 0000000..cac1060 --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/network_addr.c @@ -0,0 +1,65 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include "network_addr.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +struct in_addr _get_broadcast_address(struct in_addr addr, uint16_t netmask) { + struct in_addr result = addr; + result.s_addr = ntohl(result.s_addr); + /* bitshift by more than 31 is UB */ + if (netmask == 0) { + result.s_addr = -1; + } + else { + result.s_addr |= ((1 << (32 - netmask)) - 1); + } + result.s_addr = htonl(result.s_addr); + + return result; +} + +struct in_addr _get_network_address(struct in_addr addr, uint16_t netmask) { + struct in_addr result = addr; + result.s_addr = ntohl(result.s_addr); + + if (netmask == 0) { + result.s_addr = 0; + } + else { + result.s_addr &= ~((1 << (32 - netmask)) - 1); + } + result.s_addr = htonl(result.s_addr); + + return result; +} + +struct in_addr get_broadcast_address(struct network_addr na) { + return _get_broadcast_address(na.addr, na.netmask); +} + +struct in_addr get_network_address(struct network_addr na) { + return _get_network_address(na.addr, na.netmask); +} + +void pretty_print_network(struct network_addr na) { + char ip_addr[20]; + inet_ntop(AF_INET, &na.addr, ip_addr, sizeof(ip_addr)); + printf("%s/%d\n", ip_addr, na.netmask); +} + +struct network_addr stona(char *str) { + struct network_addr result; + char addr[20]; + size_t ip_preffix = strcspn(str, "/"); + + strncpy(addr, str, ip_preffix); + addr[ip_preffix] = 0; + inet_pton(AF_INET, addr, &(result.addr)); + result.netmask = atoi(str + ip_preffix + 1); + return result; +} diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/network_addr.h b/semestr-4/sieci/pracownia2/franciszek_malinka/network_addr.h new file mode 100644 index 0000000..6347bbd --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/network_addr.h @@ -0,0 +1,28 @@ +#ifndef ROUTER_ADDR_H +#define ROUTER_ADDR_H + +#include <arpa/inet.h> +#include <stdint.h> +#include <stdbool.h> + +/* Network address with netmask. */ +struct network_addr { + struct in_addr addr; + uint8_t netmask; +}; + +typedef struct network_addr router_addr; + +/* Returns broadcast address of a given network. */ +struct in_addr get_broadcast_address(struct network_addr na); + +/* Returns network address of a given network. */ +struct in_addr get_network_address(struct network_addr na); + +/* Prints network_addr via stdio. */ +void pretty_print_network(struct network_addr na); + +/* Converts string of ip in CIDR notation with a netmask to network_addr. */ +struct network_addr stona(char *str); + +#endif
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/router.c b/semestr-4/sieci/pracownia2/franciszek_malinka/router.c new file mode 100644 index 0000000..b5e732c --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/router.c @@ -0,0 +1,60 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <string.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include "network_addr.h" +#include "utils.h" +#include "dist_vector.h" + +uint16_t read_configuration(struct network_addr** networks, uint16_t **dists) { + uint16_t n; + scanf("%hd", &n); + *networks = malloc(n * sizeof(struct network_addr)); + *dists = malloc(n * sizeof(uint16_t)); + for (int i = 0; i < n; i++) { + char addr[20]; + char _dist[10]; + uint16_t dist; + scanf(" %s %s %hd", addr, _dist, &dist); + (*networks)[i] = stona(addr); + (*dists)[i] = dist; + } + return n; +} + +void router_loop(int sockfd, int networks_number, struct network_addr *networks, uint16_t *dists) { + list_t dv = create_list(); + init_dv(&dv, networks_number, networks); + + printf("Starting the router loop...\n"); + for (;;) { + print_dv(&dv); + propagate_distance_vector(sockfd, networks_number, networks, dists, &dv); + listen_for_routers(sockfd, TURN_LEN_MS, networks_number, networks, dists, &dv); + } +} + +int main() { + struct network_addr* networks; + uint16_t *dists; + int n = read_configuration(&networks, &dists); + int sockfd = get_socket(); + bind_to_port(sockfd, SERVER_PORT); + + router_loop(sockfd, n, networks, dists); + + close(sockfd); + free(networks); + free(dists); +}
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/test.c b/semestr-4/sieci/pracownia2/franciszek_malinka/test.c new file mode 100644 index 0000000..958ff36 --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/test.c @@ -0,0 +1,52 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include "linked_list.h" +#include <stdlib.h> +#include <stdio.h> + +/* Prints the list of ints to stdio */ +void print_list(list_t list) { + printf("List: "); + reset(&list); + while (list.it != NULL) { + printf("%d, ", *(int *)(list.it->data)); + iterate(&list); + } + printf("\n"); + reset(&list); +} + +int main() { + int n; + scanf("%d", &n); + list_t list = create_list(); + + for (int i = 0; i < n; i++) { + int t; + scanf("%d", &t); + // insert + if (t == 0) { + int val = 0; + scanf("%d", &val); + insert(&list, &val, sizeof(int)); + reset(&list); + } + if (t == 1) { + iterate(&list); + if (list.it != NULL) + printf("it: %d\n", *(int *)list.it->data); + else printf("End of list.\n"); + } + if (t == 2) { + erase_it(&list); + } + if (t == 3) { + print_list(list); + } + } + + free_list(&list); +}
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/utils.c b/semestr-4/sieci/pracownia2/franciszek_malinka/utils.c new file mode 100644 index 0000000..0c0cae5 --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/utils.c @@ -0,0 +1,208 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include "utils.h" +#include <arpa/inet.h> +#include <netinet/ip.h> +#include <stdlib.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> + +int get_socket() { + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + fprintf(stderr, "Socket error: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + return sockfd; +} + +void bind_to_port(int sockfd, uint16_t port) { + struct sockaddr_in server_address; + bzero(&server_address, sizeof(server_address)); + server_address.sin_family = AF_INET; + server_address.sin_port = htons(port); + server_address.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(sockfd, (struct sockaddr*)&server_address, sizeof(server_address)) < 0) { + fprintf(stderr, "Bind error: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + int broadcastPermission = 1; + setsockopt (sockfd, SOL_SOCKET, SO_BROADCAST, (void *)&broadcastPermission, sizeof(broadcastPermission)); +} + +long get_time_interval(struct timespec start, struct timespec finish) { + return S_TO_MS(finish.tv_sec - start.tv_sec) + NS_TO_MS(finish.tv_nsec - start.tv_nsec); +} + +int poll_socket_modify_timeout(int sockfd, int *timeout) { + if (*timeout < 0) { + *timeout = 0; + return 0; + } + + struct pollfd fds; + struct timespec start; + struct timespec finish; + + fds.fd = sockfd; + fds.events = POLLIN; + fds.revents = 0; + + clock_gettime(CLOCK_REALTIME, &start); + int result = poll(&fds, 1, *timeout); + clock_gettime(CLOCK_REALTIME, &finish); + + if (result == -1) { + fprintf(stderr, "poll error: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + if (result == 0) { + *timeout = 0; + return 0; + } + + *timeout -= get_time_interval(start, finish); + return result; +} + +size_t send_message(int sockfd, char *buffer, int buffer_len, struct in_addr network) { + struct sockaddr_in network_address; + bzero (&network_address, sizeof(network_address)); + network_address.sin_family = AF_INET; + network_address.sin_port = htons(SERVER_PORT); + network_address.sin_addr = network; + + return sendto(sockfd, buffer, buffer_len, 0, (struct sockaddr*) &network_address, sizeof(network_address)); +} + +size_t recv_message(int sockfd, char *buffer, struct sockaddr_in *sender) { + socklen_t sender_len = sizeof(*sender); + for (int i = 0; i < DV_DATAGRAM_LEN; i++) buffer[i] = 0; + size_t datagram_len = recvfrom(sockfd, buffer, IP_MAXPACKET, 0, + (struct sockaddr*)sender, &sender_len); + if (datagram_len < 0) { + fprintf(stderr, "recvfrom error: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + return datagram_len; +} + +struct vector_item parse_message(char *buffer, struct sockaddr_in *sender) { + struct vector_item res; + uint32_t ip_addr = *(uint32_t *)buffer; + uint32_t dist = *(uint32_t *)(buffer + 5); + dist = ntohl(dist); + + res.network.addr.s_addr = ip_addr; + res.network.netmask = buffer[4]; + res.is_connected_directly = true; + res.via_ip = sender->sin_addr; + res.distance = (dist < INFINITY_DIST ? dist : INFINITY_DIST); + res.reachable = 0; + + char addr[20]; + inet_ntop(AF_INET, &res.network.addr, addr, sizeof(addr)); + char via[20]; + inet_ntop(AF_INET, &sender->sin_addr, via, sizeof(via)); + return res; +} + +void _get_message(struct vector_item item, char *message) { + *(uint32_t *)message = item.network.addr.s_addr; + message[4] = item.network.netmask; + uint32_t distance = htonl(item.distance >= INFINITY_DIST ? INT_MAX : item.distance); + for (int i = 0; i < 4; i++) { + *(message + 5 + i) = *((char *)(&distance) + i); + } +} + +int _send_item(int sockfd, struct network_addr network, struct vector_item item) { + char message[DV_DATAGRAM_LEN + 1]; + _get_message(item, message); + message[DV_DATAGRAM_LEN] = 0; + ssize_t message_len = DV_DATAGRAM_LEN; + + struct in_addr na = get_broadcast_address(network); + + char addr[20]; + inet_ntop(AF_INET, &na, addr, sizeof(addr)); + + int result; + if ((result = send_message(sockfd, message, message_len, na)) != message_len) { + // fprintf(stderr, "sendto error: %s\n", strerror(errno)); + } + return result; +} + +void listen_for_routers(int sockfd, int timeout, int networks_number, struct network_addr *networks, uint16_t *dists, list_t *dv) { + char buffer[IP_MAXPACKET + 1]; + struct sockaddr_in sender; + + while (poll_socket_modify_timeout(sockfd, &timeout)) { + recv_message(sockfd, buffer, &sender); + struct vector_item new_item = parse_message(buffer, &sender); + + bool is_neighbour = false; + for (int i = 0; i < networks_number; i++) { + if (is_from_network(sender.sin_addr, networks[i])) { + is_neighbour = true; + break; + } + } + + /* Shouldn't happen, just in case. */ + if (!is_neighbour) { + char addr[20]; + inet_ntop(AF_INET, &sender.sin_addr, addr, sizeof(addr)); + fprintf(stderr, "Received datagram from %s, he is in none of my networks, ignoring\n. Maybe his VM routing table is configured incorrectly?\n", addr); + continue; + } + + if (!is_from_network(sender.sin_addr, new_item.network)) { + new_item.is_connected_directly = false; + + for (int i = 0; i < networks_number; i++) { + if (is_from_network(sender.sin_addr, networks[i])) { + new_item.distance += dists[i]; + break; + } + } + } + + update_dv_new_item(dv, new_item); + } + update_dv_reachability(dv); +} + +void propagate_distance_vector(int sockfd, int networks_number, struct network_addr *networks, uint16_t *dists, list_t *dv) { + for (int i = 0; i < networks_number; i++) { + reset(dv); + while (dv->it != NULL) { + struct vector_item data = *(struct vector_item *)dv->it->data; + if (!(get_network_address(data.network).s_addr == get_network_address(networks[i]).s_addr) && data.reachable <= REACHABILITY_WAIT_TIME) { + _send_item(sockfd, networks[i], data); + } + iterate(dv); + } + + struct vector_item self_item; + self_item.distance = dists[i]; + self_item.network = networks[i]; + _send_item(sockfd, networks[i], self_item); + } +} + +bool is_from_network(struct in_addr ip_addr, struct network_addr network) { + struct network_addr temp; + temp.addr= ip_addr; + temp.netmask = network.netmask; + return (get_network_address(temp).s_addr == get_network_address(network).s_addr); +}
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/franciszek_malinka/utils.h b/semestr-4/sieci/pracownia2/franciszek_malinka/utils.h new file mode 100644 index 0000000..edf90d0 --- /dev/null +++ b/semestr-4/sieci/pracownia2/franciszek_malinka/utils.h @@ -0,0 +1,52 @@ +#ifndef UTILS_H +#define UTILS_H +#define UTILS_H + +#include "config.h" +#include <stdint.h> +#include <time.h> +#include <poll.h> +#include "network_addr.h" +#include "dist_vector.h" + +#define NS_TO_MS(X) ((long)(X) / (long)1000000) +#define S_TO_MS(X) ((long)(X) * (long)1000) + +/* Returns a UDP socket. */ +int get_socket(); + +/* Binds socket to given port and set the broadcast permission. */ +void bind_to_port(int sockfd, uint16_t port); + +/* Computes the time elapsed between start and finish in miliseconds. */ +long get_time_interval(struct timespec start, struct timespec finish); + +/* Polls given socket with given timeout and changes the timeout accordingly. */ +int poll_socket_modify_timeout(int sockfd, int *timeout); + +/* For debug purposes only. Recieves and prints UDP message. */ +void recv_and_print(int sockfd, int networks_number, struct network_addr *networks); + +/* Sends message in buffer of length buffer_len to addr through given socket. + * IT DOES NOT TERMINATE THE PROGRAM IF SENDTO RETURNS ANY ERRORS! + * One must handle the errors on their own. + */ +size_t send_message(int sockfd, char *buffer, int buffer_len, struct in_addr addr); + +/* Receive message and write it to buffer. */ +size_t recv_message(int sockfd, char *buffer, struct sockaddr_in *sender); + +/* Parse datagram into a vector item. */ +struct vector_item parse_message(char *buffer, struct sockaddr_in *sender); + +/* Listnes for routers for timeout ms. */ +void listen_for_routers(int sockfd, int timeout, int networks_number, struct network_addr *networks, uint16_t *dists, list_t *dv); + +/* Propagates dv to all connected networks. */ +void propagate_distance_vector(int sockfd, int networks_number, struct network_addr *networks, uint16_t *dists, list_t *dv); + +/* Checks if given address is in network range. */ +bool is_from_network(struct in_addr ip_addr, struct network_addr network); + + +#endif
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/p2.pdf b/semestr-4/sieci/pracownia2/p2.pdf Binary files differnew file mode 100644 index 0000000..f0cc942 --- /dev/null +++ b/semestr-4/sieci/pracownia2/p2.pdf diff --git a/semestr-4/sieci/pracownia2/router/config.h b/semestr-4/sieci/pracownia2/router/config.h new file mode 100644 index 0000000..f83c556 --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/config.h @@ -0,0 +1,15 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define SERVER_PORT 54321 +#define TURN_LEN_S 5 + +#define INFINITY_DIST 16 +#define REACHABILITY_WAIT_TIME 3 + +#define DV_DATAGRAM_LEN 9 + +#define TURN_LEN_MS (1000 * TURN_LEN_S) +#define TURN_LEN_US (1000000 * TURN_LEN_S) + +#endif diff --git a/semestr-4/sieci/pracownia2/router/dist_vector.c b/semestr-4/sieci/pracownia2/router/dist_vector.c new file mode 100644 index 0000000..74ae82e --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/dist_vector.c @@ -0,0 +1,114 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include "dist_vector.h" +#include <stdio.h> +#include <time.h> +#include <string.h> + +bool is_connected_directly(struct vector_item item) { + return item.is_connected_directly; +} + +bool is_reachable(struct vector_item item) { + return (item.distance < INFINITY_DIST); +} + +void init_dv(list_t *dv, int n_cnt, struct network_addr *neighbours) { + for (int i = 0; i < n_cnt; i++) { + struct vector_item new_item; + new_item.network = neighbours[i]; + new_item.distance = INFINITY_DIST; + new_item.is_connected_directly = true; + insert(dv, &new_item, sizeof(new_item)); + } +} + +void update_dv_reachability(list_t *distance_vector) { + reset(distance_vector); + while (distance_vector->it != NULL) { + struct vector_item *current = (struct vector_item *)distance_vector->it->data; + if(++current->reachable > REACHABILITY_WAIT_TIME) { + if (current->distance >= INFINITY_DIST) { + if (!is_connected_directly(*current)) { + erase_it(distance_vector); + } + } else { + current->distance = INFINITY_DIST; + current->reachable = 0; + } + } + iterate(distance_vector); + } +} + +void update_dv_new_item(list_t *distance_vector, struct vector_item new_item) { + bool new_entry = true; + reset(distance_vector); + while (distance_vector->it != NULL) { + struct vector_item *current = (struct vector_item *)distance_vector->it->data; + + /* If the network is already in the distance vector, then we possibly want to change it: + * - if the new item has better distance than the previous one, then we just want to change it no matter what, + * - if the new item has the same via ip, then we want to check two things: + * - if new item has infinity dist, then we want to set infinity (if it wasn't set, then we want to change reachable to 0) + * - if new item has < inf dist, then we want to change reachable to 0 and set our dist accordingly. + * - else we ignore the entry. + */ + if (get_network_address(current->network).s_addr == get_network_address(new_item.network).s_addr) { + if (current->distance > new_item.distance) { + *current = new_item; + current->reachable = 0; + } else if(current->via_ip.s_addr == new_item.via_ip.s_addr) { + if (new_item.distance >= INFINITY_DIST) { + if (current->distance < INFINITY_DIST) { + current->distance = INFINITY_DIST; + current->reachable = 0; + } + } else { + current->distance = new_item.distance; + current->reachable = 0; + } + } + new_entry = false; + } + + iterate(distance_vector); + } + + if (new_entry && new_item.reachable < INFINITY_DIST) { + insert(distance_vector, &new_item, sizeof(new_item)); + } +} + +void print_dv(list_t *distance_vector) { + time_t rawtime; + struct tm * timeinfo; + + time ( &rawtime ); + timeinfo = localtime ( &rawtime ); + char t[100]; + strcpy(t, asctime(timeinfo)); + t[strlen(t) - 1] = 0; + printf("Distance vector [%s]:\n", t); + reset(distance_vector); + while (distance_vector->it != NULL) { + char addr[20], via_addr[20]; + struct vector_item current = *(struct vector_item *)distance_vector->it->data; + struct in_addr net_addr = get_network_address(current.network); + inet_ntop(AF_INET, &net_addr, addr, sizeof(addr)); + printf("%s/%d ", addr, current.network.netmask); + + if (is_reachable(current)) printf("distance %d ", current.distance); + else printf("unreachable "); + + inet_ntop(AF_INET, ¤t.via_ip, via_addr, sizeof(via_addr)); + if (is_connected_directly(current)) printf("connected directly\n"); + else printf("via %s\n", via_addr); + + iterate(distance_vector); + } + printf("\n"); +}
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/router/dist_vector.h b/semestr-4/sieci/pracownia2/router/dist_vector.h new file mode 100644 index 0000000..14159b4 --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/dist_vector.h @@ -0,0 +1,36 @@ +#ifndef DIST_VECTOR_H +#define DIST_VECTOR_H + +#include "linked_list.h" +#include "network_addr.h" +#include "config.h" + +/* Item of the distance vector. + * If <<reachable>> is set to 0, then it means that the network is reachable. + * If <<reachable>> has positive value, then it indicates that the network was + * unreachable for <<reachable>> turns. + */ +struct vector_item { + struct network_addr network; + struct in_addr via_ip; + uint16_t distance; + uint8_t reachable; + bool is_connected_directly; +}; + +/* Initis distance vector with given neighbours array. */ +void init_dv(list_t *dv, int n_cnt, struct network_addr *neighbours); + +/* Returns true if given distance vector item is connected directly, false otherwise. */ +bool is_connected_directly(struct vector_item item); + +/* Updates the distance vector. */ +void update_dv_new_item(list_t *distance_vector, struct vector_item new_item); + +/* Updates reachabilities. */ +void update_dv_reachability(list_t *distance_vector); + +/* Print distance vector. */ +void print_dv(list_t *distance_vector); + +#endif
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/router/linked_list.c b/semestr-4/sieci/pracownia2/router/linked_list.c new file mode 100644 index 0000000..16113ac --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/linked_list.c @@ -0,0 +1,79 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include "linked_list.h" +#include <stdlib.h> +#include <stdint.h> + +node_t *_next(node_t *node) { + return (node == NULL) ? NULL : node->next; +} + +void _insert(node_t **head, void *data, size_t data_size) { + node_t *new_node = (node_t *)malloc(sizeof(node_t)); + new_node->data = malloc(data_size); + for (int i = 0; i < data_size; i++) + *(uint8_t *)(new_node->data + i) = *(uint8_t *)(data + i); + new_node->next = *head; + *head = new_node; +} + +void _free_node(node_t *node) { + free(node->data); + free(node); +} + +void _erase(node_t **head) { + node_t *next_node = _next(*head); + _free_node(*head); + *head = next_node; +} + +void _free_list(node_t *head) { + if (head == NULL) return; + _free_list(head->next); + _free_node(head); +} + +list_t create_list() { + list_t ret; + ret.head = NULL; + ret.it = NULL; + return ret; +} + +void insert(list_t *list, void *data, size_t data_size) { + _insert(&list->head, data, data_size); +} + +void erase(list_t *list) { + _erase(&list->head); +} + +void erase_it(list_t *list) { + if(list->it == NULL) return; + if(list->prev_it == NULL) { + erase(list); + reset(list); + return; + } + list->prev_it->next = _next(list->it); + _free_node(list->it); + list->it = list->prev_it->next; +} + +void iterate(list_t *list) { + list->prev_it = list->it; + list->it = _next(list->it); +} + +void reset(list_t *list) { + list->prev_it = NULL; + list->it = list->head; +} + +void free_list(list_t *list) { + _free_list(list->head); +}
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/router/linked_list.h b/semestr-4/sieci/pracownia2/router/linked_list.h new file mode 100644 index 0000000..1574b2f --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/linked_list.h @@ -0,0 +1,42 @@ +#ifndef LINKED_LIST_H +#define LINKED_LIST_H + +#include <stddef.h> + +typedef struct node { + void *data; + struct node *next; +} node_t; + + +typedef struct list_t { + node_t *head; + node_t *it; + node_t *prev_it; +} list_t; + +/* Creates an empty list. */ +list_t create_list(); + +/* Insert a new node in the begining of a list. */ +void insert(list_t *list, void *data, size_t data_size); + +/* Erases first node from the list. */ +void erase(list_t *list); + +/* Erases element under iterator and sets iterator to the next one. */ +void erase_it(list_t *list); + +/* Moves iterator one step. */ +void iterate(list_t *list); + +/* Resets the iterator. + * Should execute the function after if you want to itarate unless you didnt insert or erase anything from the list. + */ +void reset(list_t *list); + +/* Deletes the whole list. */ +void free_list(list_t *list); + + +#endif
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/router/makefile b/semestr-4/sieci/pracownia2/router/makefile new file mode 100644 index 0000000..bf6a327 --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/makefile @@ -0,0 +1,34 @@ +CC := gcc +CFLAGS := -O2 -std=gnu17 -Wall -Wall -Wno-unused-result +TARGET := router +TEST := test +DEPS := config.h + +ODIR := obj +_OBJ := router.o utils.o linked_list.o network_addr.o dist_vector.o +OBJ := $(patsubst %,$(ODIR)/%,$(_OBJ)) + +_TEST_OBJ := test.o linked_list.o +TEST_OBJ := $(patsubst %,$(ODIR)/%,$(_TEST_OBJ)) + + +all: $(TARGET) +test: $(TEST) + +$(ODIR)/%.o: %.c $(DEPS) + $(CC) $(CFLAGS) -c -o $@ $< + +$(TARGET): $(OBJ) + $(CC) -o $@ $^ $(CFLAGS) + +$(TEST): $(TEST_OBJ) + $(CC) -o $@ $^ $(CFLAGS) + +clean: + rm -rf $(TARGET) + rm -rf test + +distclean: + rm -rf $(TARGET) + rm -rf test + rm -rf $(ODIR)/*.o diff --git a/semestr-4/sieci/pracownia2/router/network_addr.c b/semestr-4/sieci/pracownia2/router/network_addr.c new file mode 100644 index 0000000..cac1060 --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/network_addr.c @@ -0,0 +1,65 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include "network_addr.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +struct in_addr _get_broadcast_address(struct in_addr addr, uint16_t netmask) { + struct in_addr result = addr; + result.s_addr = ntohl(result.s_addr); + /* bitshift by more than 31 is UB */ + if (netmask == 0) { + result.s_addr = -1; + } + else { + result.s_addr |= ((1 << (32 - netmask)) - 1); + } + result.s_addr = htonl(result.s_addr); + + return result; +} + +struct in_addr _get_network_address(struct in_addr addr, uint16_t netmask) { + struct in_addr result = addr; + result.s_addr = ntohl(result.s_addr); + + if (netmask == 0) { + result.s_addr = 0; + } + else { + result.s_addr &= ~((1 << (32 - netmask)) - 1); + } + result.s_addr = htonl(result.s_addr); + + return result; +} + +struct in_addr get_broadcast_address(struct network_addr na) { + return _get_broadcast_address(na.addr, na.netmask); +} + +struct in_addr get_network_address(struct network_addr na) { + return _get_network_address(na.addr, na.netmask); +} + +void pretty_print_network(struct network_addr na) { + char ip_addr[20]; + inet_ntop(AF_INET, &na.addr, ip_addr, sizeof(ip_addr)); + printf("%s/%d\n", ip_addr, na.netmask); +} + +struct network_addr stona(char *str) { + struct network_addr result; + char addr[20]; + size_t ip_preffix = strcspn(str, "/"); + + strncpy(addr, str, ip_preffix); + addr[ip_preffix] = 0; + inet_pton(AF_INET, addr, &(result.addr)); + result.netmask = atoi(str + ip_preffix + 1); + return result; +} diff --git a/semestr-4/sieci/pracownia2/router/network_addr.h b/semestr-4/sieci/pracownia2/router/network_addr.h new file mode 100644 index 0000000..6347bbd --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/network_addr.h @@ -0,0 +1,28 @@ +#ifndef ROUTER_ADDR_H +#define ROUTER_ADDR_H + +#include <arpa/inet.h> +#include <stdint.h> +#include <stdbool.h> + +/* Network address with netmask. */ +struct network_addr { + struct in_addr addr; + uint8_t netmask; +}; + +typedef struct network_addr router_addr; + +/* Returns broadcast address of a given network. */ +struct in_addr get_broadcast_address(struct network_addr na); + +/* Returns network address of a given network. */ +struct in_addr get_network_address(struct network_addr na); + +/* Prints network_addr via stdio. */ +void pretty_print_network(struct network_addr na); + +/* Converts string of ip in CIDR notation with a netmask to network_addr. */ +struct network_addr stona(char *str); + +#endif
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/router/router.c b/semestr-4/sieci/pracownia2/router/router.c new file mode 100644 index 0000000..b5e732c --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/router.c @@ -0,0 +1,60 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include <stdio.h> +#include <errno.h> +#include <strings.h> +#include <string.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include "network_addr.h" +#include "utils.h" +#include "dist_vector.h" + +uint16_t read_configuration(struct network_addr** networks, uint16_t **dists) { + uint16_t n; + scanf("%hd", &n); + *networks = malloc(n * sizeof(struct network_addr)); + *dists = malloc(n * sizeof(uint16_t)); + for (int i = 0; i < n; i++) { + char addr[20]; + char _dist[10]; + uint16_t dist; + scanf(" %s %s %hd", addr, _dist, &dist); + (*networks)[i] = stona(addr); + (*dists)[i] = dist; + } + return n; +} + +void router_loop(int sockfd, int networks_number, struct network_addr *networks, uint16_t *dists) { + list_t dv = create_list(); + init_dv(&dv, networks_number, networks); + + printf("Starting the router loop...\n"); + for (;;) { + print_dv(&dv); + propagate_distance_vector(sockfd, networks_number, networks, dists, &dv); + listen_for_routers(sockfd, TURN_LEN_MS, networks_number, networks, dists, &dv); + } +} + +int main() { + struct network_addr* networks; + uint16_t *dists; + int n = read_configuration(&networks, &dists); + int sockfd = get_socket(); + bind_to_port(sockfd, SERVER_PORT); + + router_loop(sockfd, n, networks, dists); + + close(sockfd); + free(networks); + free(dists); +}
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/router/test.c b/semestr-4/sieci/pracownia2/router/test.c new file mode 100644 index 0000000..958ff36 --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/test.c @@ -0,0 +1,52 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include "linked_list.h" +#include <stdlib.h> +#include <stdio.h> + +/* Prints the list of ints to stdio */ +void print_list(list_t list) { + printf("List: "); + reset(&list); + while (list.it != NULL) { + printf("%d, ", *(int *)(list.it->data)); + iterate(&list); + } + printf("\n"); + reset(&list); +} + +int main() { + int n; + scanf("%d", &n); + list_t list = create_list(); + + for (int i = 0; i < n; i++) { + int t; + scanf("%d", &t); + // insert + if (t == 0) { + int val = 0; + scanf("%d", &val); + insert(&list, &val, sizeof(int)); + reset(&list); + } + if (t == 1) { + iterate(&list); + if (list.it != NULL) + printf("it: %d\n", *(int *)list.it->data); + else printf("End of list.\n"); + } + if (t == 2) { + erase_it(&list); + } + if (t == 3) { + print_list(list); + } + } + + free_list(&list); +}
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/router/utils.c b/semestr-4/sieci/pracownia2/router/utils.c new file mode 100644 index 0000000..0c0cae5 --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/utils.c @@ -0,0 +1,208 @@ +/* + * Program: router + * Autor: Franciszek Malinka, 316093 + */ + +#include "utils.h" +#include <arpa/inet.h> +#include <netinet/ip.h> +#include <stdlib.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> + +int get_socket() { + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + fprintf(stderr, "Socket error: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + return sockfd; +} + +void bind_to_port(int sockfd, uint16_t port) { + struct sockaddr_in server_address; + bzero(&server_address, sizeof(server_address)); + server_address.sin_family = AF_INET; + server_address.sin_port = htons(port); + server_address.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(sockfd, (struct sockaddr*)&server_address, sizeof(server_address)) < 0) { + fprintf(stderr, "Bind error: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + int broadcastPermission = 1; + setsockopt (sockfd, SOL_SOCKET, SO_BROADCAST, (void *)&broadcastPermission, sizeof(broadcastPermission)); +} + +long get_time_interval(struct timespec start, struct timespec finish) { + return S_TO_MS(finish.tv_sec - start.tv_sec) + NS_TO_MS(finish.tv_nsec - start.tv_nsec); +} + +int poll_socket_modify_timeout(int sockfd, int *timeout) { + if (*timeout < 0) { + *timeout = 0; + return 0; + } + + struct pollfd fds; + struct timespec start; + struct timespec finish; + + fds.fd = sockfd; + fds.events = POLLIN; + fds.revents = 0; + + clock_gettime(CLOCK_REALTIME, &start); + int result = poll(&fds, 1, *timeout); + clock_gettime(CLOCK_REALTIME, &finish); + + if (result == -1) { + fprintf(stderr, "poll error: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + if (result == 0) { + *timeout = 0; + return 0; + } + + *timeout -= get_time_interval(start, finish); + return result; +} + +size_t send_message(int sockfd, char *buffer, int buffer_len, struct in_addr network) { + struct sockaddr_in network_address; + bzero (&network_address, sizeof(network_address)); + network_address.sin_family = AF_INET; + network_address.sin_port = htons(SERVER_PORT); + network_address.sin_addr = network; + + return sendto(sockfd, buffer, buffer_len, 0, (struct sockaddr*) &network_address, sizeof(network_address)); +} + +size_t recv_message(int sockfd, char *buffer, struct sockaddr_in *sender) { + socklen_t sender_len = sizeof(*sender); + for (int i = 0; i < DV_DATAGRAM_LEN; i++) buffer[i] = 0; + size_t datagram_len = recvfrom(sockfd, buffer, IP_MAXPACKET, 0, + (struct sockaddr*)sender, &sender_len); + if (datagram_len < 0) { + fprintf(stderr, "recvfrom error: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + return datagram_len; +} + +struct vector_item parse_message(char *buffer, struct sockaddr_in *sender) { + struct vector_item res; + uint32_t ip_addr = *(uint32_t *)buffer; + uint32_t dist = *(uint32_t *)(buffer + 5); + dist = ntohl(dist); + + res.network.addr.s_addr = ip_addr; + res.network.netmask = buffer[4]; + res.is_connected_directly = true; + res.via_ip = sender->sin_addr; + res.distance = (dist < INFINITY_DIST ? dist : INFINITY_DIST); + res.reachable = 0; + + char addr[20]; + inet_ntop(AF_INET, &res.network.addr, addr, sizeof(addr)); + char via[20]; + inet_ntop(AF_INET, &sender->sin_addr, via, sizeof(via)); + return res; +} + +void _get_message(struct vector_item item, char *message) { + *(uint32_t *)message = item.network.addr.s_addr; + message[4] = item.network.netmask; + uint32_t distance = htonl(item.distance >= INFINITY_DIST ? INT_MAX : item.distance); + for (int i = 0; i < 4; i++) { + *(message + 5 + i) = *((char *)(&distance) + i); + } +} + +int _send_item(int sockfd, struct network_addr network, struct vector_item item) { + char message[DV_DATAGRAM_LEN + 1]; + _get_message(item, message); + message[DV_DATAGRAM_LEN] = 0; + ssize_t message_len = DV_DATAGRAM_LEN; + + struct in_addr na = get_broadcast_address(network); + + char addr[20]; + inet_ntop(AF_INET, &na, addr, sizeof(addr)); + + int result; + if ((result = send_message(sockfd, message, message_len, na)) != message_len) { + // fprintf(stderr, "sendto error: %s\n", strerror(errno)); + } + return result; +} + +void listen_for_routers(int sockfd, int timeout, int networks_number, struct network_addr *networks, uint16_t *dists, list_t *dv) { + char buffer[IP_MAXPACKET + 1]; + struct sockaddr_in sender; + + while (poll_socket_modify_timeout(sockfd, &timeout)) { + recv_message(sockfd, buffer, &sender); + struct vector_item new_item = parse_message(buffer, &sender); + + bool is_neighbour = false; + for (int i = 0; i < networks_number; i++) { + if (is_from_network(sender.sin_addr, networks[i])) { + is_neighbour = true; + break; + } + } + + /* Shouldn't happen, just in case. */ + if (!is_neighbour) { + char addr[20]; + inet_ntop(AF_INET, &sender.sin_addr, addr, sizeof(addr)); + fprintf(stderr, "Received datagram from %s, he is in none of my networks, ignoring\n. Maybe his VM routing table is configured incorrectly?\n", addr); + continue; + } + + if (!is_from_network(sender.sin_addr, new_item.network)) { + new_item.is_connected_directly = false; + + for (int i = 0; i < networks_number; i++) { + if (is_from_network(sender.sin_addr, networks[i])) { + new_item.distance += dists[i]; + break; + } + } + } + + update_dv_new_item(dv, new_item); + } + update_dv_reachability(dv); +} + +void propagate_distance_vector(int sockfd, int networks_number, struct network_addr *networks, uint16_t *dists, list_t *dv) { + for (int i = 0; i < networks_number; i++) { + reset(dv); + while (dv->it != NULL) { + struct vector_item data = *(struct vector_item *)dv->it->data; + if (!(get_network_address(data.network).s_addr == get_network_address(networks[i]).s_addr) && data.reachable <= REACHABILITY_WAIT_TIME) { + _send_item(sockfd, networks[i], data); + } + iterate(dv); + } + + struct vector_item self_item; + self_item.distance = dists[i]; + self_item.network = networks[i]; + _send_item(sockfd, networks[i], self_item); + } +} + +bool is_from_network(struct in_addr ip_addr, struct network_addr network) { + struct network_addr temp; + temp.addr= ip_addr; + temp.netmask = network.netmask; + return (get_network_address(temp).s_addr == get_network_address(network).s_addr); +}
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/router/utils.h b/semestr-4/sieci/pracownia2/router/utils.h new file mode 100644 index 0000000..edf90d0 --- /dev/null +++ b/semestr-4/sieci/pracownia2/router/utils.h @@ -0,0 +1,52 @@ +#ifndef UTILS_H +#define UTILS_H +#define UTILS_H + +#include "config.h" +#include <stdint.h> +#include <time.h> +#include <poll.h> +#include "network_addr.h" +#include "dist_vector.h" + +#define NS_TO_MS(X) ((long)(X) / (long)1000000) +#define S_TO_MS(X) ((long)(X) * (long)1000) + +/* Returns a UDP socket. */ +int get_socket(); + +/* Binds socket to given port and set the broadcast permission. */ +void bind_to_port(int sockfd, uint16_t port); + +/* Computes the time elapsed between start and finish in miliseconds. */ +long get_time_interval(struct timespec start, struct timespec finish); + +/* Polls given socket with given timeout and changes the timeout accordingly. */ +int poll_socket_modify_timeout(int sockfd, int *timeout); + +/* For debug purposes only. Recieves and prints UDP message. */ +void recv_and_print(int sockfd, int networks_number, struct network_addr *networks); + +/* Sends message in buffer of length buffer_len to addr through given socket. + * IT DOES NOT TERMINATE THE PROGRAM IF SENDTO RETURNS ANY ERRORS! + * One must handle the errors on their own. + */ +size_t send_message(int sockfd, char *buffer, int buffer_len, struct in_addr addr); + +/* Receive message and write it to buffer. */ +size_t recv_message(int sockfd, char *buffer, struct sockaddr_in *sender); + +/* Parse datagram into a vector item. */ +struct vector_item parse_message(char *buffer, struct sockaddr_in *sender); + +/* Listnes for routers for timeout ms. */ +void listen_for_routers(int sockfd, int timeout, int networks_number, struct network_addr *networks, uint16_t *dists, list_t *dv); + +/* Propagates dv to all connected networks. */ +void propagate_distance_vector(int sockfd, int networks_number, struct network_addr *networks, uint16_t *dists, list_t *dv); + +/* Checks if given address is in network range. */ +bool is_from_network(struct in_addr ip_addr, struct network_addr network); + + +#endif
\ No newline at end of file diff --git a/semestr-4/sieci/pracownia2/udp_client.c b/semestr-4/sieci/pracownia2/udp_client.c new file mode 100755 index 0000000..4e7dce4 --- /dev/null +++ b/semestr-4/sieci/pracownia2/udp_client.c @@ -0,0 +1,41 @@ +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +int main(int argc, char * argv[]) +{ + if (argc < 2) { + printf("Usage:\n\t%s [server ip]\n", argv[0]); + return -1; + } + + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + fprintf(stderr, "socket error: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + struct sockaddr_in server_address; + bzero (&server_address, sizeof(server_address)); + server_address.sin_family = AF_INET; + server_address.sin_port = htons(54321); + if (!inet_pton(AF_INET, argv[1], &server_address.sin_addr)) { + printf("Inavlid ip address\n"); + return -1; + } + + char* message = "Hello server!"; + ssize_t message_len = strlen(message); + if (sendto(sockfd, message, message_len, 0, (struct sockaddr*) &server_address, sizeof(server_address)) != message_len) { + fprintf(stderr, "sendto error: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + close (sockfd); + return EXIT_SUCCESS; +} + diff --git a/semestr-4/sieci/pracownia2/udp_server.c b/semestr-4/sieci/pracownia2/udp_server.c new file mode 100755 index 0000000..b5ae6d1 --- /dev/null +++ b/semestr-4/sieci/pracownia2/udp_server.c @@ -0,0 +1,59 @@ +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +int main() +{ + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + fprintf(stderr, "socket error: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + struct sockaddr_in server_address; + bzero (&server_address, sizeof(server_address)); + server_address.sin_family = AF_INET; + server_address.sin_port = htons(54321); + server_address.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind (sockfd, (struct sockaddr*)&server_address, sizeof(server_address)) < 0) { + fprintf(stderr, "bind error: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + for (;;) { + + struct sockaddr_in sender; + socklen_t sender_len = sizeof(sender); + u_int8_t buffer[IP_MAXPACKET+1]; + + ssize_t datagram_len = recvfrom (sockfd, buffer, IP_MAXPACKET, 0, (struct sockaddr*)&sender, &sender_len); + if (datagram_len < 0) { + fprintf(stderr, "recvfrom error: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + char sender_ip_str[20]; + inet_ntop(AF_INET, &(sender.sin_addr), sender_ip_str, sizeof(sender_ip_str)); + printf ("Received UDP packet from IP address: %s, port: %d\n", sender_ip_str, ntohs(sender.sin_port)); + + buffer[datagram_len] = 0; + printf ("%ld-byte message: +%s+\n", datagram_len, buffer); + + char* reply = "Thank you!"; + ssize_t reply_len = strlen(reply); + if (sendto(sockfd, reply, reply_len, 0, (struct sockaddr*)&sender, sender_len) != reply_len) { + fprintf(stderr, "sendto error: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + fflush(stdout); + } + + close (sockfd); + return EXIT_SUCCESS; +} + |