348 lines
8.5 KiB
C
348 lines
8.5 KiB
C
#include <pthread.h>
|
||
|
||
#include <sys/types.h>
|
||
#include <sys/socket.h>
|
||
#include <netinet/in.h>
|
||
#include <arpa/inet.h>
|
||
#include <netdb.h>
|
||
#include <errno.h>
|
||
#include <unistd.h>
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <assert.h>
|
||
|
||
#define LINK_CELL_NAME_SIZE 100
|
||
|
||
#define KEEP_SOCK_MAX(x, y) if (x < ((y) +1)){ x = (y) + 1; }
|
||
|
||
#define FOREACH_SOCKET_IN_SOCKBASKET(i, sockbasket, link) for (i = 0; \
|
||
((i < sockbasket->size) \
|
||
&& (link_basket_get(sockbasket, i, &link)) \
|
||
); \
|
||
i++) \
|
||
if (link != NULL)
|
||
|
||
#define SELECT_TIMEOUT 100000;
|
||
#define REQUEST_INTERVAL 5
|
||
#define REQUEST_TIMEOUT 30
|
||
|
||
#define MIN(x, y) (((x) < (y))?(x):(y))
|
||
|
||
#define bool short
|
||
#define true 1
|
||
#define false 0
|
||
|
||
typedef struct {
|
||
int sock_desc;
|
||
bool is_dead;
|
||
bool is_alive;
|
||
bool is_registered;
|
||
time_t request_stamp;
|
||
time_t answer_stamp;
|
||
char * name;
|
||
} link_cell_t;
|
||
|
||
typedef struct {
|
||
link_cell_t ** data;
|
||
int size;
|
||
int next;
|
||
} link_basket_t;
|
||
|
||
void show_progress(){
|
||
static int prog = 0;
|
||
prog = prog % 100;
|
||
printf("[");
|
||
if (prog < 25){
|
||
printf("|");
|
||
} else if (prog < 50) {
|
||
printf("/");
|
||
} else if (prog < 75) {
|
||
printf("-");
|
||
} else {
|
||
printf("\\");
|
||
}
|
||
printf("] ");
|
||
prog += 25;
|
||
}
|
||
bool link_basket_get (link_basket_t *sb, int index, link_cell_t ** res){
|
||
bool result;
|
||
if (index < sb->size){
|
||
*res = sb->data[ index ];
|
||
/*
|
||
if (*res != NULL){
|
||
printf ("Get at %d == %d\n", index, (*res)->sock_desc);
|
||
} */
|
||
result = 1;
|
||
} else {
|
||
*res = NULL;
|
||
result = 0;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
void link_basket_delete (link_basket_t * sb){
|
||
free (sb->data);
|
||
free (sb);
|
||
}
|
||
|
||
void link_basket_remove (link_basket_t * sb, int index){
|
||
link_cell_t * result = sb->data[ index ];
|
||
if (sb->data[ index ]){
|
||
free(result->name);
|
||
free (result);
|
||
}
|
||
sb->data[ index ] = NULL;
|
||
if (index < sb->next){
|
||
sb->next = index;
|
||
}
|
||
return;
|
||
}
|
||
|
||
void link_basket_add (link_basket_t * sb, int sockfd){
|
||
int i;
|
||
|
||
assert (sb->next != -1); // basket overflow !
|
||
|
||
link_cell_t * cell = (link_cell_t *) malloc (sizeof (link_cell_t));
|
||
|
||
cell->sock_desc = sockfd;
|
||
cell->is_dead = false;
|
||
cell->is_alive = true;
|
||
cell->is_registered = false;
|
||
cell->request_stamp = time(NULL);
|
||
cell->answer_stamp = time(NULL);
|
||
cell->name = (char *) malloc (sizeof (char) * LINK_CELL_NAME_SIZE);
|
||
memset(cell->name, 0, LINK_CELL_NAME_SIZE);
|
||
|
||
sb->data[ sb->next ] = cell;
|
||
|
||
for (i = sb->next; i < sb->size; i++){
|
||
if (sb->data[ i ] == NULL){
|
||
sb->next = i;
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
link_basket_t * link_basket_create (int size){
|
||
link_basket_t * result =
|
||
(link_basket_t *) malloc (sizeof (link_basket_t));
|
||
result->size = size;
|
||
result->data = (link_cell_t **) malloc (sizeof (link_cell_t *) * size);
|
||
result->next = 0;
|
||
|
||
int i;
|
||
for (i = 0; i < result->size; i++){
|
||
result->data[i] = NULL;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
int main (){
|
||
link_basket_t * basket = link_basket_create(10);
|
||
|
||
int main_sock ;
|
||
int port;
|
||
char * hostname;
|
||
char * portstr;
|
||
struct hostent * server;
|
||
struct sockaddr_in * myaddr;
|
||
|
||
main_sock = socket (AF_INET, SOCK_STREAM, 0);
|
||
if (main_sock < 0){
|
||
perror ("Creation de la socket impossible");
|
||
fprintf (stderr,"BOOM at %s:%d\n",__FILE__,__LINE__);
|
||
exit (-1);
|
||
}
|
||
|
||
hostname = getenv ("DETECTOR_HOSTNAME");
|
||
portstr = getenv ("DETECTOR_PORT");
|
||
if ((NULL == hostname) || (NULL == portstr)){
|
||
printf("Environment variables DETECTOR_PORT and DETECTOR_HOSTNAME should have been defined.\n");
|
||
exit(-1);
|
||
}
|
||
sscanf (portstr, "%d", &port);
|
||
|
||
|
||
printf ("Lookup for %s...\n", hostname);
|
||
server = gethostbyname(hostname);
|
||
if (server == NULL){
|
||
fprintf (stderr, "Error, no such host\n");
|
||
exit (-1);
|
||
}
|
||
printf ("Host found\n");
|
||
|
||
|
||
myaddr =
|
||
(struct sockaddr_in *) malloc (sizeof(struct sockaddr_in));
|
||
bzero (myaddr, sizeof(struct sockaddr_in));
|
||
myaddr->sin_family = AF_INET;
|
||
myaddr->sin_port = htons(port);
|
||
|
||
memcpy (&(myaddr->sin_addr.s_addr), server->h_addr, sizeof(u_long));
|
||
//myaddr->sin_addr.s_addr = INADDR_ANY;
|
||
|
||
// on bind sur le port voulu...
|
||
if (bind(main_sock, (struct sockaddr *)myaddr, sizeof(struct sockaddr)) < 0){
|
||
perror("Unable to bind");
|
||
fprintf(stderr,"Cannot bind on port %d of %s\n",port, inet_ntoa(myaddr->sin_addr));
|
||
exit(-1);
|
||
} else {
|
||
printf("Bind on port %d of %s\n",port, inet_ntoa(myaddr->sin_addr));
|
||
}
|
||
|
||
// on fait un listen
|
||
if (listen(main_sock, 10) < 0){
|
||
perror("Unable to listen");
|
||
exit(-1);
|
||
} else {
|
||
printf("Ready to accept connexions.\n");
|
||
}
|
||
|
||
fd_set sock_set;
|
||
struct timeval tv;
|
||
int sock_set_size = 0;
|
||
|
||
FD_ZERO(&sock_set);
|
||
FD_SET(main_sock, &sock_set);
|
||
sock_set_size++;
|
||
|
||
|
||
while(1){
|
||
printf("\r");
|
||
show_progress();
|
||
|
||
tv.tv_sec = 0;
|
||
tv.tv_usec = SELECT_TIMEOUT;
|
||
//
|
||
// si on recoit qqchose sur la socket principale, on fait un accept
|
||
// et on ajoute la nouvelle socket au set
|
||
link_cell_t * link;
|
||
int i;
|
||
|
||
fd_set read_set;//= sock_set;
|
||
FD_ZERO(&read_set);
|
||
FD_SET(main_sock, &read_set);
|
||
KEEP_SOCK_MAX(sock_set_size, main_sock);
|
||
|
||
|
||
// on ajoute tous les socket ouverts au read_set
|
||
FOREACH_SOCKET_IN_SOCKBASKET (i, basket, link) {
|
||
time_t curtime = time(NULL);
|
||
bool must_add = false;
|
||
if (link->is_registered){
|
||
if (link->is_alive){
|
||
// si le programme est en vie
|
||
if (difftime(curtime, link->answer_stamp) > REQUEST_INTERVAL){
|
||
// si le temps n<>cessaire est <20>coul<75> depuis la derniere r<>ponse
|
||
printf ("\nRequesting liveness for '%s'\n", link->name);
|
||
|
||
send(link->sock_desc,"status?", 7, 0);
|
||
link->request_stamp = curtime;
|
||
link->is_alive = false;
|
||
must_add = true;
|
||
} else {
|
||
// sinon on attend le temps n<>cessaire avant de douter...
|
||
// printf ("On attend que le temps s'<27>coule pour '%s'\n", link->name);
|
||
}
|
||
} else {
|
||
// sinon
|
||
if (difftime(curtime, link->request_stamp) > REQUEST_TIMEOUT){
|
||
// ou on le tue...
|
||
// FIXME: retirer de la corbeille a liens...
|
||
printf ("\nTimeout: closing connection of '%s'\n", link->name);
|
||
close(link->sock_desc);
|
||
link_basket_remove(basket, i);
|
||
} else {
|
||
// on est toujours dans les temps de r<>ponse...
|
||
//printf ("\nWaiting for '%s'\n", link->name);
|
||
must_add = true;
|
||
}
|
||
}
|
||
|
||
} else {
|
||
must_add = true;
|
||
}
|
||
|
||
if (must_add){
|
||
//printf ("Adding '%s' (%d) to the set\n", link->name, link->sock_desc);
|
||
FD_SET (link->sock_desc, &read_set);
|
||
KEEP_SOCK_MAX (sock_set_size, link->sock_desc);
|
||
}
|
||
}
|
||
|
||
printf("Select..."); fflush(stdout);
|
||
select(sock_set_size, &read_set, NULL, NULL, &tv);
|
||
printf("done"); fflush(stdout);
|
||
|
||
FOREACH_SOCKET_IN_SOCKBASKET(i, basket, link) {
|
||
time_t curtime = time(NULL);
|
||
|
||
if (FD_ISSET(link->sock_desc, &read_set)){
|
||
// on lit les donn<6E>es recues, et sinon on ferme la socket.
|
||
// on v<>rifie qu'elle sont <20>gales <20> ...
|
||
int buffer_len = 1024;
|
||
char * buffer = (char *) malloc (sizeof(char) * buffer_len);
|
||
int recv_len;
|
||
recv_len = recv(link->sock_desc, buffer, buffer_len, 0);
|
||
|
||
if (recv_len == 0){
|
||
printf("\nClient '%s' has disconnected !\n", link->name);
|
||
link_basket_remove(basket, i);
|
||
} else {
|
||
if ((recv_len >= 9) && (!strncmp("register:", buffer, 9))) {
|
||
buffer[MIN(recv_len, buffer_len - 1)] = '\0';
|
||
|
||
int i=0;
|
||
while(i < buffer_len -1){
|
||
if ((buffer[i] == 0xD) || (buffer[i] == 0xA)) { buffer[i] = '\0'; }
|
||
i++;
|
||
}
|
||
strncpy(link->name, buffer + 9, MIN(recv_len - 9, LINK_CELL_NAME_SIZE));
|
||
printf("\nRegistering client : %s\n", link->name);
|
||
link->is_registered = true;
|
||
link->answer_stamp = curtime;
|
||
|
||
} else if ((recv_len >= 6) && (!strncmp("alive!", buffer, 6))) {
|
||
//printf("Process on fd %d is alive !\n", link->sock_desc);
|
||
link->is_alive = true;
|
||
link->answer_stamp = curtime;
|
||
|
||
} else {
|
||
buffer[99] = '\0';
|
||
printf("\nUnknow message %s", buffer);
|
||
}
|
||
}
|
||
|
||
} else {
|
||
// printf("Rien sur %d\n", link->sock_desc);
|
||
}
|
||
}
|
||
|
||
if (FD_ISSET(main_sock, &read_set)){
|
||
unsigned int sin_size = sizeof(struct sockaddr_in);
|
||
struct sockaddr_in their_addr; /* Adresse du connect<63> */
|
||
int sockfd;
|
||
|
||
sockfd = accept(main_sock, (struct sockaddr *)&their_addr,
|
||
&sin_size);
|
||
link_basket_add(basket, sockfd);
|
||
printf("\nGot new connection at %d\n", sockfd);
|
||
};
|
||
|
||
|
||
// lors d'un accept, on ajoute au tableau des entr<74>es
|
||
// possibles l'hote qui se connecte
|
||
|
||
// regarder les entr<74>es...
|
||
// faire un select dessus
|
||
// garde des timer pour chaque entr<74>e
|
||
// lorsque le temps D est <20>coule pour un timer
|
||
// on envoie un paquet "WIEGEHTS" a la machine
|
||
// et on attend une r<>ponse en moins de 60 sec;
|
||
|
||
}
|
||
return EXIT_SUCCESS;
|
||
}
|