You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

380 lines
11 KiB

#include "interface.h"
#include <errno.h>
#define return_error(fonction) do { perror(#fonction); return -1; } while(0)
int char_hexa_to_uint32(const char *const argv, uint32_t *nombre) {
char* error;
error = (char*) argv;
*nombre = (uint32_t) strtol(argv,&error,16);
return (error!=argv);
}
int char_to_int(const char *const argv, int *nombre) {
char* error;
error = (char*) argv;
*nombre = (int) strtol(argv,&error,10);
return (error!=argv);
}
struct subscription_t* list_subscription_add_cell(struct list_subscription_t *list_p) {
struct list_subscription_cell_t *cell_p;
if((cell_p = (struct list_subscription_cell_t*) malloc(sizeof(struct list_subscription_cell_t))) == NULL) {
fputs("bad alloc\n", stderr);
return NULL;
}
if(list_p->list_p) {
(list_p->list_p)->next_p->prev_p = cell_p;
cell_p->next_p = (list_p->list_p)->next_p;
(list_p->list_p)->next_p = cell_p;
cell_p->prev_p = list_p->list_p;
} else
cell_p->prev_p = cell_p->next_p = cell_p;
list_p->list_p = cell_p;
if(!list_p->read_p)
list_p->read_p = list_p->list_p;
return &(cell_p->subscription);
}
struct subscription_t* list_subscription_search_cell(struct list_subscription_t *const list_p, uint32_t addr) {
struct list_subscription_cell_t *tmp_p;
tmp_p = (struct list_subscription_cell_t*) list_p->list_p;
if(list_p && list_p->list_p) {
do {
if(tmp_p->subscription.addr == addr)
return &(tmp_p->subscription);
tmp_p = tmp_p->next_p;
} while(tmp_p != list_p->list_p);
}
return NULL;
}
int list_subscription_remove_cell(struct list_subscription_t *list_p, struct subscription_t *subscription_p) {
struct list_subscription_cell_t *cell_p;
if(!list_p || !list_p->list_p || !list_p->list_p->next_p)
return -1;
cell_p = (struct list_subscription_cell_t*) subscription_p;
cell_p->prev_p->next_p = cell_p->next_p;
cell_p->next_p->prev_p = cell_p->prev_p;
if(list_p->list_p == cell_p)
list_p->list_p=cell_p->prev_p;
if(list_p->list_p == cell_p)
list_p->list_p = NULL;
if(list_p->read_p == cell_p)
list_p->read_p = list_p->list_p;
free(cell_p);
return 1;
}
int open_socket_listen(int port_listen) {
int fd_sock;
if( (fd_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return_error(socket);
/* option reuseaddr et socket non blocante */
{
int true;
true = 1;
if( setsockopt(fd_sock, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(struct sockaddr_in)) == -1)
return_error(setsockopt);
}
{
int opts;
if ((opts = fcntl(fd_sock,F_GETFL)) < 0)
return_error(fcntl);
opts = (opts | O_NONBLOCK);
if (fcntl(fd_sock,F_SETFL,opts) < 0)
return_error(fcntl);
}
{
struct sockaddr_in sock_command_listen;
memset(&sock_command_listen, 0, sizeof(struct sockaddr_in));
sock_command_listen.sin_addr.s_addr = inet_addr("127.0.0.1");
sock_command_listen.sin_port = htons(port_listen);
sock_command_listen.sin_family = AF_INET;
if(bind(fd_sock, (struct sockaddr*) &sock_command_listen, sizeof(struct sockaddr)) == -1)
return_error(bind);
}
if( listen(fd_sock, 0) == -1)
return_error(listen);
return fd_sock;
}
int list_subscription_init(struct list_subscription_t *list_p, int port_listen) {
if((list_p->fd_command_listen = open_socket_listen(port_listen)) == -1)
return -1;
list_p->fd_command_client = -1;
list_p->list_p=NULL;
list_p->read_p=NULL;
return 1;
}
void list_subscription_destroy(struct list_subscription_t *list_p) {
if(list_p->fd_command_listen >= 0)
close(list_p->fd_command_listen);
list_p->fd_command_listen = -1;
if(list_p->fd_command_client >= 0)
close(list_p->fd_command_client);
list_p->fd_command_client = -1;
while(list_p->list_p) {
/* on ferme la connexion */
if(list_p->list_p->subscription.fd_listen >= 0)
close(list_p->list_p->subscription.fd_listen);
list_p->list_p->subscription.fd_listen = -1;
if(list_p->list_p->subscription.fd_client >= 0)
close(list_p->list_p->subscription.fd_client);
list_p->list_p->subscription.fd_client = -1;
list_subscription_remove_cell(list_p, &(list_p->list_p->subscription));
}
}
int subscribe(struct list_subscription_t *list_p, uint32_t address, int port) {
struct subscription_t *subscription_p;
/* on vérifie que l'adresse n'est pas déjà inscrite */
if(list_subscription_search_cell(list_p, address) != NULL) {
fputs("il existe déjà une inscription pour cette adresse\n", stderr);
return -1;
}
/* on ajoute l'enregistrement dans la liste chainée */
if((subscription_p = list_subscription_add_cell(list_p)) == NULL ) {
fputs("impossible d'ajouter l'inscription\n", stderr);
return -1;
}
subscription_p->addr = address;
subscription_p->fd_client = -1;
if((subscription_p->fd_listen = open_socket_listen(port)) == -1) {
list_subscription_remove_cell(list_p, subscription_p);
return -1;
}
return 1;
}
int unsubscribe(struct list_subscription_t *list_p, uint32_t address) {
struct subscription_t *subscription_p;
/* on vérifie que l'adresse est inscrite */
if((subscription_p = list_subscription_search_cell(list_p, address)) == NULL) {
fputs("il n'existe pas d'inscription pour cette adresse\n", stderr);
return -1;
}
if(subscription_p->fd_listen >= 0)
close(subscription_p->fd_listen);
subscription_p->fd_listen = -1;
if(subscription_p->fd_client >= 0)
close(subscription_p->fd_client);
subscription_p->fd_client = -1;
/* on supprime dans la liste chainée */
if(list_subscription_remove_cell(list_p, subscription_p) == -1)
return -1;
return 1;
}
int command(struct list_subscription_t *list_p, char *command_raw_p) {
char *command, *command_args;
uint32_t address;
int port;
command = strtok_r(command_raw_p, " ", &command_args);
if(strcmp(command, "new")==0) {
puts("new");
} else if(strcmp(command, "subscribe")==0) {
/* on récupère l'adresse */
if(!command_args || char_hexa_to_uint32(command_args, &address) == -1) {
fputs("addresse incorrecte\n", stderr);
return -1;
}
/* on récupère le port */
strtok_r(command_args, " ", &command_args);
if(!command_args || char_to_int(command_args, &port) == -1 || port <= 0 || port >= 65536) {
fputs("port incorrect\n", stderr);
return -1;
}
/* on tente l'ajout */
if(subscribe(list_p, address, port) == -1)
return -1;
} else if(strcmp(command, "unsubscribe")==0) {
/* on récupère l'adresse */
if(!command_args || char_hexa_to_uint32(command_args, &address) == -1) {
fputs("addresse incorrecte\n", stderr);
return -1;
}
/* on tente la suppression */
if(unsubscribe(list_p, address) == -1)
return -1;
} else {
puts("commande inconnue");
return -1;
}
return 1;
}
int send_message(struct list_subscription_t *list_p, struct message_t *message_p) {
struct subscription_t *subscription_p;
if(!message_p || !(message_p->data_p)) /* on ne vient pas avec un message vide */
return -1;
/* on vérifie que l'adresse est inscrite */
if((subscription_p = list_subscription_search_cell(list_p, message_p->addr)) == NULL || subscription_p->fd_client < 0)
return 0;
return send(subscription_p->fd_client, message_p->data_p, message_p->length, 0);
}
int read_message(struct list_subscription_t *list_p, struct message_t *message_p) {
fd_set fdfs;
int nb_ready_fd, message_found;
char buffer[512];
ssize_t recv_length;
if(message_p && message_p->data_p) /* on ne vient pas avec un message dont le data est alloué */
return -1;
message_found = 0;
FD_ZERO(&fdfs);
if(list_p->fd_command_listen >= 0)
FD_SET(list_p->fd_command_listen, &fdfs);
if(list_p->fd_command_client >= 0)
FD_SET(list_p->fd_command_client, &fdfs);
/* on ajoute les fd de la liste */
if(list_p && list_p->list_p) {
struct list_subscription_cell_t *cell_p;
cell_p = list_p->list_p;
do {
if(cell_p->subscription.fd_listen >= 0)
FD_SET(cell_p->subscription.fd_listen, &fdfs);
if(cell_p->subscription.fd_client >= 0)
FD_SET(cell_p->subscription.fd_client, &fdfs);
cell_p = cell_p->next_p;
} while(cell_p != list_p->list_p);
}
{
struct timeval timeout = {0};
nb_ready_fd = select(FD_SETSIZE, &fdfs, NULL, NULL, &timeout);
}
if(nb_ready_fd < 0) /* erreur */
return_error(select);
else if(nb_ready_fd == 0) /* timeout écoulé */
return 0;
/* les sockets pour les commandes */
if(list_p->fd_command_client >= 0 && FD_ISSET(list_p->fd_command_client, &fdfs)) {
if( (recv_length = recv(list_p->fd_command_client, buffer, sizeof(buffer), MSG_DONTWAIT)) == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
perror("recv");
else if(recv_length == 0) {
close(list_p->fd_command_client);
list_p->fd_command_client = -1;
} else {
buffer[recv_length-1]='\0';
command(list_p, buffer);
}
}
if(list_p->fd_command_listen >= 0 && FD_ISSET(list_p->fd_command_listen, &fdfs)) {
if( (list_p->fd_command_client = accept(list_p->fd_command_listen, NULL, NULL)) == -1)
perror("accept");
}
if(list_p && list_p->list_p && message_p) {
struct list_subscription_cell_t *cell_p;
/* les sockets connectés */
cell_p = list_p->read_p;
do {
if(list_p->read_p->subscription.fd_client >= 0 && FD_ISSET(list_p->read_p->subscription.fd_client, &fdfs)) {
if( (recv_length = recv(list_p->read_p->subscription.fd_client, buffer, sizeof(buffer), MSG_DONTWAIT)) == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
perror("recv");
else if(recv_length == 0) {
close(list_p->read_p->subscription.fd_client);
list_p->read_p->subscription.fd_client = -1;
} else {
/* on remplit le message */
if((message_p->data_p = malloc(recv_length)) == NULL) {
fputs("bad alloc\n", stderr);
return -1;
}
memcpy(message_p->data_p, buffer, recv_length);
message_p->length = recv_length;
message_p->addr = list_p->read_p->subscription.addr;
message_found = 1;
}
}
list_p->read_p = list_p->read_p->next_p;
} while(list_p->read_p != cell_p && !message_found);
/* les sockets en écoute */
cell_p = list_p->list_p;
do {
if(cell_p->subscription.fd_listen >= 0 && FD_ISSET(cell_p->subscription.fd_listen, &fdfs)) {
if( (cell_p->subscription.fd_client = accept(cell_p->subscription.fd_listen, NULL, NULL)) == -1)
perror("accept");
}
cell_p = cell_p->next_p;
} while(list_p->list_p != cell_p);
}
return message_found;
}
/*
int quit = 0;
void quit_signal_handler(int signal) {
quit = 1;
}
int main(int argc, char **argv) {
struct list_subscription_t list;
struct message_t message;
signal(SIGINT, quit_signal_handler);
if(list_subscription_init(&list, atoi(argv[1])) == -1)
return 1;
memset(&message, 0, sizeof(struct message_t));
do {
switch(read_message(&list, &message)) {
case 1:
((char*)message.data_p)[message.length-1] ='\0';
printf("message pour %"PRIx32" (%ld octets) : « %s »\n", message.addr, message.length, ((char*) (message.data_p)));
send_message(&list, &message);
free(message.data_p);
message.data_p = NULL;
break;
case 0:
puts("pas de message");
break;
case -1:
puts("erreur");
break;
}
} while(!quit);
list_subscription_destroy(&list);
return 0;
}
*/