From c5fcf7179a83ef65c86c6a4a390029149e518649 Mon Sep 17 00:00:00 2001 From: Franciszek Malinka Date: Tue, 5 Oct 2021 21:49:54 +0200 Subject: Duzy commit ze smieciami --- .../sieci/pracownia2/franciszek_malinka/utils.c | 208 +++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 semestr-4/sieci/pracownia2/franciszek_malinka/utils.c (limited to 'semestr-4/sieci/pracownia2/franciszek_malinka/utils.c') 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 +#include +#include +#include +#include +#include +#include + +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 -- cgit v1.2.3