m2.hang-detector/src/detector-server.c
2006-03-17 17:04:59 +00:00

351 lines
8.5 KiB
C
Raw Permalink Blame History

/* vim: set sw=4 ts=4 si et: */
#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;
}