Newer
Older
#include <thread>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "GeoNetworkingLayer.hh"
#include "GeoNetworkingTypes.hh"
GeoNetworkingLayer::GeoNetworkingLayer(const std::string & p_type, const std::string & param) : TLayer<LibItsGeoNetworking__TestSystem::GeoNetworkingPort>(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());
// 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, std::string>(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<GeoNetworkingLayer>::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();
}
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) {
void GeoNetworkingLayer::sendData(OCTETSTRING& data, Params& params) {
loggers::get_instance().log_msg(">>> GeoNetworkingLayer::sendData: ", data);
while (_sendData.try_lock() == FALSE) {
// not ready yet
std::this_thread::sleep_for(std::chrono::milliseconds(1));
} // End of 'while' statement
_sendData.unlock();
loggers::get_instance().log("<<< GeoNetworkingLayer::sendData");
void GeoNetworkingLayer::receiveData(OCTETSTRING& data, Params& params) {
loggers::get_instance().log_msg(">>> GeoNetworkingLayer::receiveData: ", data);
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
} 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());
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
loggers::get_instance().log("GeoNetworkingLayer::receiveData: dst=%s", it->second.c_str());
ind.macDestinationAddress() = str2oct(CHARSTRING(it->second.c_str()));
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());
// 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());
// 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
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);
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);
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_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<unsigned int>(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);
if (sigprocmask(SIG_SETMASK, &_mask, NULL) == -1) {
loggers::get_instance().error("GeoNetworkingLayer::stop_beaconing: Sigprocmask failure: %d", errno);
}
timer_delete(_timerid);
_timerid = 0;
void GeoNetworkingLayer::send_beacon() {
loggers::get_instance().log(">>> GeoNetworkingLayer::send_beacon");
ExtendedHeader* eh = static_cast<ExtendedHeader *>(_beacon->gnPacket().packet().extendedHeader().get_opt_value());
loggers::get_instance().error("GeoNetworkingLayer::send_beacon: Wrong cast");
// Update timestamp
unsigned long long ms = std::chrono::duration_cast<std::chrono::milliseconds>(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<unsigned int>(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<ExtendedHeader>(eh),
OPTIONAL<GnRawPayload>()
);
_beacon->gnPacket().packet().payload().set_to_omit();
_beacon->gnPacket().securedMsg().set_to_omit();
// loggers::get_instance().log_msg("GeoNetworkingLayer::GeoNetworkingLayer: beacon value: ", *p._beacon);
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<GeoNetworkingLayer *>(p_signal_info->si_value.sival_ptr)->send_beacon();
} // End of method timer_irq_sigalrm_handler
class GeoNetworkingFactory: public LayerFactory {
GeoNetworkingFactory();
virtual Layer * createLayer(const std::string & type,
};
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) {
}
GeoNetworkingFactory GeoNetworkingFactory::_f;