owlps/infrastructure-centred/owlps-client/owlps-client.c

441 lines
11 KiB
C
Raw Normal View History

/*
* 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) */
2010-07-13 17:02:48 +02:00
#define OPTIONS "d:hi:l::n:p:t:"
/* Function headers */
void parse_command_line(int argc, char **argv) ;
void parse_main_options(int argc, char **argv) ;
void check_destination_ip(void) ;
void parse_calibration_data(int argc, char **argv) ;
void check_configuration(void) ;
#ifdef DEBUG
void print_configuration(void) ;
#endif // DEBUG
2010-07-13 18:20:35 +02:00
void create_socket(void) ;
void make_packet(void) ;
void send_request(void) ;
void send_packet(void) ;
void receive_position(void) ;
void print_usage(void) ;
/* Options */
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
} ;
char *program_name = NULL ;
// TRUE if the packet is a calibration request, FALSE if it is a simple
// positioning request:
BOOL is_calibration_request = FALSE ;
2010-07-13 18:20:35 +02:00
int sockfd ; // Sending socket descriptor
struct sockaddr_in server ; // Server info
char *buf = NULL ; // Packet to send
int buf_size ; // Packet size
int main(int argc, char *argv[])
{
program_name = argv[0] ;
parse_command_line(argc, argv) ;
2010-07-13 18:20:35 +02:00
create_socket() ;
make_packet() ;
send_request() ;
(void) close(sockfd) ;
if (options.listening_port != -1)
2010-07-13 18:20:35 +02:00
receive_position() ;
return 0 ;
}
void parse_command_line(int argc, char **argv)
{
parse_main_options(argc, argv) ;
check_destination_ip() ;
parse_calibration_data(argc, argv) ;
check_configuration() ;
#ifdef DEBUG
print_configuration() ;
#endif // DEBUG
}
void parse_main_options(int argc, char **argv)
{
int opt ;
while ((opt = getopt(argc, argv, OPTIONS)) != -1)
{
switch (opt)
{
case 'd' :
strncpy(options.dest_ip, optarg, 16) ;
break ;
2010-07-13 17:02:48 +02:00
case 'h' :
print_usage() ;
exit(0) ;
case 'i' :
strncpy(options.iface, optarg, IFNAMSIZ + 1) ;
break ;
case 'l' :
/* Facultative getopt options does not handle separated
* values (like -l <port>) */
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<port>, 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() ;
exit(ERR_BAD_USAGE) ;
}
}
}
void check_destination_ip()
{
/* 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() ;
exit(ERR_BAD_USAGE) ;
}
}
void parse_calibration_data(int argc, char **argv)
{
/* 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() ;
exit(ERR_BAD_USAGE) ;
}
}
}
void check_configuration()
{
// 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
void print_configuration()
{
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
2010-07-13 18:20:35 +02:00
/* Creates the packet to send. */
void make_packet()
{
int buf_offset ; // Index used to create the packet
int buf_size ; // Packet size
struct timeval request_time ;
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)) ;
}
}
/* Opens an UDP socket to the aggregator. */
void create_socket()
{
struct sockaddr_in client ;
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") ;
exit(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") ;
}
}
}
void send_request()
{
int i ;
#ifdef DEBUG
printf("Sent packets: ") ;
#endif // DEBUG
send_packet() ; // Transmit first packet
// Transmit remaining packets (if any)
for (i = 0 ; i < options.nb_pkt - 1 ; ++i)
{
usleep(options.delay) ; // Wait during the wanted delay
send_packet() ;
}
#ifdef DEBUG
putchar('\n') ;
#endif // DEBUG
}
void send_packet()
{
ssize_t 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") ;
exit(ERR_SENDING_INFO) ;
}
#ifdef DEBUG
putchar('.') ;
fflush(stdout) ;
#endif // DEBUG
}
void receive_position()
{
// Position of the mobile as computed by the infrastructure:
float x, y, z ;
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) ;
}
void print_usage()
{
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"
2010-07-13 17:02:48 +02:00
"\t-h\t\tPrint this help.\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"
,
program_name,
program_name,
LOC_REQUEST_DEFAULT_PORT,
MOBILE_DEFAULT_PORT
) ;
}