GeoNetworkingLayer.cc 14.8 KB
Newer Older
1
#include <thread>
garciay's avatar
garciay committed
2
#include <chrono>
3
4
5
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
garciay's avatar
garciay committed
6

garciay's avatar
garciay committed
7
8
9
#include "GeoNetworkingLayer.hh"
#include "GeoNetworkingTypes.hh"

garciay's avatar
garciay committed
10
#include "registration.hh"
garciay's avatar
garciay committed
11
12
#include "loggers.hh"

garciay's avatar
garciay committed
13
14
using namespace LibItsGeoNetworking__TypesAndValues;

garciay's avatar
garciay committed
15
GeoNetworkingLayer::GeoNetworkingLayer(const std::string & p_type, const std::string & param) : TLayer<LibItsGeoNetworking__TestSystem::GeoNetworkingPort>(p_type), _params(), _codec(), _beacon(NULL), _location_table(), _sendData(), _timerid{0}, _sev{0}, _its{0}, _freq_nanosecs(0), _mask{0}, _sa{0} {
garciay's avatar
garciay committed
16
  loggers::get_instance().log(">>> GeoNetworkingLayer::GeoNetworkingLayer: %s, %s", to_string().c_str(), param.c_str());
17
  
garciay's avatar
garciay committed
18
19
  // Setup parameters
  Params::convert(_params, param);
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  // 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");
garciay's avatar
garciay committed
38
39
40
  if (it == _params.cend()) {
    _params.insert(std::pair<std::string, std::string>(std::string("mac_bc"), "FFFFFFFFFFFF"));
  }
garciay's avatar
garciay committed
41
42
43
44
  // 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);
  
garciay's avatar
garciay committed
45
  // Prepare beaconing operation
46
  fill_beacon(latitude, longitude, ll_address);
47
  Params::const_iterator i = _params.find(Params::beaconing);
garciay's avatar
garciay committed
48
  if ((i != _params.cend()) && (i->second.compare("1") == 0)) { // Immediate beaconing was requested
49
50
    start_beaconing();
  }
51
} // End of constructor
52

garciay's avatar
garciay committed
53
GeoNetworkingLayer::~GeoNetworkingLayer() {
54
55
56
  if (_timerid != 0) {
    timer_delete(_timerid);
  }	
57
58
} // End of destructor

garciay's avatar
garciay committed
59
void GeoNetworkingLayer::sendMsg(const LibItsGeoNetworking__TestSystem::GeoNetworkingReq& p, Params& params) {
garciay's avatar
garciay committed
60
  loggers::get_instance().log(">>> GeoNetworkingLayer::sendMsg");
garciay's avatar
garciay committed
61
62

  // Encode GeoNetworking PDU
garciay's avatar
garciay committed
63
64
  OCTETSTRING data;
  _codec.encode(p.msgOut(), data);
garciay's avatar
garciay committed
65
  sendData(data, params);
garciay's avatar
garciay committed
66
67
}

garciay's avatar
garciay committed
68
void GeoNetworkingLayer::sendData(OCTETSTRING& data, Params& params) {
garciay's avatar
garciay committed
69
  loggers::get_instance().log_msg(">>> GeoNetworkingLayer::sendData: ", data);
70
71
72
73
  while (_sendData.try_lock() == FALSE) {
    // not ready yet
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  } // End of 'while' statement
garciay's avatar
garciay committed
74
  sendToAllLayers(data, params);
75
76
  _sendData.unlock();
  loggers::get_instance().log("<<< GeoNetworkingLayer::sendData");
garciay's avatar
garciay committed
77
78
}

