/* * This file is part of the rtap localisation project. */ #include "../../libowlps/owlps.h" #define DEBUG /* Codes d'erreurs */ #define ERR_CREATING_SOCKET 1 // Erreur lors de la création de la socket d'envoi #define ERR_BAD_USAGE 2 // Mauvais nombre d'arguments lors de l'appel au programme #define ERR_SENDING_INFO 3 // Erreur lors de l'envoi de l'une des demandes de positionnement /* Nombre de paquets envoyés */ #define DEFAULT_NBPKT_CALIB 20 // Rafale de 20 paquets lors de la calibration #define DEFAULT_NBPKT_NORMAL 10 // Nombre de paquets envoyés dans le cas d'une demande de localisation /* Délai entre chaque paquet envoyé */ #define DEFAULT_DELAY_CALIB 50000 // Délai entre chaque émission de paquet lors de la calibration (en microsecondes) #define DEFAULT_DELAY_NORMAL 25000 // Délai entre chaque émission de paquet dans le cas d'une demande de localisation (en microsecondes) /* Arguments du programme */ #define OPTIONS "d:i:l::n:p:t:" /* Affiche le mode d'emploi du programme */ void print_usage(char *prog) { printf("Usage :\n\ \t- Demande de localisation : %s -d dest_ip [-p dest_port] [-i iface] [-t delay] [-n nb_packets] [-l [port]]\n\ \t- Requête de calibration : %s -d dest_ip [-i iface] [-t delay] [-n nb_packets] direction x y z\n\ - dest_ip est l'adresse IP vers laquelle sera envoyée la demande de localisation.\n\ - dest_port est le port sur lequel sera envoyée la demande de localisation (défaut : %d).\n\ - delay est le délai d'attente entre chaque paquet émis.\n\ - nb_packets est le nombre de paquets émis pour la demande.\n\ - iface est une chaîne désignant le nom de interface réseau à partir de laquelle envoyer la demande (par exemple \"eth2\"). Si elle n'est pas spécifiée, le choix de l'interface source est automatique. Vous devez être root pour utiliser cette option.\n\ - L'option -l indique au programme qu'il doit attendre et afficher la position calculée par l'infrastructure avant de quitter. L'argument optionnel \"port\" permet de spécifier le port d'écoute ; s'il n'est pas présent, la valeur par défaut (%d) est utilisée.\n\ ", prog, prog, LOC_REQUEST_DEFAULT_PORT, MOBILE_DEFAULT_PORT) ; } int main(int argc, char *argv[]) { struct timeval request_time ; char *buf = NULL ; // Paquet à envoyer int buf_offset ; // Indice dans le paquet à envoyer, utilisé lors de sa création int buf_size ; // Taille du paquet envoyé struct sockaddr_in server, client ; int sockfd ; // Descripteur de la socket d'envoi ssize_t nsent ; // Retour de sendto int i ; // Compteur BOOL is_calibration_request = FALSE ; // Sera positionné à TRUE si le paquet est une requête de calibration (FALSE pour une simple demande de localisation) struct { char dest_ip[16] ; // Adresse IP de destination des paquets de la demande long dest_port ; char iface[IFNAMSIZ + 1] ; // Interface réseau depuis laquelle on envoit les paquets long delay ; // Temps d'attente entre chaque émission de paquet short nb_pkt ; // Nombre de paquets envoyés pour la demande long listening_port ; // Données de calibration : DIRECTION direction ; float x ; float y ; float z ; } options = {"", LOC_REQUEST_DEFAULT_PORT, "", -1, -1, -1, 0, 0, 0, 0 } ; int opt ; // Retour de getopt float x, y, z ; // Position reçue en réponse du serveur /* Parcours des arguments de la ligne de commandes */ while ((opt = getopt(argc, argv, OPTIONS)) != -1) { switch (opt) { case 'd' : strncpy(options.dest_ip, optarg, 16) ; break ; case 'i' : strncpy(options.iface, optarg, IFNAMSIZ + 1) ; break ; case 'l' : if (optarg == 0) // Les options facultatives de getopt ne gèrent pas { // les valeurs séparées (du type : -l ) if (argv[optind] == NULL // Si on est en bout de chaîne ou que l'optind || argv[optind][0] == '-') // suivant est une option, c'est qu'on a -l sans numéro de port options.listening_port = MOBILE_DEFAULT_PORT ; // on prend donc la valeur par défaut. else { // Sinon on prend la valeur de l'optind : options.listening_port = strtol(argv[optind], NULL, 0) ; optind++ ; } } else // On a une option de la forme -l, tout va bien options.listening_port = strtol(optarg, NULL, 0) ; break ; case 'n' : options.nb_pkt = strtol(optarg, NULL, 0) ; break ; case 'p' : options.dest_port = strtol(optarg, NULL, 0) ; break ; case 't' : options.delay = strtol(optarg, NULL, 0) ; break ; default : print_usage(argv[0]) ; return ERR_BAD_USAGE ; } } if (options.dest_ip[0] == '\0') // On vérifie si on a bien une adresse de destination { fprintf(stderr, "Erreur ! Vous devez spécifier une adresse de destination (-d).\n") ; print_usage(argv[0]) ; return ERR_BAD_USAGE ; } /* Parcours des arguments restants (éventuelles données de calibration) */ if (argc - optind != 0) { if (argc - optind == 4) { is_calibration_request = TRUE ; options.direction = strtol(argv[optind++], NULL, 0) ; options.x = strtod(argv[optind++], NULL) ; options.y = strtod(argv[optind++], NULL) ; options.z = strtod(argv[optind], NULL) ; } else { // Si le nombre d'arguments est mauvais, on quitte print_usage(argv[0]) ; return ERR_BAD_USAGE ; } } /* Vérifications des arguments et initialisation des données non initialisées */ if (options.delay < 0) // Délai non spécifié ou mauvais, application des valeurs par défaut { #ifdef DEBUG fprintf(stderr, "Attention ! delay : application de la valeur par défaut.\n") ; #endif // DEBUG if (is_calibration_request) options.delay = DEFAULT_DELAY_CALIB ; else options.delay = DEFAULT_DELAY_NORMAL ; } if (options.nb_pkt < 1) // Nombre de paquets non spécifié ou mauvais, application des valeurs par défaut { #ifdef DEBUG fprintf(stderr, "Attention ! nb_pkt : application de la valeur par défaut.\n") ; #endif // DEBUG if (is_calibration_request) options.nb_pkt = DEFAULT_NBPKT_CALIB ; else options.nb_pkt = DEFAULT_NBPKT_NORMAL ; } if (is_calibration_request && options.listening_port != -1) { #ifdef DEBUG fprintf(stderr, "Attention ! Vous ne pouvez pas attendre de réponse du serveur lorsque vous effectuez une requête de calibration. Option -l ignorée...\n") ; #endif // DEBUG options.listening_port = -1 ; } #ifdef DEBUG fprintf(stderr, "Options :\n\ \tDestination IP : %s\n\ \tDestination port : %ld\n\ \tInterface : %s\n\ \tDelay : %ld\n\ \tNumber of packets : %d\n\ \tListening port : %ld\n\ \tDirection : %d\n\ \tX : %f\n\ \tY : %f\n\ \tZ : %f\n", options.dest_ip, options.dest_port, options.iface, options.delay, options.nb_pkt, options.listening_port, options.direction, options.x, options.y, options.z ) ; #endif // DEBUG /* Ouverture de la socket UDP vers le serveur d'aggrégation */ sockfd = create_udp_sending_socket(options.dest_ip, options.dest_port, &server, &client) ; if (sockfd < 0) { perror("Erreur ! Impossible de créer la socket vers le serveur d'aggrégation \n"); return ERR_CREATING_SOCKET ; } if (options.iface[0] != '\0') // Si on a spécifié un nom d'interface { if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, options.iface, strlen(options.iface) + 1) == -1) { fprintf(stderr, "Erreur ! Impossible de sélectionner l'interface %s pour l'envoi du paquet : ", options.iface) ; perror("") ; fprintf(stderr, "Envoi sur l'interface par défaut.\n") ; } } /* Création du paquet à envoyer */ gettimeofday(&request_time, NULL) ; if (is_calibration_request) // Paquet calibration { printf("Envoi Calibration effectué à : %llu\n", timeval_to_ms(request_time)) ; buf_offset = 0 ; buf_size = sizeof(char) * 2 + sizeof(struct timeval) + sizeof(float) * 3 ; buf = malloc(buf_size) ; buf[buf_offset++] = PACKET_TYPE_CALIBRATION ; // Type de paquet = calibration memcpy(&buf[buf_offset], &request_time, sizeof(request_time)) ; buf_offset += sizeof(request_time) ; buf[buf_offset++] = options.direction ; // Direction /* float posX = options.x ; float posY = options.y ; float posZ = options.z ; */ #ifdef DEBUG printf("Direction = %d, X = %f, Y = %f, Z = %f\n", buf[buf_offset - 1], options.x, options.y, options.z) ; #endif // DEBUG memcpy(&buf[buf_offset], &options.x, sizeof(float)) ; buf_offset += sizeof(float) ; memcpy(&buf[buf_offset], &options.y, sizeof(float)) ; buf_offset += sizeof(float) ; memcpy(&buf[buf_offset], &options.z, sizeof(float)) ; } else // Paquet normal { printf("Envoi normal effectué à : %llu\n", timeval_to_ms(request_time)) ; buf_size = sizeof(char) + sizeof(struct timeval) ; buf = malloc(buf_size) ; buf[0] = PACKET_TYPE_NORMAL ; // Type de paquet = demande memcpy(&buf[1], &request_time, sizeof(request_time)) ; } /* Envoi des infos au serveur d'aggrégation */ nsent = sendto(sockfd, (void *) buf, buf_size, 0, (struct sockaddr *) &server, (socklen_t) sizeof(server)) ; // Envoi d'un paquet. if (nsent != (ssize_t) buf_size) { perror("Erreur lors de l'envoi des informations au serveur ") ; return ERR_SENDING_INFO ; } #ifdef DEBUG printf("Paquets envoyés : .") ; fflush(stdout) ; #endif // DEBUG for (i = 0 ; i < options.nb_pkt - 1 ; i++) // Si tels sont les paramètres, on envoit éventuellement la suite de la rafale de paquets : { usleep(options.delay) ; // On attend le temps voulu entre chaque paquet. nsent = sendto(sockfd, (void *) buf, buf_size, 0, (struct sockaddr *) &server, (socklen_t) sizeof(server)) ; if (nsent != (ssize_t) buf_size) { perror("Erreur lors de l'envoi des infos au serveur ") ; return ERR_SENDING_INFO ; } #ifdef DEBUG putchar('.') ; fflush(stdout) ; #endif // DEBUG } #ifdef DEBUG putchar('\n') ; #endif // DEBUG (void) close(sockfd) ; /* Attente de la position du serveur */ if (options.listening_port != -1) { sockfd = create_udp_listening_socket(options.listening_port); recvfrom(sockfd, &x, sizeof(float), 0, NULL, NULL); recvfrom(sockfd, &y, sizeof(float), 0, NULL, NULL); recvfrom(sockfd, &z, sizeof(float), 0, NULL, NULL); (void) close(sockfd) ; printf("Position reçue : (%.4f;%.4f;%.4f)\n", x, y, z); } return 0 ; }