diff --git a/Makefile b/Makefile index 037415e..335f549 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,28 @@ +ifndef MAKE + MAKE = make +endif + .PHONY: \ all c clean purge help \ libowlps \ libowlps-client \ + libowlps-resultreader \ owlps-client \ owlps-listener \ owlps-aggregator \ + owlps-udp-to-http \ owlps-positioning \ install \ install-owlps-client \ install-owlps-listener \ install-owlps-aggregator \ + install-owlps-udp-to-http \ install-owlps-positioning \ uninstall \ uninstall-owlps-client \ uninstall-owlps-listener \ uninstall-owlps-aggregator \ + uninstall-owlps-udp-to-http \ uninstall-owlps-positioning ## Compilation ## @@ -26,22 +34,28 @@ all: \ c: \ libowlps \ libowlps-client \ + libowlps-resultreader \ owlps-client \ owlps-listener \ - owlps-aggregator + owlps-aggregator \ + owlps-udp-to-http libowlps: - @make -C $@ + @$(MAKE) -C $@ libowlps-client: libowlps - @make -C $@ + @$(MAKE) -C $@ +libowlps-resultreader: libowlps + @$(MAKE) -C $@ owlps-client: libowlps libowlps-client - @make -C $@ + @$(MAKE) -C $@ owlps-listener: libowlps libowlps-client - @make -C $@ + @$(MAKE) -C $@ owlps-aggregator: libowlps - @make -C $@ + @$(MAKE) -C $@ +owlps-udp-to-http: libowlps libowlps-resultreader + @$(MAKE) -C $@ owlps-positioning: libowlps - @make -C $@ + @$(MAKE) -C $@ ## Installation ## @@ -51,18 +65,21 @@ install : \ install-owlps-client \ install-owlps-listener \ install-owlps-aggregator \ + install-owlps-udp-to-http \ install-owlps-positioning install-libowlps: - @make -C $(subst install-,,$@) install + @$(MAKE) -C $(subst install-,,$@) install install-owlps-client: install-libowlps - @make -C $(subst install-,,$@) install + @$(MAKE) -C $(subst install-,,$@) install install-owlps-listener: install-libowlps - @make -C $(subst install-,,$@) install + @$(MAKE) -C $(subst install-,,$@) install install-owlps-aggregator: install-libowlps - @make -C $(subst install-,,$@) install + @$(MAKE) -C $(subst install-,,$@) install +install-owlps-udp-to-http: install-libowlps + @$(MAKE) -C $(subst install-,,$@) install install-owlps-positioning: install-libowlps - @make -C $(subst install-,,$@) install + @$(MAKE) -C $(subst install-,,$@) install ## Uninstallation ## @@ -72,37 +89,44 @@ uninstall : \ uninstall-owlps-client \ uninstall-owlps-listener \ uninstall-owlps-aggregator \ + uninstall-owlps-udp-to-http \ uninstall-owlps-positioning uninstall-libowlps: - @make -C $(subst uninstall-,,$@) uninstall + @$(MAKE) -C $(subst uninstall-,,$@) uninstall uninstall-owlps-client: - @make -C $(subst uninstall-,,$@) uninstall + @$(MAKE) -C $(subst uninstall-,,$@) uninstall uninstall-owlps-listener: - @make -C $(subst uninstall-,,$@) uninstall + @$(MAKE) -C $(subst uninstall-,,$@) uninstall uninstall-owlps-aggregator: - @make -C $(subst uninstall-,,$@) uninstall + @$(MAKE) -C $(subst uninstall-,,$@) uninstall +uninstall-owlps-udp-to-http: + @$(MAKE) -C $(subst uninstall-,,$@) uninstall uninstall-owlps-positioning: - @make -C $(subst uninstall-,,$@) uninstall + @$(MAKE) -C $(subst uninstall-,,$@) uninstall ## Cleaning ## clean : - @make -C libowlps clean - @make -C libowlps-client clean - @make -C owlps-client clean - @make -C owlps-listener clean - @make -C owlps-aggregator clean - @make -C owlps-positioning clean + @$(MAKE) -C libowlps clean + @$(MAKE) -C libowlps-client clean + @$(MAKE) -C libowlps-resultreader clean + @$(MAKE) -C owlps-client clean + @$(MAKE) -C owlps-listener clean + @$(MAKE) -C owlps-aggregator clean + @$(MAKE) -C owlps-udp-to-http clean + @$(MAKE) -C owlps-positioning clean purge : - @make -C libowlps purge - @make -C libowlps-client purge - @make -C owlps-client purge - @make -C owlps-listener purge - @make -C owlps-aggregator purge - @make -C owlps-positioning purge + @$(MAKE) -C libowlps purge + @$(MAKE) -C libowlps-client purge + @$(MAKE) -C libowlps-resultreader purge + @$(MAKE) -C owlps-client purge + @$(MAKE) -C owlps-listener purge + @$(MAKE) -C owlps-aggregator purge + @$(MAKE) -C owlps-udp-to-http purge + @$(MAKE) -C owlps-positioning purge ## Help ## diff --git a/TODO b/TODO index 5279ed0..6ab278c 100644 --- a/TODO +++ b/TODO @@ -1,11 +1,21 @@ * Global +- Known bugs + ° libconfuse bugs (Listener & Aggregator): + . http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=639074 + . http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=639115 +- Rename some fields in the structures + ° start_time -> rx_time, first_rx_time +- Eliminate remaining exit() calls to avoid memory leaks on exit. - Add option dump-configuration (displays the config & exits). - Makefiles: ° Translate comments & help. ° Merge Makefile and Makefile_atheros*. Use template makefiles, autohell, cmake…? -- Use string for network exchanges? +- Use a string for positioning requests + Instead of a binary packet, use a CSV string containing the request + information. This will allow easy developments of clients in other + languages. - Mark arguments as const in function headers if needed Mostly done in the owlps-positioning C++ code (should check that), but not constantly in C modules. @@ -52,30 +62,56 @@ Get rid of the "Cannot open configuration file" error, in quiet mode and when the default configuration file has to be used (no file specified by the user with -f). -- Listen for autocalibration requests without sending requests? +- Filter the number of implicit packets per mobile? + Currently, in passive or mixed mode, *all* the receive packets are + transmitted to the aggregator. +- Option "read-only autocalibration"? + Listen for autocalibration requests without sending requests. - read_packet(): use ieee80211_header_size for all implicit packets Currently the size is corrected only for data packets. +- BSD port + http://www.unixgarden.com/index.php/programmation/introduction-a-la-programmation-wifi-en-c-sous-netbsd +- Use the "official" radiotap parser? (Expat license) + http://git.sipsolutions.net/?p=radiotap.git * Client -- Handle signals. - Add verbose & quiet options. - Log sent requests? - Allow to use a string for the direction? Could be nice, but probably useless. +* UDP to HTTP + +- Command-line options (port numbers, -v/-q, -h, -V). +- Delete inactive clients after a given amount of time. +- Refactor prepare_answer(). + + * Positioning - Known bugs ° Cannot compute the error (Real) with autocalibration requests. - Algorithms + ° Add to the result the information "area error" (whether on not the + computed result is in the same room as the real position). + ° Delete reference points after a given amount of time. This is to + avoid meaningless old reference points, for instance if an AP was + shut down. + ° Handle the power and antenna gain difference between the + calibration mobile (or pseudo-mobile, for autocalibration) and the + mobile to position. ° MinMax: use a different step for X, Y and Z? - Autocalibration ° Generate reference points in 3D. + ° Check what happens with >4 APs, and fix it. We certainly should + select APs not only by the angle proximity, but also by the + distance proximity. Maybe implement three options: angle, distance, + and angle + distance. ° Handle 2 APs, not only >2 APs. ° Find why some CalibrationRequest were not deleted when calling Stock::delete_calibration_request() (via @@ -109,7 +145,12 @@ with relative path in owlps-positioning.cfg in the same directory). - Optimisation & code improvement - ° Multithread algorithm calls. + ° Multithreading: + . algorithm (parallelize computation of the different algorithms + for the same request) ; + . and/or requests (parallelize computation of several requests). + It would be possible (overkill?) to have a group of worker threads + and a job queue. ° ReferencePoint: the request list should be an unordered_set instead of a vector, to guarantee the unicity of the elements. ° Pre-allocate vectors' memory with reserve(). diff --git a/libowlps-client/Makefile b/libowlps-client/Makefile index 033d797..04556b6 100644 --- a/libowlps-client/Makefile +++ b/libowlps-client/Makefile @@ -23,6 +23,7 @@ OBJS=$(LIB_CIBLE).o # Flags LIBOWLPS_DIR = ../libowlps CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes -O -I$(LIBOWLPS_DIR) +#CFLAGS += -g -O0 CFLAGS += -D DEBUG DEPFLAGS=-MMD XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) diff --git a/libowlps-client/Makefile_atheros_openwrt-10.03 b/libowlps-client/Makefile_atheros_openwrt-10.03 index 5cb21ed..b874e5c 100644 --- a/libowlps-client/Makefile_atheros_openwrt-10.03 +++ b/libowlps-client/Makefile_atheros_openwrt-10.03 @@ -26,6 +26,7 @@ OBJS=$(LIB_CIBLE).o # Flags LIBOWLPS_DIR = ../libowlps CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes -O -I$(LIBOWLPS_DIR) +#CFLAGS += -g -O0 CFLAGS += -D DEBUG DEPFLAGS=-MMD XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) diff --git a/libowlps-client/Makefile_atheros_openwrt-8.09 b/libowlps-client/Makefile_atheros_openwrt-8.09 index 95b4248..0e1e12b 100644 --- a/libowlps-client/Makefile_atheros_openwrt-8.09 +++ b/libowlps-client/Makefile_atheros_openwrt-8.09 @@ -26,6 +26,7 @@ OBJS=$(LIB_CIBLE).o # Flags LIBOWLPS_DIR = ../libowlps CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes -O -I$(LIBOWLPS_DIR) +#CFLAGS += -g -O0 CFLAGS += -D DEBUG DEPFLAGS=-MMD XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) diff --git a/libowlps-client/libowlps-client.c b/libowlps-client/libowlps-client.c index 4451097..2e68518 100644 --- a/libowlps-client/libowlps-client.c +++ b/libowlps-client/libowlps-client.c @@ -16,10 +16,10 @@ * 'iface' if specified (if you want the interface to be selected, * automatically, this parameter should be NULL or an empty string). */ -int owlclient_create_trx_socket(const char *const dest_ip, - const uint_fast16_t dest_port, - struct sockaddr_in *const server, - const char *const iface) +int owl_create_trx_socket(const char *const dest_ip, + const uint_fast16_t dest_port, + struct sockaddr_in *const server, + const char *const iface) { struct sockaddr_in client ; @@ -29,12 +29,12 @@ int owlclient_create_trx_socket(const char *const dest_ip, { perror("Error! Cannot create UDP sending socket to the aggregation" " server") ; - exit(ERR_CREATING_SOCKET) ; + exit(OWL_ERR_SOCKET_CREATE) ; } // If we specified an interface name if (iface != NULL && iface[0] != '\0') - owlclient_use_iface(sockfd, iface) ; + owl_use_iface(sockfd, iface) ; return sockfd ; } @@ -42,7 +42,7 @@ int owlclient_create_trx_socket(const char *const dest_ip, /* Selects 'iface' as sending interface for the socket 'sockfd'. */ -void owlclient_use_iface(const int sockfd, const char *const iface) +void owl_use_iface(const int sockfd, const char *const iface) { #ifdef __GLIBC__ if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, iface, @@ -66,12 +66,12 @@ void owlclient_use_iface(const int sockfd, const char *const iface) * nb_pkt: number of packets to transmit. * delay: delay between two transmissions, in milliseconds. */ -void owlclient_send_request(const int sockfd, - const struct sockaddr_in *const server, - const void *const packet, - const uint_fast16_t packet_size, - const uint_fast16_t nb_pkt, - const uint_fast32_t delay) +void owl_send_request(const int sockfd, + const struct sockaddr_in *const server, + const void *const packet, + const uint_fast16_t packet_size, + const uint_fast16_t nb_pkt, + const uint_fast32_t delay) { uint_fast16_t i ; @@ -83,13 +83,13 @@ void owlclient_send_request(const int sockfd, #endif // DEBUG // Transmit first packet: - owlclient_send_packet(sockfd, server, packet, packet_size) ; + owl_send_packet(sockfd, server, packet, packet_size) ; // Transmit remaining packets (if any): for (i = 0 ; i < nb_pkt - 1 ; ++i) { - usleep(delay * 1000) ; // Wait during the wanted delay - owlclient_send_packet(sockfd, server, packet, packet_size) ; + owl_msleep(delay) ; // Wait during the wanted delay + owl_send_packet(sockfd, server, packet, packet_size) ; } #ifdef DEBUG @@ -99,10 +99,10 @@ void owlclient_send_request(const int sockfd, -void owlclient_send_packet(const int sockfd, - const struct sockaddr_in *const server, - const void *const packet, - const uint_fast16_t packet_size) +void owl_send_packet(const int sockfd, + const struct sockaddr_in *const server, + const void *const packet, + const uint_fast16_t packet_size) { ssize_t nsent = sendto(sockfd, packet, packet_size, 0, (struct sockaddr *) server, @@ -110,7 +110,7 @@ void owlclient_send_packet(const int sockfd, if (nsent != (ssize_t) packet_size) { perror("Error sending data to the aggregation server") ; - exit(ERR_SENDING_INFO) ; + exit(OWL_ERR_SOCKET_SEND) ; } #ifdef DEBUG diff --git a/libowlps-client/owlps-client.h b/libowlps-client/owlps-client.h index 210df38..cb464d6 100644 --- a/libowlps-client/owlps-client.h +++ b/libowlps-client/owlps-client.h @@ -8,27 +8,23 @@ #include -/* Error codes */ -#define ERR_CREATING_SOCKET 151 // Error when creating output socket -#define ERR_SENDING_INFO 152 // Error sending a localisation request - /* Function headers */ -int owlclient_create_trx_socket(const char *const dest_ip, - const uint_fast16_t dest_port, - struct sockaddr_in *const server, - const char *const iface) ; -void owlclient_use_iface(const int sockfd, const char *const iface) ; -void owlclient_send_request(const int sockfd, - const struct sockaddr_in *const server, - const void *const packet, - const uint_fast16_t packet_size, - const uint_fast16_t nb_pkt, - const uint_fast32_t delay) ; -void owlclient_send_packet(const int sockfd, - const struct sockaddr_in *const server, - const void *const packet, - const uint_fast16_t packet_size) ; +int owl_create_trx_socket(const char *const dest_ip, + const uint_fast16_t dest_port, + struct sockaddr_in *const server, + const char *const iface) ; +void owl_use_iface(const int sockfd, const char *const iface) ; +void owl_send_request(const int sockfd, + const struct sockaddr_in *const server, + const void *const packet, + const uint_fast16_t packet_size, + const uint_fast16_t nb_pkt, + const uint_fast32_t delay) ; +void owl_send_packet(const int sockfd, + const struct sockaddr_in *const server, + const void *const packet, + const uint_fast16_t packet_size) ; #endif // _LIBOWLPS_CLIENT_ diff --git a/libowlps-resultreader/Makefile b/libowlps-resultreader/Makefile new file mode 100644 index 0000000..14fd90f --- /dev/null +++ b/libowlps-resultreader/Makefile @@ -0,0 +1,82 @@ +# Compilateur +COLORGCC := $(shell which colorgcc >/dev/null 2>&1 ; echo $$?) +ifeq ($(COLORGCC), 0) + CC = colorgcc +endif + +# Autres outils +AR = ar +RANLIB = ranlib +RM = rm -f + +# Variables générales +LIB_CIBLE = libowlps-resultreader +VERSION = 1.0 + +# Cibles à construire +STATIC = $(LIB_CIBLE).a +HEADER = owlps-resultreader.h +EXAMPLE = owlps-resultreader-udp + +# Composition de la bibliothèque +OBJS = $(LIB_CIBLE).o + +# Flags +LIBOWLPS_DIR = ../libowlps +CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes -O -I$(LIBOWLPS_DIR) +#CFLAGS += -g -O0 +CFLAGS += -D DEBUG +DEPFLAGS = -MMD +XCFLAGS = $(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) +PICFLAG = -fPIC +#STRIPFLAGS = -Wl,-s +#LDFLAGS = + + +## Cibles de compilation standard ## + +.PHONY : all static clean purge help + +all : static example +static : $(STATIC) +example : $(EXAMPLE) + +# Cancel implicit make rule +%: %.c + +%.o : %.c $(HEADER) + $(CC) $(XCFLAGS) -c $< + +% : %.o $(HEADER) $(STATIC) + $(CC) $(STRIPFLAGS) $(XCFLAGS) -o $@ $< \ + $(STATIC) -L$(LIBOWLPS_DIR) -lowlps -lrt + +# Compilation de la bibliothèque statique +$(STATIC) : $(OBJS) + $(RM) $@ + $(AR) cru $@ $^ + $(RANLIB) $@ + + +## Nettoyage ## + +clean : + @$(RM) *~ *.o *.d + +purge : clean + @$(RM) $(STATIC) $(EXAMPLE) + + +## Aide ## + +help : + @echo "Bibliothèques nécessaires à la compilation :" + @echo " libowlps-dev" + @echo + @echo "Cibles possibles :" + @echo " static : Compile la bibliothèque statique (.a)." + @echo " example : Compile le programme d'exemple." + @echo " (Cible par défaut : static et example.)" + @echo + @echo " clean : Supprime les fichiers temporaires." + @echo " purge : Supprime le résultat de la compilation." diff --git a/libowlps-resultreader/libowlps-resultreader.c b/libowlps-resultreader/libowlps-resultreader.c new file mode 100644 index 0000000..d3602ab --- /dev/null +++ b/libowlps-resultreader/libowlps-resultreader.c @@ -0,0 +1,438 @@ +#include "owlps-resultreader.h" + +#include +#include +#include + +#include + + +#define CSV_DELIMITER ";" + + +/* + * Receives a result from the socket of file descriptor 'sockfd', fills + * an owl_result structure with the received information, and returns a + * pointer to it. + * + * Note that the new owl_result is allocated with malloc() and must be + * deleted using free(). + * + * In case of error, a message is printed, except if owl_run (from + * libowlps) is false, and NULL is returned. + */ +owl_result* owl_receive_position(int sockfd) +{ + ssize_t nread ; // recvfrom return value + char csv[OWL_CSV_RESULT_STRLEN] ; // Read string + + nread = recvfrom(sockfd, &csv, OWL_CSV_RESULT_STRLEN, + 0, NULL, NULL) ; + + if (nread <= 0) + { + if (owl_run) + perror("No request received from listener") ; + return NULL ; + } + + return owl_fill_result(csv) ; +} + + +/* + * Splits the 'csv' string received from OwlPS Positioning and stores + * the fields in a new owl_result, and returns a pointer to it (or NULL + * in case of error). + * + * Note that the new owl_result is allocated with malloc() and must be + * deleted using free(). + * + * Handled CSV format: + * Mobile_MAC;Request_type;Request_timestamp;Algorithm;X;Y;Z;Error;Area + * The Request_timestamp format is: + * seconds.nanoseconds + * The Area field can be empty. + */ +owl_result* owl_fill_result(char *csv) +{ + char *csv_field = NULL ; + owl_result *result = NULL ; + + result = malloc(sizeof(owl_result)) ; + memset(result, 0, sizeof(*result)) ; + + /* Mobile MAC address */ + csv_field = strsep(&csv, CSV_DELIMITER) ; + if (! csv_field) + { + fprintf(stderr, + "Error reading the mobile's MAC address from the CSV" + " string (empty string?)!\n") ; + goto error ; + } + result->mobile_mac_addr = + strndup(csv_field, OWL_ETHER_ADDR_STRLEN) ; + + /* Request type */ + csv_field = strsep(&csv, CSV_DELIMITER) ; + if (! csv_field) + { + fprintf(stderr, + "Error reading the request type from the CSV string!\n") ; + goto error ; + } + result->request_type = atoi(csv_field) ; + + /* Timestamp */ + // Seconds + csv_field = strsep(&csv, ".") ; + if (! csv_field) + { + fprintf(stderr, + "Error reading the timestamp (seconds) from the CSV" + " string!\n") ; + goto error ; + } + result->mobile_timestamp.tv_sec = atol(csv_field) ; + // Nanoseconds + csv_field = strsep(&csv, CSV_DELIMITER) ; + if (! csv_field) + { + fprintf(stderr, + "Error reading the timestamp (nanoseconds) from the CSV" + " string!\n") ; + goto error ; + } + result->mobile_timestamp.tv_nsec = atol(csv_field) ; + + /* Algorithm results */ + do + { + owl_algorithm_result *current_algo = + owl_fill_algorithm_result(&csv) ; + if (current_algo == NULL) + { + fprintf(stderr, "Error reading the algorithm #%d!\n", + result->nb_results + 1) ; + break ; + } + // Insert the current algorithm at the begining of the list + current_algo->next = result->results ; + result->results = current_algo ; + ++result->nb_results ; + } + while (csv) ; + + return result ; // Success + + error: + owl_free_result(result) ; + return NULL ; +} + + +/* + * Splits the 'csv' string, stores the fields in a new + * owl_algorithm_result, and returns a pointer to it (or NULL + * in case of error). + * + * Note that the new owl_algorithm_result is allocated with malloc() + * and must be deleted using free(). + * + * 'csv' must follow this CSV format: + * Algorithm;X;Y;Z;Error;Area + * The Area field can be empty. + */ +owl_algorithm_result* owl_fill_algorithm_result(char **csv) +{ + owl_algorithm_result *algo ; + char *csv_field = NULL ; + + algo = malloc(sizeof(owl_algorithm_result)) ; + memset(algo, 0, sizeof(*algo)) ; + + // Algorithm name + csv_field = strsep(csv, CSV_DELIMITER) ; + if (! csv_field) + { + fprintf(stderr, + "Error reading the algorithm name from the CSV string!\n") ; + goto error ; + } + algo->algorithm = + strndup(csv_field, OWL_ALGORITHM_STRLEN) ; + + // X coordinate + csv_field = strsep(csv, CSV_DELIMITER) ; + if (! csv_field) + { + fprintf(stderr, + "Error reading the X coordinate from the CSV string!\n") ; + goto error ; + } + algo->x = atof(csv_field) ; + + // Y coordinate + csv_field = strsep(csv, CSV_DELIMITER) ; + if (! csv_field) + { + fprintf(stderr, + "Error reading the Y coordinate from the CSV string!\n") ; + goto error ; + } + algo->y = atof(csv_field) ; + + // Z coordinate + csv_field = strsep(csv, CSV_DELIMITER) ; + if (! csv_field) + { + fprintf(stderr, + "Error reading the Z coordinate from the CSV string!\n") ; + goto error ; + } + algo->z = atof(csv_field) ; + + // Distance error + csv_field = strsep(csv, CSV_DELIMITER) ; + if (! csv_field) + { + fprintf(stderr, + "Error reading the distance error from the CSV string!\n") ; + goto error ; + } + algo->error = atof(csv_field) ; + + // Area name (optional) + csv_field = strsep(csv, CSV_DELIMITER) ; + if (csv_field) + algo->area = strndup(csv_field, OWL_AREA_STRLEN) ; + + return algo ; // Success + + error: + owl_free_algorithm_result(algo) ; + return NULL ; +} + + +/* + * Converts an owl_result back to a CSV string. + * 'dst' must be an allocated string of at least OWL_CSV_RESULT_STRLEN + * characters. + * + * CSV format: + * Mobile_MAC;Request_type;Request_timestamp;Nb_algo;Algo_1;…;Algo_n + * Nb_algo is the number of algorithms in the result. + * The format of Algo_i is documented in owl_algorithm_result_to_csv(). + */ +void owl_result_to_csv(char dst[OWL_CSV_RESULT_STRLEN], + const owl_result *const src) +{ + size_t dst_len ; + char timestamp_str[OWL_TIMESTAMP_STRLEN] ; + + assert(src) ; + + owl_timestamp_to_string(timestamp_str, src->mobile_timestamp) ; + snprintf(dst, OWL_CSV_RESULT_REQUEST_STRLEN, + "%s;%"PRIu8";%s;%u", + src->mobile_mac_addr, + src->request_type, + timestamp_str, + src->nb_results) ; + dst_len = strlen(dst) ; + + owl_algorithm_result *algo = src->results ; + while (algo) + { + char algo_str[OWL_CSV_ALGORITHM_RESULT_STRLEN] ; + owl_algorithm_result_to_csv(algo_str, algo) ; + dst[dst_len++] = ';' ; + strncpy(dst + dst_len, algo_str, OWL_CSV_ALGORITHM_RESULT_STRLEN) ; + dst_len += strlen(algo_str) ; + algo = algo->next ; + } +} + + +/* + * Converts an owl_algorithm_result back to a CSV string. + * 'dst' must be an allocated string of at least + * OWL_CSV_ALGORITHM_RESULT_STRLEN characters. + * + * CSV format: + * Algorithm_name;X;Y;Z;Error;Area_name + * Error is the distance from the true coordinates of the mobile, if + * known; if unknown, Error is set to -1. + * Area_name is the name of the area or room in which the mobile is (may + * be empty). + */ +void +owl_algorithm_result_to_csv(char dst[OWL_CSV_ALGORITHM_RESULT_STRLEN], + const owl_algorithm_result *const src) +{ + assert(src) ; + + snprintf(dst, OWL_CSV_ALGORITHM_RESULT_STRLEN, + "%s;%f;%f;%f;%f;%s", + src->algorithm, + src->x, + src->y, + src->z, + src->error, + src->area ? src->area : "") ; +} + + +/* + * Converts an owl_result back to a CSV string, in a simplified format. + * Only the *first* algorithm in the result's algorithm list will be + * included in the string. + * 'dst' must be an allocated string of at least + * OWL_CSV_RESULT_SIMPLE_STRLEN characters. + * + * CSV format: + * Mobile_MAC;First_algorithm + * First_algorithm is the first algorithm in src->results. Its format + * is documented in owl_algorithm_result_to_csv_simple(). + */ +void owl_result_to_csv_simple(char dst[OWL_CSV_RESULT_SIMPLE_STRLEN], + const owl_result *const src) +{ + size_t dst_len ; + char algo_str[OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN] ; + + assert(src) ; + + strncpy(dst, src->mobile_mac_addr, OWL_ETHER_ADDR_STRLEN) ; + dst[OWL_ETHER_ADDR_STRLEN - 1] = ';' ; + dst_len = OWL_ETHER_ADDR_STRLEN ; + + if (! src->results) + return ; + + owl_algorithm_result_to_csv_simple(algo_str, src->results) ; + strncpy(dst + dst_len, algo_str, + OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN) ; +} + + +/* + * Converts an owl_algorithm_result back to a CSV string, in a + * simplified format. + * 'dst' must be an allocated string of at least + * OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN characters. + * + * CSV format: + * X;Y;Z;Area_name + * Area_name is the name of the area or room in which the mobile is (may + * be empty). + */ +void owl_algorithm_result_to_csv_simple +(char dst[OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN], + const owl_algorithm_result *const src) +{ + assert(src) ; + + snprintf(dst, OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN, + "%f;%f;%f;%s", + src->x, + src->y, + src->z, + src->area ? src->area : "") ; +} + + +/* + * Prints an owl_result to the given stream. + */ +void owl_fprint_result(FILE *stream, const owl_result *const src) +{ + char timestamp_str[OWL_TIMESTAMP_STRLEN] ; + + assert(src) ; + + owl_timestamp_to_string(timestamp_str, src->mobile_timestamp) ; + fprintf(stream, + "Mobile MAC: %s\n" + "Request type: %"PRIu8"\n" + "Mobile timestamp: %s\n" + "%u results:\n" + , + src->mobile_mac_addr, + src->request_type, + timestamp_str, + src->nb_results) ; + + owl_algorithm_result *algo = src->results ; + while (algo) + { + owl_fprint_algorithm_result(stream, algo) ; + algo = algo->next ; + } +} + + +/* + * Prints an owl_algorithm_result to the given stream. + */ +void owl_fprint_algorithm_result(FILE *stream, + const owl_algorithm_result *const src) +{ + assert(src) ; + + fprintf(stream, + "* Algorithm: %s\n" + " X: %f\n" + " Y: %f\n" + " Z: %f\n" + " Error: %f\n" + " Area: %s\n" + , + src->algorithm, + src->x, + src->y, + src->z, + src->error, + src->area ? src->area : "" + ) ; +} + + + +/* + * Frees the memory allocated by an owl_result. The 'results' and + * 'mobile_mac_addr' fields *must* be defined, either to NULL or to a + * valid memory block allocated with malloc(). + * Note that the pointer will not set to NULL. + */ +void owl_free_result(owl_result *result) +{ + if (! result) + return ; + while (result->results) + { + owl_algorithm_result *algo = result->results ; + result->results = algo->next ; + owl_free_algorithm_result(algo) ; + } + free(result->mobile_mac_addr) ; + free(result) ; +} + + +/* + * Frees the memory allocated by a single owl_algorithm_result (*not* + * recursively). The 'algorithm' and 'area' fields *must* be defined, + * either to NULL or to a valid memory block allocated with malloc(). + * Note that the pointer will not set to NULL. + */ +void owl_free_algorithm_result(owl_algorithm_result *algo) +{ + if (! algo) + return ; + free(algo->algorithm) ; + free(algo->area) ; + free(algo) ; +} diff --git a/libowlps-resultreader/owlps-resultreader-udp.c b/libowlps-resultreader/owlps-resultreader-udp.c new file mode 100644 index 0000000..d0476e1 --- /dev/null +++ b/libowlps-resultreader/owlps-resultreader-udp.c @@ -0,0 +1,47 @@ +/* + * This is a simple program to demonstrate the use of + * libowlps-resultreader-udp. + * It must be linked against libowlps and its dependencies + * (see the Makefile). + */ + +#include "owlps-resultreader.h" + +#include +#include + +int main(void) +{ + struct sigaction action ; // Signal handler structure + owl_result *result ; + int sockfd ; + + /* Set up signal handlers */ + action.sa_flags = 0 ; + sigemptyset(&action.sa_mask) ; + action.sa_handler = owl_sigint_handler ; + sigaction(SIGINT, &action, NULL) ; + action.sa_handler = owl_sigterm_handler ; + sigaction(SIGTERM, &action, NULL) ; + + /* Open the socket */ + sockfd = owl_create_udp_listening_socket(OWL_DEFAULT_RESULT_PORT) ; + if (sockfd < 0) + return 1 ; + + /* Read loop */ + owl_run = owl_true ; + while (owl_run) + { + if (! (result = owl_receive_position(sockfd))) + return 1 ; + owl_print_result(result) ; + owl_free_result(result) ; + printf("--------------\n") ; + } + + /* Cleaning */ + close(sockfd) ; + + return 0 ; +} diff --git a/libowlps-resultreader/owlps-resultreader.h b/libowlps-resultreader/owlps-resultreader.h new file mode 100644 index 0000000..8d0d08e --- /dev/null +++ b/libowlps-resultreader/owlps-resultreader.h @@ -0,0 +1,105 @@ +/* + * This library provides functions to read results sent on UDP by OwlPS + * Positioning. + * See the example program owlps-resultreader-udp.c. + */ + +#ifndef _LIBOWLPS_RESULTREADER_CSV_ +#define _LIBOWLPS_RESULTREADER_CSV_ + +#include + +#include +#include + + +/* Maximum size of a result CSV string sent by OwlPS Positioning. + * Request's information: + * MAC, request type (2 chars), timestamp, ';' + * Plus, for each algorithm: + * Name, three coordinates, error (we assume the same size as the + * coordinates), area name, ';' + * Let's define OWL_NB_ALGORITHMS as the number of implemented + * algorithms (this is ugly). + */ +#define OWL_NB_ALGORITHMS 10 +#define OWL_CSV_RESULT_REQUEST_STRLEN \ + (OWL_ETHER_ADDR_STRLEN + OWL_TIMESTAMP_STRLEN + 3) +#define OWL_CSV_ALGORITHM_RESULT_STRLEN \ + (OWL_ALGORITHM_STRLEN + 4 * OWL_COORDINATE_STRLEN + \ + OWL_AREA_STRLEN + 1) +#define OWL_CSV_RESULT_STRLEN \ + (OWL_CSV_RESULT_REQUEST_STRLEN + \ + OWL_NB_ALGORITHMS * OWL_CSV_ALGORITHM_RESULT_STRLEN + 1) + +/* Same thing, but for the simplified CSV strings created by + * *_to_csv_simple(). + * Request's information is only the MAC address. + * For the algorithm: + * = 12 characters per coordinate + OWL_AREA_STRLEN + */ +#define OWL_CSV_RESULT_REQUEST_SIMPLE_STRLEN OWL_ETHER_ADDR_STRLEN +#define OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN \ + (3 * OWL_COORDINATE_STRLEN + OWL_AREA_STRLEN + 1) +#define OWL_CSV_RESULT_SIMPLE_STRLEN \ + (OWL_CSV_RESULT_REQUEST_SIMPLE_STRLEN + \ + OWL_NB_ALGORITHMS * OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN + 1) + + +/* Linked list of algorithms' results. + * Each structure is the result of a single algorithm. + */ +typedef struct _owl_algorithm_result +{ + char *algorithm ; + float x ; + float y ; + float z ; + float error ; + char *area ; + + struct _owl_algorithm_result *next ; +} owl_algorithm_result ; + + +/* Results for a request. Includes the request's data, and the + * list of algorithms' results. + */ +typedef struct _owl_result +{ + char *mobile_mac_addr ; + uint8_t request_type ; + owl_timestamp mobile_timestamp ; + unsigned int nb_results ; + owl_algorithm_result *results ; +} owl_result ; + + +owl_result* owl_receive_position(int sockfd) ; +owl_result* owl_fill_result(char *csv) ; +owl_algorithm_result* owl_fill_algorithm_result(char **csv) ; + +void owl_result_to_csv(char dst[OWL_CSV_RESULT_STRLEN], + const owl_result *const src) ; +void +owl_algorithm_result_to_csv(char dst[OWL_CSV_ALGORITHM_RESULT_STRLEN], + const owl_algorithm_result *const src) ; +void owl_result_to_csv_simple(char dst[OWL_CSV_RESULT_SIMPLE_STRLEN], + const owl_result *const src) ; +void owl_algorithm_result_to_csv_simple +(char dst[OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN], + const owl_algorithm_result *const src) ; + +void owl_fprint_result(FILE *stream, const owl_result *const src) ; +void owl_fprint_algorithm_result(FILE *stream, + const owl_algorithm_result *const src) ; +#define owl_print_result(SRC) \ + (owl_fprint_result(stdout, (SRC))) +#define owl_print_algorithm_result(SRC) \ + (owl_fprint_algorithm_result(stdout, (SRC))) + +void owl_free_result(owl_result *result) ; +void owl_free_algorithm_result(owl_algorithm_result *algo) ; + + +#endif // _LIBOWLPS_RESULTREADER_CSV_ diff --git a/libowlps/Makefile b/libowlps/Makefile index 0afa9f3..5a3374d 100644 --- a/libowlps/Makefile +++ b/libowlps/Makefile @@ -35,6 +35,7 @@ OBJS=$(LIB_CIBLE).o # Flags CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes -O +#CFLAGS += -g -O0 #CFLAGS += -D NDEBUG DEPFLAGS=-MMD XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) diff --git a/libowlps/Makefile_atheros_openwrt-10.03 b/libowlps/Makefile_atheros_openwrt-10.03 index e9f76cd..197c8c5 100644 --- a/libowlps/Makefile_atheros_openwrt-10.03 +++ b/libowlps/Makefile_atheros_openwrt-10.03 @@ -38,6 +38,7 @@ OBJS=$(LIB_CIBLE).o # Flags CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes -O +#CFLAGS += -g -O0 #CFLAGS += -D NDEBUG DEPFLAGS=-MMD XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) diff --git a/libowlps/Makefile_atheros_openwrt-8.09 b/libowlps/Makefile_atheros_openwrt-8.09 index 2543c40..dbbfba1 100644 --- a/libowlps/Makefile_atheros_openwrt-8.09 +++ b/libowlps/Makefile_atheros_openwrt-8.09 @@ -38,6 +38,7 @@ OBJS=$(LIB_CIBLE).o # Flags CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes -O +#CFLAGS += -g -O0 #CFLAGS += -D NDEBUG DEPFLAGS=-MMD XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) diff --git a/libowlps/libowlps.c b/libowlps/libowlps.c index aaa0881..d2300a5 100644 --- a/libowlps/libowlps.c +++ b/libowlps/libowlps.c @@ -19,7 +19,7 @@ -owl_bool owl_run = TRUE ; +owl_bool owl_run = owl_true ; @@ -57,7 +57,7 @@ void owl_mac_bytes_to_string_r(const uint8_t *const mac_binary, /* * Compares two MAC addresses. - * Returns TRUE if they are identical, FALSE otherwise. + * Returns owl_true if they are identical, owl_false otherwise. */ owl_bool owl_mac_equals(const uint8_t *const mac1, const uint8_t *const mac2) @@ -65,8 +65,8 @@ owl_bool owl_mac_equals(const uint8_t *const mac1, int i ; for (i = 0 ; i < ETHER_ADDR_LEN ; ++i) if(mac1[i] != mac2[i]) - return FALSE ; - return TRUE ; + return owl_false ; + return owl_true ; } @@ -132,6 +132,40 @@ uint_fast8_t owl_frequency_to_channel(const uint_fast16_t channel) /* *** Time *** */ +/* + * Sleeps for a given amount of milliseconds. + * 'time_ms' is an unsigned value, so please be careful: passing a + * negative value may not do what you think. + * In case of error, a message is displayed and a non-zero error code + * is returned (if positive, it is the number of non-sleeped seconds). + */ +int owl_msleep(uint32_t time_ms) +{ + int ret ; + uint_fast32_t seconds, microseconds ; + + if (! time_ms) + return 0 ; + + seconds = time_ms / 1000 ; + microseconds = time_ms % 1000 * 1000 ; + + if ((ret = sleep(seconds))) + { + perror("Cannot sleep()") ; + return ret ; + } + + if ((ret = usleep(microseconds))) + { + perror("Cannot usleep()") ; + return ret ; + } + + return 0 ; +} + + /* * Sets the owl_timestamp 'now' at the current time. * Returns 0 in case of success non-zero otherwise. @@ -200,12 +234,12 @@ uint64_t owl_timestamp_to_ms(const owl_timestamp d) /* * Converts a owl_timestamp date value into a printable string. - * 'dst' must be an allocated array of at least owl_timestamp_STR_LEN + * 'dst' must be an allocated array of at least OWL_TIMESTAMP_STRLEN * characters. */ void owl_timestamp_to_string(char *const dst, const owl_timestamp src) { - snprintf(dst, OWL_TIMESTAMP_STR_LEN, "%"PRIu32".%"PRIu32, + snprintf(dst, OWL_TIMESTAMP_STRLEN, "%"PRIu32".%"PRIu32, src.tv_sec, src.tv_nsec) ; } @@ -297,6 +331,7 @@ float owl_swap_float(const float f) * description will be saved. * - client_description (in/out): the structure in which the client * description will be saved. + * Returns a negative error code in case of error. */ int owl_create_udp_trx_socket(const char *const server_address, const uint_fast16_t server_port, @@ -310,7 +345,7 @@ int owl_create_udp_trx_socket(const char *const server_address, if (sockfd < 0) { perror("UDP socket creation failed") ; - return sockfd ; + return -OWL_ERR_SOCKET_CREATE ; } /* Initialise the client structure */ @@ -334,6 +369,7 @@ int owl_create_udp_trx_socket(const char *const server_address, * Creates a UDP reception socket and returns its descriptor. * Parameters: * - port: port on which the socket listens. + * Returns a negative error code in case of error. */ int owl_create_udp_listening_socket(const uint_fast16_t port) { @@ -346,7 +382,7 @@ int owl_create_udp_listening_socket(const uint_fast16_t port) if (sockfd < 0) { perror("UDP socket creation failed") ; - return sockfd ; + return -OWL_ERR_SOCKET_CREATE ; } /* Initialise the server structure */ @@ -363,7 +399,7 @@ int owl_create_udp_listening_socket(const uint_fast16_t port) { perror("Cannot bind the UDP socket") ; close(sockfd) ; - return ret ; + return -OWL_ERR_SOCKET_CREATE ; } return sockfd ; @@ -383,10 +419,10 @@ void owl_sigint_handler(const int num) { fprintf(stderr, "Error! The SIGINT handler was called but the" " signal is not SIGINT.\n") ; - exit(ERR_BAD_SIGNAL) ; + exit(OWL_ERR_BAD_SIGNAL) ; } - owl_run = FALSE ; + owl_run = owl_false ; #ifndef NDEBUG fprintf(stderr, "\nSignal received: end.\n"); @@ -404,7 +440,7 @@ void owl_sigterm_handler(const int num) { fprintf(stderr, "Error! The SIGTERM handler was called but the" " signal is not SIGTERM.\n") ; - exit(ERR_BAD_SIGNAL) ; + exit(OWL_ERR_BAD_SIGNAL) ; } owl_sigint_handler(SIGINT) ; diff --git a/libowlps/owlps.h b/libowlps/owlps.h index 40bd0ba..fe918b4 100644 --- a/libowlps/owlps.h +++ b/libowlps/owlps.h @@ -20,27 +20,27 @@ extern "C" { // Port on which the positioning request is sent by the mobile: -#define LOC_REQUEST_DEFAULT_PORT 9900 +#define OWL_DEFAULT_REQUEST_PORT 9900 // Port on which listeners and aggregator communicate: -#define AGGREGATE_DEFAULT_PORT 9901 +#define OWL_DEFAULT_LISTENER_PORT 9901 // Port on which aggregator and positioning server communicate: -#define POSITIONER_DEFAULT_PORT 9902 +#define OWL_DEFAULT_AGGREGATION_PORT 9902 // Port on which autocalibration requests are sent by the listeners: -#define DEFAULT_AUTOCALIBRATION_REQUEST_PORT 9903 +#define OWL_DEFAULT_AUTOCALIBRATION_REQUEST_PORT 9903 // Port on which the aggregator listens for hello messages from the // listeners, and the listeners listen for orders from the aggregator: -#define DEFAULT_AUTOCALIBRATION_PORT 9904 +#define OWL_DEFAULT_AUTOCALIBRATION_PORT 9904 // Port on which the mobile listens for its position: -#define MOBILE_DEFAULT_PORT 9910 +#define OWL_DEFAULT_RESULT_PORT 9910 /* Boolean type */ -typedef enum {FALSE, TRUE} owl_bool ; +typedef enum {owl_false, owl_true} owl_bool ; #define OWL_BOOL_TO_STRING(B) ((B) ? "true" : "false") /* Direction type */ -enum {NORTH = 1, EAST, SOUTH, WEST} ; +enum {owl_north = 1, owl_east, owl_south, owl_west} ; #define OWL_DIRECTION_MIN 1 #define OWL_DIRECTION_MAX 4 typedef uint8_t owl_direction ; @@ -53,7 +53,7 @@ typedef struct _owl_timestamp uint32_t tv_nsec ; } owl_timestamp ; // Length of a owl_timestamp when converted to string: -#define OWL_TIMESTAMP_STR_LEN 22 // 22 = 10 digits, '.', 10 digits, '\0' +#define OWL_TIMESTAMP_STRLEN 22 // 22 = 10 digits, '.', 10 digits, '\0' /* Message sent by the listener to the aggregator */ @@ -160,6 +160,12 @@ typedef struct _owl_autocalibration_order /* Misc. */ // Length of a MAC address in string format (including '\0') #define OWL_ETHER_ADDR_STRLEN 18 +// Maximum length of an algorithm name (including '\0') +#define OWL_ALGORITHM_STRLEN 31 +// Maximum length of an area name (including '\0') +#define OWL_AREA_STRLEN 31 +// Maximum length of a coordinate X, Y or Z (including '\0') +#define OWL_COORDINATE_STRLEN 16 /* Global variables */ @@ -167,8 +173,31 @@ typedef struct _owl_autocalibration_order extern owl_bool owl_run ; -/* Function error codes */ -#define ERR_BAD_SIGNAL 111 +/* Error codes */ +/* User interface */ +// Wrong program invokation (command-line arguments): +#define OWL_ERR_BAD_USAGE 100 +// Error when reading/parsing the configuration file: +#define OWL_ERR_CONFIG_FILE 101 +/* System */ +// Error when creating a thread: +#define OWL_ERR_THREAD_CREATE 110 +// Wrong signal received: +#define OWL_ERR_BAD_SIGNAL 111 +/* Network communication */ +// Error when creating a socket: +#define OWL_ERR_SOCKET_CREATE 120 +// Error when sending a message on a socket: +#define OWL_ERR_SOCKET_SEND 121 +// Error when reading from a socket: +#define OWL_ERR_SOCKET_RECV 122 +/* Network interface / capture */ +// Error when opening the capture interface: +#define OWL_ERR_IFACE_PCAP_OPEN 130 +// Error when reading the interface Wi-Fi mode: +#define OWL_ERR_IFACE_MODE_GET 131 +// Error when setting the interface Wi-Fi mode: +#define OWL_ERR_IFACE_MODE_SET 132 /* Function headers */ @@ -181,6 +210,7 @@ owl_bool owl_mac_equals(const uint8_t *const mac1, uint_fast8_t owl_frequency_to_channel(const uint_fast16_t channel) ; // Time +int owl_msleep(uint32_t time_ms) ; int owl_timestamp_now(owl_timestamp *const now) ; owl_timestamp owl_timespec_to_timestamp(const struct timespec d) ; owl_timestamp owl_timeval_to_timestamp(const struct timeval d) ; @@ -226,16 +256,6 @@ void owl_close_fd(void *const fd) ; void owl_close_file(void *const file) ; -/* Macros */ - -/* - * Test if a IEEE 802.11 frame is a retry. - * Input: IEEE 802.11 header flags. - * Returns 0 if the Retry bit is absent, a positive value if present. - */ -#define IS_RETRY(IEEE80211_FLAGS) ((IEEE80211_FLAGS) & 0x08) - - #ifdef __cplusplus } #endif // __cplusplus diff --git a/owlps-aggregator/Makefile b/owlps-aggregator/Makefile index 8767453..f1ef561 100644 --- a/owlps-aggregator/Makefile +++ b/owlps-aggregator/Makefile @@ -27,6 +27,7 @@ HEADER=owlps-aggregator.h # Flags LIBOWLPS_DIR = ../libowlps CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes -O -I$(LIBOWLPS_DIR) +#CFLAGS += -g -O0 DEPFLAGS=-MMD XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) PICFLAG=-fPIC diff --git a/owlps-aggregator/owlps-aggregator.h b/owlps-aggregator/owlps-aggregator.h index 930ce88..97a129d 100644 --- a/owlps-aggregator/owlps-aggregator.h +++ b/owlps-aggregator/owlps-aggregator.h @@ -27,15 +27,6 @@ #define VERBOSE_REQUESTS cfg_getint(cfg, "verbose") >= 4 -/* Error codes */ -#define ERR_NO_MESSAGE_RECEIVED 1 // Error when reading the socket -#define ERR_CREATING_SOCKET 2 // Erreur when creating listening socket -#define ERR_BAD_USAGE 3 // Bad program call -#define ERR_PARSING_CONFIG_FILE 4 // Error reading the configuration file -#define ERR_SENDING_INFO 5 // Error sending a message on a socket -#define ERR_CREATING_THREAD 6 // Error creating a thread - - /* Linked list storing data of each request */ typedef struct _request_info_list { @@ -86,10 +77,10 @@ typedef struct _ap_list /* Function headers */ -void initialise_configuration(int argc, char **argv) ; -void parse_config_file(int argc, char **argv) ; -void parse_command_line(int argc, char **argv) ; -void check_configuration(void) ; +int initialise_configuration(int argc, char **argv) ; +int parse_config_file(int argc, char **argv) ; +int parse_command_line(int argc, char **argv) ; +int check_configuration(void) ; int read_loop(int sockfd) ; void got_request(owl_captured_request request) ; diff --git a/owlps-aggregator/owlps-aggregatord.c b/owlps-aggregator/owlps-aggregatord.c index 7047e3f..ecc3db7 100644 --- a/owlps-aggregator/owlps-aggregatord.c +++ b/owlps-aggregator/owlps-aggregatord.c @@ -42,10 +42,14 @@ int main(int argc, char **argv) monitor_aps_thread, // APs monitoring thread autocalibration_hello_thread ; // Hello messages reception thread uint_fast16_t listening_port ; - int sockfd ; // UDP listening socket + int sockfd = -1 ; // UDP listening socket + + owl_run = owl_true ; program_name = argv[0] ; - initialise_configuration(argc, argv) ; + ret = initialise_configuration(argc, argv) ; + if (! owl_run) + goto exit ; /* Set up signal handlers */ action.sa_flags = 0 ; @@ -66,7 +70,7 @@ int main(int argc, char **argv) fprintf(stderr, "Error! Cannot listen on port %"PRIuFAST16".\n", listening_port) ; - ret = ERR_CREATING_SOCKET ; + ret = OWL_ERR_SOCKET_CREATE ; goto exit ; } @@ -75,7 +79,7 @@ int main(int argc, char **argv) if (ret != 0) { perror("Cannot create monitor thread") ; - ret = ERR_CREATING_THREAD ; + ret = OWL_ERR_THREAD_CREATE ; goto exit ; } if (cfg_getbool(cfg, "autocalibration")) @@ -85,7 +89,7 @@ int main(int argc, char **argv) if (ret != 0) { perror("Cannot create autocalibration hello thread") ; - ret = ERR_CREATING_THREAD ; + ret = OWL_ERR_THREAD_CREATE ; goto exit ; } ret = pthread_create(&monitor_aps_thread, NULL, @@ -93,12 +97,11 @@ int main(int argc, char **argv) if (ret != 0) { perror("Cannot create monitor APs thread") ; - ret = ERR_CREATING_THREAD ; + ret = OWL_ERR_THREAD_CREATE ; goto exit ; } } - owl_run = TRUE ; ret = read_loop(sockfd) ; /* Wait for the threads to terminate */ @@ -140,7 +143,8 @@ int main(int argc, char **argv) /* Last cleaning tasks */ exit: - close(sockfd) ; // Close socket + if (sockfd >= 0) + close(sockfd) ; // Close socket free_request_list() ; free_ap_list() ; cfg_free(cfg) ; // Clean configuration @@ -154,11 +158,28 @@ int main(int argc, char **argv) -void initialise_configuration(int argc, char **argv) +/* + * Read the configuration from both the command line and the + * configuration file. + * Returns an error code, or 0 in case of success. If the program should + * stop (because of a special option or a configuration error), owl_run + * is set to false. + */ +int initialise_configuration(int argc, char **argv) { - parse_config_file(argc, argv) ; - parse_command_line(argc, argv) ; - check_configuration() ; + int ret ; + + ret = parse_config_file(argc, argv) ; + if (! owl_run) + return ret ; + + ret = parse_command_line(argc, argv) ; + if (! owl_run) + return ret ; + + ret = check_configuration() ; + if (! owl_run) + return ret ; /* Configuration printing */ if (VERBOSE_INFO) @@ -166,10 +187,12 @@ void initialise_configuration(int argc, char **argv) fprintf(stderr, "Configuration:\n") ; cfg_print(cfg, stderr) ; } + + return 0 ; } -void parse_config_file(int argc, char **argv) +int parse_config_file(int argc, char **argv) { // Config file options for confuse cfg_opt_t opts[] = @@ -178,10 +201,10 @@ void parse_config_file(int argc, char **argv) CFG_INT("verbose", 0, CFGF_NONE), // Aggregation listening port - CFG_INT("listening_port", AGGREGATE_DEFAULT_PORT, CFGF_NONE), + CFG_INT("listening_port", OWL_DEFAULT_LISTENER_PORT, CFGF_NONE), // Port and IP address of the localisation server: - CFG_INT("positioner_port", POSITIONER_DEFAULT_PORT, CFGF_NONE), + CFG_INT("positioner_port", OWL_DEFAULT_AGGREGATION_PORT, CFGF_NONE), CFG_STR("positioner_ip", POSITIONER_DEFAULT_IP, CFGF_NONE), CFG_STR("output_file", "", CFGF_NONE), @@ -196,7 +219,7 @@ void parse_config_file(int argc, char **argv) // Autocalibration activated? CFG_BOOL("autocalibration", cfg_false, CFGF_NONE), // Port on which autocalibration data are exchanged: - CFG_INT("autocalibration_port", DEFAULT_AUTOCALIBRATION_PORT, + CFG_INT("autocalibration_port", OWL_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), @@ -221,10 +244,12 @@ void parse_config_file(int argc, char **argv) break ; case 'h' : print_usage() ; - exit(0) ; + owl_run = owl_false ; + return EXIT_SUCCESS ; case 'V' : print_version() ; - exit(0) ; + owl_run = owl_false ; + return EXIT_SUCCESS ; } } @@ -250,13 +275,16 @@ void parse_config_file(int argc, char **argv) "Error! Parsing of configuration file « %s » failed!\n", config_file) ; free(config_file) ; - exit(ERR_PARSING_CONFIG_FILE) ; + owl_run = owl_false ; + return OWL_ERR_CONFIG_FILE ; } free(config_file) ; + + return 0 ; } -void parse_command_line(int argc, char **argv) +int parse_command_line(int argc, char **argv) { int opt ; @@ -281,9 +309,6 @@ void parse_command_line(int argc, char **argv) break ; case 'f' : // Config file break ; // (already parsed) - case 'h' : - print_usage() ; - exit(0) ; case 'i' : cfg_setstr(cfg, "positioner_ip", optarg) ; break ; @@ -316,20 +341,24 @@ void parse_command_line(int argc, char **argv) break ; default : print_usage() ; - exit(ERR_BAD_USAGE) ; + owl_run = owl_false ; + return OWL_ERR_BAD_USAGE ; } } + + return 0 ; } -void check_configuration() +int 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) ; + owl_run = owl_false ; + return OWL_ERR_BAD_USAGE ; } // listening_port // @@ -339,7 +368,7 @@ void check_configuration() if (VERBOSE_WARNING) fprintf(stderr, "Warning! Bad listening_port:" " failing back to the default value.\n") ; - cfg_setint(cfg, "listening_port", AGGREGATE_DEFAULT_PORT) ; + cfg_setint(cfg, "listening_port", OWL_DEFAULT_LISTENER_PORT) ; } // positioner_port // @@ -349,7 +378,7 @@ void check_configuration() if (VERBOSE_WARNING) fprintf(stderr, "Warning! Bad positioner_port:" " failing back to the default value.\n") ; - cfg_setint(cfg, "positioner_port", POSITIONER_DEFAULT_PORT) ; + cfg_setint(cfg, "positioner_port", OWL_DEFAULT_AGGREGATION_PORT) ; } // positioner_ip // @@ -358,7 +387,8 @@ void check_configuration() fprintf(stderr, "Error! You must specify the IP address of the" " localisation server.\n") ; print_usage() ; - exit(ERR_BAD_USAGE) ; + owl_run = owl_false ; + return OWL_ERR_BAD_USAGE ; } // aggregate_timeout // @@ -405,6 +435,8 @@ void check_configuration() " failing back to the default value.\n") ; cfg_setint(cfg, "ap_check_interval", DEFAULT_AP_CHECK_INTERVAL) ; } + + return 0 ; } @@ -422,8 +454,8 @@ int read_loop(int sockfd) char // Return values of mobile_ip_str[INET_ADDRSTRLEN], // inet_ntop() // and owl_timestamp_to_string(): - request_time_str[OWL_TIMESTAMP_STR_LEN], - start_time_str[OWL_TIMESTAMP_STR_LEN] ; + request_time_str[OWL_TIMESTAMP_STRLEN], + start_time_str[OWL_TIMESTAMP_STRLEN] ; while (owl_run) { @@ -435,7 +467,7 @@ int read_loop(int sockfd) if (owl_run) { perror("No request received from listener") ; - ret = ERR_NO_MESSAGE_RECEIVED ; + ret = OWL_ERR_SOCKET_RECV ; } break ; } @@ -506,7 +538,7 @@ void* monitor_requests(void *NULL_value) FILE *fd = NULL ; char mac_str[OWL_ETHER_ADDR_STRLEN] ; uint_fast32_t sub ; // owl_time_elapsed_ms() result - char request_time_str[OWL_TIMESTAMP_STR_LEN] ; + char request_time_str[OWL_TIMESTAMP_STRLEN] ; uint_fast32_t aggregate_timeout = cfg_getint(cfg, "aggregate_timeout") ; @@ -679,7 +711,7 @@ void* monitor_requests(void *NULL_value) fflush(NULL) ; // Wait to check again: - usleep(cfg_getint(cfg, "check_interval") * 1000) ; + owl_msleep(cfg_getint(cfg, "check_interval")) ; } /* Close output file & socket */ @@ -872,7 +904,7 @@ void* listen_for_aps(void *NULL_value) { perror("Error! Cannot create UDP listening socket from the" " listeners") ; - exit(ERR_CREATING_SOCKET) ; + exit(OWL_ERR_SOCKET_CREATE) ; } pthread_cleanup_push(&owl_close_fd, &listen_sockfd) ; @@ -1045,7 +1077,7 @@ void* monitor_aps(void *NULL_value) } sem_post(&lock_aps) ; - usleep(cfg_getint(cfg, "ap_check_interval") * 1000) ; + owl_msleep(cfg_getint(cfg, "ap_check_interval")) ; } pthread_exit(NULL_value) ; @@ -1146,7 +1178,7 @@ void order_send(ap_list *ap) if (nsent != (ssize_t) sizeof(message)) { perror("Error sending order to the listener") ; - exit(ERR_SENDING_INFO) ; + exit(OWL_ERR_SOCKET_SEND) ; } close(sockfd) ; @@ -1191,8 +1223,8 @@ void print_request_list() request_info_list *info_ptr = NULL ; char mobile_mac_str[OWL_ETHER_ADDR_STRLEN] ; char - request_time_str[OWL_TIMESTAMP_STR_LEN], - start_time_str[OWL_TIMESTAMP_STR_LEN] ; + request_time_str[OWL_TIMESTAMP_STRLEN], + start_time_str[OWL_TIMESTAMP_STRLEN] ; sem_wait(&lock_requests) ; @@ -1329,12 +1361,12 @@ void print_usage() program_name, DEFAULT_CONFIG_FILE, POSITIONER_DEFAULT_IP, - POSITIONER_DEFAULT_PORT, - AGGREGATE_DEFAULT_PORT, + OWL_DEFAULT_AGGREGATION_PORT, + OWL_DEFAULT_LISTENER_PORT, DEFAULT_AGGREGATE_TIMEOUT, DEFAULT_KEEP_TIMEOUT, DEFAULT_CHECK_INTERVAL, - DEFAULT_AUTOCALIBRATION_PORT, + OWL_DEFAULT_AUTOCALIBRATION_PORT, DEFAULT_AP_KEEP_TIMEOUT, DEFAULT_AP_CHECK_INTERVAL ) ; diff --git a/owlps-ardrone/owlps-drone.c b/owlps-ardrone/owlps-drone.c index 6dca8ea..6dcd7a9 100644 --- a/owlps-ardrone/owlps-drone.c +++ b/owlps-ardrone/owlps-drone.c @@ -54,7 +54,7 @@ struct { float z ; } options = { "", - LOC_REQUEST_DEFAULT_PORT, + OWL_DEFAULT_REQUEST_PORT, "", -1, 0, @@ -64,9 +64,9 @@ struct { char *program_name = NULL ; -// TRUE if the packet is a calibration request, FALSE if it is a simple +// True if the packet is a calibration request, false if it is a simple // positioning request: -owl_bool is_calibration_request = FALSE ; +owl_bool is_calibration_request = owl_false ; int socksendfd ; // Sending socket descriptor (send positioning packets) int sockreceivefd ; // Receiving socket descriptor (Receive position) @@ -540,7 +540,7 @@ void parse_main_options(int argc, char **argv) * 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 ; + options.listening_port = OWL_DEFAULT_RESULT_PORT ; else { // Take the optind value: @@ -592,7 +592,7 @@ void parse_calibration_data(int argc, char **argv) { if (argc - optind == 4) { - is_calibration_request = TRUE ; + is_calibration_request = owl_true ; options.direction = strtoul(argv[optind++], NULL, 0) ; options.x = strtod(argv[optind++], NULL) ; options.y = strtod(argv[optind++], NULL) ; @@ -652,7 +652,7 @@ void check_configuration() #ifdef DEBUG fprintf(stderr, "Warning! Bad dest_port:" " failing back to default value.\n") ; - options.dest_port = LOC_REQUEST_DEFAULT_PORT ; + options.dest_port = OWL_DEFAULT_REQUEST_PORT ; #endif // DEBUG } if (options.listening_port > 65535) @@ -711,8 +711,8 @@ void print_configuration() void create_socket() { socksendfd = - owlclient_create_trx_socket(options.dest_ip, options.dest_port, - &server, options.iface) ; + owl_create_trx_socket(options.dest_ip, options.dest_port, + &server, options.iface) ; sockreceivefd = owl_create_udp_listening_socket(options.listening_port) ; } @@ -724,7 +724,7 @@ void make_packet() { uint_fast16_t offset ; // Index used to create the packet owl_timestamp request_time ; - char request_time_str[OWL_TIMESTAMP_STR_LEN] ; + char request_time_str[OWL_TIMESTAMP_STRLEN] ; // Get the current time and copy it as a string before to switch it to // network endianess: @@ -776,8 +776,8 @@ void make_packet() void send_request() { - owlclient_send_request(socksendfd, &server, packet, packet_size, - options.nb_pkt, options.delay) ; + owl_send_request(socksendfd, &server, packet, packet_size, + options.nb_pkt, options.delay) ; } @@ -816,7 +816,7 @@ void string2data(char* string_data) int count_algo= 0 ; int count_print = 0 ; int onetime = 0 ; - owl_bool error_present = FALSE ; + owl_bool error_present = owl_false ; while(onetime<1) { @@ -867,7 +867,7 @@ void string2data(char* string_data) break ; strncpy(results[count_algo].algo, ptr, ALGO_STRLEN) ; if(!strcmp(results[count_algo].algo,"Real")) - error_present = TRUE ; + error_present = owl_true ; // X coordinate ptr = strtok(NULL, delims) ; @@ -1030,12 +1030,12 @@ void print_usage() , program_name, program_name, - LOC_REQUEST_DEFAULT_PORT, + OWL_DEFAULT_REQUEST_PORT, DEFAULT_DELAY_NORMAL, DEFAULT_DELAY_CALIB, DEFAULT_NBPKT_NORMAL, DEFAULT_NBPKT_CALIB, - MOBILE_DEFAULT_PORT + OWL_DEFAULT_RESULT_PORT ) ; } diff --git a/owlps-client/Makefile b/owlps-client/Makefile index 68fabe0..859a08d 100644 --- a/owlps-client/Makefile +++ b/owlps-client/Makefile @@ -27,15 +27,19 @@ HEADER= # Flags LIBOWLPS_DIR = ../libowlps LIBOWLPSCLIENT_DIR = ../libowlps-client +LIBOWLPSRESULTREADER_DIR = ../libowlps-resultreader CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes \ - -I$(LIBOWLPS_DIR) -I$(LIBOWLPSCLIENT_DIR) + -I$(LIBOWLPS_DIR) -I$(LIBOWLPSCLIENT_DIR) \ + -I$(LIBOWLPSRESULTREADER_DIR) +#CFLAGS += -g -O0 DEPFLAGS = -MMD XCFLAGS = $(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) PICFLAG = -fPIC OWLPSFLAGS = -D OWLPS_VERSION=\"$(OWLPS_VERSION)\" OWLPSFLAGS += -D DEBUG LIBS = -L$(LIBOWLPS_DIR) -lowlps \ - -L$(LIBOWLPSCLIENT_DIR) -lowlps-client + -L$(LIBOWLPSCLIENT_DIR) -lowlps-client \ + -L$(LIBOWLPSRESULTREADER_DIR) -lowlps-resultreader OS := $(shell uname) ifeq ("$(OS)", "Linux") @@ -93,6 +97,7 @@ purge : clean help : @echo "Bibliothèques nécessaires à la compilation :" @echo " libowlps1.0 (fournie)" + @echo " libowlps-client1.0 (fournie)" @echo @echo "Cibles possibles :" @echo " $(TARGET) (cible par défaut) : Compile le programme \ diff --git a/owlps-client/Makefile_atheros_openwrt-10.03 b/owlps-client/Makefile_atheros_openwrt-10.03 index b7c93b1..516ea76 100644 --- a/owlps-client/Makefile_atheros_openwrt-10.03 +++ b/owlps-client/Makefile_atheros_openwrt-10.03 @@ -32,6 +32,7 @@ LIBOWLPS_DIR = ../libowlps LIBOWLPSCLIENT_DIR = ../libowlps-client CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes \ -I$(LIBOWLPS_DIR) -I$(LIBOWLPSCLIENT_DIR) +#CFLAGS += -g -O0 DEPFLAGS = -MMD XCFLAGS = $(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) PICFLAG = -fPIC diff --git a/owlps-client/Makefile_atheros_openwrt-8.09 b/owlps-client/Makefile_atheros_openwrt-8.09 index 702da67..15ab520 100644 --- a/owlps-client/Makefile_atheros_openwrt-8.09 +++ b/owlps-client/Makefile_atheros_openwrt-8.09 @@ -32,6 +32,7 @@ LIBOWLPS_DIR = ../libowlps LIBOWLPSCLIENT_DIR = ../libowlps-client CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes \ -I$(LIBOWLPS_DIR) -I$(LIBOWLPSCLIENT_DIR) +#CFLAGS += -g -O0 DEPFLAGS = -MMD XCFLAGS = $(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) PICFLAG = -fPIC diff --git a/owlps-client/owlps-client.c b/owlps-client/owlps-client.c index 2a3f8c8..e3a5718 100644 --- a/owlps-client/owlps-client.c +++ b/owlps-client/owlps-client.c @@ -2,20 +2,19 @@ * This file is part of the rtap localisation project. */ -#include "../libowlps-client/owlps-client.h" +#include +#include #include #include #include #include #include +#include #include -/* Error codes */ -#define ERR_BAD_USAGE 1 // Bad program call (bad number of arguments) - /* 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 @@ -43,7 +42,7 @@ void print_configuration(void) ; void create_socket(void) ; void make_packet(void) ; void send_request(void) ; -void receive_position(void) ; +int receive_position(void) ; void print_usage(void) ; void print_version(void) ; @@ -64,7 +63,7 @@ struct { float z ; } options = { "", - LOC_REQUEST_DEFAULT_PORT, + OWL_DEFAULT_REQUEST_PORT, "", -1, 0, @@ -75,9 +74,9 @@ struct { char *program_name = NULL ; -// TRUE if the packet is a calibration request, FALSE if it is a simple -// positioning request: -owl_bool is_calibration_request = FALSE ; +// owl_true if the packet is a calibration request, owl_false if it is +// a simple positioning request: +owl_bool is_calibration_request = owl_false ; int sockfd ; // Sending socket descriptor struct sockaddr_in server ; // Server info @@ -88,28 +87,36 @@ uint_fast16_t packet_size ; // Packet size int main(int argc, char *argv[]) { + struct sigaction action ; // Signal handler structure + int ret = 0 ; + program_name = argv[0] ; parse_command_line(argc, argv) ; + /* Set up signal handlers */ + action.sa_flags = 0 ; + sigemptyset(&action.sa_mask) ; + action.sa_handler = owl_sigint_handler ; + sigaction(SIGINT, &action, NULL) ; + action.sa_handler = owl_sigterm_handler ; + sigaction(SIGTERM, &action, NULL) ; + create_socket() ; - request_transmission: - make_packet() ; send_request() ; - free(packet) ; - - if (options.flood_delay >= 0) + while (owl_run && options.flood_delay >= 0) { - usleep(options.flood_delay * 1000) ; - goto request_transmission ; + owl_msleep(options.flood_delay) ; + if (owl_run) // owl_run can have been set to false during the sleep + send_request() ; } close(sockfd) ; if (options.listening_port > 0) - receive_position() ; + ret = receive_position() ; - return 0 ; + return ret ; } @@ -179,7 +186,7 @@ void parse_main_options(int argc, char **argv) * 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 ; + options.listening_port = OWL_DEFAULT_RESULT_PORT ; else { // Take the optind value: @@ -203,7 +210,7 @@ void parse_main_options(int argc, char **argv) exit(0) ; default : print_usage() ; - exit(ERR_BAD_USAGE) ; + exit(OWL_ERR_BAD_USAGE) ; } } } @@ -218,7 +225,7 @@ void check_destination_ip() fprintf(stderr, "Error! You must specify a destination IP address" " (-d).\n") ; print_usage() ; - exit(ERR_BAD_USAGE) ; + exit(OWL_ERR_BAD_USAGE) ; } } @@ -231,7 +238,7 @@ void parse_calibration_data(int argc, char **argv) { if (argc - optind == 4) { - is_calibration_request = TRUE ; + is_calibration_request = owl_true ; options.direction = strtoul(argv[optind++], NULL, 0) ; options.x = strtod(argv[optind++], NULL) ; options.y = strtod(argv[optind++], NULL) ; @@ -240,7 +247,7 @@ void parse_calibration_data(int argc, char **argv) else // Bad number of arguments { print_usage() ; - exit(ERR_BAD_USAGE) ; + exit(OWL_ERR_BAD_USAGE) ; } } } @@ -282,7 +289,7 @@ void check_configuration() { fprintf(stderr, "Error! « %"PRIu8" » is not a valid" " direction.\n", options.direction) ; - exit(ERR_BAD_USAGE) ; + exit(OWL_ERR_BAD_USAGE) ; } // Check port numbers @@ -291,7 +298,7 @@ void check_configuration() #ifdef DEBUG fprintf(stderr, "Warning! Bad dest_port:" " failing back to default value.\n") ; - options.dest_port = LOC_REQUEST_DEFAULT_PORT ; + options.dest_port = OWL_DEFAULT_REQUEST_PORT ; #endif // DEBUG } if (options.listening_port > 65535) @@ -362,18 +369,33 @@ void print_configuration() void create_socket() { sockfd = - owlclient_create_trx_socket(options.dest_ip, options.dest_port, - &server, options.iface) ; + owl_create_trx_socket(options.dest_ip, options.dest_port, + &server, options.iface) ; } -/* Creates the packet to send. */ +/* + * Prepares a new request and sends it. + */ +void send_request() +{ + make_packet() ; + owl_send_request(sockfd, &server, packet, packet_size, + options.nb_pkt, options.delay) ; + free(packet) ; +} + + + +/* + * Creates the packet to send. + */ void make_packet() { uint_fast16_t offset ; // Index used to create the packet owl_timestamp request_time ; - char request_time_str[OWL_TIMESTAMP_STR_LEN] ; + char request_time_str[OWL_TIMESTAMP_STRLEN] ; // Get the current time and copy it as a string before to switch it to // network endianess: @@ -399,14 +421,21 @@ void make_packet() printf("Direction = %d, X = %f, Y = %f, Z = %f\n", packet[offset - 1], options.x, options.y, options.z) ; #endif // DEBUG + // Convert the coordinates to the network endianess options.x = owl_htonf(options.x) ; options.y = owl_htonf(options.y) ; options.z = owl_htonf(options.z) ; + // Copy the coordinates to the packet memcpy(&packet[offset], &options.x, sizeof(float)) ; offset += sizeof(float) ; memcpy(&packet[offset], &options.y, sizeof(float)) ; offset += sizeof(float) ; memcpy(&packet[offset], &options.z, sizeof(float)) ; + // Convert the coordinates back to the host endianess (mandatory + // in flood mode) + options.x = owl_ntohf(options.x) ; + options.y = owl_ntohf(options.y) ; + options.z = owl_ntohf(options.z) ; } else // Standard packet @@ -423,26 +452,31 @@ void make_packet() -void send_request() +/* + * Receives a position computed by the infrastructure. + * Note that it is currently not guaranteed that the received result + * correspond to the request sent. + * Returns 0, or a non-zero value in case of error. + */ +int receive_position() { - owlclient_send_request(sockfd, &server, packet, packet_size, - options.nb_pkt, options.delay) ; -} + owl_result *result ; - - -void receive_position() -{ - // Position of the mobile as computed by the infrastructure: - float x, y, z ; + printf("Waiting for the result from the infrastructure...\n") ; sockfd = owl_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) ; - close(sockfd) ; + if (sockfd < 0) + return OWL_ERR_SOCKET_CREATE ; - printf("Computed position: (%.4f;%.4f;%.4f)\n", x, y, z) ; + result = owl_receive_position(sockfd) ; + if (result == NULL) + return OWL_ERR_SOCKET_RECV ; + + close(sockfd) ; + owl_print_result(result) ; + owl_free_result(result) ; + + return 0 ; } @@ -482,13 +516,13 @@ void print_usage() , program_name, program_name, - LOC_REQUEST_DEFAULT_PORT, + OWL_DEFAULT_REQUEST_PORT, DEFAULT_DELAY_NORMAL, DEFAULT_DELAY_CALIB, DEFAULT_NBPKT_NORMAL, DEFAULT_NBPKT_CALIB, DEFAULT_FLOOD_DELAY, - MOBILE_DEFAULT_PORT + OWL_DEFAULT_RESULT_PORT ) ; } diff --git a/owlps-listener/Makefile b/owlps-listener/Makefile index fb08469..58141d9 100644 --- a/owlps-listener/Makefile +++ b/owlps-listener/Makefile @@ -29,6 +29,7 @@ LIBOWLPS_DIR = ../libowlps LIBOWLPSCLIENT_DIR = ../libowlps-client CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes \ -I$(LIBOWLPS_DIR) -I$(LIBOWLPSCLIENT_DIR) +#CFLAGS += -g -O0 DEPFLAGS = -MMD XCFLAGS = $(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) PICFLAG = -fPIC diff --git a/owlps-listener/Makefile_atheros_openwrt-10.03 b/owlps-listener/Makefile_atheros_openwrt-10.03 index 343175e..7799960 100644 --- a/owlps-listener/Makefile_atheros_openwrt-10.03 +++ b/owlps-listener/Makefile_atheros_openwrt-10.03 @@ -32,6 +32,7 @@ LIBOWLPS_DIR = ../libowlps LIBOWLPSCLIENT_DIR = ../libowlps-client CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes \ -I$(LIBOWLPS_DIR) -I$(LIBOWLPSCLIENT_DIR) +#CFLAGS += -g -O0 DEPFLAGS = -MMD XCFLAGS = $(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) PICFLAG = -fPIC diff --git a/owlps-listener/Makefile_atheros_openwrt-8.09 b/owlps-listener/Makefile_atheros_openwrt-8.09 index a5bc864..2151bf9 100644 --- a/owlps-listener/Makefile_atheros_openwrt-8.09 +++ b/owlps-listener/Makefile_atheros_openwrt-8.09 @@ -32,6 +32,7 @@ LIBOWLPS_DIR = ../libowlps LIBOWLPSCLIENT_DIR = ../libowlps-client CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes \ -I$(LIBOWLPS_DIR) -I$(LIBOWLPSCLIENT_DIR) +#CFLAGS += -g -O0 DEPFLAGS = -MMD XCFLAGS = $(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) PICFLAG = -fPIC diff --git a/owlps-listener/owlps-listener.h b/owlps-listener/owlps-listener.h index fd657e8..b52a48f 100644 --- a/owlps-listener/owlps-listener.h +++ b/owlps-listener/owlps-listener.h @@ -94,6 +94,13 @@ enum {MODE_ACTIVE = 'a', MODE_PASSIVE = 'p', MODE_MIXED = 'm'} ; #define IS_FRAME_FROM_STA(FC2) \ (((FC2) & FRAME_FROM_STA_MASK) != FRAME_FROM_STA_MASK) +/* + * Test if a IEEE 802.11 frame is a retry. + * Input: IEEE 802.11 header flags. + * Returns 0 if the Retry bit is absent, a positive value if present. + */ +#define IS_RETRY(IEEE80211_FLAGS) ((IEEE80211_FLAGS) & 0x08) + /* Positions of the radiotap header fixed fields (in bytes) */ #define RTAP_P_HREVISION 0 // Header revision @@ -147,24 +154,15 @@ enum {MODE_ACTIVE = 'a', MODE_PASSIVE = 'p', MODE_MIXED = 'm'} ; //#define RTAP_EXT 31 -/* Error codes */ -#define ERR_OPENING_IFACE 2 // Error when opening capture interface -#define ERR_BAD_USAGE 3 // Bad program call -#define ERR_PARSING_CONFIG_FILE 4 // Error reading the configuration file -#define ERR_CREATING_THREAD 6 // Error creating a thread -#define ERR_SETTING_MODE 101 -#define ERR_READING_MODE 104 - - /* Function headers */ -void initialise_configuration(int argc, char **argv) ; -void parse_config_file(int argc, char **argv) ; -void parse_command_line(int argc, char **argv) ; -void parse_main_options(int argc, char **argv) ; +int initialise_configuration(int argc, char **argv) ; +int parse_config_file(int argc, char **argv) ; +int parse_command_line(int argc, char **argv) ; +int parse_main_options(int argc, char **argv) ; #ifdef USE_PTHREAD -void parse_calibration_data(int argc, char **argv) ; +int parse_calibration_data(int argc, char **argv) ; #endif // USE_PTHREAD -void check_configuration(void) ; +int check_configuration(void) ; #ifdef DEBUG void print_configuration(void) ; #endif // DEBUG @@ -307,7 +305,7 @@ void print_version(void) ; (options.aggregation_ip) #ifdef USE_PTHREAD #define SET_KEEP_MONITOR() \ - (options.keep_monitor = TRUE) + (options.keep_monitor = owl_true) #define GET_KEEP_MONITOR() \ (options.keep_monitor) #endif // USE_PTHREAD @@ -330,7 +328,7 @@ void print_version(void) ; #ifdef USE_PTHREAD #define SET_AUTOCALIBRATION() \ - (options.autocalibration = TRUE) + (options.autocalibration = owl_true) #define GET_AUTOCALIBRATION() \ (options.autocalibration) #define SET_AUTOCALIBRATION_IP(IP) \ @@ -382,9 +380,9 @@ void print_version(void) ; #define GET_VERBOSE() \ (options.verbose) #define SET_DISPLAY_CAPTURED() \ - (options.display_captured = TRUE) + (options.display_captured = owl_true) #define UNSET_DISPLAY_CAPTURED() \ - (options.display_captured = FALSE) + (options.display_captured = owl_false) #define GET_DISPLAY_CAPTURED() \ (options.display_captured) #endif // USE_CONFIG_FILE diff --git a/owlps-listener/owlps-listenerd.c b/owlps-listener/owlps-listenerd.c index 56e0033..7cc7aeb 100644 --- a/owlps-listener/owlps-listenerd.c +++ b/owlps-listener/owlps-listenerd.c @@ -45,12 +45,12 @@ struct sockaddr_in aggregation_server ; #ifdef USE_PTHREAD int autocalibration_send_sockfd ; struct sockaddr_in autocalibration_send_server ; -// TRUE if the coordinates of the listener were provided by the user: -owl_bool coordinates_provided = FALSE ; +// owl_true if the coordinates of the listener were provided by the user: +owl_bool coordinates_provided = owl_false ; #endif // USE_PTHREAD #ifdef USE_CONFIG_FILE -cfg_t *cfg ; // Configuration structure +cfg_t *cfg = NULL ; // Configuration structure #else // USE_CONFIG_FILE /* If we do not use libconfuse, we declare a structure to store getopt @@ -84,25 +84,25 @@ struct { } options = { // Initalise default options: MODE_ACTIVE, "127.0.0.1", - AGGREGATE_DEFAULT_PORT, - LOC_REQUEST_DEFAULT_PORT, + OWL_DEFAULT_LISTENER_PORT, + OWL_DEFAULT_REQUEST_PORT, #ifdef USE_PTHREAD - FALSE, + owl_false, #endif // USE_PTHREAD "", "", #ifdef USE_PTHREAD - FALSE, + owl_false, "", - DEFAULT_AUTOCALIBRATION_REQUEST_PORT, - DEFAULT_AUTOCALIBRATION_PORT, + OWL_DEFAULT_AUTOCALIBRATION_REQUEST_PORT, + OWL_DEFAULT_AUTOCALIBRATION_PORT, DEFAULT_AUTOCALIBRATION_HELLO_DELAY, DEFAULT_AUTOCALIBRATION_DELAY, DEFAULT_AUTOCALIBRATION_NBPKT, 0, 0, 0, 0, #endif // USE_PTHREAD 0, - FALSE + owl_false } ; #endif // USE_CONFIG_FILE @@ -119,12 +119,15 @@ int main(int argc, char *argv[]) autocalibration_hello_thread ; #endif // USE_PTHREAD - program_name = argv[0] ; - initialise_configuration(argc, argv) ; + owl_run = owl_true ; - owl_run = TRUE ; + program_name = argv[0] ; + ret = initialise_configuration(argc, argv) ; + if (! owl_run) + goto exit ; /* Set up signal handlers */ + action.sa_flags = 0 ; sigemptyset(&action.sa_mask) ; action.sa_handler = sigint_handler ; sigaction(SIGINT, &action, NULL) ; @@ -149,7 +152,7 @@ int main(int argc, char *argv[]) if (ret != 0) { perror("Cannot create keep monitor thread") ; - ret = ERR_CREATING_THREAD ; + ret = OWL_ERR_THREAD_CREATE ; goto exit ; } } @@ -161,7 +164,7 @@ int main(int argc, char *argv[]) if (ret != 0) { perror("Cannot create autocalibration thread") ; - ret = ERR_CREATING_THREAD ; + ret = OWL_ERR_THREAD_CREATE ; goto exit ; } @@ -170,7 +173,7 @@ int main(int argc, char *argv[]) if (ret != 0) { perror("Cannot create autocalibration hello thread") ; - ret = ERR_CREATING_THREAD ; + ret = OWL_ERR_THREAD_CREATE ; goto exit ; } } @@ -244,19 +247,38 @@ int main(int argc, char *argv[]) -void initialise_configuration(int argc, char **argv) +/* + * Read the configuration from both the command line and the + * configuration file. + * Returns an error code, or 0 in case of success. If the program should + * stop (because of a special option or a configuration error), owl_run + * is set to false. + */ +int initialise_configuration(int argc, char **argv) { - parse_config_file(argc, argv) ; - parse_command_line(argc, argv) ; - check_configuration() ; + int ret ; + + ret = parse_config_file(argc, argv) ; + if (! owl_run) + return ret ; + + ret = parse_command_line(argc, argv) ; + if (! owl_run) + return ret ; + + ret = check_configuration() ; + if (! owl_run) + return ret ; if (VERBOSE_INFO) print_configuration() ; + + return 0 ; } -void parse_config_file(int argc, char **argv) +int parse_config_file(int argc, char **argv) { #ifdef USE_CONFIG_FILE // If we use libconfuse, we declare options: @@ -268,9 +290,9 @@ void parse_config_file(int argc, char **argv) // IP address of the aggregator (default: loopback): CFG_STR("aggregation_ip", "127.0.0.1", CFGF_NONE), // Port on which the aggregator listens: - CFG_INT("aggregation_port", AGGREGATE_DEFAULT_PORT, CFGF_NONE), + CFG_INT("aggregation_port", OWL_DEFAULT_LISTENER_PORT, CFGF_NONE), // Port on which mobiles send active requests: - CFG_INT("listening_port", LOC_REQUEST_DEFAULT_PORT, CFGF_NONE), + CFG_INT("listening_port", OWL_DEFAULT_REQUEST_PORT, CFGF_NONE), #ifdef USE_PTHREAD // Activate the active monitor mode keeping-up (read the code if // you do not understand what I mean): @@ -289,9 +311,9 @@ void parse_config_file(int argc, char **argv) CFG_STR("autocalibration_ip", "", CFGF_NONE), // Port on which autocalibration requests are sent: CFG_INT("autocalibration_request_port", - DEFAULT_AUTOCALIBRATION_REQUEST_PORT, CFGF_NONE), + OWL_DEFAULT_AUTOCALIBRATION_REQUEST_PORT, CFGF_NONE), // Port on which autocalibration data are exchanged: - CFG_INT("autocalibration_port", DEFAULT_AUTOCALIBRATION_PORT, + CFG_INT("autocalibration_port", OWL_DEFAULT_AUTOCALIBRATION_PORT, CFGF_NONE), // Delay between two hello messages: CFG_INT("autocalibration_hello_delay", @@ -342,10 +364,12 @@ void parse_config_file(int argc, char **argv) break ; case 'h' : print_usage() ; - exit(0) ; + owl_run = owl_false ; + return EXIT_SUCCESS ; case 'V' : print_version() ; - exit(0) ; + owl_run = owl_false ; + return EXIT_SUCCESS ; } } @@ -372,25 +396,37 @@ void parse_config_file(int argc, char **argv) "Error! Parsing of configuration file « %s » failed!\n", config_file) ; free(config_file) ; - exit(ERR_PARSING_CONFIG_FILE) ; + owl_run = owl_false ; + return OWL_ERR_CONFIG_FILE ; } free(config_file) ; #endif // USE_CONFIG_FILE + + return 0 ; } -void parse_command_line(int argc, char **argv) +int parse_command_line(int argc, char **argv) { - parse_main_options(argc, argv) ; + int ret ; + + ret = parse_main_options(argc, argv) ; + if (! owl_run) + return ret ; + #ifdef USE_PTHREAD - parse_calibration_data(argc, argv) ; + ret = parse_calibration_data(argc, argv) ; + if (! owl_run) + return ret ; #endif // USE_PTHREAD + + return 0 ; } -void parse_main_options(int argc, char **argv) +int parse_main_options(int argc, char **argv) { int opt ; @@ -429,8 +465,6 @@ void parse_main_options(int argc, char **argv) break ; case 'f' : // Config file break ; // (already parsed) - case 'h' : // Usage - break ; // (already parsed) case 'H' : #ifdef USE_PTHREAD SET_AUTOCALIBRATION_HELLO_DELAY(strtol(optarg, NULL, 0)) ; @@ -482,29 +516,30 @@ void parse_main_options(int argc, char **argv) case 'v' : INCREMENT_VERBOSE() ; break ; - case 'V' : // Version - break ; // (already parsed) case 'w' : SET_WIFI_IFACE(optarg) ; break ; default : print_usage() ; - exit(ERR_BAD_USAGE) ; + owl_run = owl_false ; + return OWL_ERR_BAD_USAGE ; } } + + return 0 ; } #ifdef USE_PTHREAD -void parse_calibration_data(int argc, char **argv) +int parse_calibration_data(int argc, char **argv) { /* Parse remaining arguments (possible calibration data) */ if (argc - optind != 0) { if (argc - optind == 4) { - coordinates_provided = TRUE ; + coordinates_provided = owl_true ; SET_MY_DIRECTION(strtoul(argv[optind++], NULL, 0)) ; SET_MY_POSITION_X(strtod(argv[optind++], NULL)) ; SET_MY_POSITION_Y(strtod(argv[optind++], NULL)) ; @@ -513,15 +548,18 @@ void parse_calibration_data(int argc, char **argv) else // Bad number of arguments { print_usage() ; - exit(ERR_BAD_USAGE) ; + owl_run = owl_false ; + return OWL_ERR_BAD_USAGE ; } } + + return 0 ; } #endif // USE_PTHREAD -void check_configuration() +int check_configuration() { switch (GET_MODE()) { @@ -532,7 +570,8 @@ void check_configuration() default : fprintf(stderr, "Error! Unknown mode « %c ».\n", (char) GET_MODE()) ; print_usage() ; - exit(ERR_BAD_USAGE) ; + owl_run = owl_false ; + return OWL_ERR_BAD_USAGE ; } if (GET_RTAP_IFACE()[0] == '\0') @@ -540,7 +579,8 @@ void check_configuration() fprintf(stderr, "Error! You must specify a radiotap interface" " for the capture.\n") ; print_usage() ; - exit(ERR_BAD_USAGE) ; + owl_run = owl_false ; + return OWL_ERR_BAD_USAGE ; } if (GET_WIFI_IFACE()[0] == '\0') @@ -558,14 +598,14 @@ void check_configuration() if (VERBOSE_WARNING) fprintf(stderr, "Warning! Bad aggregation_port:" " failing back to the default value.\n") ; - SET_AGGREGATION_PORT(AGGREGATE_DEFAULT_PORT) ; + SET_AGGREGATION_PORT(OWL_DEFAULT_LISTENER_PORT) ; } if (GET_LISTENING_PORT() < 1 || GET_LISTENING_PORT() > 65535) { if (VERBOSE_WARNING) fprintf(stderr, "Warning! Bad listening_port:" " failing back to the default value.\n") ; - SET_LISTENING_PORT(LOC_REQUEST_DEFAULT_PORT) ; + SET_LISTENING_PORT(OWL_DEFAULT_REQUEST_PORT) ; } // Autocalibration stuff // @@ -598,7 +638,7 @@ void check_configuration() if (VERBOSE_WARNING) fprintf(stderr, "Warning! Bad autocalibration_request_port:" " failing back to the default value.\n") ; - SET_AUTOCALIBRATION_REQUEST_PORT(DEFAULT_AUTOCALIBRATION_REQUEST_PORT) ; + SET_AUTOCALIBRATION_REQUEST_PORT(OWL_DEFAULT_AUTOCALIBRATION_REQUEST_PORT) ; } if (GET_AUTOCALIBRATION_PORT() < 1 || GET_AUTOCALIBRATION_PORT() > 65535) @@ -606,10 +646,12 @@ void check_configuration() if (VERBOSE_WARNING) fprintf(stderr, "Warning! Bad autocalibration_port:" " failing back to the default value.\n") ; - SET_AUTOCALIBRATION_PORT(DEFAULT_AUTOCALIBRATION_PORT) ; + SET_AUTOCALIBRATION_PORT(OWL_DEFAULT_AUTOCALIBRATION_PORT) ; } } #endif // USE_PTHREAD + + return 0 ; } @@ -707,7 +749,7 @@ int iface_mode_monitor(const char *const iface) if (ioctl(sockfd, SIOCGIWMODE, &wrq) == -1) // Get current mode { perror("Error reading interface mode") ; - return ERR_READING_MODE ; + return OWL_ERR_IFACE_MODE_GET ; } // If interface is not yet in Monitor mode @@ -717,7 +759,7 @@ int iface_mode_monitor(const char *const iface) if (ioctl(sockfd, SIOCSIWMODE, &wrq) == -1) // Set up Monitor mode { perror("Error setting up Monitor mode") ; - return ERR_SETTING_MODE ; + return OWL_ERR_IFACE_MODE_SET ; } } @@ -743,14 +785,13 @@ int capture() if (capture_handler == NULL) // Capture starting failed { fprintf(stderr, "Cannot open capture interface %s\n", errbuf) ; - return ERR_OPENING_IFACE ; + return OWL_ERR_IFACE_PCAP_OPEN ; } /* Open UDP socket to the aggregator */ aggregation_sockfd = - owlclient_create_trx_socket(GET_AGGREGATION_IP(), - GET_AGGREGATION_PORT(), - &aggregation_server, NULL) ; + owl_create_trx_socket(GET_AGGREGATION_IP(), GET_AGGREGATION_PORT(), + &aggregation_server, NULL) ; while (owl_run) // Capture one packet at time, and call read_packet() on it: @@ -784,9 +825,10 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, // Pointer to the (possible) UDP header of the packet: struct udphdr *packet_udp_header = NULL ; // Localisation request type (request, calibration, autocalibration): - owl_bool is_explicit_packet = TRUE ; // Is the packet an explicit request? + // Is the packet an explicit request? + owl_bool is_explicit_packet = owl_true ; // Is the packet an autocalibration positioning request? - owl_bool uses_autocalibration_request_port = FALSE ; + owl_bool uses_autocalibration_request_port = owl_false ; ssize_t nsent ; // sendto return value // Blank the request: @@ -852,7 +894,7 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, #ifdef USE_PTHREAD if (GET_AUTOCALIBRATION() && dest_port == (uint_fast16_t) GET_AUTOCALIBRATION_REQUEST_PORT()) - uses_autocalibration_request_port = TRUE ; + uses_autocalibration_request_port = owl_true ; else #endif // USE_PTHREAD if (dest_port != (uint_fast16_t) GET_LISTENING_PORT()) @@ -864,7 +906,7 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, not_explicit_packet : if (GET_MODE() == MODE_ACTIVE) return ; - is_explicit_packet = FALSE ; + is_explicit_packet = owl_false ; process_packet : @@ -884,8 +926,9 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, // Copy AP MAC : memcpy(request.ap_mac_addr_bytes, my_mac_bytes, ETHER_ADDR_LEN) ; - // Capture time is in the pcap header (net-endian): - request.start_time = owl_timeval_to_timestamp(header->ts) ; + // Capture time is in the pcap header (host-endian): + request.start_time = + owl_hton_timestamp(owl_timeval_to_timestamp(header->ts)) ; /* Active mode */ if (is_explicit_packet @@ -935,7 +978,7 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, printf("\nStrange explicit packet received\n") ; fprintf(stderr, "Error! Unknown request type (%d).\n", request.type) ; - is_explicit_packet = FALSE ; + is_explicit_packet = owl_false ; } if (! is_explicit_packet) @@ -977,8 +1020,8 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, if (GET_DISPLAY_CAPTURED()) { char - request_time_str[OWL_TIMESTAMP_STR_LEN], - start_time_str[OWL_TIMESTAMP_STR_LEN] ; + request_time_str[OWL_TIMESTAMP_STRLEN], + start_time_str[OWL_TIMESTAMP_STRLEN] ; owl_timestamp_to_string(request_time_str, owl_ntoh_timestamp(request.request_time)) ; owl_timestamp_to_string(start_time_str, @@ -1041,7 +1084,7 @@ void extract_calibration_data(const u_char *packet, /* * Fills 'request' with the required data extracted from the Radiotap - * header of 'packet'. The elements of 'rtap_fields' are set to TRUE + * header of 'packet'. The elements of 'rtap_fields' are set to owl_true * when the corresponding Radiotap flag is found in the packet. */ void extract_radiotap_data(const u_char *packet, @@ -1059,7 +1102,7 @@ void extract_radiotap_data(const u_char *packet, rtap_presentflags = le32toh(rtap_presentflags) ; for (i = 0 ; i < 15 ; ++i) // Initialise present flags structure - rtap_fields[i] = FALSE ; + rtap_fields[i] = owl_false ; rtap_position = 8 ; // Begining of the present flags determined fields // Test the first 15 bits of the flag field in order to check their @@ -1071,15 +1114,15 @@ void extract_radiotap_data(const u_char *packet, switch(i) { case RTAP_MACTS: - rtap_fields[RTAP_MACTS] = TRUE ; + rtap_fields[RTAP_MACTS] = owl_true ; rtap_position += RTAP_L_MACTS ; break ; case RTAP_FLAGS: - rtap_fields[RTAP_FLAGS] = TRUE; + rtap_fields[RTAP_FLAGS] = owl_true; rtap_position += RTAP_L_FLAGS ; break ; case RTAP_RATE: - rtap_fields[RTAP_RATE] = TRUE; + rtap_fields[RTAP_RATE] = owl_true; rtap_position += RTAP_L_RATE ; break ; case RTAP_CHANNEL: @@ -1087,52 +1130,52 @@ void extract_radiotap_data(const u_char *packet, rtap_position += RTAP_L_CHANNELTYPE ; break ; case RTAP_FHSS: - rtap_fields[RTAP_FHSS] = TRUE; + rtap_fields[RTAP_FHSS] = owl_true; rtap_position += RTAP_L_FHSS ; break ; case RTAP_ANTENNASIGNALDBM: memcpy(&request->antenna_signal_dbm, &packet[rtap_position], RTAP_L_ANTENNASIGNALDBM) ; - rtap_fields[RTAP_ANTENNASIGNALDBM] = TRUE; + rtap_fields[RTAP_ANTENNASIGNALDBM] = owl_true; if (VERBOSE_INFO) printf("Antenna signal: %d dBm\n", request->antenna_signal_dbm - 0x100); rtap_position += RTAP_L_ANTENNASIGNALDBM ; break ; case RTAP_ANTENNANOISEDBM: - rtap_fields[RTAP_ANTENNANOISEDBM] = TRUE; + rtap_fields[RTAP_ANTENNANOISEDBM] = owl_true; rtap_position += RTAP_L_ANTENNANOISEDBM ; break ; case RTAP_LOCKQUALITY: - rtap_fields[RTAP_LOCKQUALITY] = TRUE; + rtap_fields[RTAP_LOCKQUALITY] = owl_true; rtap_position += RTAP_L_LOCKQUALITY ; break ; case RTAP_TXATTENUATION: - rtap_fields[RTAP_TXATTENUATION] = TRUE; + rtap_fields[RTAP_TXATTENUATION] = owl_true; rtap_position += RTAP_L_TXATTENUATION ; break ; case RTAP_TXATTENUATIONDB: - rtap_fields[RTAP_TXATTENUATIONDB] = TRUE; + rtap_fields[RTAP_TXATTENUATIONDB] = owl_true; rtap_position += RTAP_L_TXATTENUATIONDB ; break ; case RTAP_TXATTENUATIONDBM: - rtap_fields[RTAP_TXATTENUATIONDBM] = TRUE; + rtap_fields[RTAP_TXATTENUATIONDBM] = owl_true; rtap_position += RTAP_L_TXATTENUATIONDBM ; break ; case RTAP_ANTENNA: - rtap_fields[RTAP_ANTENNA] = TRUE; + rtap_fields[RTAP_ANTENNA] = owl_true; rtap_position += RTAP_L_ANTENNA ; break ; case RTAP_ANTENNASIGNALDB: - rtap_fields[RTAP_ANTENNASIGNALDB] = TRUE; + rtap_fields[RTAP_ANTENNASIGNALDB] = owl_true; rtap_position += RTAP_L_ANTENNASIGNALDB ; break ; case RTAP_ANTENNANOISEDB: - rtap_fields[RTAP_ANTENNANOISEDB] = TRUE; + rtap_fields[RTAP_ANTENNANOISEDB] = owl_true; rtap_position += RTAP_L_ANTENNANOISEDB ; break ; case RTAP_FCS: - rtap_fields[RTAP_FCS] = TRUE; + rtap_fields[RTAP_FCS] = owl_true; rtap_position += RTAP_L_FCS ; break ; } @@ -1213,17 +1256,16 @@ void* autocalibrate_hello(void *NULL_value) fprintf(stderr, "Autocalibration Hello thread launched.\n") ; send_sockfd = - owlclient_create_trx_socket(GET_AGGREGATION_IP(), - GET_AUTOCALIBRATION_PORT(), - &serv, NULL) ; + owl_create_trx_socket(GET_AGGREGATION_IP(), + GET_AUTOCALIBRATION_PORT(), &serv, NULL) ; pthread_cleanup_push(&owl_close_fd, &send_sockfd) ; memcpy(&message.ap_mac_addr_bytes, my_mac_bytes, ETHER_ADDR_LEN) ; while (owl_run) { - owlclient_send_packet(send_sockfd, &serv, - &message, sizeof(message)) ; + owl_send_packet(send_sockfd, &serv, + &message, sizeof(message)) ; sleep(GET_AUTOCALIBRATION_HELLO_DELAY()) ; } @@ -1248,10 +1290,10 @@ void* autocalibrate(void *NULL_value) // Socket to send autocalibration positioning requests autocalibration_send_sockfd = - owlclient_create_trx_socket(GET_AUTOCALIBRATION_IP(), - GET_AUTOCALIBRATION_REQUEST_PORT(), - &autocalibration_send_server, - GET_WIFI_IFACE()) ; + owl_create_trx_socket(GET_AUTOCALIBRATION_IP(), + GET_AUTOCALIBRATION_REQUEST_PORT(), + &autocalibration_send_server, + GET_WIFI_IFACE()) ; // Socket to receive orders from the aggregator listen_sockfd = @@ -1260,7 +1302,7 @@ void* autocalibrate(void *NULL_value) { perror("Error! Cannot create UDP listening socket from the" " aggregation server") ; - exit(ERR_CREATING_SOCKET) ; + exit(OWL_ERR_SOCKET_CREATE) ; } pthread_cleanup_push(&owl_close_fd, &listen_sockfd) ; @@ -1301,11 +1343,11 @@ void send_autocalibration_request() uint8_t *packet ; uint_fast16_t packet_size = make_packet(&packet) ; - owlclient_send_request(autocalibration_send_sockfd, - &autocalibration_send_server, - packet, packet_size, - GET_AUTOCALIBRATION_NBPKT(), - GET_AUTOCALIBRATION_DELAY()) ; + owl_send_request(autocalibration_send_sockfd, + &autocalibration_send_server, + packet, packet_size, + GET_AUTOCALIBRATION_NBPKT(), + GET_AUTOCALIBRATION_DELAY()) ; free(packet) ; } @@ -1332,7 +1374,7 @@ uint_fast16_t make_packet(uint8_t **packet) if (VERBOSE_CHATTERBOX) { - char request_time_str[OWL_TIMESTAMP_STR_LEN] ; + char request_time_str[OWL_TIMESTAMP_STRLEN] ; owl_timestamp_to_string(request_time_str, request_time) ; printf("Autocalibration time: %s\n", request_time_str) ; } @@ -1457,10 +1499,10 @@ void print_usage() program_name, program_name, DEFAULT_CONFIG_FILE, - LOC_REQUEST_DEFAULT_PORT, - AGGREGATE_DEFAULT_PORT, - DEFAULT_AUTOCALIBRATION_REQUEST_PORT, - DEFAULT_AUTOCALIBRATION_PORT, + OWL_DEFAULT_REQUEST_PORT, + OWL_DEFAULT_LISTENER_PORT, + OWL_DEFAULT_AUTOCALIBRATION_REQUEST_PORT, + OWL_DEFAULT_AUTOCALIBRATION_PORT, DEFAULT_AUTOCALIBRATION_HELLO_DELAY, DEFAULT_AUTOCALIBRATION_DELAY, DEFAULT_AUTOCALIBRATION_NBPKT diff --git a/owlps-positioning/Makefile b/owlps-positioning/Makefile index ab42305..0bb79e7 100644 --- a/owlps-positioning/Makefile +++ b/owlps-positioning/Makefile @@ -33,9 +33,9 @@ endif # Flags LIBOWLPS_DIR = ../libowlps -#DEBUG = -g TESTSGXXFLAGS = -I$(TESTS_DIR) -I$(SRC_DIR) -I. -GXXFLAGS = $(DEBUG) -O2 -Wall -Wextra -I$(LIBOWLPS_DIR) +GXXFLAGS = -O2 -Wall -Wextra -I$(LIBOWLPS_DIR) +#GXXFLAGS += -g -O0 LD = $(CXX) LDFLAGS = -lstdc++ -lm -lboost_program_options \ -L$(LIBOWLPS_DIR) -lowlps diff --git a/owlps-positioning/src/outputtcpsocketevaal.cc b/owlps-positioning/src/outputtcpsocketevaal.cc index 68b0d24..ebec47e 100644 --- a/owlps-positioning/src/outputtcpsocketevaal.cc +++ b/owlps-positioning/src/outputtcpsocketevaal.cc @@ -123,8 +123,9 @@ area_of_interest_number(const Point3D &position) const */ bool OutputTCPSocketEvAAL::send_data(const string &data) const { - ssize_t nsent = send(sockfd, data.c_str(), data.size(), 0) ; - if (nsent != static_cast(data.size())) + unsigned int data_len = data.size() + 1 ; // +1 for the '\0' + ssize_t nsent = send(sockfd, data.c_str(), data_len, 0) ; + if (nsent != static_cast(data_len)) { perror("Error sending result data through the TCPEvAAL socket") ; return false ; diff --git a/owlps-positioning/src/outputudpsocket.cc b/owlps-positioning/src/outputudpsocket.cc index ebc8350..1984e04 100644 --- a/owlps-positioning/src/outputudpsocket.cc +++ b/owlps-positioning/src/outputudpsocket.cc @@ -45,10 +45,11 @@ bool OutputUDPSocket::init_socket() */ bool OutputUDPSocket::send_data(const string &data) const { - ssize_t nsent = sendto(sockfd, data.c_str(), data.size(), 0, + unsigned int data_len = data.size() + 1 ; // +1 for the '\0' + ssize_t nsent = sendto(sockfd, data.c_str(), data_len, 0, (struct sockaddr *) &server_info, sizeof(server_info)) ; - if (nsent != static_cast(data.size())) + if (nsent != static_cast(data_len)) { perror("Error sending result data through the UDP socket") ; return false ; diff --git a/owlps-positioning/src/owlps-positioning.cc b/owlps-positioning/src/owlps-positioning.cc index 9103c21..d0807d3 100644 --- a/owlps-positioning/src/owlps-positioning.cc +++ b/owlps-positioning/src/owlps-positioning.cc @@ -14,27 +14,31 @@ using namespace std ; int main(int argc, char **argv) { + owl_run = owl_true ; + /* Read options & configuration */ delete new UserInterface(argc, argv) ; - /* Read input data */ - delete new InputDataReader() ; + if (owl_run) + { + /* Read input data */ + delete new InputDataReader() ; - /* Set up signal handlers */ - struct sigaction action ; - action.sa_flags = 0 ; - sigemptyset(&action.sa_mask) ; - action.sa_handler = owl_sigint_handler ; - sigaction(SIGINT, &action, NULL) ; - action.sa_handler = owl_sigterm_handler ; - sigaction(SIGTERM, &action, NULL) ; + /* Set up signal handlers */ + struct sigaction action ; + action.sa_flags = 0 ; + sigemptyset(&action.sa_mask) ; + action.sa_handler = owl_sigint_handler ; + sigaction(SIGINT, &action, NULL) ; + action.sa_handler = owl_sigterm_handler ; + sigaction(SIGTERM, &action, NULL) ; - /* Run! */ - owl_run = TRUE ; - Positioning positioning ; + /* Run! */ + Positioning positioning ; - /* Clean */ - Stock::clear() ; + /* Clean */ + Stock::clear() ; + } cerr << argv[0] << ": end." << endl ; return 0 ; diff --git a/owlps-positioning/src/stock.cc b/owlps-positioning/src/stock.cc index e258180..5b7d7a4 100644 --- a/owlps-positioning/src/stock.cc +++ b/owlps-positioning/src/stock.cc @@ -678,7 +678,10 @@ closest_calibration_request(const Request &request) // No non-AP reference point was found, we are forced to consider // the AP reference points if (i == calibration_requests.end()) - ignore_aps = false ; + { + i = calibration_requests.begin() ; + ignore_aps = false ; + } } float distance = i->ss_square_distance(request) ; diff --git a/owlps-positioning/src/userinterface.cc b/owlps-positioning/src/userinterface.cc index 867dbcc..04fb535 100644 --- a/owlps-positioning/src/userinterface.cc +++ b/owlps-positioning/src/userinterface.cc @@ -149,7 +149,7 @@ void UserInterface::fill_input_options() ("input.csv-file,C", po::value(), "CSV file to use for input (when input.medium = CSV).") ("input.udp-port,p", po::value() - ->default_value(POSITIONER_DEFAULT_PORT), + ->default_value(OWL_DEFAULT_AGGREGATION_PORT), "Port on which the UDP socket listens (when input.medium = UDP).") ; @@ -263,7 +263,7 @@ void UserInterface::fill_output_options() ("output.udp-host", po::value(), "Host to which the UDP data is sent (when output.medium = UDP).") ("output.udp-port", po::value() - ->default_value(MOBILE_DEFAULT_PORT), + ->default_value(OWL_DEFAULT_RESULT_PORT), "Port on which the UDP data is sent (when output.medium = UDP).") ("output.tcpevaal-host", po::value() ->default_value(DEFAULT_TCPEVAAL_HOST), @@ -293,7 +293,9 @@ void UserInterface::fill_misc_options() void UserInterface::parse_options() { parse_command_line() ; - print_information_and_exit_if_requested() ; + print_information() ; + if (! owl_run) + return ; parse_file() ; @@ -310,10 +312,12 @@ void UserInterface::parse_command_line() const } -void UserInterface::print_information_and_exit_if_requested() const +/** + * If information is printed, owl_run is set to false, to indicate that + * the program should stop. + */ +void UserInterface::print_information() const { - bool exit_program = false ; - // Print version if requested if (Configuration::is_configured("version")) { @@ -326,18 +330,15 @@ void UserInterface::print_information_and_exit_if_requested() const "unknown version" #endif // OWLPS_VERSION << ".\n" ; - exit_program = true ; + owl_run = owl_false ; // Tell main() to exit } // Print usage if requested if (Configuration::is_configured("help")) { cout << *cli_options ; - exit_program = true ; + owl_run = owl_false ; // Tell main() to exit } - - if (exit_program) - exit(0) ; } diff --git a/owlps-positioning/src/userinterface.hh b/owlps-positioning/src/userinterface.hh index 91c21cd..8a23420 100644 --- a/owlps-positioning/src/userinterface.hh +++ b/owlps-positioning/src/userinterface.hh @@ -37,7 +37,7 @@ protected: void parse_file(void) const ; /// Prints usage and/or version information if requested by the user - void print_information_and_exit_if_requested(void) const ; + void print_information(void) const ; //@} public: diff --git a/owlps-udp-to-http/Makefile b/owlps-udp-to-http/Makefile new file mode 100644 index 0000000..afe8558 --- /dev/null +++ b/owlps-udp-to-http/Makefile @@ -0,0 +1,110 @@ +# Source version +ifndef OWLPS_VERSION + OWLPS_VERSION := $(shell git describe 2>/dev/null || echo 'UNKNOWN_VERSION') +endif + +# Répertoire d'installation +PREFIX=/usr/local +INSTALL_DIR= $(PREFIX)/bin +INSTALL_LIB= $(PREFIX)/lib +INSTALL_INC= $(PREFIX)/include +INSTALL_MAN= $(PREFIX)/share/man + +# Compilateur +COLORGCC := $(shell which colorgcc >/dev/null 2>&1 ; echo $$?) +ifeq ($(COLORGCC), 0) + CC = colorgcc +endif + +# Commandes d'installation et de désinstallation +RM = rm -f +CP = cp + +# Cible +TARGET = owlps-udp-to-http +HEADER = + +# Flags +LIBOWLPS_DIR = ../libowlps +LIBOWLPSRESULTREADER_DIR = ../libowlps-resultreader +CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes \ + -I$(LIBOWLPS_DIR) -I$(LIBOWLPSRESULTREADER_DIR) +#CFLAGS += -g -O0 +DEPFLAGS = -MMD +XCFLAGS = $(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) +PICFLAG = -fPIC +OWLPSFLAGS = -D OWLPS_VERSION=\"$(OWLPS_VERSION)\" +OWLPSFLAGS += -D DEBUG +LIBS = -pthread -L$(LIBOWLPS_DIR) -lowlps \ + -L$(LIBOWLPSRESULTREADER_DIR) -lowlps-resultreader + +OS := $(shell uname) +ifeq ("$(OS)", "Linux") + LIBS += -lrt +endif + +STATIC_LIBS = + + +## Cibles de compilation standard ## + +.PHONY : all dynamic static install uninstall clean purge help + +dynamic : $(TARGET) +static : $(TARGET).static +all : dynamic static + +# Cancel implicit make rule +%: %.c + +%: %.o + $(CC) $(LDFLAGS) $(STRIPFLAGS) $(XCFLAGS) -o $@ $^ $(LIBS) +%.static: %.o + $(CC) $(STRIPFLAGS) $(XCFLAGS) -o $@ $^ \ + $(LDFLAGS) $(LIBS) $(STATIC_LIBS) -static +%.o: %.c $(HEADER) + $(CC) $(XCFLAGS) $(OWLPSFLAGS) -c $< + + +## Installation / désinstallation ## + +install : $(TARGET) + @$(CP) $(TARGET) $(INSTALL_DIR) + @cd $(INSTALL_DIR) ; chown root:root $(TARGET) ; chmod 755 $(TARGET) + +install-static : $(TARGET).static + @$(CP) $(TARGET).static $(INSTALL_DIR) + @cd $(INSTALL_DIR) ; chown root:root $(TARGET).static ; chmod 755 $(TARGET).static + +uninstall : + @$(RM) $(INSTALL_DIR)/{$(TARGET),$(TARGET).static} + + +## Nettoyage ## + +clean : + @$(RM) *~ *.o *.d + +purge : clean + @$(RM) $(TARGET) $(TARGET).static + + +## Aide ## + +help : + @echo "Bibliothèques nécessaires à la compilation :" + @echo " libowlps1.0 (fournie)" + @echo " libowlps-resultreader1.0 (fournie)" + @echo + @echo "Cibles possibles :" + @echo " $(TARGET) (cible par défaut) : Compile le programme \ +$(TARGET)." + @echo " $(TARGET).static : Compile le programme $(TARGET).static \ +(version sans lien dynamique)." + @echo " install : Installe le programme $(TARGET)." + @echo " uninstall : Désinstalle le programme $(TARGET)." + @echo " clean : Supprime les fichiers temporaires." + @echo " purge : Supprime le résultat de la compilation." + @echo + @echo "Note : l'installation se fait dans l'arborescence $(PREFIX). \ +Modifiez la variable PREFIX du Makefile pour changer ce comportement." diff --git a/owlps-udp-to-http/owlps-udp-to-http.c b/owlps-udp-to-http/owlps-udp-to-http.c new file mode 100644 index 0000000..1b24d73 --- /dev/null +++ b/owlps-udp-to-http/owlps-udp-to-http.c @@ -0,0 +1,512 @@ +/* + * This program listens for results sent by OwlPS Positioning on a UDP + * socket, and listens for a client on a TCP socket. The client is + * expected to send an HTTP GET request, with the request string as the + * first variable value (the variable name does not matter). + * For example, a correct request is detected if you load + * http://localhost:8080/?request=ReadSimpleResults + * (assuming the host running this program is localhost). + * + * The UDP listening port is the port on which OwlPS Positioning sends + * result by default. + * The TCP listening port is 8080. + * + * Only the last result read from the positioning server, for each + * mobile, is memorised and provided to the HTTP client. + * + * The HTTP requests currently implemented are listed bellow. + * + * ** Request "ReadResults" ** + * Answer in case of error: + * Results;NOK;Explanation + * Normal answer: + * Results;OK;Nb_results;Result_1;…;Result_n + * Nb_results is the number of results in the answer (number of mobiles). + * Result_i follows this format: + * Mobile_MAC;Request_type;Request_timestamp;Nb_algo;Algo_1;…;Algo_n + * Nb_algo is the number of algorithms in the result. + * Algo_i follows this format: + * Algorithm_name;X;Y;Z;Error;Area_name + * Error is the distance from the true coordinates of the mobile, if + * known; if unknown, Error is set to -1. + * Area_name is the name of the area or room in which the mobile is (may + * be empty). + * + * ** Unknown request ** + * If a unknown request is received, the answer format is: + * UnknownRequest;NOK + * + * ** Request "ReadSimpleResults" ** + * Answer in case of error: + * SimpleResults;NOK;Explanation + * Normal answer: + * SimpleResults;OK;Nb_results;Result_1;…;Result_n + * Nb_results is the number of results in the answer (number of mobiles). + * Result_i follows this format: + * Mobile_MAC;X;Y;Z;Area_name + * Area_name is the name of the area or room in which the mobile is (may + * be empty). + */ + +#include "owlps-udp-to-http.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + + +char *program_name = NULL ; + +results_list *results = NULL ; +unsigned int nb_results = 0 ; +sem_t lock_results ; + +int udp_sockfd = -1 ; +int tcp_sockfd = -1 ; + +char *answer = NULL ; // Answer to send to the client +size_t answer_strlen = 0 ; // Total size of the answer string +size_t answer_buflen = 0 ; // Size of the answer allocated buffer + + +int main(int argc, char *argv[]) +{ + struct sigaction action ; // Signal handler structure + int ret = 0 ; // Program return value + pthread_t tcp_server_thread ; + + program_name = argv[0] ; + owl_run = owl_true ; + + if (argc > 1) + fprintf(stderr, + "Sorry, this program does not take any argument yet.\n") ; + + /* Set up signal handlers */ + action.sa_flags = 0 ; + sigemptyset(&action.sa_mask) ; + action.sa_handler = owl_sigint_handler ; + sigaction(SIGINT, &action, NULL) ; + action.sa_handler = owl_sigterm_handler ; + sigaction(SIGTERM, &action, NULL) ; + + /* Set up the semaphore */ + sem_init(&lock_results, 0, 1) ; + + /* Prepare the TCP socket */ + ret = init_tcp_socket() ; + if (ret) + goto exit ; + + /* Launch the TCP thread */ + ret = pthread_create(&tcp_server_thread, NULL, + &tcp_server, NULL) ; + if (ret) + { + perror("Cannot create the TCP server thread") ; + ret = OWL_ERR_THREAD_CREATE ; + goto exit ; + } + + /* Main loop */ + ret = receive_udp() ; + + /* Stop the TCP thread */ + // We must cancel the thread because it can be blocked on the + // recv() call: + if (pthread_cancel(tcp_server_thread)) + perror("Cannot cancel the TCP server thread") ; + if (pthread_join(tcp_server_thread, NULL)) + perror("Cannot join the TCP server thread") ; + + exit: + /* Close sockets */ + if (tcp_sockfd >= 0) + if (close(tcp_sockfd)) + perror("Error closing the TCP socket") ; + if (udp_sockfd >= 0) + if (close(udp_sockfd)) + perror("Error closing the UDP socket") ; + + /* Last cleaning */ + free(answer) ; + free_results_list() ; + sem_destroy(&lock_results) ; + + printf("%s: end.\n", program_name) ; + return ret ; +} + + +/* + * Opens the UDP socket and reads from it the results sent by OwlPS + * Positioning. + * Returns a non-zero value in case of error. + */ +int receive_udp() +{ + owl_result *result ; + + /* Open the UDP socket */ + udp_sockfd = owl_create_udp_listening_socket(OWL_DEFAULT_RESULT_PORT) ; + if (udp_sockfd < 0) + return OWL_ERR_SOCKET_CREATE ; + + /* UDP read loop */ + while (owl_run) + { + result = owl_receive_position(udp_sockfd) ; + if (result == NULL) + return OWL_ERR_SOCKET_RECV ; + owl_print_result(result) ; + store_result(result) ; + printf("--------------\n") ; + } + + return 0 ; +} + + +/* + * Adds a new owl_result to the results' list. + */ +void store_result(owl_result *new_result) +{ + sem_wait(&lock_results) ; + + // The results' list does not exist yet + if (! results) + { + results = malloc(sizeof(results_list)) ; + ++nb_results ; + results->result = new_result ; + results->next = NULL ; + } + + // The results' list contains at least 1 element + else + { + // Search for an existing result with the same mobile's MAC + results_list *res = results ; + while (res != NULL) + { + char *mac = res->result->mobile_mac_addr ; + if (strncmp(mac, new_result->mobile_mac_addr, + OWL_ETHER_ADDR_STRLEN) == 0) + break ; + res = res->next ; + } + + if (res == NULL) // Not found, adding an element + { + res = malloc(sizeof(results_list)) ; + ++nb_results ; + res->next = results ; + results = res ; + } + else // Found, clearing it + owl_free_result(res->result) ; + + res->result = new_result ; + } + + sem_post(&lock_results) ; +} + + +/* + * Opens the TCP socket. + * Returns a non-zero value in case of error. + */ +int init_tcp_socket() +{ + struct sockaddr_in server_addr ; + + tcp_sockfd = socket(AF_INET, SOCK_STREAM, 0) ; + if (tcp_sockfd < 0) + { + perror("Error opening the TCP socket") ; + return OWL_ERR_SOCKET_CREATE ; + } + + bzero((char *) &server_addr, sizeof(server_addr)) ; + server_addr.sin_family = AF_INET ; + server_addr.sin_addr.s_addr = INADDR_ANY ; + server_addr.sin_port = htons(TCP_PORT) ; + + + if (bind(tcp_sockfd, (struct sockaddr *) &server_addr, + sizeof(server_addr)) < 0) + { + perror("Error binding the TCP socket") ; + return OWL_ERR_SOCKET_CREATE ; + } + + return 0 ; +} + + +/* + * Waits for requests from HTTP clients. + */ +void* tcp_server(void *NULL_value) +{ + int newsockfd ; + socklen_t client_len ; + struct sockaddr_in client_addr ; + ssize_t nbytes ; // recv/send return value + char client_message[CLIENT_MESSAGE_STRLEN] ; + char client_request[CLIENT_REQUEST_STRLEN] ; + int request_id ; + + listen(tcp_sockfd, NB_CONNECTIONS) ; + client_len = sizeof(client_addr) ; + + // Prepare the answer, assuming there is only 1 full result (an error + // message will also fit) + answer_buflen = ANSWER_HDR_STRLEN + OWL_CSV_RESULT_STRLEN ; + answer = malloc(answer_buflen) ; + strncpy(answer, ANSWER_HDR, ANSWER_HDR_STRLEN) ; + + while (owl_run) + { + newsockfd = accept(tcp_sockfd, + (struct sockaddr*) &client_addr, &client_len) ; + if (newsockfd < 0) + { + perror("Error accepting a connection on the TCP socket") ; + continue ; + } + + nbytes = + recv(newsockfd, client_message, CLIENT_MESSAGE_STRLEN, 0) ; + if (nbytes < 0) + { + perror("Error reading from the TCP socket") ; + close(newsockfd) ; + continue ; + } + client_message[nbytes] = '\0' ; + +#ifdef DEBUG + printf("Got a message from the client:\n" + "\"%s\"\n", client_message) ; +#endif // DEBUG + + request_id = + extract_request_from_message(client_request, client_message) ; + prepare_answer(request_id) ; + +#ifdef DEBUG + printf("Answer to send:\n\"%s\"\n", answer) ; +#endif // DEBUG + + /* Send the answer */ + nbytes = send(newsockfd, answer, answer_strlen, 0) ; + if (nbytes < 0) + perror("Error sending answer to the TCP socket") ; + + close(newsockfd) ; + } + + pthread_exit(NULL_value) ; +} + + +/* + * Reads a message and search for a request in it. + * Returns the identifier of a request if found, or 0 if not found. + */ +int +extract_request_from_message(char client_request[CLIENT_REQUEST_STRLEN], + char *client_message) +{ + char *token ; + + token = strchr(client_message, '=') ; + if (! token) + return 0 ; + ++token ; + token = strsep(&token, " ") ; + + if (strncmp(SIMPLE_RESULTS_REQUEST, token, + strlen(SIMPLE_RESULTS_REQUEST)) == 0) + { + strncpy(client_request, SIMPLE_RESULTS_REQUEST, + CLIENT_REQUEST_STRLEN) ; + return SIMPLE_RESULTS_ID ; + } + + if (strncmp(RESULTS_REQUEST, token, + strlen(RESULTS_REQUEST)) == 0) + { + strncpy(client_request, RESULTS_REQUEST, + CLIENT_REQUEST_STRLEN) ; + return RESULTS_ID ; + } + + return 0 ; // No known request found +} + + +/* + * Prepare the answer string to send to the TCP client. + */ +void prepare_answer(int request_id) +{ + // Reset the answer's length: + answer_strlen = ANSWER_HDR_STRLEN ; + + switch (request_id) + { + case RESULTS_ID: + strncpy(answer + answer_strlen, RESULTS_ANSWER, + strlen(RESULTS_ANSWER)) ; + answer_strlen += strlen(RESULTS_ANSWER) ; + + sem_wait(&lock_results) ; + + if (! results) + { + char answer_end[] = ";NOK;NoResult" ; + strncpy(answer + answer_strlen, answer_end, + strlen(answer_end)) ; + answer_strlen += strlen(answer_end) ; + } + + else + { + results_list *result ; + char answer_begin[10] ; + size_t answer_begin_len ; + + snprintf(answer_begin, 10, ";OK;%u", nb_results) ; + answer_begin_len = strlen(answer_begin) ; + strncpy(answer + answer_strlen, answer_begin, + answer_begin_len) ; + answer_strlen += answer_begin_len ; + + realloc_answer(answer_strlen + + nb_results * OWL_CSV_RESULT_STRLEN) ; + + result = results ; + while (result != NULL) + { + char result_str[OWL_CSV_RESULT_STRLEN] ; + size_t result_len ; + owl_result_to_csv(result_str, result->result) ; + result_len = strlen(result_str) ; + answer[answer_strlen++] = ';' ; + assert(answer_strlennext ; + } + } + + sem_post(&lock_results) ; + + break ; + + case SIMPLE_RESULTS_ID: + strncpy(answer + answer_strlen, SIMPLE_RESULTS_ANSWER, + strlen(SIMPLE_RESULTS_ANSWER)) ; + answer_strlen += strlen(SIMPLE_RESULTS_ANSWER) ; + + sem_wait(&lock_results) ; + + if (! results) + { + char answer_end[] = ";NOK;NoResult" ; + strncpy(answer + answer_strlen, answer_end, + strlen(answer_end)) ; + answer_strlen += strlen(answer_end) ; + } + + else + { + results_list *result ; + char answer_begin[10] ; + size_t answer_begin_len ; + + snprintf(answer_begin, 10, ";OK;%u", nb_results) ; + answer_begin_len = strlen(answer_begin) ; + strncpy(answer + answer_strlen, answer_begin, + answer_begin_len) ; + answer_strlen += answer_begin_len ; + + realloc_answer(answer_strlen + + nb_results * OWL_CSV_RESULT_SIMPLE_STRLEN) ; + + result = results ; + while (result != NULL) + { + char result_str[OWL_CSV_RESULT_SIMPLE_STRLEN] ; + size_t result_len ; + owl_result_to_csv_simple(result_str, result->result) ; + result_len = strlen(result_str) ; + answer[answer_strlen++] = ';' ; + strncpy(answer + answer_strlen, result_str, + result_len) ; + answer_strlen += result_len ; + result = result->next ; + } + } + + sem_post(&lock_results) ; + + break ; + + default: + { + char answer_end[] = "UnknownRequest;NOK" ; + strncpy(answer + ANSWER_HDR_STRLEN, answer_end, + strlen(answer_end)) ; + answer_strlen += strlen(answer_end) ; + } + } + + answer[answer_strlen] = '\0' ; +} + + +/* + * Realloc the answer buffer to the if needed: grows it if new_size is + * greater than the current size, shrink it if the current size is + * greater than the double of new_size. + */ +void realloc_answer(size_t new_size) +{ + if (new_size > answer_buflen) + answer_buflen = new_size ; + else if (answer_buflen / 2 >= new_size) + answer_buflen /= 2 ; + else + return ; + + answer = realloc(answer, answer_buflen) ; +} + + +/* + * Frees the memory allocated for the results' list. + */ +void free_results_list() +{ + results_list *tmp_res ; + while (results != NULL) + { + owl_free_result(results->result) ; + tmp_res = results ; + results = results->next ; + free(tmp_res) ; + } + nb_results = 0 ; +} diff --git a/owlps-udp-to-http/owlps-udp-to-http.h b/owlps-udp-to-http/owlps-udp-to-http.h new file mode 100644 index 0000000..9ceb98a --- /dev/null +++ b/owlps-udp-to-http/owlps-udp-to-http.h @@ -0,0 +1,52 @@ +#ifndef _OWLPS_UDP_TO_HTTP_H_ +#define _OWLPS_UDP_TO_HTTP_H_ + +#include + +#define TCP_PORT 8080 +#define NB_CONNECTIONS 1 +#define CLIENT_MESSAGE_STRLEN 2500 + +#define CLIENT_REQUEST_STRLEN 21 +#define SIMPLE_RESULTS_ID 1 +#define SIMPLE_RESULTS_REQUEST "ReadSimpleResults" +#define SIMPLE_RESULTS_ANSWER "SimpleResults" +#define RESULTS_ID 2 +#define RESULTS_REQUEST "ReadResults" +#define RESULTS_ANSWER "Results" + +#ifndef OWLPS_VERSION +# define OWLPS_VERSION "unknown version" +#endif // OWLPS_VERSION + +#define ANSWER_HDR \ + "HTTP/1.1 200 OK\n" \ + "Date: Sat, 01 Jan 0001 00:00:01 GMT\n" \ + "Server: OwlPS UDP-to-HTTP ["OWLPS_VERSION"]\n" \ + "Access-Control-Allow-Origin: *\n" \ + "Connection: close\n" \ + "Content-Type: text/html\n" \ + "\n" +#define ANSWER_HDR_STRLEN strlen(ANSWER_HDR) + + +typedef struct _results_list +{ + owl_result *result ; + struct _results_list *next ; +} results_list ; + + +int receive_udp(void) ; +void store_result(owl_result *result) ; +int init_tcp_socket(void) ; +void* tcp_server(void *NULL_value) ; +int +extract_request_from_message(char client_request[CLIENT_REQUEST_STRLEN], + char *client_message) ; +void prepare_answer(int request_id) ; +void realloc_answer(size_t new_size) ; +void free_results_list(void) ; + + +#endif // _OWLPS_UDP_TO_HTTP_H_