/* * This file is part of the Owl Positioning System (OwlPS) project. * It is subject to the copyright notice and license terms in the * COPYRIGHT.t2t file found in the top-level directory of this * distribution and at * https://code.lm7.fr/mcy/owlps/src/master/COPYRIGHT.t2t * No part of the OwlPS Project, including this file, may be copied, * modified, propagated, or distributed except according to the terms * contained in the COPYRIGHT.t2t file; the COPYRIGHT.t2t file must be * distributed along with this file, either separately or by replacing * this notice by the COPYRIGHT.t2t file's contents. */ #include "inputudpsocket.hh" #include "posexcept.hh" #include "stock.hh" #include "configuration.hh" #include #include #include // For perror() #include // For close() #include // For inet_ntop() #include using namespace std ; /* *** 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 *** */ /** * @returns `true` if the socket were successfully opened. * @returns `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. * @returns `true` if the socket were successfully closed or were not * opened. * @returns `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 fills the current Request from the UDP input socket. * * @returns `true` if #current_request was correctly filled. * @returns `false` in case of error (socket not opened, bad packet * format). */ bool InputUDPSocket::fill_current_request() { if (eof()) return false ; // Read the main request data owl_request request ; ssize_t nread = recvfrom(sockfd, &request, sizeof(request), 0, nullptr, nullptr) ; if (nread <= 0) { cerr << "InputUDPSocket: No request received!" << endl ; return false ; } // Endianess conversions request.nb_packets = ntohs(request.nb_packets) ; owl_ntoh_timestamp(&request.request_time) ; request.nb_info = ntohs(request.nb_info) ; request.x_position = owl_ntohf(request.x_position) ; request.y_position = owl_ntohf(request.y_position) ; request.z_position = owl_ntohf(request.z_position) ; // Mobile MAC string mac_mobile( owl_mac_bytes_to_string(request.mobile_mac_addr_bytes)) ; PosUtil::to_upper(mac_mobile) ; // Mobile IP char ip_mobile_str[INET_ADDRSTRLEN] ; inet_ntop(AF_INET, &request.mobile_ip_addr_bytes, ip_mobile_str, INET_ADDRSTRLEN) ; string ip_mobile(ip_mobile_str) ; PosUtil::to_upper(ip_mobile) ; // Display request's info if (Configuration::is_configured("verbose")) cerr << "*** Request received from the aggregator ***" << "\n\tType: " << static_cast(request.type) << "\n\tNumber of packets: " << request.nb_packets << "\n\tMobile MAC: " << mac_mobile << "\n\tMobile IP: " << ip_mobile << "\n\tRequest timestamp: " << Timestamp(request.request_time) << "\n\tPosition X: " << request.x_position << "\n\tPosition Y: " << request.y_position << "\n\tPosition Z: " << request.z_position << "\n\tDirection: " << static_cast(request.direction) << "\n\tNumber of SS: " << request.nb_info << '\n' ; // Mobile MAC (continued) if (! Configuration::bool_value("positioning.accept-new-mobiles") && ! Stock::mobile_exists(mac_mobile)) { if (Configuration::is_configured("verbose")) cerr << "Dropping request from unknown mobile " << mac_mobile << ".\n" ; return false ; } const Mobile &mobile = Stock::find_create_mobile(mac_mobile) ; // Update the mobile's IP address: const_cast(mobile).set_ip_addr(ip_mobile) ; current_request->set_mobile(&mobile) ; // Request type current_request->set_type(request.type) ; // Number of packets current_request->set_nb_packets(request.nb_packets) ; // Timestamp current_request->set_time_sent(Timestamp(request.request_time)) ; // Position Point3D position(request.x_position, request.y_position, request.z_position) ; // Read the {MAC_CP;SS} couples (request_info) unordered_map measurements ; owl_request_info request_info ; for (int i = 0 ; i < request.nb_info ; ++i) { nread = recvfrom(sockfd, &request_info, sizeof(request_info), 0, nullptr, nullptr) ; if (nread <= 0) { cerr << "No request info received!" << endl ; return false ; } pkt_id_t packet_id = ntohs(request_info.packet_id) ; string mac_cp( owl_mac_bytes_to_string(request_info.cp_mac_addr_bytes)) ; PosUtil::to_upper(mac_cp) ; owl_ntoh_timestamp(&request_info.capture_time) ; Timestamp capture_time(request_info.capture_time) ; ss_t ss = request_info.ss_dbm ; if (Configuration::is_configured("verbose")) cerr << "\t* Packet received from the aggregator:" << "\n\t\tPacket number: " << packet_id << "\n\t\tCP MAC: " << mac_cp << "\n\t\tCapture timestamp: " << capture_time << "\n\t\tSignal: " << ss << " dBm" << '\n' ; if (! Configuration::bool_value("positioning.accept-new-cps") && ! Stock::cp_exists(mac_cp)) { if (Configuration::is_configured("verbose")) cerr << "Dropping packet from unknown CP " << mac_cp << ".\n" ; continue ; } const CapturePoint &cp = Stock::find_create_cp(mac_cp) ; measurements[mac_cp].set_cp(&cp) ; measurements[mac_cp].add_ss(packet_id, ss) ; } if (measurements.empty()) return false ; current_request->set_measurements(measurements) ; // Calibration request? fill_calibration_request_data( mac_mobile, position, request.direction, request.type) ; return true ; }