GeoNetworkingLayer.cc 13.7 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
10
11
#include "GeoNetworkingLayer.hh"
#include "GeoNetworkingTypes.hh"

#include "loggers.hh"

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

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

garciay's avatar
garciay committed
48
GeoNetworkingLayer::~GeoNetworkingLayer() {
49
50
51
  if (_timerid != 0) {
    timer_delete(_timerid);
  }	
52
53
} // End of destructor

garciay's avatar
garciay committed
54
void GeoNetworkingLayer::sendMsg(const LibItsGeoNetworking__TestSystem::GeoNetworkingReq& p, Params& params) {
garciay's avatar
garciay committed
55
  loggers::get_instance().log(">>> GeoNetworkingLayer::sendMsg");
garciay's avatar
garciay committed
56
57

  // Encode GeoNetworking PDU
garciay's avatar
garciay committed
58
59
  OCTETSTRING data;
  _codec.encode(p.msgOut(), data);
garciay's avatar
garciay committed
60
  sendData(data, params);
garciay's avatar
garciay committed
61
62
}

garciay's avatar
garciay committed
63
void GeoNetworkingLayer::sendData(OCTETSTRING& data, Params& params) {
garciay's avatar
garciay committed
64
  loggers::get_instance().log_msg(">>> GeoNetworkingLayer::sendData: ", data);
65
66
67
68
  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
69
  sendToAllLayers(data, params);
70
71
  _sendData.unlock();
  loggers::get_instance().log("<<< GeoNetworkingLayer::sendData");
garciay's avatar
garciay committed
72
73
}

garciay's avatar
garciay committed
74
void GeoNetworkingLayer::receiveData(OCTETSTRING& data, Params& params) { 
garciay's avatar
garciay committed
75
  loggers::get_instance().log_msg(">>> GeoNetworkingLayer::receiveData: ", data);
garciay's avatar
garciay committed
76
  // Decode the payload
garciay's avatar
garciay committed
77
78
79
80
81
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
  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
131
  // Add lower layers parameters
garciay's avatar
garciay committed
132
  // 1. Destination MAC address
garciay's avatar
garciay committed
133
  Params::const_iterator it = params.find(Params::mac_dst);
garciay's avatar
garciay committed
134
  if (it != params.cend()) {
135
    loggers::get_instance().log("GeoNetworkingLayer::receiveData: dst=%s", it->second.c_str());
garciay's avatar
garciay committed
136
    ind.macDestinationAddress() = str2oct(CHARSTRING(it->second.c_str()));
garciay's avatar
garciay committed
137
  } else {
garciay's avatar
garciay committed
138
    ind.macDestinationAddress() = str2oct(CHARSTRING(_params["mac_bc"].c_str()));
garciay's avatar
garciay committed
139
140
141
142
  }
  // 2. ssp
  it = params.find(Params::ssp);
  if (it != params.cend()) {
143
    loggers::get_instance().log("GeoNetworkingLayer::receiveData: ssp=%s", it->second.c_str());
garciay's avatar
garciay committed
144
    ind.ssp() = str2bit(CHARSTRING(it->second.c_str()));
garciay's avatar
garciay committed
145
  } else {
garciay's avatar
garciay committed
146
    ind.ssp().set_to_omit();
garciay's avatar
garciay committed
147
  }
garciay's avatar
garciay committed
148
149
150
  // 3. its_aid
  it = params.find(Params::its_aid);
  if (it != params.cend()) {
151
    loggers::get_instance().log("GeoNetworkingLayer::receiveData: its_aid=%s", it->second.c_str());
garciay's avatar
garciay committed
152
    ind.its__aid() = std::stoi(it->second.c_str());
garciay's avatar
garciay committed
153
  } else {
garciay's avatar
garciay committed
154
    ind.its__aid().set_to_omit();
garciay's avatar
garciay committed
155
156
  }
  
157
158
159
160
161
162
163
164
165
166
  // 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
167
  toAllUpperPorts(ind, params);
garciay's avatar
garciay committed
168
169
}

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
void GeoNetworkingLayer::start_beaconing() {
  loggers::get_instance().log(">>> GeoNetworkingLayer::start_beaconing");
  
  // Establish handler for timer signal
  loggers::get_instance().log("GeoNetworkingLayer::start_beaconing: Establishing handler for signal %d\n", SIGALRM);
  _sa.sa_flags = SA_SIGINFO;
  _sa.sa_sigaction = timer_irq_sigalrm_handler;
  sigemptyset(&_sa.sa_mask);
  if (sigaction(SIGALRM, &_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", SIGALRM);
  sigemptyset(&_mask);
  sigaddset(&_mask, SIGALRM);
  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 = SIGALRM; // 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<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", SIGALRM);
  if (sigprocmask(SIG_UNBLOCK, &_mask, NULL) == -1) {
    loggers::get_instance().error("GeoNetworkingLayer::start_beaconing: Sigprocmask failure: %d", errno);
  }
}

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", SIGALRM);
  sigemptyset(&_mask);
  sigaddset(&_mask, SIGALRM);
  if (sigprocmask(SIG_SETMASK, &_mask, NULL) == -1) {
    loggers::get_instance().error("GeoNetworkingLayer::stop_beaconing: Sigprocmask failure: %d", errno);
  }	
  timer_delete(_timerid);
  _timerid = 0;
}

231
232
void GeoNetworkingLayer::send_beacon() {
  loggers::get_instance().log(">>> GeoNetworkingLayer::send_beacon");
233
  
234
  ExtendedHeader* eh = static_cast<ExtendedHeader *>(_beacon->gnPacket().packet().extendedHeader().get_opt_value());
garciay's avatar
garciay committed
235
  if (eh == NULL) {
236
    loggers::get_instance().error("GeoNetworkingLayer::send_beacon: Wrong cast");
garciay's avatar
garciay committed
237
  }
238
239
240
241
242
243
244
245
246
247
  // 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__() = ms;
  // 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
248
  
249
250
  loggers::get_instance().log("<<< GeoNetworkingLayer::send_beacon");
} // End of send_beacon method
garciay's avatar
garciay committed
251

252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
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),
299
300
									      0
									      ),
301
302
303
304
305
306
307
308
309
310
311
312
313
								 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);
}

314
315
316
317
318
319
320
  
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\n", p_signal);

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

garciay's avatar
garciay committed
321
class GeoNetworkingFactory: public LayerFactory {
garciay's avatar
garciay committed
322
  static GeoNetworkingFactory _f;
garciay's avatar
garciay committed
323
public:
garciay's avatar
garciay committed
324
325
326
  GeoNetworkingFactory();
  virtual Layer * createLayer(const std::string & type,
			      const std::string & param);
garciay's avatar
garciay committed
327
328
329
};

GeoNetworkingFactory::GeoNetworkingFactory() {
garciay's avatar
garciay committed
330
331
332
  // Register factory
  loggers::get_instance().log(">>> GeoNetworkingFactory::GeoNetworkingFactory");
  LayerStackBuilder::RegisterLayerFactory("GN", this);
garciay's avatar
garciay committed
333
334
335
}

Layer * GeoNetworkingFactory::createLayer(const std::string & type, const std::string & param) {
garciay's avatar
garciay committed
336
  return new GeoNetworkingLayer(type, param);
garciay's avatar
garciay committed
337
338
339
}

GeoNetworkingFactory GeoNetworkingFactory::_f;