816 lines
26 KiB
C
816 lines
26 KiB
C
/*
|
|
* This file is part of the rtap localisation project.
|
|
*/
|
|
|
|
|
|
#include "owlps-aggregator.h"
|
|
|
|
|
|
|
|
cfg_t *cfg ; // Structure contenant la configuration
|
|
|
|
char* ip_bytes_to_string(unsigned char *ip_binary)
|
|
{
|
|
int taille = 16, i = 0;
|
|
for(i = 0; i < 4; i++)
|
|
{
|
|
if(ip_binary[i] < 0x64)
|
|
taille--;
|
|
if(ip_binary[i] < 0x10)
|
|
taille--;
|
|
}
|
|
|
|
char *ret = malloc(sizeof(char) * taille) ;
|
|
|
|
|
|
sprintf(ret, "%d.%d.%d.%d", ip_binary[0], ip_binary[1], ip_binary[2], ip_binary[3]) ;
|
|
ret[taille-1] = '\0' ;
|
|
|
|
return ret ;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int ret = 0 ; // Valeur de retour du programme
|
|
couple_list *couples = NULL ; // Liste des données traitées
|
|
struct sigaction action ; // Structure de mise en place des gestionnaires de signaux
|
|
int sockfd ; // Socket d'écoute UDP
|
|
int nread ; // Retour de recvfrom
|
|
struct sockaddr_in client; // Structure pour le client UDP
|
|
socklen_t client_len = sizeof(client) ; // Taille du client pour la socket
|
|
couple_message message ; // Message lu sur la socket
|
|
pthread_t thread ; // Thread pour la fonction de surveillance de la liste d'informations agrégées
|
|
char *ap_mac_string, *mobile_mac_string ; // Pointeurs pour retour de mac_bytes_to_string()
|
|
char *mobile_ip_string ;
|
|
BOOL ref;
|
|
|
|
cfg_opt_t opts[] = { // Options reconnues par confuse dans le fichier de config
|
|
CFG_INT("listening_port", AGGREGATE_DEFAULT_PORT, CFGF_NONE), // Port d'écoute
|
|
CFG_INT("positioner_port", POSITIONER_DEFAULT_PORT, CFGF_NONE), // Port d'envoi sur le serveur de calcul
|
|
CFG_STR("positioner_ip", POSITIONER_DEFAULT_IP, CFGF_NONE), // Adresse IP du serveur de géolocalisation
|
|
CFG_STR("output_file", "", CFGF_NONE), // Fichier de sortie
|
|
CFG_INT("aggregate_timeout", DEFAULT_AGGREGATE_TIMEOUT, CFGF_NONE), // Timeout d'agrégation (en millisecondes)
|
|
CFG_INT("keep_timeout", DEFAULT_KEEP_TIMEOUT, CFGF_NONE), // Temps que l'on conserve les données dans la liste (en millisecondes)
|
|
CFG_INT("check_interval", DEFAULT_CHECK_INTERVAL, CFGF_NONE), // Temps entre deux vérifications de la liste (en micro-secondes)
|
|
CFG_STR("host_db", DEFAULT_DB_HOST, CFGF_NONE),
|
|
CFG_STR("db_name", DEFAULT_DB_NAME, CFGF_NONE),
|
|
CFG_STR("user_db", DEFAULT_DB_USER, CFGF_NONE),
|
|
CFG_STR("pass_db", DEFAULT_DB_PASS, CFGF_NONE),
|
|
CFG_END() } ;
|
|
char *config_file ; // Nom du fichier de configuration
|
|
int opt ; // Retour de getopt
|
|
|
|
|
|
/* L'option -f sert à spécifier un fichier de configuration alternatif,
|
|
* on regarde en premier si elle est présente */
|
|
do
|
|
opt = getopt(argc, argv, OPTIONS) ;
|
|
while (opt != 'f' && opt != -1) ;
|
|
if (opt == 'f')
|
|
{
|
|
config_file = malloc((strlen(optarg) + 1) * sizeof(char)) ;
|
|
strcpy(config_file, optarg) ;
|
|
}
|
|
else // Si -f n'est pas présente, on utilise le fichier de config par défaut
|
|
{
|
|
config_file = malloc((strlen(DEFAULT_CONFIG_FILE) + 1) * sizeof(char)) ;
|
|
strcpy(config_file, DEFAULT_CONFIG_FILE) ;
|
|
}
|
|
|
|
/* Lecture du fichier de configuration */
|
|
cfg = cfg_init(opts, CFGF_NONE) ; // Initialisation des options
|
|
if (cfg_parse(cfg, config_file) == CFG_PARSE_ERROR)
|
|
{
|
|
free(config_file) ;
|
|
return ERR_PARSING_CONFIG_FILE ;
|
|
}
|
|
free(config_file) ;
|
|
|
|
/* Lecture des arguments de la ligne de commandes */
|
|
optind = 1 ; // On reprend l'analyse des arguments au début
|
|
while ((opt = getopt(argc, argv, OPTIONS)) != -1)
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 'a' :
|
|
cfg_setint(cfg, "aggregate_timeout", strtol(optarg, NULL, 0)) ;
|
|
break ;
|
|
case 'c' :
|
|
cfg_setint(cfg, "check_interval", strtol(optarg, NULL, 0)) ;
|
|
break ;
|
|
case 'f' : // Fichier de configuration
|
|
// Déjà traité.
|
|
break ;
|
|
case 'H' :
|
|
cfg_setstr(cfg, "host_db", optarg) ;
|
|
break ;
|
|
case 'i' :
|
|
cfg_setstr(cfg, "positioner_ip", optarg) ;
|
|
break ;
|
|
case 'k' :
|
|
cfg_setint(cfg, "keep_timeout", strtol(optarg, NULL, 0)) ;
|
|
break ;
|
|
case 'l' :
|
|
cfg_setint(cfg, "listening_port", strtol(optarg, NULL, 0)) ;
|
|
break ;
|
|
case 'N' :
|
|
cfg_setstr(cfg, "db_name", optarg) ;
|
|
break ;
|
|
case 'o' :
|
|
cfg_setstr(cfg, "output_file", optarg) ;
|
|
break ;
|
|
case 'p' :
|
|
cfg_setint(cfg, "positioner_port", strtol(optarg, NULL, 0)) ;
|
|
break ;
|
|
case 'P' :
|
|
cfg_setstr(cfg, "pass_db", optarg) ;
|
|
break ;
|
|
case 'U' :
|
|
cfg_setstr(cfg, "user_db", optarg) ;
|
|
break ;
|
|
default :
|
|
print_usage(argv[0]) ;
|
|
return ERR_BAD_USAGE ;
|
|
}
|
|
}
|
|
|
|
/* Vérification des arguments */
|
|
// output_file //
|
|
if (cfg_getstr(cfg, "output_file")[0] == '\0')
|
|
{
|
|
fprintf(stderr, "Erreur ! Vous devez spécifier un fichier de sortie.\n") ;
|
|
print_usage(argv[0]) ;
|
|
return ERR_BAD_USAGE ;
|
|
}
|
|
// positioner_ip //
|
|
if (cfg_getstr(cfg, "positioner_ip")[0] == '\0')
|
|
{
|
|
fprintf(stderr, "Erreur ! Vous devez spécifier l'adresse IP du serveur de géolocalisation.\n") ;
|
|
print_usage(argv[0]) ;
|
|
return ERR_BAD_USAGE ;
|
|
}
|
|
// aggregate_timeout //
|
|
if (cfg_getint(cfg, "aggregate_timeout") < 0)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "Attention ! aggregate_timeout n'admet pas de valeur négative : application de la valeur par défaut.\n") ;
|
|
#endif // DEBUG
|
|
cfg_setint(cfg, "aggregate_timeout", DEFAULT_AGGREGATE_TIMEOUT) ;
|
|
}
|
|
// keep_timeout //
|
|
if (cfg_getint(cfg, "keep_timeout") < 0)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "Attention ! keep_timeout n'admet pas de valeur négative : application de la valeur par défaut.\n") ;
|
|
#endif // DEBUG
|
|
cfg_setint(cfg, "keep_timeout", DEFAULT_KEEP_TIMEOUT) ;
|
|
}
|
|
// check_interval //
|
|
if (cfg_getint(cfg, "check_interval") < 0)
|
|
{
|
|
#ifdef DEBUG
|
|
fprintf(stderr, "Attention ! check_interval n'admet pas de valeur négative : application de la valeur par défaut.\n") ;
|
|
#endif // DEBUG
|
|
cfg_setint(cfg, "check_interval", DEFAULT_CHECK_INTERVAL) ;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
/* Affichage de la configuration */
|
|
fprintf(stderr, "Configuration :\n") ;
|
|
cfg_print(cfg, stderr) ;
|
|
#endif // DEBUG
|
|
|
|
run = TRUE ;
|
|
|
|
/* Mise en place des gestionnaires de signaux */
|
|
sigemptyset(&action.sa_mask) ;
|
|
action.sa_handler = sigint_handler ;
|
|
sigaction(SIGINT, &action, NULL) ;
|
|
action.sa_handler = sigterm_handler ;
|
|
sigaction(SIGTERM, &action, NULL) ;
|
|
|
|
/* Création de la socket UDP */
|
|
if ((sockfd = create_udp_listening_socket(cfg_getint(cfg, "listening_port"))) < 0)
|
|
{
|
|
fprintf(stderr, "Erreur ! Impossible d'écouter sur le port %ld.\n", cfg_getint(cfg, "listening_port")) ;
|
|
return ERR_CREATING_SOCKET ;
|
|
}
|
|
|
|
/* Création du thread */
|
|
pthread_create(&thread, NULL, (void *) &monitor_couple_list, &couples) ;
|
|
|
|
/* Lecture sur la socket */
|
|
while (run)
|
|
{
|
|
nread = recvfrom(sockfd, &message, sizeof(message), 0, (struct sockaddr *) &client, &client_len) ;
|
|
|
|
if (nread <= 0)
|
|
{
|
|
if (run)
|
|
{
|
|
fprintf(stderr, "Aucun message reçu du client !\n") ;
|
|
ret = ERR_NO_MESSAGE_RECEIVED ;
|
|
}
|
|
break ;
|
|
}
|
|
ap_mac_string = mac_bytes_to_string(message.ap_mac_addr_bytes) ;
|
|
mobile_mac_string = mac_bytes_to_string(message.mobile_mac_addr_bytes) ;
|
|
mobile_ip_string = ip_bytes_to_string(message.mobile_ip_addr_bytes) ;
|
|
printf("\n\
|
|
*** Message reçu du client ***\n\
|
|
\tMAC AP : %s\n\
|
|
\tMAC mobile : %s\n\
|
|
\tIP mobile : %s\n\
|
|
\tNuméro de séquence (heure de la demande) : %llu\n\
|
|
\tHeure d'arrivée de la demande de localisation sur l'AP : %llu\n\
|
|
\tSignal : %d dBm\n\
|
|
\tPosition X : %f\n\
|
|
\tPosition Y : %f\n\
|
|
\tPosition Z : %f\n\
|
|
\tDirection : %hhd\n\
|
|
",
|
|
ap_mac_string,
|
|
mobile_mac_string,
|
|
mobile_ip_string,
|
|
timeval_to_ms(message.request_time),
|
|
timeval_to_ms(message.start_time),
|
|
message.antenna_signal_dbm - 0x100,
|
|
message.x_position,
|
|
message.y_position,
|
|
message.z_position,
|
|
message.direction
|
|
) ;
|
|
free(ap_mac_string) ;
|
|
free(mobile_mac_string) ;
|
|
free(mobile_ip_string) ;
|
|
|
|
ref = (message.x_position != 0 && message.y_position != 0 && message.z_position != 0)? TRUE : FALSE;
|
|
|
|
Db_write_request(message, ref);
|
|
if(!ref) got_couple_info(&couples, message) ;
|
|
}
|
|
|
|
(void) close(sockfd) ; // Fermeture de la socket
|
|
free_couple_list(&couples) ; // Nettoyage de la liste
|
|
cfg_free(cfg) ; // Nettoyage de la configuration
|
|
|
|
printf("%s : fin.\n", argv[0]) ;
|
|
return ret ;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fonction du thread, qui surveille la liste et envoie les infos au serveur de localisation au bout du timeout */
|
|
void* monitor_couple_list(couple_list **couples)
|
|
{
|
|
couple_list *couple_ptr, *couple_prev ;
|
|
couple_info_list *couple_info_ptr ;
|
|
struct timeval current_time ;
|
|
FILE *fd = NULL ;
|
|
char *ap_mac_string ;
|
|
unsigned long sub ; // Résultat de sub_date().
|
|
|
|
struct sockaddr_in serv;
|
|
struct sockaddr_in client ;
|
|
socklen_t serv_len = sizeof(serv);
|
|
request demande;
|
|
couple_info info;
|
|
int sockfd;
|
|
|
|
sockfd = create_udp_sending_socket(cfg_getstr(cfg, "positioner_ip"), cfg_getint(cfg, "positioner_port"), &serv, &client);
|
|
|
|
fd = fopen(cfg_getstr(cfg, "output_file"), "a") ; // Ouverture du fichier de sortie en ajout
|
|
if (fd == NULL) // Si ouverture échouée,
|
|
{
|
|
perror("Impossible d'ouvrir le fichier de sortie ") ;
|
|
fprintf(stderr, "Redirection de la sortie sur la sortie standard.") ;
|
|
fd = stdout ; // on redirige sur stdout
|
|
}
|
|
|
|
while (run)
|
|
{
|
|
couple_ptr = *couples ;
|
|
couple_prev = NULL ;
|
|
couple_info_ptr = NULL ;
|
|
gettimeofday(¤t_time, NULL) ;
|
|
|
|
while (couple_ptr != NULL) // Parcours de la liste
|
|
{
|
|
sub = sub_date(couple_ptr->start_time, current_time) ;
|
|
|
|
if (couple_ptr->info != NULL) // Si le couple atteint n'a pas déjà été traité
|
|
{
|
|
if (sub > (unsigned long) cfg_getint(cfg, "aggregate_timeout")) // Si le timeout est atteint,
|
|
{
|
|
printf("* Timeout dépassé.") ;
|
|
#ifdef DEBUG
|
|
printf(" sub=%lu > aggregate_timeout=%ld\n", sub, cfg_getint(cfg, "aggregate_timeout")) ;
|
|
#else // DEBUG
|
|
putchar('\n') ;
|
|
#endif // DEBUG
|
|
|
|
#ifdef TIMESTAMP
|
|
fprintf(fd, "%llu;", timeval_to_ms(couple_ptr->request_time)) ; // Inscription de la date de la demande (sur le mobile) dans le fichier
|
|
#endif // TIMESTAMP
|
|
fprintf(fd, "%0.2f;%0.2f;%0.2f;%hhd", couple_ptr->x_position, couple_ptr->y_position, couple_ptr->z_position, couple_ptr->direction) ; // Inscription des infos du couple dans le fichier
|
|
|
|
memcpy(demande.mobile_mac_addr_bytes, couple_ptr -> mobile_mac_addr_bytes, 6);
|
|
demande.request_time = couple_ptr->request_time;
|
|
demande.nb_couples = 0 ;
|
|
|
|
couple_info_ptr = couple_ptr->info ;
|
|
while (couple_info_ptr != NULL)
|
|
{
|
|
demande.nb_couples++;
|
|
couple_info_ptr = couple_info_ptr->next ;
|
|
}
|
|
sendto(sockfd, (void *)&demande, sizeof(request), 0, (struct sockaddr *)&serv, serv_len) ;
|
|
|
|
|
|
couple_info_ptr = couple_ptr->info ;
|
|
while (couple_info_ptr != NULL) // On envoi les couples au serveur et on vide la liste
|
|
{
|
|
// Envoi des infos de l'AP vers le serveur de géolocalisation
|
|
memcpy(info.ap_mac_addr_bytes, couple_info_ptr->ap_mac_addr_bytes, 6);
|
|
info.antenna_signal_dbm = couple_info_ptr->antenna_signal_dbm - 0x100;
|
|
sendto(sockfd, (void *)&info, sizeof(couple_info), 0, (struct sockaddr *)&serv, serv_len);
|
|
|
|
// Inscription des infos de l'AP dans le fichier
|
|
ap_mac_string = mac_bytes_to_string(couple_info_ptr->ap_mac_addr_bytes) ;
|
|
fprintf(fd, ";%s;%d", ap_mac_string, couple_info_ptr->antenna_signal_dbm - 0x100) ;
|
|
free(ap_mac_string) ;
|
|
|
|
// Suppression du maillon
|
|
couple_info_ptr = couple_info_ptr->next ;
|
|
free(couple_ptr->info) ;
|
|
couple_ptr->info = couple_info_ptr ;
|
|
}
|
|
|
|
fprintf(fd, "\n") ;
|
|
}
|
|
}
|
|
|
|
else if (sub > (unsigned long) cfg_getint(cfg, "keep_timeout")) // Si le couple a été traité et que le temps de garde est écoulé
|
|
{
|
|
couple_list *couple_tmp = couple_ptr ;
|
|
|
|
printf("* Délai de garde dépassé.") ;
|
|
#ifdef DEBUG
|
|
printf(" sub=%lu > keep_timeout=%ld\n", sub, cfg_getint(cfg, "keep_timeout")) ;
|
|
#else // DEBUG
|
|
putchar('\n') ;
|
|
#endif // DEBUG
|
|
|
|
couple_ptr = couple_ptr->next ;
|
|
|
|
if (couple_prev == NULL) // Si on est en tête de liste,
|
|
*couples = couple_ptr ; // on positionne la tête sur le suivant
|
|
else
|
|
couple_prev->next = couple_ptr ; // sinon on positionne le suivant du précédent sur le suivant.
|
|
|
|
free(couple_tmp) ;
|
|
|
|
continue ; // On saute les instructions pour aller au suivant puisque c'est déjà fait
|
|
}
|
|
|
|
// Couple suivant
|
|
couple_prev = couple_ptr ;
|
|
couple_ptr = couple_ptr->next ;
|
|
}
|
|
|
|
fflush(NULL) ;
|
|
usleep(cfg_getint(cfg, "check_interval")) ; // On attend avant de vérifier à nouveau
|
|
}
|
|
|
|
/* Fermeture du fichier */
|
|
if (fclose(fd) != 0)
|
|
perror("Erreur lors de la fermeture du fichier de sortie ") ;
|
|
|
|
return NULL ;
|
|
}
|
|
|
|
|
|
|
|
/* Fonction appelée lors de la réception d'un paquet */
|
|
void got_couple_info(couple_list **couples, couple_message message)
|
|
{
|
|
couple_list *tmp_couple = NULL ;
|
|
couple_info_list *tmp_info = NULL ;
|
|
struct timeval start_time ; // Heure de réception du paquet par l'agrégateur
|
|
|
|
gettimeofday(&start_time, NULL) ;
|
|
|
|
/* Initialisation d'un nouveau sous-maillon */
|
|
tmp_info = malloc(sizeof(couple_info_list)) ;
|
|
memcpy(tmp_info->ap_mac_addr_bytes, message.ap_mac_addr_bytes, 6) ;
|
|
tmp_info->antenna_signal_dbm = message.antenna_signal_dbm ;
|
|
tmp_info->next = NULL ;
|
|
|
|
/* Ajout dans la liste */
|
|
tmp_couple = *couples ;
|
|
if (*couples == NULL) // Si la liste de couples n'existe pas encore,
|
|
{
|
|
printf("Création de la liste des couples.\n") ;
|
|
tmp_couple = malloc(sizeof(couple_list)) ; // on la crée.
|
|
memcpy(tmp_couple->mobile_mac_addr_bytes, message.mobile_mac_addr_bytes, 6) ;
|
|
if (timeval_to_ms(message.request_time) != 0) // Paquet explicite
|
|
tmp_couple->request_time = message.request_time ; // Heure d'émission par le mobile
|
|
else // Paquet implicite
|
|
tmp_couple->request_time = message.start_time ; // Heure de réception par l'AP
|
|
tmp_couple->start_time = start_time ; // Enregistrement de la date locale de l'agrégateur et non de la date de réception de la demande sur l'AP
|
|
tmp_couple->x_position = message.x_position ;
|
|
tmp_couple->y_position = message.y_position ;
|
|
tmp_couple->z_position = message.z_position ;
|
|
tmp_couple->direction = message.direction ;
|
|
tmp_couple->next = NULL ;
|
|
tmp_couple->info = tmp_info ;
|
|
*couples = tmp_couple ;
|
|
}
|
|
else
|
|
{ // Sinon on cherche si le couple existe déjà dans la liste
|
|
if (timeval_to_ms(message.request_time) != 0) // Paquet explicite
|
|
{
|
|
while (tmp_couple != NULL)
|
|
{ // Critère : MAC et heure d'émission identiques.
|
|
if(mac_cmp(message.mobile_mac_addr_bytes, tmp_couple->mobile_mac_addr_bytes) == 1
|
|
&& sub_date(message.request_time, tmp_couple->request_time) == 0)
|
|
break ; // Si le couple existe déjà, on s'arrête dessus.
|
|
tmp_couple = tmp_couple->next ;
|
|
}
|
|
}
|
|
else // Paquet implicite
|
|
{
|
|
while (tmp_couple != NULL)
|
|
{ // Critère : MAC identiques et décalage des heures de réception par les AP d'au maximum 10 ms.
|
|
if(mac_cmp(message.mobile_mac_addr_bytes, tmp_couple->mobile_mac_addr_bytes) == 1
|
|
&& sub_date(message.start_time, tmp_couple->request_time) <= 10) // TODO : définir un paramètre pour le décalage maximal
|
|
break ; // Si le couple existe déjà, on s'arrête dessus.
|
|
tmp_couple = tmp_couple->next ;
|
|
}
|
|
}
|
|
|
|
if (tmp_couple == NULL) // Si couple inexistant dans la liste
|
|
{
|
|
printf("Création du couple.\n") ;
|
|
tmp_couple = malloc(sizeof(couple_list)) ; // on crée un nouveau couple.
|
|
memcpy(tmp_couple->mobile_mac_addr_bytes, message.mobile_mac_addr_bytes, 6) ;
|
|
if (timeval_to_ms(message.request_time) != 0) // Paquet explicite
|
|
tmp_couple->request_time = message.request_time ; // Heure d'émission par le mobile
|
|
else // Paquet implicite
|
|
tmp_couple->request_time = message.start_time ; // Heure de réception par l'AP
|
|
tmp_couple->start_time = start_time ; // Enregistrement de la date locale de l'agrégateur et non de la date de réception de la demande sur l'AP
|
|
tmp_couple->x_position = message.x_position ;
|
|
tmp_couple->y_position = message.y_position ;
|
|
tmp_couple->z_position = message.z_position ;
|
|
tmp_couple->direction = message.direction ;
|
|
tmp_couple->next = *couples ;
|
|
tmp_couple->info = tmp_info ;
|
|
*couples = tmp_couple ;
|
|
}
|
|
else // Si couple trouvé dans la liste
|
|
{
|
|
if (tmp_couple->info == NULL) // Si on a déjà envoyé les infos de ce couple au serveur
|
|
{
|
|
printf("Demande déjà traitée.\n") ;
|
|
free(tmp_info) ;
|
|
}
|
|
else
|
|
{
|
|
printf("Ajout des informations au couple.\n") ;
|
|
tmp_info->next = tmp_couple->info ; // on ajoute l'info.
|
|
tmp_couple->info = tmp_info ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Vide la liste chaînée de couples */
|
|
void free_couple_list(couple_list **couples)
|
|
{
|
|
couple_list *couple_ptr = *couples ;
|
|
couple_info_list *couple_info_ptr = NULL ;
|
|
|
|
if (*couples != NULL)
|
|
{
|
|
while (couple_ptr != NULL)
|
|
{
|
|
couple_info_ptr = couple_ptr->info ;
|
|
while (couple_info_ptr != NULL)
|
|
{
|
|
couple_info_ptr = couple_info_ptr->next ;
|
|
free(couple_ptr->info) ;
|
|
couple_ptr->info = couple_info_ptr ;
|
|
}
|
|
couple_ptr = couple_ptr->next ;
|
|
free(*couples) ;
|
|
*couples = couple_ptr ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
/* Affiche la liste des couples */
|
|
void print_couple_list(couple_list *couples)
|
|
{
|
|
couple_list *couple_ptr = couples ;
|
|
couple_info_list *info_ptr = NULL ;
|
|
char *mobile_mac_string ;
|
|
|
|
if (couples == NULL) // Si la liste est vide
|
|
{
|
|
printf("Aucun couple.\n") ; // on l'affiche.
|
|
return ;
|
|
}
|
|
|
|
while (couple_ptr != NULL)
|
|
{
|
|
info_ptr = couple_ptr->info ; // On récupère le pointeur de la sous-liste
|
|
|
|
mobile_mac_string = mac_bytes_to_string(couple_ptr->mobile_mac_addr_bytes) ;
|
|
printf("MAC du mobile : %s\n\
|
|
Numéro de séquence : %llu\n\
|
|
Heure de réception de la demande de localisation : %llu\n\
|
|
\n",
|
|
mobile_mac_string,
|
|
timeval_to_ms(couple_ptr->request_time),
|
|
timeval_to_ms(couple_ptr->start_time)
|
|
) ;
|
|
free(mobile_mac_string) ;
|
|
|
|
while (info_ptr != NULL) // On parcourt toutes les informations relative au couple courant
|
|
{
|
|
print_couple_info(info_ptr) ;
|
|
putchar('\n') ;
|
|
info_ptr = info_ptr->next ;
|
|
}
|
|
|
|
printf("\n\n") ;
|
|
|
|
couple_ptr = couple_ptr->next ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Affiche un maillon d'une couple_info_list */
|
|
void print_couple_info(couple_info_list *info)
|
|
{
|
|
char *ap_mac_string ;
|
|
if (info == NULL)
|
|
return ;
|
|
|
|
ap_mac_string = mac_bytes_to_string(info->ap_mac_addr_bytes) ;
|
|
printf("\tMAC de l'AP : %s\n\
|
|
\tPuissance du signal : %d dBm\n",
|
|
ap_mac_string,
|
|
info->antenna_signal_dbm - 0x100
|
|
) ;
|
|
free(ap_mac_string) ;
|
|
}
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
int Db_write_request(couple_message message, BOOL ref)
|
|
{
|
|
char *buf = (char *) malloc(100 * sizeof(char));
|
|
sprintf(buf, "hostaddr = '%s' dbname = '%s' user = '%s' password = '%s'", cfg_getstr(cfg, "host_db"), cfg_getstr(cfg, "db_name"), cfg_getstr(cfg, "user_db"), cfg_getstr(cfg, "pass_db"));
|
|
|
|
const char* conninfo = buf;
|
|
PGconn *conn;
|
|
|
|
int id_ap, id_mobile, id_request, id_point = -1;
|
|
|
|
conn = PQconnectdb(conninfo);
|
|
|
|
if(PQstatus(conn) != CONNECTION_OK){
|
|
printf("Connection à la base de donnée échouée : %s\n", PQerrorMessage(conn));
|
|
PQfinish(conn);
|
|
return 1;
|
|
}
|
|
|
|
if((id_ap = DbAccessPoint(message, conn)) < 0) return 1;
|
|
if((id_mobile = DbMobile(message, conn)) < 0) return 1;
|
|
if((id_request = DbRequest(message, conn, id_mobile, &id_point, ref)) < 0) return 1;
|
|
DbPacket(message, conn, id_ap, id_request, ref);
|
|
|
|
PQfinish(conn);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int DbAccessPoint(couple_message message, PGconn *conn)
|
|
{
|
|
char *buf = (char *) malloc(200 * sizeof(char));
|
|
char *ap_mac_string;
|
|
int id_ap;
|
|
|
|
PGresult *res;
|
|
|
|
/** Recherche de l'AP conserné **/
|
|
ap_mac_string = mac_bytes_to_string(message.ap_mac_addr_bytes) ;
|
|
|
|
sprintf(buf, "SELECT id_ap, ap_addr FROM ap WHERE ap_addr = '%s';", ap_mac_string);
|
|
|
|
res = PQexec(conn, buf);
|
|
if(PQresultStatus(res) != PGRES_TUPLES_OK){
|
|
printf("Commande incorrect : %s\n", PQerrorMessage(conn));
|
|
return -1;
|
|
}else if(PQntuples(res) == 0){
|
|
PQclear(res);
|
|
sprintf(buf, "SELECT * FROM ap;");
|
|
res = PQexec(conn, buf);
|
|
id_ap = (PQntuples(res) != 0)? atoi(PQgetvalue(res, PQntuples(res) - 1, 0)) + 1 : 1;
|
|
|
|
sprintf(buf, "INSERT INTO ap VALUES('%d','%s', '0', '0', '0', '0', '2417000000', '5', '20');",id_ap, ap_mac_string);
|
|
|
|
PQexec(conn, buf);
|
|
|
|
}else{
|
|
id_ap = atoi(PQgetvalue(res, 0, 0));
|
|
}
|
|
PQclear(res);
|
|
free(buf);
|
|
|
|
return id_ap;
|
|
}
|
|
|
|
|
|
|
|
int DbMobile(couple_message message, PGconn *conn)
|
|
{
|
|
char *mobile_mac_string, *mobile_ip_string;
|
|
char *buf = (char *) malloc(200 * sizeof(char));
|
|
int id_mobile;
|
|
|
|
PGresult *res;
|
|
|
|
/** Recherche du mobile conserné **/
|
|
mobile_mac_string = mac_bytes_to_string(message.mobile_mac_addr_bytes);
|
|
mobile_ip_string = ip_bytes_to_string(message.mobile_ip_addr_bytes);
|
|
|
|
sprintf(buf, "SELECT * FROM mobile WHERE mobile_addr = '%s';", mobile_mac_string);
|
|
|
|
res = PQexec(conn, buf);
|
|
if(PQresultStatus(res) != PGRES_TUPLES_OK){
|
|
printf("Commande incorrect : %s\n", PQerrorMessage(conn));
|
|
return -1;
|
|
}else if(PQntuples(res) == 0){
|
|
PQclear(res);
|
|
sprintf(buf, "SELECT * FROM mobile;");
|
|
res = PQexec(conn, buf);
|
|
id_mobile = (PQntuples(res) != 0)? atoi(PQgetvalue(res, PQntuples(res) - 1, 0)) + 1 : 1;
|
|
|
|
sprintf(buf, "INSERT INTO mobile(id_mobile, mobile_addr, ip_mobile, last_connect) VALUES('%d','%s','%s','%llu');",id_mobile, mobile_mac_string, mobile_ip_string, timeval_to_ms(message.request_time));
|
|
|
|
PQexec(conn, buf);
|
|
}else{
|
|
id_mobile = atoi(PQgetvalue(res, 0, 0));
|
|
|
|
sprintf(buf, "UPDATE mobile SET last_connect = %llu, ip_mobile = '%s' WHERE id_mobile = %d;", timeval_to_ms(message.request_time), mobile_ip_string, id_mobile);
|
|
|
|
PQexec(conn, buf);
|
|
}
|
|
PQclear(res);
|
|
free(buf);
|
|
|
|
return id_mobile;
|
|
}
|
|
|
|
|
|
|
|
int DbRefPoint(couple_message message, PGconn *conn)
|
|
{
|
|
char *buf = (char *) malloc(200 * sizeof(char));
|
|
int id_ref_point;
|
|
char d = ' ';
|
|
|
|
PGresult *res;
|
|
|
|
switch(message.direction){
|
|
case 1:
|
|
d = 'N';
|
|
break;
|
|
case 2:
|
|
d = 'E';
|
|
break;
|
|
case 3:
|
|
d = 'S';
|
|
break;
|
|
case 4:
|
|
d = 'W';
|
|
break;
|
|
default :
|
|
d = ' ';
|
|
printf("Erreur : direction inconnue\n");
|
|
}
|
|
|
|
strcpy(buf, "SELECT * FROM ref_point;");
|
|
res = PQexec(conn, buf);
|
|
id_ref_point = (PQntuples(res) != 0)? atoi(PQgetvalue(res, PQntuples(res) - 1, 0)) + 1: 1;
|
|
|
|
sprintf(buf, "INSERT INTO ref_point(id_ref_point, x, y, z, direction) VALUES('%d','%f','%f','%f','%c');", id_ref_point, message.x_position, message.y_position, message.z_position, d);
|
|
|
|
PQexec(conn, buf);
|
|
|
|
return id_ref_point;
|
|
}
|
|
|
|
|
|
|
|
int DbRequest(couple_message message, PGconn *conn, int id_mobile, int *id_point, BOOL ref)
|
|
{
|
|
char *buf = (char *) malloc(200 * sizeof(char));
|
|
int id_request;
|
|
|
|
PGresult *res;
|
|
|
|
/** Ajout de la requete si elle n'existe pas **/
|
|
if(ref) sprintf(buf, "SELECT * FROM ref_request WHERE mobile_time = %llu AND id_mobile = %d;", timeval_to_ms(message.request_time), id_mobile);
|
|
else sprintf(buf, "SELECT * FROM request WHERE mobile_time = %llu AND id_mobile = %d;", timeval_to_ms(message.request_time), id_mobile);
|
|
|
|
res = PQexec(conn, buf);
|
|
if(PQresultStatus(res) != PGRES_TUPLES_OK){
|
|
printf("Commande incorrect : %s\n", PQerrorMessage(conn));
|
|
return -1;
|
|
}else if(PQntuples(res) == 0){
|
|
PQclear(res);
|
|
if(ref) sprintf(buf, "SELECT * FROM ref_request;");
|
|
else sprintf(buf, "SELECT * FROM request;");
|
|
res = PQexec(conn, buf);
|
|
id_request = (PQntuples(res) != 0)? atoi(PQgetvalue(res, PQntuples(res) - 1, 0)) + 1: 1;
|
|
if(ref){
|
|
if((*id_point = DbRefPoint(message, conn)) < 0) return -1;
|
|
sprintf(buf, "INSERT INTO ref_request(id_ref_request, mobile_time, id_mobile, id_ref_point) VALUES('%d','%llu','%d','%d');", id_request, timeval_to_ms(message.request_time), id_mobile, *id_point);
|
|
}else sprintf(buf, "INSERT INTO request(id_request, mobile_time, id_mobile) VALUES('%d','%llu','%d');", id_request, timeval_to_ms(message.request_time), id_mobile);
|
|
|
|
PQexec(conn, buf);
|
|
}else{
|
|
id_request = atoi(PQgetvalue(res, 0, 0));
|
|
if(ref) *id_point = atoi(PQgetvalue(res, 0, 3));
|
|
}
|
|
PQclear(res);
|
|
free(buf);
|
|
|
|
return id_request;
|
|
}
|
|
|
|
|
|
|
|
int DbPacket(couple_message message, PGconn *conn, int id_ap, int id_request, BOOL ref)
|
|
{
|
|
char *buf = (char *) malloc(200 * sizeof(char));
|
|
|
|
/** Ajout du paquet **/
|
|
if(ref) sprintf(buf, "INSERT INTO ref_packet(ap_time, power, id_ap, id_ref_request) VALUES('%llu','%d','%d','%d');", timeval_to_ms(message.start_time), message.antenna_signal_dbm - 0x100, id_ap, id_request);
|
|
else sprintf(buf, "INSERT INTO packet(ap_time, power, id_ap, id_request) VALUES('%llu','%d','%d','%d');", timeval_to_ms(message.start_time), message.antenna_signal_dbm - 0x100, id_ap, id_request);
|
|
|
|
PQexec(conn, buf);
|
|
free(buf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* Affiche le mode d'emploi du programme */
|
|
void print_usage(char *prog)
|
|
{
|
|
printf("Usage :\n\
|
|
\t%s [-f config_file] [-l listening_port] [-i positionner_ip] [-p positioner_port] [-a aggregate_timeout] [-k keep_timeout] [-c check_interval] [-o output_file] [-H db_addr] [-N db_name] [-U db_user] [-P db_passwd]\n\
|
|
Options générales :\n\
|
|
\t-f config_file : spécifie un fichier de configuration à lire à la place du fichier par défaut.\n\
|
|
Options serveur :\n\
|
|
\t-l listening_port : seules les demandes envoyées sur ce port seront retenues (défaut : %d).\n\
|
|
\t-i positionner_ip : adresse IP du serveur de calcul auquel seront transmises les demandes (défaut : %s).\n\
|
|
\t-p positioner_port : les demandes agrégées seront transmises sur ce port du serveur de calcul (défaut : %d).\n\
|
|
Options d'agrégation :\n\
|
|
\t-a aggregate_timeout : temps d'agrégation (défaut : %d millisecondes)\n\
|
|
\t-a keep_timeout : temps de garde des demandes (défaut : %d millisecondes)\n\
|
|
\t-a check_interval : délai entre deux vérifications des demandes en mémoire, et agrégation (défaut : %d micro-secondes)\n\
|
|
Options relatives à la base de données :\n\
|
|
\t-H db_addr : adresse du serveur de BdD (défaut : %s).\n\
|
|
\t-N db_name : nom de la base (défaut : %s).\n\
|
|
\t-U db_user : nom d'utilisateur pour l'accès à la BdD (défaut : %s).\n\
|
|
\t-P db_passwd : mot de passe pour l'accès à la BdD (défaut : %s).\n\
|
|
",
|
|
prog,
|
|
AGGREGATE_DEFAULT_PORT,
|
|
POSITIONER_DEFAULT_IP,
|
|
POSITIONER_DEFAULT_PORT,
|
|
DEFAULT_AGGREGATE_TIMEOUT,
|
|
DEFAULT_KEEP_TIMEOUT,
|
|
DEFAULT_CHECK_INTERVAL,
|
|
DEFAULT_DB_HOST,
|
|
DEFAULT_DB_NAME,
|
|
DEFAULT_DB_USER,
|
|
DEFAULT_DB_PASS
|
|
) ;
|
|
}
|