/* * This file is part of the rtap localisation project. */ #include "owlps-aggregator.h" #include char *program_name = NULL ; cfg_t *cfg = NULL ; // Configuration structure couple_list *couples = NULL ; // Computed data list ap_list *token_aps = NULL ; // Token ring of the APs uint_fast16_t nb_aps = 0 ; // Number of APs in the AP ring int main(int argc, char **argv) { int ret = 0 ; // Program return value struct sigaction action ; // Signal handler structure pthread_t monitor_thread, // Aggregated data monitoring thread monitor_aps_thread, // APs monitoring thread autocalibration_hello_thread ; // Hello messages reception thread uint_fast16_t listening_port ; int sockfd ; // UDP listening socket program_name = argv[0] ; initialise_configuration(argc, argv) ; /* Set up signal handlers */ sigemptyset(&action.sa_mask) ; action.sa_handler = sigint_handler ; sigaction(SIGINT, &action, NULL) ; action.sa_handler = sigterm_handler ; sigaction(SIGTERM, &action, NULL) ; /* Create UDP socket */ listening_port = cfg_getint(cfg, "listening_port") ; if ((sockfd = create_udp_listening_socket(listening_port)) < 0) { fprintf(stderr, "Error! Cannot listen on port %"PRIuFAST16".\n", listening_port) ; return ERR_CREATING_SOCKET ; } /* Set up threads */ pthread_create(&monitor_thread, NULL, (void *) &monitor_couples, NULL) ; if (cfg_getbool(cfg, "autocalibration")) { pthread_create(&autocalibration_hello_thread, NULL, (void *) &listen_for_aps, NULL) ; pthread_create(&monitor_aps_thread, NULL, (void *) &monitor_aps, NULL) ; } run = TRUE ; ret = read_loop(sockfd) ; (void) close(sockfd) ; // Close socket free_couple_list() ; free_ap_list() ; cfg_free(cfg) ; // Clean configuration printf("%s: end.\n", program_name) ; return ret ; } void initialise_configuration(int argc, char **argv) { parse_config_file(argc, argv) ; parse_command_line(argc, argv) ; check_configuration() ; #ifdef DEBUG /* Configuration printing */ fprintf(stderr, "Configuration:\n") ; cfg_print(cfg, stderr) ; #endif // DEBUG } void parse_config_file(int argc, char **argv) { // Config file options for confuse cfg_opt_t opts[] = { // Be verbose? CFG_BOOL("verbose", cfg_false, CFGF_NONE), // Aggregation listening port CFG_INT("listening_port", AGGREGATE_DEFAULT_PORT, CFGF_NONE), // Port and IP address of the localisation server: CFG_INT("positioner_port", POSITIONER_DEFAULT_PORT, CFGF_NONE), CFG_STR("positioner_ip", POSITIONER_DEFAULT_IP, CFGF_NONE), CFG_STR("output_file", "", CFGF_NONE), // Timeouts (in milliseconds): CFG_INT("aggregate_timeout", DEFAULT_AGGREGATE_TIMEOUT, CFGF_NONE), CFG_INT("keep_timeout", DEFAULT_KEEP_TIMEOUT, CFGF_NONE), // Time between two list checks (in microseconds): CFG_INT("check_interval", DEFAULT_CHECK_INTERVAL, CFGF_NONE), // Autocalibration activated? CFG_BOOL("autocalibration", cfg_false, CFGF_NONE), // Port on which autocalibration data are exchanged: CFG_INT("autocalibration_port", DEFAULT_AUTOCALIBRATION_PORT, CFGF_NONE), // Time we keep APs in the list (in seconds): CFG_INT("ap_keep_timeout", DEFAULT_AP_KEEP_TIMEOUT, CFGF_NONE), // Time between two checks of the AP list (in milliseconds): CFG_INT("ap_check_interval", DEFAULT_AP_CHECK_INTERVAL, CFGF_NONE), CFG_END() } ; char *config_file ; // Option -f specifies a config file, so we search for it first int opt ; 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 // If -f isn't found, we use the default config file { config_file = malloc((strlen(DEFAULT_CONFIG_FILE) + 1) * sizeof(char)) ; strcpy(config_file, DEFAULT_CONFIG_FILE) ; } /* Parse config file */ cfg = cfg_init(opts, CFGF_NONE) ; // Initialise options switch (cfg_parse(cfg, config_file)) { case CFG_FILE_ERROR : fprintf(stderr, "Error! Cannot open configuration file « %s »: %s.\n", config_file, strerror(errno)) ; break ; case CFG_PARSE_ERROR : fprintf(stderr, "Error! Parsing of configuration file « %s » failed!\n", config_file) ; free(config_file) ; exit(ERR_PARSING_CONFIG_FILE) ; } free(config_file) ; } void parse_command_line(int argc, char **argv) { int opt ; optind = 1 ; // Rewind argument parsing while ((opt = getopt(argc, argv, OPTIONS)) != -1) { switch (opt) { case 'A' : cfg_setbool(cfg, "autocalibration", cfg_true) ; break ; case 'a' : cfg_setint(cfg, "autocalibration_port", strtol(optarg, NULL, 0)) ; break ; case 'c' : cfg_setint(cfg, "check_interval", strtol(optarg, NULL, 0)) ; break ; case 'C' : cfg_setint(cfg, "ap_check_interval", strtol(optarg, NULL, 0)) ; break ; case 'f' : // Config file break ; // (already parsed) case 'h' : print_usage() ; exit(0) ; case 'i' : cfg_setstr(cfg, "positioner_ip", optarg) ; break ; case 'k' : cfg_setint(cfg, "keep_timeout", strtol(optarg, NULL, 0)) ; break ; case 'K' : cfg_setint(cfg, "ap_keep_timeout", strtol(optarg, NULL, 0)) ; break ; case 'l' : cfg_setint(cfg, "listening_port", strtol(optarg, NULL, 0)) ; break ; case 'o' : cfg_setstr(cfg, "output_file", optarg) ; break ; case 'p' : cfg_setint(cfg, "positioner_port", strtol(optarg, NULL, 0)) ; break ; case 't' : cfg_setint(cfg, "aggregate_timeout", strtol(optarg, NULL, 0)) ; break ; case 'v' : cfg_setbool(cfg, "verbose", cfg_true) ; break ; default : print_usage() ; exit(ERR_BAD_USAGE) ; } } } void check_configuration() { // output_file // if (cfg_getstr(cfg, "output_file")[0] == '\0') { fprintf(stderr, "Error! You must specify an output file.\n") ; print_usage() ; exit(ERR_BAD_USAGE) ; } // positioner_ip // if (cfg_getstr(cfg, "positioner_ip")[0] == '\0') { fprintf(stderr, "Error! You must specify the IP address of the" " localisation server.\n") ; print_usage() ; exit(ERR_BAD_USAGE) ; } // aggregate_timeout // if (cfg_getint(cfg, "aggregate_timeout") < 0) { #ifdef DEBUG fprintf(stderr, "Warning! aggregate_timeout cannot be negative:" " failing back to default value.\n") ; #endif // DEBUG cfg_setint(cfg, "aggregate_timeout", DEFAULT_AGGREGATE_TIMEOUT) ; } // keep_timeout // if (cfg_getint(cfg, "keep_timeout") < 0) { #ifdef DEBUG fprintf(stderr, "Warning! keep_timeout cannot be negative:" " failing back to default value.\n") ; #endif // DEBUG cfg_setint(cfg, "keep_timeout", DEFAULT_KEEP_TIMEOUT) ; } // check_interval // if (cfg_getint(cfg, "check_interval") < 0) { #ifdef DEBUG fprintf(stderr, "Warning! check_interval cannot be negative:" " failing back to default value.\n") ; #endif // DEBUG cfg_setint(cfg, "check_interval", DEFAULT_CHECK_INTERVAL) ; } // ap_keep_timeout // if (cfg_getint(cfg, "ap_keep_timeout") < 0) { #ifdef DEBUG fprintf(stderr, "Warning! ap_keep_timeout cannot be negative:" " failing back to default value.\n") ; #endif // DEBUG cfg_setint(cfg, "ap_keep_timeout", DEFAULT_AP_KEEP_TIMEOUT) ; } // ap_check_interval // if (cfg_getint(cfg, "ap_check_interval") < 0) { #ifdef DEBUG fprintf(stderr, "Warning! ap_check_interval cannot be negative:" " failing back to default value.\n") ; #endif // DEBUG cfg_setint(cfg, "ap_check_interval", DEFAULT_AP_CHECK_INTERVAL) ; } } /* * Reads packets while the program is not stopped. */ int read_loop(int sockfd) { int ret = 0 ; // Return value int nread ; // recvfrom return value struct sockaddr_in client; // UDP client structure socklen_t client_len = sizeof(client) ; // Size of clients couple_message message ; // Message read on the socket char *ap_mac_string, // Return pointers for mac_bytes_to_string() *mobile_mac_string, *mobile_ip_string ; // and ip_bytes_to_string() while (run) { nread = recvfrom(sockfd, &message, sizeof(message), 0, (struct sockaddr *) &client, &client_len) ; if (nread <= 0) { if (run) { fprintf(stderr, "No message received from client!\n") ; ret = ERR_NO_MESSAGE_RECEIVED ; } break ; } if (cfg_getbool(cfg, "verbose")) { 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" "*** Request received from AP ***\n" "\tAP MAC: %s\n" "\tMobile MAC: %s\n" "\tMobile IP: %s\n" "\tSequence number (request timestamp): %"PRIu64"\n" "\tRequest arrival time on the AP: %"PRIu64"\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, timestamp_to_ms(message.request_time), timestamp_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) ; } #ifdef DEBUG else { ap_mac_string = mac_bytes_to_string(message.ap_mac_addr_bytes) ; fprintf(stderr, "Request received from AP « %s ».\n", ap_mac_string) ; free(ap_mac_string) ; } #endif // DEBUG got_couple_info(message) ; } return ret ; } /* * Thread function. Monitors the list and sends information to the * localisation server when the timeout is reached. */ void* monitor_couples() { couple_list *couple_ptr, *couple_prev ; couple_info_list *couple_info_ptr ; TIMESTAMP current_time ; FILE *fd = NULL ; char *mac_string ; uint_fast32_t sub ; // time_elapsed() result uint_fast32_t aggregate_timeout = cfg_getint(cfg, "aggregate_timeout") ; uint_fast32_t keep_timeout = cfg_getint(cfg, "keep_timeout") ; struct sockaddr_in serv; struct sockaddr_in client ; socklen_t serv_len = sizeof(serv); request demande; couple_info info; int sockfd; #ifdef DEBUG fprintf(stderr, "Monitor couples thread launched.\n") ; #endif // DEBUG sockfd = create_udp_sending_socket(cfg_getstr(cfg, "positioner_ip"), cfg_getint(cfg, "positioner_port"), &serv, &client) ; /* Open output file */ fd = fopen(cfg_getstr(cfg, "output_file"), "a") ; // We use add mode if (fd == NULL) // If we failed to open the file, { perror("Cannot open output file") ; fprintf(stderr, "Redirecting output to standard output.") ; fd = stdout ; // we fail back to stdout. } while (run) { couple_ptr = couples ; couple_prev = NULL ; couple_info_ptr = NULL ; timestamp_now(¤t_time) ; while (couple_ptr != NULL) // Parsing list { sub = time_elapsed(couple_ptr->start_time, current_time) ; // If the couple was not treated already if (couple_ptr->info != NULL) { // If the timeout is reached if (sub > aggregate_timeout) { printf("* Timeout reached.") ; #ifdef DEBUG printf(" sub=%"PRIuFAST32" >" " aggregate_timeout=%"PRIuFAST32"\n", sub, aggregate_timeout) ; #else // DEBUG putchar('\n') ; #endif // DEBUG #ifdef USE_TIMESTAMP // Print request mobile timestamp to the output file fprintf(fd, "%"PRIu64";", timestamp_to_ms(couple_ptr->request_time)) ; #endif // USE_TIMESTAMP // Print mobile MAC address to the output file mac_string = mac_bytes_to_string(couple_ptr ->mobile_mac_addr_bytes) ; fprintf(fd, "%s;", mac_string) ; free(mac_string) ; // Print couple info to the output file fprintf(fd, "%0.2f;%0.2f;%0.2f;%hhd", couple_ptr->x_position, couple_ptr->y_position, couple_ptr->z_position, couple_ptr->direction) ; 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) ; // Send couples to the server and empty the list couple_info_ptr = couple_ptr->info ; while (couple_info_ptr != NULL) { // Send AP info to the localisation server 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) ; // Print AP info to the output file mac_string = mac_bytes_to_string(couple_info_ptr ->ap_mac_addr_bytes) ; fprintf(fd, ";%s;%d", mac_string, couple_info_ptr->antenna_signal_dbm - 0x100) ; free(mac_string) ; // Delete couple couple_info_ptr = couple_info_ptr->next ; free(couple_ptr->info) ; couple_ptr->info = couple_info_ptr ; } fprintf(fd, "\n") ; } } // If the couple was treated and keep timeout is reached else if (sub > keep_timeout) { couple_list *couple_tmp = couple_ptr ; printf("* Keep timeout reached.") ; #ifdef DEBUG printf(" sub=%"PRIuFAST32" >" " keep_timeout=%"PRIuFAST32"\n", sub, keep_timeout) ; #else // DEBUG putchar('\n') ; #endif // DEBUG couple_ptr = couple_ptr->next ; // If it is the first couple of the list if (couple_prev == NULL) couples = couple_ptr ; // we shift the head else // else we put the next of the previous on the next couple_prev->next = couple_ptr ; free(couple_tmp) ; continue ; } // Next couple couple_prev = couple_ptr ; couple_ptr = couple_ptr->next ; } fflush(NULL) ; usleep(cfg_getint(cfg, "check_interval")) ; // Wait to check again } /* Close output file & socket */ if (fclose(fd) != 0) perror("Error closing output file") ; (void) close(sockfd) ; return NULL ; } /* * Treats a received packet. */ void got_couple_info(couple_message message) { couple_list *tmp_couple = NULL ; couple_info_list *tmp_info = NULL ; TIMESTAMP start_time ; // Reception time on the aggregator timestamp_now(&start_time) ; /* Create a new couple */ 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 ; /* Add it in the list */ tmp_couple = couples ; if (couples == NULL) // If the couple list does not exist, { printf("Creating couple list.\n") ; tmp_couple = malloc(sizeof(couple_list)) ; // create it. memcpy(tmp_couple->mobile_mac_addr_bytes, message.mobile_mac_addr_bytes, 6) ; if (timestamp_to_ms(message.request_time) != 0) // Explicit packet // Transmission time on the mobile: tmp_couple->request_time = message.request_time ; else // Implicit packet // Reception time on the AP: tmp_couple->request_time = message.start_time ; // Save locale time on the aggregator (not the reception time // on the AP): tmp_couple->start_time = start_time ; 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 // If the couple list exists already { // we search the list for the couple if (timestamp_to_ms(message.request_time) != 0) // Explicit packet { while (tmp_couple != NULL) { // Research criterion: MAC and transmission time if (mac_equals(message.mobile_mac_addr_bytes, tmp_couple->mobile_mac_addr_bytes) == 1 && time_elapsed(message.request_time, tmp_couple->request_time) == 0) break ; // If the couple exists, we stop on it tmp_couple = tmp_couple->next ; } } else // Implicit packet { while (tmp_couple != NULL) { // Research criterion: MAC addresses equals and reception // times on the APs less than 10 ms // TODO : define an option for the maximal difference time. if (mac_equals(message.mobile_mac_addr_bytes, tmp_couple->mobile_mac_addr_bytes) == 1 && time_elapsed(message.start_time, tmp_couple->request_time) <= 10) break ; // If the couple exists, we stop on it tmp_couple = tmp_couple->next ; } } if (tmp_couple == NULL) // If the couple does not exist in the list, { printf("Create new couple.\n") ; tmp_couple = malloc(sizeof(couple_list)) ; // create it. memcpy(tmp_couple->mobile_mac_addr_bytes, message.mobile_mac_addr_bytes, 6) ; if (timestamp_to_ms(message.request_time) != 0) // Explicit packet // Transmission time on the mobile: tmp_couple->request_time = message.request_time ; else // Implicit packet // Reception time on the AP: tmp_couple->request_time = message.start_time ; // Save locale time on the aggregator (not the reception time // on the AP): tmp_couple->start_time = start_time ; 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 // If the couple was found in the list { if (tmp_couple->info == NULL) { // We already sent to the server data for this couple printf("Request already treated.\n") ; free(tmp_info) ; } else { printf("Add information to the couple.\n") ; tmp_info->next = tmp_couple->info ; // Add data tmp_couple->info = tmp_info ; } } } } /* * Empties the couple list. */ void free_couple_list() { couple_list *next_couple ; couple_info_list *next_couple_info ; while (couples != NULL) { while (couples->info != NULL) { next_couple_info = couples->info->next ; free(couples->info) ; couples->info = next_couple_info ; } next_couple = couples->next ; free(couples) ; couples = next_couple ; } } /* * Thread function. Listens for hello messages from APs. */ void listen_for_aps(void) { int listen_sockfd ; int nread ; // recvfrom return value struct sockaddr_in client; // UDP client structure socklen_t client_len = sizeof(client) ; // Size of clients autocalibration_hello message ; char ap_ip_addr[16] ; #ifdef DEBUG fprintf(stderr, "Autocalibration Hello thread launched.\n") ; #endif // DEBUG listen_sockfd = create_udp_listening_socket(cfg_getint(cfg, "autocalibration_port")) ; if (listen_sockfd < 0) { perror("Error! Cannot create UDP listening socket from the" " listeners") ; exit(ERR_CREATING_SOCKET) ; } while (run) { nread = recvfrom(listen_sockfd, &message, sizeof(message), 0, (struct sockaddr *) &client, &client_len) ; if (nread <= 0 && run) { if (run) fprintf(stderr, "No message received from listener!\n") ; continue ; } strncpy(ap_ip_addr, inet_ntoa(client.sin_addr), 16) ; #ifdef DEBUG fprintf(stderr, "Got a Hello message from « %s »\n", ap_ip_addr) ; #endif // DEBUG update_ap(message.ap_mac_addr_bytes, ap_ip_addr) ; } (void) close(listen_sockfd) ; } /* * Updates the timestamp of the AP with the given MAC address if it is in * the AP list, or add a new AP with this MAC address to the AP list. */ void update_ap(uint8_t mac_addr_bytes[6], char ip_addr[16]) { ap_list *found ; if ((found = find_ap(mac_addr_bytes)) == NULL) { ap_list *new_ap = add_ap_front(mac_addr_bytes) ; update_ap_ip_addr(new_ap, ip_addr) ; } else update_ap_seen(found) ; } /* * Searches the AP list for an AP with the given MAC address and returns * it. */ ap_list* find_ap(uint8_t mac_addr_bytes[6]) { ap_list *found ; if (token_aps == NULL) return NULL ; found = token_aps ; do { if (mac_equals(found->mac_addr_bytes, mac_addr_bytes)) return found ; found = found->next ; } while (found != token_aps) ; return NULL ; } /* * Adds a new AP in front of the AP list. */ ap_list* add_ap_front(uint8_t mac_addr_bytes[6]) { #ifdef DEBUG char *mac = mac_bytes_to_string(mac_addr_bytes) ; fprintf(stderr, "Creating AP with MAC address « %s »...\n", mac) ; free(mac) ; #endif // DEBUG ap_list *ap = malloc(sizeof(ap_list)) ; memcpy(ap->mac_addr_bytes, mac_addr_bytes, 6) ; update_ap_seen(ap) ; push_ap(ap) ; return ap ; } /* * Change the IP address of the AP 'ap' with 'ip_addr'. */ void update_ap_ip_addr(ap_list *ap, char ip_addr[16]) { strncpy(ap->ip_addr, ip_addr, 16) ; } /* * Updates the timestamp of the given AP. */ void update_ap_seen(ap_list *ap) { assert(ap) ; timestamp_now(&ap->last_seen) ; } /* * Puts an existing AP in front of the AP list. The AP must not be in * the list yet. */ void push_ap(ap_list *ap) { assert(ap) ; ++nb_aps ; if (token_aps == NULL) // List does not exist yet { token_aps = ap ; ap->next = ap ; ap->previous = ap ; return ; } ap->previous = token_aps->previous ; ap->previous->next = ap ; ap->next = token_aps ; token_aps->previous = ap ; token_aps = ap ; } /* * Monitors the AP list: sends orders to APs following their order in * the list, and deletes old APs. */ void monitor_aps() { #ifdef DEBUG fprintf(stderr, "Monitor AP thread launched.\n") ; #endif // DEBUG while (run) { delete_old_aps() ; if (nb_aps > 1) { order_send(token_aps) ; token_aps = token_aps->next ; } usleep(cfg_getint(cfg, "ap_check_interval") * 1000) ; } } /* * Deletes APs that did not send any Hello packet for a while, following * the list order. Stops on the first not-to-be-deleted AP. */ void delete_old_aps() { TIMESTAMP now ; timestamp_now(&now) ; while (token_aps != NULL) if (time_elapsed(token_aps->last_seen, now) > (uint_fast32_t) cfg_getint(cfg, "ap_keep_timeout") * 1000) delete_ap(token_aps) ; else return ; } /* * Deletes the given AP from the AP list. */ void delete_ap(ap_list *ap) { #ifdef DEBUG assert(ap) ; char *mac = mac_bytes_to_string(token_aps->mac_addr_bytes) ; fprintf(stderr, "Deleting AP « %s »...\n", mac) ; free(mac) ; #endif // DEBUG unlink_ap(ap) ; free(ap) ; } /* * Extracts the given AP from the AP list (it will not be linked to any * other element of the list). */ void unlink_ap(ap_list *ap) { ap_list *ap_previous, *ap_next ; assert(ap) ; ap_previous = ap->previous ; ap_next = ap->next ; assert(ap_previous) ; assert(ap_next) ; ap_previous->next = ap_next ; ap_next->previous = ap_previous ; if (ap == token_aps) { if (ap->next == ap) // It was the last AP in the ring token_aps = NULL ; else token_aps = ap_next ; } --nb_aps ; } /* * Sends a 'send' order to the given AP. */ void order_send(ap_list *ap) { autocalibration_order message ; struct sockaddr_in serv; struct sockaddr_in client ; socklen_t serv_len = sizeof(serv); int sockfd ; ssize_t nsent ; #ifdef DEBUG fprintf(stderr, "Sending an order to %s...\n", ap->ip_addr) ; #endif // DEBUG sockfd = create_udp_sending_socket(ap->ip_addr, cfg_getint(cfg, "autocalibration_port"), &serv, &client) ; message.order = htonl(AUTOCALIBRATION_ORDER_SEND) ; nsent = sendto(sockfd, (void *)&message, sizeof(message), 0, (struct sockaddr *)&serv, serv_len) ; if (nsent != (ssize_t) sizeof(message)) { perror("Error sending order to the listener") ; exit(ERR_SENDING_INFO) ; } (void) close(sockfd) ; } /* * Empties the AP list. */ void free_ap_list() { ap_list *ap_ptr ; if (token_aps == NULL) return ; ap_ptr = token_aps->next ; assert(ap_ptr) ; while (ap_ptr != token_aps) { ap_list *ap_tmp = ap_ptr ; ap_ptr = ap_ptr->next ; free(ap_tmp) ; } free(token_aps) ; token_aps = NULL ; } #ifdef DEBUG /* * Prints the couple list. */ void print_couple_list() { couple_list *couple_ptr = couples ; couple_info_list *info_ptr = NULL ; char *mobile_mac_string ; if (couples == NULL) // Empty list { printf("Aucun couple.\n") ; return ; } while (couple_ptr != NULL) { info_ptr = couple_ptr->info ; // Get the sub-list pointer mobile_mac_string = mac_bytes_to_string(couple_ptr->mobile_mac_addr_bytes) ; printf("Mobile MAC: %s\n" "Sequence number: %"PRIu64"\n" "Reception timestamp: %"PRIu64"\n" "\n", mobile_mac_string, timestamp_to_ms(couple_ptr->request_time), timestamp_to_ms(couple_ptr->start_time) ) ; free(mobile_mac_string) ; // Parse information relative to the current couple while (info_ptr != NULL) { print_couple_info(info_ptr) ; putchar('\n') ; info_ptr = info_ptr->next ; } printf("\n\n") ; couple_ptr = couple_ptr->next ; } } /* * Prints an element of a 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("\tAP MAC: %s\n" "\tSignal strength: %d dBm\n", ap_mac_string, info->antenna_signal_dbm - 0x100 ) ; free(ap_mac_string) ; } #endif // DEBUG char* ip_bytes_to_string(uint8_t ip_binary[4]) { int_fast8_t size = 16, i = 0 ; for (i = 0 ; i < 4 ; ++i) { if (ip_binary[i] < 0x64) size-- ; if (ip_binary[i] < 0x10) size-- ; } char *ret = malloc(sizeof(char) * size) ; sprintf(ret, "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8, ip_binary[0], ip_binary[1], ip_binary[2], ip_binary[3]) ; ret[size-1] = '\0' ; return ret ; } void print_usage() { printf("Usage:\n" "\t%s" " [-f config_file]" " [-v]" " [-o output_file]" " [-i positionner_ip]" " [-p positioner_port]" " [-l listening_port]" " [-t aggregate_timeout]" " [-k keep_timeout]" " [-c check_interval]" " [-A]" " [-a autocalibration_port]" " [-K ap_keep_timeout]" " [-C ap_check_interval]" "\n" "Main options:\n" "\t-h\t\tPrint this help.\n" "\t-f config_file\tUse 'config_file' instead of the default" " configuration file (%s).\n" "\t-v\t\tBe verbose (print detailed info on each received" " message).\n" "Output options:\n" "\t-o output_file\t\tAggregated requests will be appended to" " this file.\n" "\t-i positionner_ip\tIP address of the localisation server" " (default: %s).\n" "\t-p positioner_port\tAggregated requests are transmitted to" " the localisation server on this port (default: %d).\n" "Aggregation options:\n" "\t-l listening_port\tOnly requests sent on this port will be" " treated (default: %d).\n" "\t-t aggregate_timeout\tRequests are stored during" " 'aggregate_timeout' milliseconds before to be grouped" " (default: %d ms).\n" "\t-k keep_timeout\t\tAggregated requests are kept during" " 'keep_timeout' milliseconds (default: %d ms).\n" "\t-c check_interval\tTime between two checks of the stored" " requests (default\t%d microseconds).\n" "Autocalibration options:\n" "\t-A\t\t\tEnable autocalibration (default: disabled).\n" "\t-a port\t\t\tPort on which autocalibration data" " are exchanged with the listeners (default: %d).\n" "\t-K ap_keep_timeout\tInactive APs are kept during" " 'ap_keep_timeout' seconds (default: %d s).\n" "\t-C ap_check_interval\tTime (in milliseconds) between two" " checks of the stored APs (default: %d ms).\n" , program_name, DEFAULT_CONFIG_FILE, POSITIONER_DEFAULT_IP, POSITIONER_DEFAULT_PORT, AGGREGATE_DEFAULT_PORT, DEFAULT_AGGREGATE_TIMEOUT, DEFAULT_KEEP_TIMEOUT, DEFAULT_CHECK_INTERVAL, DEFAULT_AUTOCALIBRATION_PORT, DEFAULT_AP_KEEP_TIMEOUT, DEFAULT_AP_CHECK_INTERVAL ) ; }