#include #include #include #include #include #include "GeoNetworkingLayer.hh" #include "GeoNetworkingTypes.hh" #include "registration.hh" #include "loggers.hh" using namespace LibItsGeoNetworking__TypesAndValues; GeoNetworkingLayer::GeoNetworkingLayer(const std::string & p_type, const std::string & param) : TLayer(p_type), _params(), _codec(), _beacon(nullptr), _location_table(), _pass_beacon_table(), _sendData(), _timerid{0}, _sev{0}, _its{0}, _freq_nanosecs(0), _mask{0}, _sa{0} { loggers::get_instance().log(">>> GeoNetworkingLayer::GeoNetworkingLayer: %s, %s", to_string().c_str(), param.c_str()); // Setup parameters Params::convert(_params, param); // Sanity checks INTEGER latitude; Params::const_iterator it = _params.find(Params::latitude); if (it != _params.cend()) { latitude = str2int(CHARSTRING(it->second.c_str())); } INTEGER longitude; it = _params.find(Params::longitude); if (it != _params.cend()) { longitude = str2int(CHARSTRING(it->second.c_str())); } OCTETSTRING ll_address; it = _params.find(Params::ll_address); if (it != _params.cend()) { ll_address = str2oct(CHARSTRING(it->second.c_str())); } // Add broadcast address if needed it = _params.find("mac_bc"); if (it == _params.cend()) { _params.insert(std::pair(std::string("mac_bc"), "FFFFFFFFFFFF")); } // Register this object for AdapterControlPort loggers::get_instance().log("GeoNetworkingLayer::GeoNetworkingLayer: register %s/%p", p_type.c_str(), this); registration::get_instance().add_item(p_type, this); Params::const_iterator i = _params.find(Params::beaconing); if ((i != _params.cend()) && (i->second.compare("1") == 0)) { // Immediate beaconing was requested // Prepare beaconing operation fill_beacon(latitude, longitude, ll_address); start_beaconing(); } } // End of constructor GeoNetworkingLayer::~GeoNetworkingLayer() { loggers::get_instance().log(">>> GeoNetworkingLayer::~GeoNetworkingLayer"); if (_timerid != 0) { timer_delete(_timerid); } if (_beacon != nullptr) { delete _beacon; } } // End of destructor void GeoNetworkingLayer::sendMsg(const LibItsGeoNetworking__TestSystem::GeoNetworkingReq& p, Params& params) { loggers::get_instance().log(">>> GeoNetworkingLayer::sendMsg"); // Encode GeoNetworking PDU OCTETSTRING data; _codec.encode(p.msgOut(), data); sendData(data, params); } void GeoNetworkingLayer::sendData(OCTETSTRING& data, Params& params) { loggers::get_instance().log_msg(">>> GeoNetworkingLayer::sendData: ", data); //params.log(); // TODO Take into account the Security Params::const_iterator it = params.find(Params::packetize); /*if (it != params.cend()) { LibItsGeoNetworking__TypesAndValues::GeoNetworkingPacket gnp; if (_params[Params::btp_type].compare("btpA") == 0) { header.btpAHeader() = LibItsGeoNetworking__TypesAndValues::GeoNetworkingAHeader( std::stoi(_params[Params::btp_destination_port]), std::stoi(_params[Params::btp_info]) ); } else { header.btpBHeader() = LibItsGeoNetworking__TypesAndValues::GeoNetworkingBHeader( std::stoi(_params[Params::btp_destination_port]), std::stoi(_params[Params::btp_info]) ); } LibItsGeoNetworking__TypesAndValues::GeoNetworkingPacket p( LibItsGeoNetworking__TypesAndValues::BasicHeader( 1, LibItsGeoNetworking__TypesAndValues::BasicNextHeader(LibItsGeoNetworking__TypesAndValues::BasicNextHeader::e__commonHeader), // TODO Take into acount the Security 0, LibItsGeoNetworking__TypesAndValues::Lifetime( LibItsGeoNetworking__TypesAndValues::Ltbase(LibItsGeoNetworking__TypesAndValues::Ltbase::e__50ms), std::stoi(_params[Params::expity]) / 50 ), 10 ), LibItsGeoNetworking__TypesAndValues::GeoNetworkingPacket(gnp) ); loggers::get_instance().log_msg("GeoNetworkingLayer::sendData: ", p); // Encode GeoNetworking PDU OCTETSTRING os; _codec.encode(p, os); data = os; }*/ // TODO To be removed while (_sendData.try_lock() == FALSE) { // not ready yet std::this_thread::sleep_for(std::chrono::milliseconds(1)); } // End of 'while' statement sendToAllLayers(data, params); _sendData.unlock(); loggers::get_instance().log("<<< GeoNetworkingLayer::sendData"); } void GeoNetworkingLayer::receiveData(OCTETSTRING& data, Params& params) { loggers::get_instance().log_msg(">>> GeoNetworkingLayer::receiveData: ", data); // Decode the payload LibItsGeoNetworking__TestSystem::GeoNetworkingInd ind; _codec.decode(data, ind.msgIn(), ¶ms); // Update GeoNetworking layer if (ind.msgIn().basicHeader().version() == 0) { // Non secured mode const LibItsGeoNetworking__TypesAndValues::LongPosVector* sopv = nullptr; const LibItsGeoNetworking__TypesAndValues::GnNonSecuredPacket& p = ind.msgIn().gnPacket().packet(); const LibItsGeoNetworking__TypesAndValues::HeaderTST& htst = p.commonHeader().headerTST(); if (p.extendedHeader().ispresent()) { // Update location table const LibItsGeoNetworking__TypesAndValues::ExtendedHeader& ex = p.extendedHeader(); if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_beaconHdr)) { // Receive a beacon sopv = &ex.beaconHeader().srcPosVector(); } else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_tsbHdr)) { // Receive a topologicallyScopeBroadcast if (ex.ischosen(LibItsGeoNetworking__TypesAndValues::ExtendedHeader::ALT_tsbHeader)) { sopv = &ex.tsbHeader().srcPosVector(); } else { sopv = &ex.shbHeader().srcPosVector(); } } else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_geoBroadcastHdr)) { sopv = &ex.geoBroadcastHeader().srcPosVector(); } else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_lsHdr)) { // Receive a location service if (ex.ischosen(LibItsGeoNetworking__TypesAndValues::ExtendedHeader::ALT_lsRequestHeader)) { // Receive a LocationService/LsRequest sopv = &ex.lsRequestHeader().srcPosVector(); // TODO Send LsReply if we are not in context of GN ATS } else { sopv = &ex.lsReplyHeader().srcPosVector(); } } else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_geoAnycastHdr)) { // Receive a GeoAnycast sopv = &ex.geoAnycastHeader().srcPosVector(); } else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_geoUnicastHdr)) { sopv = &ex.geoUnicastHeader().srcPosVector(); /*} else if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_saHdr)) { // Receive Service Advertisement if (ex.ischosen(LibItsGeoNetworking__TypesAndValues::ExtendedHeader::ALT_xxx)) { sopv = &ex.xxxHeader().srcPosVector(); } else { sopv = &ex.xxxHeader().srcPosVector(); }*/ } // else, nothing to do loggers::get_instance().log("GeoNetworkingLayer::receiveData: sopv is boud: %d", sopv->is_bound()); if(sopv->is_bound()) { const LibItsGeoNetworking__TypesAndValues::LongPosVector& lpv = *sopv; _location_table.add_entry(lpv); } } // By default incoming beacons are filtered by the test adapter if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_beaconHdr)) { loggers::get_instance().log_msg("GeoNetworkingLayer::receiveData: Pass beaconing processing", htst); if (_pass_beacon_table.empty()) { // Discard beacon loggers::get_instance().log("GeoNetworkingLayer::receiveData: Pass beaconing table empty, skip it"); return; } else { // TODO Add beacon filter for StartPassBeaconing/Stop if (!_pass_beacon_table.has_entry(sopv->gnAddr().mid())) { // Discard beacon loggers::get_instance().log_msg("GeoNetworkingLayer::receiveData: Not in pass beaconing table, skip it", *sopv); return; } // else, continue } } // else, continue } // TODO else security mode, becarefull to duplicate code // Add lower layers parameters // 1. Destination MAC address Params::const_iterator it = params.find(Params::mac_dst); if (it != params.cend()) { loggers::get_instance().log("GeoNetworkingLayer::receiveData: dst=%s", it->second.c_str()); ind.macDestinationAddress() = str2oct(CHARSTRING(it->second.c_str())); } else { ind.macDestinationAddress() = str2oct(CHARSTRING(_params["mac_bc"].c_str())); } // 2. ssp it = params.find(Params::ssp); if (it != params.cend()) { loggers::get_instance().log("GeoNetworkingLayer::receiveData: ssp=%s", it->second.c_str()); ind.ssp() = str2bit(CHARSTRING(it->second.c_str())); } else { ind.ssp().set_to_omit(); } // 3. its_aid it = params.find(Params::its_aid); if (it != params.cend()) { loggers::get_instance().log("GeoNetworkingLayer::receiveData: its_aid=%s", it->second.c_str()); ind.its__aid() = std::stoi(it->second.c_str()); } else { ind.its__aid().set_to_omit(); } // Pass the GeoNetworking raw payload to the upper layers if any it = params.find(Params::gn_payload); if (it != params.cend()) { loggers::get_instance().log("GeoNetworkingLayer::receiveData: gn_payload=%s", it->second.c_str()); OCTETSTRING os(str2oct(CHARSTRING(it->second.c_str()))); receiveToAllLayers(os, params); } else { loggers::get_instance().warning("GeoNetworkingLayer::receiveData: No payload to pass to upper layers"); } // Pass it to the ports toAllUpperPorts(ind, params); } OCTETSTRING GeoNetworkingLayer::trigger_ac_event(OCTETSTRING& data, Params& params) { loggers::get_instance().log_to_hexa(">>> GeoNetworkingLayer::trigger_ac_event: ", data); return int2oct(0, 2); } // End of trigger_ac_event method void GeoNetworkingLayer::start_beaconing() { loggers::get_instance().log(">>> GeoNetworkingLayer::start_beaconing"); loggers::get_instance().log_msg("GeoNetworkingLayer::start_beaconing: _beacon=", *_beacon); // Establish handler for timer signal loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: Establishing handler for signal %d\n", _signal_id); _sa.sa_flags = SA_SIGINFO; _sa.sa_sigaction = timer_irq_sigalrm_handler; sigemptyset(&_sa.sa_mask); if (sigaction(_signal_id, &_sa, NULL) == -1) { loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Sigaction failure: %d", errno); } // Block timer signal temporarily loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: Blocking signal %d\n", _signal_id); sigemptyset(&_mask); sigaddset(&_mask, _signal_id); if (sigprocmask(SIG_SETMASK, &_mask, NULL) == -1) { loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Sigprocmask failure: %d", errno); } // Create the timer _sev.sigev_notify = SIGEV_SIGNAL; _sev.sigev_signo = _signal_id; // Use signal alarm _sev.sigev_value.sival_ptr = this; // The GeoNetworkingLayer object address if (timer_create(CLOCK_REALTIME, &_sev, &_timerid) == -1) { loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Timer failure: %d", errno); } loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: timer ID is 0x%lx\n", (long)_timerid); // Start the timer unsigned int expiry = 1000; // Default expiry time 1000ms Params::const_iterator i = _params.find("expiry"); if (i != _params.cend()) { expiry = static_cast(std::strtoul(i->second.c_str(), NULL, 10)); } _freq_nanosecs = expiry * 1000000; _its.it_value.tv_sec = _freq_nanosecs / 1000000000; _its.it_value.tv_nsec = _freq_nanosecs % 1000000000; _its.it_interval.tv_sec = _its.it_value.tv_sec; _its.it_interval.tv_nsec = _its.it_value.tv_nsec; if (timer_settime(_timerid, 0, &_its, NULL) == -1) { loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Sigprocmask failure: %d", errno); } // Unlock the timer signal, so that timer notification can be delivered loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: Unblocking signal %d\n", _signal_id); if (sigprocmask(SIG_UNBLOCK, &_mask, NULL) == -1) { loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Sigprocmask failure: %d", errno); } } // End of start_beaconing method void GeoNetworkingLayer::start_beaconing(const LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu& p_beacon) { loggers::get_instance().log_msg(">>> GeoNetworkingLayer::start_beaconing", p_beacon); // Initialize the beacon if (_beacon != nullptr) { delete _beacon; } _beacon = new LibItsGeoNetworking__TypesAndValues::GeoNetworkingPdu(p_beacon); start_beaconing(); // TODO Refined adding a boolean return code } // End of start_beaconing method void GeoNetworkingLayer::stop_beaconing() { loggers::get_instance().log(">>> GeoNetworkingLayer::stop_beaconing"); // Block timer signal temporarily loggers::get_instance().log("GeoNetworkingLayer::stop_beaconing: Blocking signal %d\n", _signal_id); sigemptyset(&_mask); sigaddset(&_mask, _signal_id); if (sigprocmask(SIG_SETMASK, &_mask, NULL) == -1) { loggers::get_instance().error("GeoNetworkingLayer::stop_beaconing: Sigprocmask failure: %d", errno); } timer_delete(_timerid); _timerid = 0; } // End of stop_beaconing method void GeoNetworkingLayer::send_beacon() { loggers::get_instance().log(">>> GeoNetworkingLayer::send_beacon"); ExtendedHeader* eh = static_cast(_beacon->gnPacket().packet().extendedHeader().get_opt_value()); if (eh == NULL) { loggers::get_instance().error("GeoNetworkingLayer::send_beacon: Wrong cast"); } // Update timestamp unsigned long long ms = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count() - 1072911600000L; // TODO Add method such as its_tme() & its_time_mod() eh->beaconHeader().srcPosVector().timestamp__().set_long_long_val(static_cast(ms)); //loggers::get_instance().log_msg("GeoNetworkingLayer::send_beacon: ", *_beacon); // Encode message using TITAN because of payload in omited TTCN_Buffer encoding_buffer; _beacon->encode(*(_beacon->get_descriptor()), encoding_buffer, TTCN_EncDec::CT_RAW); OCTETSTRING data(encoding_buffer.get_len(), encoding_buffer.get_data()); // Send it Params params(_params); sendData(data, params); //loggers::get_instance().log("<<< GeoNetworkingLayer::send_beacon"); } // End of send_beacon method void GeoNetworkingLayer::start_pass_beaconing(const LibItsGeoNetworking__TypesAndValues::BeaconHeader& p_beacon) { loggers::get_instance().log_msg(">>> GeoNetworkingLayer::start_pass_beaconing", p_beacon); const LibItsGeoNetworking__TypesAndValues::LongPosVector& lpv = p_beacon.srcPosVector(); if (!_pass_beacon_table.has_entry(lpv.gnAddr().mid())) { _pass_beacon_table.add_entry(lpv); } // TODO Refined adding a boolean return code } // End of start_pass_beaconing method void GeoNetworkingLayer::stop_pass_beaconing() { loggers::get_instance().log(">>> GeoNetworkingLayer::stop_pass_beaconing"); _pass_beacon_table.reset(); } // End of stop_pass_beaconing method const LongPosVector* GeoNetworkingLayer::get_lpv(const GN__Address& p_gn_address) { loggers::get_instance().log_msg(">>> GeoNetworkingLayer::get_lpv", p_gn_address); const LongPosVector* lpv = nullptr; if (_location_table.has_entry(p_gn_address.mid())) { lpv = _location_table.get_entry(p_gn_address.mid()); } return lpv; } // End of get_lpv void GeoNetworkingLayer::fill_beacon(INTEGER& p_latitude, INTEGER& p_longitude, OCTETSTRING& p_ll_address) { _beacon = new GeoNetworkingPdu(); HeaderTST h; h.beaconHdr() = BeaconHeaderType( HeaderType(HeaderType::e__beacon), 0 ); ExtendedHeader eh; eh.beaconHeader() = BeaconHeader( LongPosVector( GN__Address( TypeOfAddress(TypeOfAddress::e__manual), StationType(StationType::e__roadSideUnit), 33, p_ll_address ), 0, p_latitude, p_longitude, int2bit(0, 1), 0, 0 ) ); _beacon->basicHeader() = BasicHeader( 0, BasicNextHeader( BasicNextHeader::e__commonHeader ), 0, Lifetime( 4, LtBase(LtBase::e__50ms) ), 5 ); _beacon->gnPacket().packet() = GnNonSecuredPacket( CommonHeader( NextHeader( NextHeader::e__any ), 0, h, TrafficClass( SCF(SCF::e__scfDisabled), ChannelOffload(ChannelOffload::e__choffDisabled), 0 ), int2bit(0, 8), 0, 1, 0 ), OPTIONAL(eh), OPTIONAL() ); _beacon->gnPacket().packet().payload().set_to_omit(); _beacon->gnPacket().securedMsg().set_to_omit(); // loggers::get_instance().log_msg("GeoNetworkingLayer::GeoNetworkingLayer: beacon value: ", *p._beacon); } // End of fill_beacon method void GeoNetworkingLayer::timer_irq_sigalrm_handler(int p_signal, siginfo_t *p_signal_info, void *p_uc) { //loggers::get_instance().log(">>> GeoNetworkingLayer::timer_irq_sigalrm_handler: Caught signal %d", p_signal); static_cast(p_signal_info->si_value.sival_ptr)->send_beacon(); } // End of method timer_irq_sigalrm_handler class GeoNetworkingFactory: public LayerFactory { static GeoNetworkingFactory _f; public: GeoNetworkingFactory(); virtual Layer * createLayer(const std::string & type, const std::string & param); }; GeoNetworkingFactory::GeoNetworkingFactory() { // Register factory loggers::get_instance().log(">>> GeoNetworkingFactory::GeoNetworkingFactory"); LayerStackBuilder::RegisterLayerFactory("GN", this); } Layer * GeoNetworkingFactory::createLayer(const std::string & type, const std::string & param) { return new GeoNetworkingLayer(type, param); } GeoNetworkingFactory GeoNetworkingFactory::_f;