garciay's avatar
garciay committed
79
void GeoNetworkingLayer::receiveData(OCTETSTRING& data, Params& params) { 
garciay's avatar
garciay committed
80
  loggers::get_instance().log_msg(">>> GeoNetworkingLayer::receiveData: ", data);
garciay's avatar
garciay committed
81
  // Decode the payload
garciay's avatar
garciay committed
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  LibItsGeoNetworking__TestSystem::GeoNetworkingInd ind;
  _codec.decode(data, ind.msgIn(), &params);
  
  // 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);
      }
    }
    
    // TODO Add beacon filter for StartPassBeaconing/Stop
    // By default incoming beacons are filtered by the test adapter
    if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_beaconHdr)) { // Discard beacon
      return;	  
    }
  } // TODO else security mode, becarfull to duplicate code

garciay's avatar
garciay committed
136
  // Add lower layers parameters
garciay's avatar
garciay committed
137
  // 1. Destination MAC address
garciay's avatar
garciay committed
138
  Params::const_iterator it = params.find(Params::mac_dst);
garciay's avatar
garciay committed
139
  if (it != params.cend()) {
140
    loggers::get_instance().log("GeoNetworkingLayer::receiveData: dst=%s", it->second.c_str());
garciay's avatar
garciay committed
141
    ind.macDestinationAddress() = str2oct(CHARSTRING(it->second.c_str()));
garciay's avatar
garciay committed
142
  } else {
garciay's avatar
garciay committed
143
    ind.macDestinationAddress() = str2oct(CHARSTRING(_params["mac_bc"].c_str()));
garciay's avatar
garciay committed
144
145
146
147
  }
  // 2. ssp
  it = params.find(Params::ssp);
  if (it != params.cend()) {
148
    loggers::get_instance().log("GeoNetworkingLayer::receiveData: ssp=%s", it->second.c_str());
garciay's avatar
garciay committed
149
    ind.ssp() = str2bit(CHARSTRING(it->second.c_str()));
garciay's avatar
garciay committed
150
  } else {
garciay's avatar
garciay committed
151
    ind.ssp().set_to_omit();
garciay's avatar
garciay committed
152
  }
garciay's avatar
garciay committed
153
154
155
  // 3. its_aid
  it = params.find(Params::its_aid);
  if (it != params.cend()) {
156
    loggers::get_instance().log("GeoNetworkingLayer::receiveData: its_aid=%s", it->second.c_str());
garciay's avatar
garciay committed
157
    ind.its__aid() = std::stoi(it->second.c_str());
garciay's avatar
garciay committed
158
  } else {
garciay's avatar
garciay committed
159
    ind.its__aid().set_to_omit();
garciay's avatar
garciay committed
160
161
  }
  
162
163
164
165
166
167
168
169
170
171
  // 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
garciay's avatar
garciay committed
172
  toAllUpperPorts(ind, params);
garciay's avatar
garciay committed
173
174
}

garciay's avatar
garciay committed
175
176
177
178
179
180
181
182
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

183
184
185
186
void GeoNetworkingLayer::start_beaconing() {
  loggers::get_instance().log(">>> GeoNetworkingLayer::start_beaconing");
  
  // Establish handler for timer signal
garciay's avatar
garciay committed
187
  loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: Establishing handler for signal %d\n", _signal_id);
188
189
190
  _sa.sa_flags = SA_SIGINFO;
  _sa.sa_sigaction = timer_irq_sigalrm_handler;
  sigemptyset(&_sa.sa_mask);
garciay's avatar
garciay committed
191
  if (sigaction(_signal_id, &_sa, NULL) == -1) {
192
193
194
    loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Sigaction failure: %d", errno);
  }
  // Block timer signal temporarily
garciay's avatar
garciay committed
195
  loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: Blocking signal %d\n", _signal_id);
196
  sigemptyset(&_mask);
garciay's avatar
garciay committed
197
  sigaddset(&_mask, _signal_id);
198
199
200
201
202
  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;
garciay's avatar
garciay committed
203
  _sev.sigev_signo = _signal_id; // Use signal alarm
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  _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
garciay's avatar
garciay committed
224
  loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: Unblocking signal %d\n", _signal_id);
225
226
227
  if (sigprocmask(SIG_UNBLOCK, &_mask, NULL) == -1) {
    loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Sigprocmask failure: %d", errno);
  }
garciay's avatar
garciay committed
228
} // End of start_beacon method
229
230
231
232
233

