From f0bd9763ea4be22f0f235c0f3aa6628944a56c7e Mon Sep 17 00:00:00 2001
From: Franciszek Malinka <franciszek.malinka@gmail.com>
Date: Thu, 6 May 2021 14:28:59 +0200
Subject: Aktualizacja

---
 .../sieci/pracownia2/franciszek_malinka.tar.xz     | Bin 0 -> 6012 bytes
 .../sieci/pracownia2/franciszek_malinka/config.h   |  15 ++
 .../pracownia2/franciszek_malinka/dist_vector.c    | 114 +++++++++++
 .../pracownia2/franciszek_malinka/dist_vector.h    |  36 ++++
 .../pracownia2/franciszek_malinka/linked_list.c    |  79 ++++++++
 .../pracownia2/franciszek_malinka/linked_list.h    |  42 +++++
 .../sieci/pracownia2/franciszek_malinka/makefile   |  34 ++++
 .../pracownia2/franciszek_malinka/network_addr.c   |  65 +++++++
 .../pracownia2/franciszek_malinka/network_addr.h   |  28 +++
 .../sieci/pracownia2/franciszek_malinka/router.c   |  60 ++++++
 .../sieci/pracownia2/franciszek_malinka/test.c     |  52 ++++++
 .../sieci/pracownia2/franciszek_malinka/utils.c    | 208 +++++++++++++++++++++
 .../sieci/pracownia2/franciszek_malinka/utils.h    |  52 ++++++
 13 files changed, 785 insertions(+)
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka.tar.xz
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/config.h
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/dist_vector.c
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/dist_vector.h
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/linked_list.c
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/linked_list.h
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/makefile
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/network_addr.c
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/network_addr.h
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/router.c
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/test.c
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/utils.c
 create mode 100644 Semestr 4/sieci/pracownia2/franciszek_malinka/utils.h

(limited to 'Semestr 4/sieci')

diff --git a/Semestr 4/sieci/pracownia2/franciszek_malinka.tar.xz b/Semestr 4/sieci/pracownia2/franciszek_malinka.tar.xz
new file mode 100644
index 0000000..ac3b1f7
Binary files /dev/null and b/Semestr 4/sieci/pracownia2/franciszek_malinka.tar.xz differ
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, &current.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
-- 
cgit v1.2.3