/* * This file is part of the rtap localisation project. */ #include "../../libowlps/owlps.h" #define DEBUG /* Error codes */ #define ERR_CREATING_SOCKET 1 // Error when creating output socket #define ERR_BAD_USAGE 2 // Bad program call (bad number of arguments) #define ERR_SENDING_INFO 3 // Error sending a localisation request /* Number of packets to send */ #define DEFAULT_NBPKT_CALIB 20 // 20 packets when calibrating #define DEFAULT_NBPKT_NORMAL 10 // 10 packets when requesting the position /* Delay between two packet transmissions (in microseconds) */ #define DEFAULT_DELAY_CALIB 50000 // Calibration request #define DEFAULT_DELAY_NORMAL 25000 // Localisation request /* Program arguments (getopt string) */ #define OPTIONS "d:i:l::n:p:t:" /* Function headers */ void print_usage(char *prog) ; int main(int argc, char *argv[]) { struct timeval request_time ; char *buf = NULL ; // Packet to send int buf_offset ; // Index used to create the packet int buf_size ; // Packet size struct sockaddr_in server, client ; int sockfd ; // Sending socket descriptor ssize_t nsent ; // sendto() return value int i ; // Iterator // TRUE if the packet is a calibration request, FALSE if it is a simple // positioning request: BOOL is_calibration_request = FALSE ; struct { char dest_ip[16] ; // Destination IP of the packets long dest_port ; char iface[IFNAMSIZ + 1] ; // Source network interface long delay ; // Time between two packet transmissions short nb_pkt ; // Number of packets to send long listening_port ; // Calibration data: DIRECTION direction ; float x ; float y ; float z ; } options = { "", LOC_REQUEST_DEFAULT_PORT, "", -1, -1, -1, 0, 0, 0, 0 } ; int opt ; // getopt return value // Position of the mobile as computed by the infrastructure: float x, y, z ; /* Parse command line */ 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' : /* Facultative getopt options does not handle separated * values (like -l ) */ if (optarg == 0) { /* If we are at the end of the string, or the next optind * is an option, we have -l without a port number */ if (argv[optind] == NULL || argv[optind][0] == '-') // Take the default value: options.listening_port = MOBILE_DEFAULT_PORT ; else { // Take the optind value: options.listening_port = strtol(argv[optind], NULL, 0) ; optind++ ; } } else // We got an option like -l, it's OK 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 ; } } /* Check if we got a destination IP address */ if (options.dest_ip[0] == '\0') { fprintf(stderr, "Error! You must specify a destination IP address" " (-d).\n") ; print_usage(argv[0]) ; return ERR_BAD_USAGE ; } /* Parse remaining arguments (possible calibration data) */ 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 // Bad number of arguments { print_usage(argv[0]) ; return ERR_BAD_USAGE ; } } /* Check options and initialise uninitialised data */ // Delay not specified (or bad delay): if (options.delay < 0) { #ifdef DEBUG fprintf(stderr, "Warning! delay: failing back to default value.\n") ; #endif // DEBUG if (is_calibration_request) options.delay = DEFAULT_DELAY_CALIB ; else options.delay = DEFAULT_DELAY_NORMAL ; } // Number of packet not specified (or bad number) if (options.nb_pkt < 1) { #ifdef DEBUG fprintf(stderr, "Warning! nb_pkt: failing back to default value.\n") ; #endif // DEBUG if (is_calibration_request) options.nb_pkt = DEFAULT_NBPKT_CALIB ; else options.nb_pkt = DEFAULT_NBPKT_NORMAL ; } // We want to send a calibration request AND to be located, which is // not allowed: if (is_calibration_request && options.listening_port != -1) { #ifdef DEBUG fprintf(stderr, "Warning! You cannot wait for a server answer when" " you calibrate. Option -l ignored…\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 /* Open UDP socket to the aggregator */ sockfd = create_udp_sending_socket(options.dest_ip, options.dest_port, &server, &client) ; if (sockfd < 0) { perror("Error! Cannot create UDP sending socket to the aggregation" " server") ; return ERR_CREATING_SOCKET ; } if (options.iface[0] != '\0') // If we specified an interface name { if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, options.iface, strlen(options.iface) + 1) == -1) { fprintf(stderr, "Error! Cannot select interface %s to send the" " packet: ", options.iface) ; perror("") ; fprintf(stderr, "Sending through the default interface.\n") ; } } /* Create packet to send */ gettimeofday(&request_time, NULL) ; if (is_calibration_request) // Calibration packet { printf("Calibration time: %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 ; // Packet type memcpy(&buf[buf_offset], &request_time, sizeof(request_time)) ; buf_offset += sizeof(request_time) ; buf[buf_offset++] = options.direction ; // Direction #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 // Standard packet { printf("Request time: %llu\n", timeval_to_ms(request_time)) ; buf_size = sizeof(char) + sizeof(struct timeval) ; buf = malloc(buf_size) ; buf[0] = PACKET_TYPE_NORMAL ; // Packet type memcpy(&buf[1], &request_time, sizeof(request_time)) ; } /* Send data to the aggregator */ nsent = sendto(sockfd, (void *) buf, buf_size, 0, (struct sockaddr *) &server, (socklen_t) sizeof(server)) ; if (nsent != (ssize_t) buf_size) { perror("Error sending data to the aggregation server") ; return ERR_SENDING_INFO ; } #ifdef DEBUG printf("Sent packets: .") ; fflush(stdout) ; #endif // DEBUG // Transmit remaining packets (if any) for (i = 0 ; i < options.nb_pkt - 1 ; i++) { usleep(options.delay) ; // Wait during the wanted delay nsent = sendto(sockfd, (void *) buf, buf_size, 0, (struct sockaddr *) &server, (socklen_t) sizeof(server)) ; if (nsent != (ssize_t) buf_size) { perror("Error sending data to the aggregation server") ; return ERR_SENDING_INFO ; } #ifdef DEBUG putchar('.') ; fflush(stdout) ; #endif // DEBUG } #ifdef DEBUG putchar('\n') ; #endif // DEBUG (void) close(sockfd) ; /* Wait for the computed position */ 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("Computed position: (%.4f;%.4f;%.4f)\n", x, y, z); } return 0 ; } void print_usage(char *prog) { printf("Usage:\n" "Localisation request:\n" "\t%s -d dest_ip [-p dest_port] [-i iface] [-t delay]" " [-n nb_packets] [-l [port]]\n" "Calibration request:\n" "\t%s -d dest_ip [-i iface] [-t delay] [-n nb_packets]" " direction x y z\n" "\n" "Options:\n" "\t-d dest_ip\tDestination IP address of the localisation request.\n" "\t-p dest_port\tDestination port of the localisation request" " (default: %d).\n" "\t-t delay\tTime between each packet transmission.\n" "\t-n nb_packets\tNumber of packet transmitted for the request.\n" "\t-i iface\tName of the network interface used to transmit the" " request (e.g. \"eth2\"). If this option is absent, interface" " is selected automatically. You must be root to use this" " option.\n" "\t-l [port]\tWait for the computed position and display it." " Optional argument 'port' allows to specify the listening" " port (default: %d).\n" , prog, prog, LOC_REQUEST_DEFAULT_PORT, MOBILE_DEFAULT_PORT ) ; }