void GeoNetworkingLayer::stop_beaconing() {
  loggers::get_instance().log(">>> GeoNetworkingLayer::stop_beaconing");
  
  // Block timer signal temporarily
garciay's avatar
garciay committed
234
  loggers::get_instance().log("GeoNetworkingLayer::stop_beaconing: Blocking signal %d\n", _signal_id);
235
  sigemptyset(&_mask);
garciay's avatar
garciay committed
236
  sigaddset(&_mask, _signal_id);
237
238
239
240
241
  if (sigprocmask(SIG_SETMASK, &_mask, NULL) == -1) {
    loggers::get_instance().error("GeoNetworkingLayer::stop_beaconing: Sigprocmask failure: %d", errno);
  }	
  timer_delete(_timerid);
  _timerid = 0;
garciay's avatar
garciay committed
242
} // End of stop_beacon method
243

244
245
void GeoNetworkingLayer::send_beacon() {
  loggers::get_instance().log(">>> GeoNetworkingLayer::send_beacon");
246
  
247
  ExtendedHeader* eh = static_cast<ExtendedHeader *>(_beacon->gnPacket().packet().extendedHeader().get_opt_value());
garciay's avatar
garciay committed
248
  if (eh == NULL) {
249
    loggers::get_instance().error("GeoNetworkingLayer::send_beacon: Wrong cast");
garciay's avatar
garciay committed
250
  }
251
  // Update timestamp
garciay's avatar
garciay committed
252
253
254
  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);
255
256
257
258
259
260
261
  // 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);
garciay's avatar
garciay committed
262
  
garciay's avatar
garciay committed
263
  //loggers::get_instance().log("<<< GeoNetworkingLayer::send_beacon");
264
} // End of send_beacon method
garciay's avatar
garciay committed
265

garciay's avatar
garciay committed
266
267
268
269
270
271
272
273
274
275
276
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

277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
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),
324
325
									      0
									      ),
326
327
328
329
330
331
332
333
334
335
336
								 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);
garciay's avatar
garciay committed
337
} // End of fill_beacon method
338
339
  
void GeoNetworkingLayer::timer_irq_sigalrm_handler(int p_signal, siginfo_t *p_signal_info, void *p_uc) {
garciay's avatar
garciay committed
340
  //loggers::get_instance().log(">>> GeoNetworkingLayer::timer_irq_sigalrm_handler: Caught signal %d", p_signal);
341
342
343
344

  static_cast<GeoNetworkingLayer *>(p_signal_info->si_value.sival_ptr)->send_beacon();
} // End of method timer_irq_sigalrm_handler

garciay's avatar
garciay committed
345
class GeoNetworkingFactory: public LayerFactory {
garciay's avatar
garciay committed
346
  static GeoNetworkingFactory _f;
garciay's avatar
garciay committed
347
public:
garciay's avatar
garciay committed
348
349
350
  GeoNetworkingFactory();
  virtual Layer * createLayer(const std::string & type,
			      const std::string & param);
garciay's avatar
garciay committed
351
352
353
};

GeoNetworkingFactory::GeoNetworkingFactory() {
garciay's avatar
garciay committed
354
355
356
  // Register factory
  loggers::get_instance().log(">>> GeoNetworkingFactory::GeoNetworkingFactory");
  LayerStackBuilder::RegisterLayerFactory("GN", this);
garciay's avatar
garciay committed
357
358
359
}

Layer * GeoNetworkingFactory::createLayer(const std::string & type, const std::string & param) {
garciay's avatar
garciay committed
360
  return new GeoNetworkingLayer(type, param);
garciay's avatar
garciay committed
361
362
363
}

GeoNetworkingFactory GeoNetworkingFactory::_f;