|
|
@ -1,53 +1,21 @@ |
|
|
|
#include "helpers.h" |
|
|
|
|
|
|
|
/*
|
|
|
|
* Function based on this example: |
|
|
|
* http://man7.org/linux/man-pages/man3/getifaddrs.3.html#EXAMPLE
|
|
|
|
*/ |
|
|
|
int get_own_id(void) { |
|
|
|
int id = -1; |
|
|
|
struct ifaddrs *ifaddr, *ifa; |
|
|
|
int family, s, n; |
|
|
|
char host[NI_MAXHOST]; |
|
|
|
|
|
|
|
if (getifaddrs(&ifaddr) == -1) { |
|
|
|
perror("Couldn't get network interfaces."); |
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
|
|
|
|
// Walks through linked list, maintaining head pointer so we can free list later
|
|
|
|
for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) { |
|
|
|
if (ifa->ifa_addr == NULL) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
family = ifa->ifa_addr->sa_family; |
|
|
|
|
|
|
|
// Gets the address of an AF_INET* interface address
|
|
|
|
if (family == AF_INET || family == AF_INET6) { |
|
|
|
s = getnameinfo(ifa->ifa_addr, |
|
|
|
(family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), |
|
|
|
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); |
|
|
|
if (s != 0) { |
|
|
|
printf("getnameinfo() failed: %s\n", gai_strerror(s)); |
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
|
|
|
|
id = extract_id_from_ip(host); |
|
|
|
if (id < 0) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
#include <unistd.h> |
|
|
|
#include <ifaddrs.h> |
|
|
|
#include <arpa/inet.h> |
|
|
|
#include <signal.h> |
|
|
|
#include <stdio.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <string.h> |
|
|
|
#include <sys/select.h> |
|
|
|
#include <sys/time.h> |
|
|
|
#include <netdb.h> |
|
|
|
#include <time.h> |
|
|
|
#include <assert.h> |
|
|
|
|
|
|
|
freeifaddrs(ifaddr); |
|
|
|
#include "helpers.h" |
|
|
|
|
|
|
|
return(id); |
|
|
|
} |
|
|
|
// Private Functions
|
|
|
|
|
|
|
|
char get_ip_from_sockaddr(sockaddr_in addr) { |
|
|
|
char *get_ip_from_sockaddr(address_t addr) { |
|
|
|
// Beware: The inet_ntoa() function returns a string in a statically allocated buffer, which
|
|
|
|
// subsequent calls will overwrite!
|
|
|
|
return inet_ntoa(addr.sin_addr); |
|
|
@ -57,9 +25,13 @@ char get_ip_from_sockaddr(sockaddr_in addr) { |
|
|
|
// #define FUNCTION_NAME(signal) MAKE_FN_NAME(signal)
|
|
|
|
} |
|
|
|
|
|
|
|
int extract_id_from_ip(const char *ip) { |
|
|
|
// APIs
|
|
|
|
|
|
|
|
node_id_t extract_id_from_ip(const ipv4_t ip) { |
|
|
|
assert(ip); |
|
|
|
|
|
|
|
const char separator[2] = "."; |
|
|
|
int id = 0; |
|
|
|
node_id_t id = 0; |
|
|
|
char *rest, *token, *ip_cp; |
|
|
|
|
|
|
|
ip_cp = malloc(strlen(ip) * sizeof(char)); |
|
|
@ -68,30 +40,34 @@ int extract_id_from_ip(const char *ip) { |
|
|
|
rest = ip_cp; |
|
|
|
token = strtok_r(rest, separator, &rest); |
|
|
|
if (!token || atoi(token) != 10) { |
|
|
|
return -1; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
token = strtok_r(rest, separator, &rest); |
|
|
|
if (!token || atoi(token) != 0) { |
|
|
|
return -1; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
token = strtok_r(rest, separator, &rest); |
|
|
|
if (!token) { |
|
|
|
return -1; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
id = atoi(token) * 100; |
|
|
|
|
|
|
|
token = strtok_r(rest, separator, &rest); |
|
|
|
if (!token) { |
|
|
|
return -1; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
id += atoi(token); |
|
|
|
|
|
|
|
free(ip_cp); |
|
|
|
|
|
|
|
return id; |
|
|
|
} |
|
|
|
|
|
|
|
void set_timer_and_handler(void (*handler)(int), long int wakeup_time) { |
|
|
|
assert(handler); |
|
|
|
|
|
|
|
struct itimerval timer; |
|
|
|
struct sigaction signal_action; |
|
|
|
|
|
|
@ -116,27 +92,30 @@ void set_timer_and_handler(void (*handler)(int), long int wakeup_time) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void create_message(node_handle_t *neighbors, char *new_message, int own_id, |
|
|
|
uint8_t num_neighbors, uint16_t max_message_length) { |
|
|
|
uint16_t create_message(char *new_message, uint16_t max_message_length, node_handle_t *neighbors, |
|
|
|
uint8_t num_neighbors, node_id_t own_id) { |
|
|
|
assert(new_message && neighbors); |
|
|
|
node_handle_t random_node = neighbors[rand() % (num_neighbors)]; |
|
|
|
|
|
|
|
int peer_id = extract_id_from_ip(get_ip_from_sockaddr(node_get_addr(random_node))); |
|
|
|
if (peer_id < 0) { |
|
|
|
node_id_t peer_id = node_get_id(random_node); |
|
|
|
if (!peer_id) { |
|
|
|
perror("Couldn't extract peer's ID."); |
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
|
|
|
|
snprintf(new_message, max_message_length, "%04d_%04d_%ld_%s", own_id, peer_id, time(NULL), |
|
|
|
"It's amazing... It's fantastic!"); |
|
|
|
|
|
|
|
return strlen(new_message); |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Function based on this example: |
|
|
|
* https://www.gnu.org/software/libc/manual/html_node/Inet-Example.html#Inet-Example
|
|
|
|
*/ |
|
|
|
int create_socket_and_listen(uint16_t port, uint8_t backlog_size) { |
|
|
|
int create_socket_and_listen(port_t port, uint8_t backlog_size) { |
|
|
|
int in_sock; |
|
|
|
struct sockaddr_in own_name; |
|
|
|
address_t own_name; |
|
|
|
|
|
|
|
// Creates the socket
|
|
|
|
in_sock = socket(PF_INET, SOCK_STREAM, 0); |
|
|
@ -164,10 +143,11 @@ int create_socket_and_listen(uint16_t port, uint8_t backlog_size) { |
|
|
|
return in_sock; |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: change soccaddr_in to node
|
|
|
|
// TODO: change message to struct
|
|
|
|
void send_message(struct sockaddr_in peer_name, const char *message) { |
|
|
|
void send_message(node_handle_t peer, message_handle_t message) { |
|
|
|
assert(peer && message); |
|
|
|
|
|
|
|
int out_sock; |
|
|
|
address_t peer_address = node_get_addr(peer); |
|
|
|
|
|
|
|
// Creates the socket
|
|
|
|
out_sock = socket(PF_INET, SOCK_STREAM, 0); |
|
|
@ -177,82 +157,134 @@ void send_message(struct sockaddr_in peer_name, const char *message) { |
|
|
|
} |
|
|
|
|
|
|
|
// Connects to the peer
|
|
|
|
if (connect(out_sock, (struct sockaddr *) &peer_name, sizeof(peer_name))) { |
|
|
|
printf("Couldn't connect to peer : %d.\n", get_ip_from_sockaddr(peer_name)); |
|
|
|
// TODO: add timestamp to node
|
|
|
|
if (connect(out_sock, (struct sockaddr *) &(peer_address), sizeof(node_get_addr(peer)))) { |
|
|
|
printf("Couldn't connect to peer : %s.\n", get_ip_from_sockaddr(node_get_addr(peer))); |
|
|
|
node_add_timestamp(peer, time(NULL), false); |
|
|
|
} else { |
|
|
|
// Sends data to the peer
|
|
|
|
write_to_peer(out_sock, message); |
|
|
|
// TODO: add timestamp to node
|
|
|
|
// TODO: add sent_to to message
|
|
|
|
int ignored; |
|
|
|
write_to_peer(out_sock, message_get(message, &ignored)); |
|
|
|
node_add_timestamp(peer, time(NULL), true); |
|
|
|
message_add_sent_to(message, node_get_id(peer)); |
|
|
|
} |
|
|
|
|
|
|
|
close(out_sock); |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: add neighbors array as arg
|
|
|
|
void accept_connection(int sock, struct sockaddr_in *peer_name, fd_set *active_fd_set) { |
|
|
|
node_id_t accept_connection(int sock, address_t *peer_name, fd_set *active_fd_set, |
|
|
|
int *listens_on) { |
|
|
|
assert(peer_name && active_fd_set && listens_on); |
|
|
|
|
|
|
|
size_t peer_name_size = sizeof((*peer_name)); |
|
|
|
int comm_socket = accept(sock, (struct sockaddr *) peer_name, &peer_name_size); |
|
|
|
if (comm_socket < 0) { |
|
|
|
perror("Couldn't accept the connection."); |
|
|
|
// TODO maye be remove this?
|
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
|
|
|
|
*(listens_on) = comm_socket; |
|
|
|
|
|
|
|
char *node_addr = get_ip_from_sockaddr(*peer_name); |
|
|
|
fprintf(stderr, "Connected to host %s, port %hd.\n", |
|
|
|
get_ip_from_sockaddr(*peer_name), ntohs((*peer_name).sin_port)); |
|
|
|
// TODO: add timestamp to node
|
|
|
|
// Maybe do that in zaqar (main)
|
|
|
|
node_addr, ntohs((*peer_name).sin_port)); |
|
|
|
|
|
|
|
FD_SET(comm_socket, active_fd_set); |
|
|
|
|
|
|
|
return extract_id_from_ip(node_addr); |
|
|
|
} |
|
|
|
|
|
|
|
uint16_t checkAddNode(node_handle_t **neighbors, uint16_t num_neighbors , |
|
|
|
address_t peer_name, node_id_t node_id) { |
|
|
|
assert(neighbors); |
|
|
|
|
|
|
|
bool node_exists = false; |
|
|
|
|
|
|
|
for (int i = 0; i < num_neighbors; ++i) { |
|
|
|
if (node_get_id((*neighbors)[i]) == node_id) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!node_exists) { |
|
|
|
node_handle_t *r_neighbors = realloc((*neighbors), |
|
|
|
(num_neighbors + 1) * sizeof(node_handle_t)); |
|
|
|
if (!r_neighbors) { |
|
|
|
free(r_neighbors); |
|
|
|
perror("Unable to reallocate memory for neighbor IP."); |
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
|
|
|
|
(*neighbors) = r_neighbors; |
|
|
|
(*neighbors)[num_neighbors] = node_init(peer_name, node_id); |
|
|
|
|
|
|
|
return num_neighbors + 1; |
|
|
|
} |
|
|
|
|
|
|
|
return num_neighbors; |
|
|
|
} |
|
|
|
|
|
|
|
void write_to_peer(int file_desc, const char *message) { |
|
|
|
assert(message); |
|
|
|
|
|
|
|
int num_bytes = write(file_desc, message, strlen(message) + 1); |
|
|
|
if (num_bytes < 0) { |
|
|
|
perror("Couldn't write to peer."); |
|
|
|
// TODO maye be remove this?
|
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
int read_from_peer(int file_des, uint16_t max_line) { |
|
|
|
int read_from_peer(int file_des, uint16_t max_line, cbuf_handle_t *message_buffer, |
|
|
|
node_handle_t **neighbors, uint16_t num_neighbors) { |
|
|
|
char buffer[max_line]; |
|
|
|
int num_bytes; |
|
|
|
|
|
|
|
num_bytes = read(file_des, buffer, sizeof(buffer)); |
|
|
|
if (num_bytes < 0) { |
|
|
|
perror("Couldn't read from peer."); |
|
|
|
// TODO maye be remove this?
|
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} else if (num_bytes == 0) |
|
|
|
} else if (num_bytes == 0) { |
|
|
|
// End-of-file
|
|
|
|
return -1; |
|
|
|
else { |
|
|
|
} else { |
|
|
|
fprintf(stderr, "Got message: `%s'\n", buffer); |
|
|
|
// TODO: create new message struct
|
|
|
|
|
|
|
|
node_id_t received_from = -1; |
|
|
|
for (int i = 0; i < num_neighbors; ++i) { |
|
|
|
if (node_get_comm_socket((*neighbors)[i])) { |
|
|
|
received_from = node_get_id((*neighbors)[i]); |
|
|
|
node_set_comm_socket((*neighbors)[i], -1); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
message_handle_t new_message = message_init(buffer, num_bytes, received_from); |
|
|
|
circ_buf_put(*(message_buffer), &new_message); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void fread_neighbors(char *AEM_file, node_handle_t **neighbors, uint16_t *num_neighbors, uint16_t port) { |
|
|
|
uint16_t fread_neighbors(char *AEM_file, node_handle_t **neighbors, port_t port) { |
|
|
|
assert(AEM_file && neighbors); |
|
|
|
uint16_t num_neighbors = 0; |
|
|
|
|
|
|
|
// Reads the ARP file checking for connected devices
|
|
|
|
FILE *aems_file = fopen(AEM_file, "r"); |
|
|
|
if (!aems_file) { |
|
|
|
perror("Neighbors file: Failed to open file \"" AEM_file "\""); |
|
|
|
perror("Neighbors file: Failed to open file containing the AEMs."); |
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
|
|
|
|
// Extracts IP addresses found in the file
|
|
|
|
char ip_addr[AEM_BUFFER_LEN]; |
|
|
|
char **neighbors_ips = (char **) malloc(sizeof(char *)); |
|
|
|
if (!neighbors_ips) { |
|
|
|
perror("Unable to allocate memory for neighbors array."); |
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
|
|
|
|
int (*num_neighbors) = 0; |
|
|
|
char **neighbors_ips; |
|
|
|
while (1 == fscanf(aems_file, AEM_LINE_FORMAT, ip_addr)) { |
|
|
|
++(*num_neighbors); |
|
|
|
if ((*num_neighbors) > 1) { |
|
|
|
char **r_neighbors_ips = realloc(neighbors_ips, (*num_neighbors) * sizeof(char *)); |
|
|
|
++num_neighbors; |
|
|
|
|
|
|
|
char **r_neighbors_ips = realloc(neighbors_ips, num_neighbors * sizeof(char *)); |
|
|
|
if (!r_neighbors_ips) { |
|
|
|
free(r_neighbors_ips); |
|
|
|
perror("Unable to reallocate memory for neighbor IP."); |
|
|
@ -260,41 +292,44 @@ void fread_neighbors(char *AEM_file, node_handle_t **neighbors, uint16_t *num_ne |
|
|
|
} |
|
|
|
|
|
|
|
neighbors_ips = r_neighbors_ips; |
|
|
|
} |
|
|
|
|
|
|
|
neighbors_ips[(*num_neighbors) - 1] = (char *) malloc(AEM_BUFFER_LEN * sizeof(char)); |
|
|
|
strcpy(neighbors_ips[(*num_neighbors) - 1], ip_addr); |
|
|
|
neighbors_ips[num_neighbors - 1] = (char *) malloc(AEM_BUFFER_LEN * sizeof(char)); |
|
|
|
strcpy(neighbors_ips[num_neighbors - 1], ip_addr); |
|
|
|
} |
|
|
|
|
|
|
|
// Allocates memory for the new neighbors structs
|
|
|
|
(*neighbors) = (node_handle_t *) malloc((*num_neighbors) * sizeof(node_handle_t)); |
|
|
|
(*neighbors) = (node_handle_t *) malloc(num_neighbors * sizeof(node_handle_t)); |
|
|
|
if (!neighbors_ips) { |
|
|
|
perror("Unable to allocate memory for nodes."); |
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
|
|
|
|
// Creates the neighbors structs
|
|
|
|
for (uint8_t i = 0; i < (*num_neighbors); ++i) { |
|
|
|
struct sockaddr_in peer_name; |
|
|
|
for (uint8_t i = 0; i < num_neighbors; ++i) { |
|
|
|
address_t peer_name; |
|
|
|
init_sockaddr(&peer_name, neighbors_ips[i], port); |
|
|
|
(*neighbors)[(*num_neighbors)++] = node_init(peer_name); |
|
|
|
(*neighbors)[num_neighbors++] = node_init(peer_name, |
|
|
|
extract_id_from_ip(get_ip_from_sockaddr(peer_name))); |
|
|
|
} |
|
|
|
|
|
|
|
fclose(aems_file); |
|
|
|
|
|
|
|
return num_neighbors; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Function based on this example: |
|
|
|
* https://www.gnu.org/software/libc/manual/html_node/Inet-Example.html#Inet-Example
|
|
|
|
*/ |
|
|
|
void init_sockaddr(struct sockaddr_in *peer_name, const char *ipv4, uint16_t port) { |
|
|
|
void init_sockaddr(address_t *peer_name, const ipv4_t hostname, port_t port) { |
|
|
|
assert(peer_name && hostname); |
|
|
|
struct hostent *hostinfo; |
|
|
|
|
|
|
|
peer_name->sin_family = AF_INET; |
|
|
|
peer_name->sin_port = htons(port); |
|
|
|
hostinfo = gethostbyname(ipv4); |
|
|
|
hostinfo = gethostbyname(hostname); |
|
|
|
if (hostinfo == NULL) { |
|
|
|
fprintf(stderr, "Unknown host %s.\n", ipv4); |
|
|
|
fprintf(stderr, "Unknown host %s.\n", hostname); |
|
|
|
exit(EXIT_FAILURE); |
|
|
|
} |
|
|
|
|