From 161157dae7c423beae1d643db843d010e1d391ef Mon Sep 17 00:00:00 2001 From: Matteo Cypriani Date: Fri, 18 Mar 2011 10:37:06 +0100 Subject: [PATCH] [Positioning] Add InputUDPSocket The positioning server can now read the requests sent by the aggregator via UDP. This data exchange does not concern (auto)calibration requests yet. --- Makefile | 4 +- owlps-positioning/Makefile | 18 ++- owlps-positioning/src/input.cc | 10 ++ owlps-positioning/src/inputudpsocket.cc | 142 ++++++++++++++++++++++++ owlps-positioning/src/inputudpsocket.hh | 56 ++++++++++ owlps-positioning/src/userinterface.cc | 4 +- 6 files changed, 228 insertions(+), 6 deletions(-) create mode 100644 owlps-positioning/src/inputudpsocket.cc create mode 100644 owlps-positioning/src/inputudpsocket.hh diff --git a/Makefile b/Makefile index 61df7e2..3a9813f 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ owlps-listener: libowlps libowlps-client @make -C $@ owlps-aggregator: libowlps @make -C $@ -owlps-positioning: +owlps-positioning: libowlps @make -C $@ @@ -61,7 +61,7 @@ install-owlps-listener: install-libowlps @make -C $(subst install-,,$@) install install-owlps-aggregator: install-libowlps @make -C $(subst install-,,$@) install -install-owlps-positioning: +install-owlps-positioning: install-libowlps @make -C $(subst install-,,$@) install diff --git a/owlps-positioning/Makefile b/owlps-positioning/Makefile index 344ca16..a515ffe 100644 --- a/owlps-positioning/Makefile +++ b/owlps-positioning/Makefile @@ -22,16 +22,20 @@ STYLE = astyle --style=gnu --formatted CPPCHECK = cppcheck --enable=all DOXYGEN = doxygen >/dev/null -# Compilation tools and flags +# Compilation tools COLORGCC := $(shell which colorgcc >/dev/null 2>&1 ; echo $$?) ifeq ($(COLORGCC), 0) CXX = colorgcc endif + +# Flags +LIBOWLPS_DIR = ../libowlps #DEBUG = -g TESTSGXXFLAGS = -I$(TESTS_DIR) -I$(SRC_DIR) -I. -GXXFLAGS = $(DEBUG) -Wall -Wextra +GXXFLAGS = $(DEBUG) -Wall -Wextra -I$(LIBOWLPS_DIR) LD = $(CXX) -LDFLAGS = -lstdc++ -lm -lrt -lboost_program_options +LDFLAGS = -lstdc++ -lm -lrt -lboost_program_options \ + -L$(LIBOWLPS_DIR) -lowlps # Targets TARGET = owlps-positioning @@ -75,6 +79,7 @@ OBJ_LIST = \ positioning.o \ input.o \ inputcsv.o \ + inputudpsocket.o \ inputlogcsv.o OBJ_NOTEST_LIST = \ posexcept.o \ @@ -184,11 +189,18 @@ $(OBJ_DIR)/inputcsv.o: \ $(OBJ_DIR)/request.o \ $(OBJ_DIR)/calibrationrequest.o \ $(OBJ_DIR)/stock.o +$(OBJ_DIR)/inputudpsocket.o: \ + $(OBJ_DIR)/inputmedium.o \ + $(OBJ_DIR)/posexcept.o \ + $(OBJ_DIR)/request.o \ + $(OBJ_DIR)/calibrationrequest.o \ + $(OBJ_DIR)/stock.o $(OBJ_DIR)/inputlogcsv.o: \ $(SRC_DIR)/inputlogmedium.hh \ $(OBJ_DIR)/request.o $(OBJ_DIR)/input.o: \ $(OBJ_DIR)/inputcsv.o \ + $(OBJ_DIR)/inputudpsocket.o \ $(OBJ_DIR)/inputlogcsv.o \ $(OBJ_DIR)/calibrationrequest.o \ $(OBJ_DIR)/configuration.o \ diff --git a/owlps-positioning/src/input.cc b/owlps-positioning/src/input.cc index d21fd88..4890f71 100644 --- a/owlps-positioning/src/input.cc +++ b/owlps-positioning/src/input.cc @@ -1,5 +1,6 @@ #include "input.hh" #include "inputcsv.hh" +#include "inputudpsocket.hh" #include "inputlogcsv.hh" #include "calibrationrequest.hh" #include "configuration.hh" @@ -56,6 +57,15 @@ void Input::initialise_input_medium() InputCSV(Configuration::string_value("input.csv-file")) ; } + if (medium_name == "UDP") + { + if (! Configuration::is_configured("input.udp-port")) + throw missing_configuration( + "No input UDP port specified in the configuration!") ; + medium = new + InputUDPSocket(Configuration::int_value("input.udp-port")) ; + } + else throw bad_configuration( "The specified input medium « "+ medium_name +" » is unknown!") ; diff --git a/owlps-positioning/src/inputudpsocket.cc b/owlps-positioning/src/inputudpsocket.cc new file mode 100644 index 0000000..596a2ea --- /dev/null +++ b/owlps-positioning/src/inputudpsocket.cc @@ -0,0 +1,142 @@ +#include "inputudpsocket.hh" +#include "posexcept.hh" +#include "stock.hh" + +#include + +#include +#include + +using namespace std ; +using std::tr1::unordered_map ; + + + +/* *** Constructors *** */ + + +InputUDPSocket::InputUDPSocket(const uint_fast16_t _port): + listening_port(_port) +{ + if (! init_socket()) + throw error_opening_input_file("UDP socket") ; +} + + +InputUDPSocket::~InputUDPSocket() +{ + close_socket() ; +} + + + +/* *** Operations *** */ + + +/** + * @return true if the socket were successfully opened, false in case of + * error. + */ +bool InputUDPSocket::init_socket() +{ + sockfd = owl_create_udp_listening_socket(listening_port) ; + return sockfd >= 0 ; +} + + +/** + * Normally, the socket is closed automatically by the destructor. Use + * this if you want to close the socket prematurely. + * #sockfd is set to -1, even in case of error. + * @return \em true if the socket were successfully closed or were not + * opened. + * @return \em false in case of error. + */ +bool InputUDPSocket::close_socket() +{ + if (sockfd >= 0) + { + if (close(sockfd)) + { + perror("Cannot close UDP socket") ; + return false ; + } + + sockfd = -1 ; + } + + return true ; +} + + +/** + * This function reads the next Request in the UDP input socket. + * It cannot read calibration requests. + * + * #sockfd should be opened before processing requests; otherwise, + * #current_request is \link Request::clear() cleared\endlink and a + * blank Request is returned. + * + * @return The read Request, or a blank Request in case of error (socket + * not opened, bad packet format). + */ +const Request& InputUDPSocket::get_next_request() +{ + clear_current_request() ; + + if (eof()) + return *current_request ; + + struct sockaddr_in client; // UDP client structure + socklen_t client_len = sizeof(client) ; // Size of clients + + // Read the main request data + owl_request request ; + ssize_t nread = recvfrom(sockfd, &request, sizeof(request), 0, + (struct sockaddr *) &client, &client_len) ; + if (nread <= 0) + { + cerr << "No request received!" << endl ; + return *current_request ; + } + + // Endianess conversions + request.request_time = owl_ntoh_timestamp(request.request_time) ; + request.nb_info = ntohs(request.nb_info) ; + + // Mobile MAC + char *mac_mobile = + owl_mac_bytes_to_string(request.mobile_mac_addr_bytes) ; + const Mobile &mobile = Stock::find_create_mobile(mac_mobile) ; + free(mac_mobile) ; + current_request->set_mobile(&mobile) ; + + // Timestamp + current_request->set_time_sent(Timestamp(request.request_time)) ; + + // Read {MAC_AP;SS} mcouples (request_info) + unordered_map measurements ; + owl_request_info request_info ; + char *mac_ap ; + for (int i = 0 ; i < request.nb_info ; ++i) + { + nread = recvfrom(sockfd, &request_info, sizeof(request_info), 0, + (struct sockaddr *) &client, &client_len) ; + if (nread <= 0) + { + cerr << "No request info received!" << endl ; + current_request->clear() ; + return *current_request ; + } + mac_ap = owl_mac_bytes_to_string(request_info.ap_mac_addr_bytes) ; + const AccessPoint &ap = Stock::find_create_ap(mac_ap) ; + measurements[mac_ap].set_ap(&ap) ; + measurements[mac_ap].add_ss(static_cast + (request_info.antenna_signal_dbm)) ; + free(mac_ap) ; + } + + current_request->set_measurements(measurements) ; + + return *current_request ; +} diff --git a/owlps-positioning/src/inputudpsocket.hh b/owlps-positioning/src/inputudpsocket.hh new file mode 100644 index 0000000..eff21f0 --- /dev/null +++ b/owlps-positioning/src/inputudpsocket.hh @@ -0,0 +1,56 @@ +#ifndef _OWLPS_POSITIONING_INPUTUDPSOCKET_HH_ +#define _OWLPS_POSITIONING_INPUTUDPSOCKET_HH_ + +#include "inputmedium.hh" + +/// Receives \link Request requests \endlink from a UDP socket +class InputUDPSocket: public InputMedium +{ +protected: + int sockfd ; + uint_fast16_t listening_port ; + + /** @name Operations */ + //@{ + /// Initialises the socket + bool init_socket(void) ; + //@} + +public: + InputUDPSocket(const uint_fast16_t _port) ; + + ~InputUDPSocket(void) ; + + /** @name Read accessors */ + //@{ + /// Always false + bool eof(void) const ; + //@} + + /** @name Operations */ + //@{ + /// Reads the next request + const Request& get_next_request(void) ; + /// Closes the socket + bool close_socket(void) ; + //@} +} ; + + + +/* *** Read accessors *** */ + + +/** + * Note that by definition, the end of a socket is never reached. + * @return \em true if the socket is closed. + * @return \em false if the socket is opened. + */ +inline bool InputUDPSocket::eof() const +{ + return sockfd < 0 ; +} + + + +#endif // _OWLPS_POSITIONING_INPUTUDPSOCKET_HH_ diff --git a/owlps-positioning/src/userinterface.cc b/owlps-positioning/src/userinterface.cc index f583bd2..3e473c5 100644 --- a/owlps-positioning/src/userinterface.cc +++ b/owlps-positioning/src/userinterface.cc @@ -145,9 +145,11 @@ void UserInterface::fill_input_options() options.add_options() ("input.medium,I", po::value(), - "Medium from which requests are read. Allowed: CSV.") + "Medium from which requests are read. Allowed: CSV, UDP.") ("input.csv-file,C", po::value(), "CSV file to use for input (when input.medium = CSV).") + ("input.udp-port,p", po::value(), + "Port on which the UDP socket listens (when input.medium = UDP).") ; file_options->add(options) ;