361 lines
8.0 KiB
C
Executable File
361 lines
8.0 KiB
C
Executable File
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <time.h>
|
|
|
|
#include "localsys.h"
|
|
#include "netmod.h"
|
|
#include "local_queue.h"
|
|
#include "globals.h"
|
|
#include "mastermod.h"
|
|
|
|
|
|
int ping_tries = 0;
|
|
|
|
int tcp_write(int sock, char s[]) {
|
|
return send(sock, s, BUFLEN_TCP, 0);
|
|
}
|
|
|
|
void* tcp_read(void* s) {
|
|
int sock = (int) s;
|
|
char rec_buf[BUFLEN_TCP];
|
|
char sen_buf[BUFLEN_TCP];
|
|
//char order_buf[BUFLEN_TCP];
|
|
int flag = -1;
|
|
int cand_isset = 0;
|
|
int err;
|
|
|
|
while (1) {
|
|
err = recv(sock, rec_buf, BUFLEN_TCP, 0);
|
|
if (err < 0) {
|
|
printf("Connection error recv from socket id %d\n", sock);
|
|
if (get_role() != SLAVE) set_alive(sock, 0);
|
|
return NULL;
|
|
}
|
|
else if (err == 0){
|
|
printf("Connection with socket id %d was shut down\n", sock);
|
|
if (get_role() != SLAVE) set_alive(sock, 0);
|
|
return NULL;
|
|
}
|
|
flag = (int) rec_buf[0];
|
|
|
|
switch (flag) {
|
|
case PING:
|
|
if (!cand_isset) {
|
|
if (sock == get_master_cand_sock()) {
|
|
sen_buf[0] = (char) CANDIDATE;
|
|
sen_buf[1] = (char) 1;
|
|
cand_isset = 1;
|
|
if (write(sock, sen_buf, BUFLEN_TCP) == -1) printf("Couldnt set candidate!\n");
|
|
}
|
|
else {
|
|
sen_buf[0] = (char) CANDIDATE;
|
|
sen_buf[1] = (char) 0;
|
|
if (write(sock, sen_buf, BUFLEN_TCP) == -1) printf("Couldnt set candidate!\n");
|
|
cand_isset = 1;
|
|
}
|
|
}
|
|
sen_buf[0] = (char) PONG;
|
|
write(sock, sen_buf, BUFLEN_TCP);
|
|
break;
|
|
|
|
case PONG:
|
|
ping_tries = 0;
|
|
break;
|
|
|
|
case STATUS:
|
|
set_elev_state(sock, rec_buf);
|
|
printf("Status update: state %d, floor %d, end destination %d\n", rec_buf[1], rec_buf[2], rec_buf[3]);
|
|
|
|
break;
|
|
|
|
case ORDER:
|
|
printf("New order. Call %d, floor %d\n", rec_buf[1], rec_buf[2]);
|
|
/*order_buf[0] = (char) ORDER;
|
|
order_buf[1] = rec_buf[1];
|
|
order_buf[2] = rec_buf[2];*/
|
|
sen_buf[0] = (char) REQUEST;
|
|
sen_buf[1] = (char) rec_buf[1];
|
|
sen_buf[2] = (char) rec_buf[2];
|
|
|
|
int elev = find_opt_elev((int) rec_buf[1], (int) rec_buf[2]);
|
|
printf("Optimal elevator has socketid %d\n", elev);
|
|
|
|
if (elev != -1) {
|
|
if (write(elev, sen_buf, BUFLEN_TCP) == -1) printf("Couldnt deliver order!\n");
|
|
}
|
|
else add_to_queue((int) rec_buf[1], (int) rec_buf[2]);
|
|
break;
|
|
|
|
case REQUEST:
|
|
elev_set_button_lamp((int) rec_buf[1], (int) rec_buf[2], 1);
|
|
printf("New request\n");
|
|
add_to_queue((int) rec_buf[1], (int) rec_buf[2]);
|
|
break;
|
|
|
|
case CANDIDATE:
|
|
if ((int) rec_buf[1]) {
|
|
printf("Taking role as master candidate\n");
|
|
master_init(sock);
|
|
set_role(MASTER_CAND);
|
|
}
|
|
else {
|
|
printf("Taking role as slave\n");
|
|
set_role(SLAVE);
|
|
}
|
|
break;
|
|
|
|
case (-1):
|
|
printf("Flag is not set\n");
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void* ping_master(void* s) {
|
|
int socket = (int) s;
|
|
char msg[BUFLEN_TCP];
|
|
msg[0] = (char) PING;
|
|
while(1) {
|
|
//printf("-> Ping...\n");
|
|
write(socket, msg, BUFLEN_TCP);
|
|
if(ping_tries == PING_ATTEMPTS) {
|
|
printf("Lost connection to master\n");
|
|
break;
|
|
}
|
|
ping_tries++;
|
|
sleep(TCP_PING_INTERVAL);
|
|
}
|
|
|
|
printf("No pong response!\n");
|
|
net_init();
|
|
return NULL;
|
|
|
|
}
|
|
|
|
void* tcp_listen(void* timeout_id) {
|
|
struct sockaddr_in socklisten_addr;
|
|
struct sockaddr_in master_addr;
|
|
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
socklen_t addrlen;
|
|
|
|
if (sock == -1) {
|
|
perror("socket");
|
|
exit(1);
|
|
}
|
|
|
|
memset(&socklisten_addr, 0, sizeof socklisten_addr);
|
|
socklisten_addr.sin_family = AF_INET;
|
|
socklisten_addr.sin_port = htons(PORT);
|
|
socklisten_addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
int reuse = 1;
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse) == -1) {
|
|
perror("setsockopt");
|
|
close(sock);
|
|
exit(1);
|
|
}
|
|
|
|
if (bind(sock, (struct sockaddr *)&socklisten_addr, sizeof socklisten_addr) == -1) {
|
|
perror("bind");
|
|
close(sock);
|
|
//exit(1);
|
|
}
|
|
|
|
if (listen(sock, 1) < 0) {
|
|
perror("listen");
|
|
exit(1);
|
|
}
|
|
|
|
printf("Waiting to accept...\n");
|
|
addrlen = sizeof master_addr;
|
|
int sock_master = accept(sock, (struct sockaddr *)&master_addr, &addrlen);
|
|
|
|
printf("Connected to master\n");
|
|
set_master_sock(sock_master);
|
|
set_role(SLAVE);
|
|
|
|
pthread_t read_th, ping_th;
|
|
pthread_create(&read_th, NULL, tcp_read, (void*) sock_master);
|
|
pthread_create(&ping_th, NULL, ping_master, (void*) sock_master);
|
|
|
|
printf("Network initialization complete.\n");
|
|
|
|
close(sock);
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
void tcp_connect(char ip[]) {
|
|
struct sockaddr_in sockconn_addr;
|
|
int sockid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
if (sockid == -1) {
|
|
perror("socket");
|
|
exit(1);
|
|
}
|
|
|
|
memset(&sockconn_addr, 0, sizeof sockconn_addr);
|
|
sockconn_addr.sin_family = AF_INET;
|
|
sockconn_addr.sin_port = htons(PORT);
|
|
|
|
if(inet_pton(AF_INET, ip, &sockconn_addr.sin_addr) == 0) {
|
|
perror("Not a valid ip");
|
|
close(sockid);
|
|
exit(1);
|
|
}
|
|
|
|
printf("Connecting to %s ...\n", ip);
|
|
if (connect(sockid, (struct sockaddr *)&sockconn_addr, sizeof sockconn_addr) == -1) {
|
|
perror("connect");
|
|
close(sockid);
|
|
exit(1);
|
|
}
|
|
|
|
printf("Connected to slave with socket ID %d\n", sockid);
|
|
add_slave(sockid);
|
|
|
|
pthread_t read_th;
|
|
pthread_create(&read_th, NULL, tcp_read, (void*) sockid);
|
|
}
|
|
|
|
void udp_broadcast() {
|
|
int sock;
|
|
struct sockaddr_in broadcast_addr;
|
|
struct hostent *he;
|
|
int broadcast = 1;
|
|
|
|
char dummymsg[BUFLEN_UDP] = "\0";
|
|
|
|
if ((he = gethostbyname(IPGROUP)) == NULL) {
|
|
perror("gethostbyname");
|
|
exit(1);
|
|
}
|
|
|
|
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
|
|
perror("socket");
|
|
exit(1);
|
|
}
|
|
|
|
// Allow broadcast
|
|
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast) == -1) {
|
|
perror("setsockopt (SO_BROADCAST)");
|
|
close(sock);
|
|
exit(1);
|
|
}
|
|
|
|
broadcast_addr.sin_family = AF_INET;
|
|
broadcast_addr.sin_port = htons(PORT);
|
|
broadcast_addr.sin_addr = *((struct in_addr *)he->h_addr);
|
|
memset(broadcast_addr.sin_zero, '\0', sizeof broadcast_addr.sin_zero);
|
|
|
|
|
|
printf("Broadcasting to %s\n", IPGROUP);
|
|
if (sendto(sock, dummymsg, strlen(dummymsg), 0, (struct sockaddr *)&broadcast_addr, sizeof broadcast_addr) == -1) {
|
|
perror("sendto");
|
|
exit(1);
|
|
}
|
|
|
|
close(sock);
|
|
}
|
|
|
|
void* udp_listen() {
|
|
int sock;
|
|
struct addrinfo hints;
|
|
struct addrinfo *result, *rp;
|
|
struct sockaddr_in slave_addr;
|
|
char buf[BUFLEN_UDP];
|
|
socklen_t addrlen = sizeof(struct sockaddr);
|
|
|
|
memset(&hints, 0, sizeof hints);
|
|
hints.ai_family = AF_INET;
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
hints.ai_flags = AI_PASSIVE;
|
|
|
|
if (getaddrinfo(NULL, PORTSTR, &hints, &result) != 0) {
|
|
perror("getaddrinfo");
|
|
exit(1);
|
|
}
|
|
|
|
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
|
sock = socket(rp->ai_family, rp->ai_socktype, 0);
|
|
|
|
if (sock == -1)
|
|
continue;
|
|
|
|
if (bind(sock, rp->ai_addr, rp->ai_addrlen) == 0)
|
|
break;
|
|
|
|
close(sock);
|
|
}
|
|
|
|
freeaddrinfo(result);
|
|
printf("Waiting for slaves...\n");
|
|
|
|
while(1) {
|
|
|
|
if (recvfrom(sock, buf, BUFLEN_UDP, 0, (struct sockaddr *)&slave_addr, &addrlen) == -1) {
|
|
perror("recvfrom");
|
|
exit(1);
|
|
}
|
|
|
|
printf("Found new slave\n");
|
|
tcp_connect(inet_ntoa(slave_addr.sin_addr));
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void* timeout(void* tcp_listen_id) {
|
|
sleep(TCP_LISTEN_TIMEOUT);
|
|
|
|
if (get_role() == MASTER) {
|
|
printf("Master is not present\nStarting as master...\n");
|
|
master_init(-1);
|
|
pthread_cancel((pthread_t) tcp_listen_id);
|
|
printf("Start listening for slave broadcasts through UDP\n");
|
|
pthread_t udp_listen_th;
|
|
pthread_create(&udp_listen_th, NULL, udp_listen, NULL);
|
|
printf("Network initialization complete.\n");
|
|
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void net_init() {
|
|
printf("Starting search for master\n");
|
|
|
|
if (get_role() == MASTER_CAND) {
|
|
set_role(MASTER);
|
|
set_master_flag();
|
|
printf("I am master candidate. Taking role as master...\n");
|
|
pthread_t udp_listen_th;
|
|
pthread_create(&udp_listen_th, NULL, udp_listen, NULL);
|
|
}
|
|
else {
|
|
pthread_t tcp_listen_th, timeout_th;
|
|
pthread_create(&tcp_listen_th, NULL, tcp_listen, (void*) timeout_th);
|
|
pthread_create(&timeout_th, NULL, timeout, (void*) tcp_listen_th);
|
|
|
|
udp_broadcast();
|
|
|
|
pthread_join(timeout_th, NULL);
|
|
}
|
|
}
|
|
|
|
|