GeoNetworkingPort.cc 15.2 KB
Newer Older
// This Test Port skeleton source file was generated by the
// TTCN-3 Compiler of the TTCN-3 Test Executor version CRL 113 200/5 R3A
// for U-ERICSSON\ethgry (ethgry@HU00078339) on Sat Aug 15 22:33:04 2015

// Copyright Ericsson Telecom AB 2000-2014

// You may modify this file. Complete the body of empty functions and
// add your member functions here.

/*#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>*/

#include "GeoNetworkingPort.hh"
garciay's avatar
garciay committed
#include "GeoNetworkingLayer.hh"
garciay's avatar
garciay committed
#include "loggers.hh"

namespace LibItsGeoNetworking__TestSystem {

garciay's avatar
garciay committed
  GeoNetworkingPort::GeoNetworkingPort(const char *par_port_name)
    : GeoNetworkingPort_BASE(par_port_name), _cfg_params(), _layer_params(), _layer(NULL), _time_key("GeoNetworkingPort::outgoing_send") /*, _use_posix_timer(true), _child(-1), _child_pids{-1, -1}, _parent_pids{-1, -1}, _timerid{0}, _sev{0}, _its{0}, _freq_nanosecs(0), _mask{0}, _sa{0}*/ {
      // Nothing to do
  } // End of constructor
  
garciay's avatar
garciay committed
  GeoNetworkingPort::~GeoNetworkingPort()
  {
    loggers::get_instance().log(">>> GeoNetworkingPort::~GeoNetworkingPort");
    
    /*if (_use_posix_timer && (_timerid != 0)) {
      timer_delete(_timerid);
      }*/	
    if (_layer != NULL) {
garciay's avatar
garciay committed
      delete _layer;
garciay's avatar
garciay committed
  void GeoNetworkingPort::set_parameter(const char * parameter_name, const char * parameter_value)
  {
    loggers::get_instance().log("GeoNetworkingPort::set_parameter: %s=%s", parameter_name, parameter_value);
    _cfg_params.insert(std::pair<std::string, std::string>(std::string(parameter_name), std::string(parameter_value)));
garciay's avatar
garciay committed
  }
garciay's avatar
garciay committed
  /*void GeoNetworkingPort::Handle_Fd_Event(int fd, boolean is_readable,
    boolean is_writable, boolean is_error) {}*/
garciay's avatar
garciay committed
  void GeoNetworkingPort::Handle_Fd_Event_Error(int /*fd*/)
  {
garciay's avatar
garciay committed
  }
garciay's avatar
garciay committed
  void GeoNetworkingPort::Handle_Fd_Event_Writable(int /*fd*/)
  {
garciay's avatar
garciay committed
  }
garciay's avatar
garciay committed
  void GeoNetworkingPort::Handle_Fd_Event_Readable(int /*fd*/)
  {
garciay's avatar
garciay committed
  }
garciay's avatar
garciay committed
  /*void GeoNetworkingPort::Handle_Timeout(double time_since_last_call) {}*/
garciay's avatar
garciay committed
  void GeoNetworkingPort::user_map(const char * system_port)
  {
    loggers::get_instance().log(">>> GeoNetworkingPort::user_map: %s", system_port);
garciay's avatar
garciay committed
    // Build layer stack
garciay's avatar
garciay committed
    Params::iterator it = _cfg_params.find(std::string("params"));
    if (it != _cfg_params.end()) {
      //loggers::get_instance().log("GeoNetworkingPort::user_map<%d>: %s", _child, it->second.c_str());
      // Setup parameters
      Params::convert(_layer_params, it->second);
      // Create layer
garciay's avatar
garciay committed
      _layer = LayerStackBuilder::GetInstance()->createLayerStack(it->second.c_str());
      if (static_cast<GeoNetworkingLayer *>(_layer) == NULL) {
	loggers::get_instance().error("GeoNetworkingPort::user_map: Invalid stack configuration: %s", it->second.c_str());
      }
garciay's avatar
garciay committed
      static_cast<GeoNetworkingLayer *>(_layer)->addUpperPort(this);

      /*if (_use_posix_timer) {	
	// Establish handler for timer signal
	loggers::get_instance().log("GeoNetworkingPort::user_map: 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("GeoNetworkingPort::user_map: Sigaction failure: %d", errno);
	}
	// Block timer signal temporarily
	loggers::get_instance().log("GeoNetworkingPort::user_map: Blocking signal %d\n", SIGALRM);
	sigemptyset(&_mask);
	sigaddset(&_mask, SIGALRM);
	if (sigprocmask(SIG_SETMASK, &_mask, NULL) == -1) {
	  loggers::get_instance().error("GeoNetworkingPort::user_map: 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 GeoNetworkingPort object address
	if (timer_create(CLOCK_REALTIME, &_sev, &_timerid) == -1) {
	  loggers::get_instance().error("GeoNetworkingPort::user_map: Timer failure: %d", errno);
	}
	loggers::get_instance().log("GeoNetworkingPort::user_map: timer ID is 0x%lx\n", (long)_timerid);
	// Start the timer
	unsigned int expiry = 1000; // One second
	Params::const_iterator i = _layer_params.find("expiry");
	if (i != _layer_params.cend()) {
	  expiry = static_cast<unsigned int>(std::strtoul(it->second.c_str(), NULL, 10));
	}
	_freq_nanosecs = 1000*1000000; // expiry time 1000ms
	_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("GeoNetworkingPort::user_map: Sigprocmask failure: %d", errno);
	}
	// Unlock the timer signal, so that timer notification can be delivered
	loggers::get_instance().log("GeoNetworkingPort::user_map: Unblocking signal %d\n", SIGALRM);
	if (sigprocmask(SIG_UNBLOCK, &_mask, NULL) == -1) {
	  loggers::get_instance().error("GeoNetworkingPort::user_map: Sigprocmask failure: %d", errno);
	}
      }*/
      /*else { // _use_posix_timer
	// TODO If timer mechanism is enought, remove fork code
	if (_child > 0) { // Start beaconing if required
	  Params::const_iterator i = _layer_params.find(Params::beaconing);
	  if ((i != _layer_params.cend()) && (i->second.compare("1") == 0)) {  
	    unsigned char *buffer = new unsigned char[it->second.length() + 1];
	    buffer[0] = 0x01;
	    copy(it->second.begin(), it->second.end(), buffer + 1);
	    write(_child_pids[1], buffer, it->second.length() + 1);
	    bool ack = false;
	    while (!ack) {
	      if ((read(_parent_pids[0], buffer, 1) > 0) && (buffer[0] == 0xAA)) {
		loggers::get_instance().log("GeoNetworkingPort::user_map: Receive ack from child");
		ack = true;
	      }
	    } // End of 'while' statement
	    delete [] buffer;
	  } else {
	    loggers::get_instance().log("GeoNetworkingPort::user_map: Beaconing not requested");
	  }
	} // else, in child process
	}*/
garciay's avatar
garciay committed
      loggers::get_instance().error("GeoNetworkingPort::user_map: No layers defined in configuration file");
garciay's avatar
garciay committed
  void GeoNetworkingPort::user_unmap(const char * system_port)
  {
    loggers::get_instance().log(">>> GeoNetworkingPort::user_unmap: %s", system_port);

    // Stop timer
    /*if (_use_posix_timer) {	
      // Block timer signal temporarily
      loggers::get_instance().log("GeoNetworkingPort::user_unmap: Blocking signal %d\n", SIGALRM);
      sigemptyset(&_mask);
      sigaddset(&_mask, SIGALRM);
      if (sigprocmask(SIG_SETMASK, &_mask, NULL) == -1) {
	loggers::get_instance().error("GeoNetworkingPort::user_map: Sigprocmask failure: %d", errno);
      }	
      timer_delete(_timerid);
      _timerid = 0;
      }*/
    // Reset layers
    if (_layer != NULL) {
garciay's avatar
garciay committed
      delete _layer;
      _layer = NULL;
garciay's avatar
garciay committed
  void GeoNetworkingPort::user_start()
  {
    loggers::get_instance().log(">>> GeoNetworkingPort::user_start");
    // TODO If timer mechanism is enought, remove fork code
    /*if (!_use_posix_timer) { // Use fork
      // Set up pipes for process communication
      if (pipe2(_parent_pids, O_NONBLOCK) != 0) { // Failed to create pipe
	loggers::get_instance().error("GeoNetworkingPort::user_start: Parent pipe creation failure: %d", errno);
      }
      if (pipe2(_child_pids, O_NONBLOCK) != 0) { // Failed to create pipe
	loggers::get_instance().error("GeoNetworkingPort::user_start: Child pipe creation failure: %d", errno);
      }
      
      // Fork port for beaconing beacause of TITAN is not multithread at all :-(
      // NOTE Need to fork process very early due to issues for handle dup operation
      _child = fork();
      if (_child == -1) { // Fork failure
	close(_parent_pids[0]);
	close(_parent_pids[1]);
	close(_child_pids[0]);
	close(_child_pids[1]);
	loggers::get_instance().error("GeoNetworkingPort::user_start: Fork failure: %d", errno);
      } else if (_child == 0) { // Child process
	loggers::get_instance().log("GeoNetworkingPort::user_start: Child process is running");
	// This is a hack
	// All fds (except the pipe) should be closed in order to avoid some "funny" communication lost between the mctr and PTC
	for (int i = 4; i < 128; i++) {
	  if (
	      (i != _parent_pids[0]) && (i != _parent_pids[1]) &&
	      (i != _child_pids[0]) && (i != _child_pids[1])
	      ) {
	    if (dup(i) == EBADF) {
	      loggers::get_instance().log("GeoNetworkingPort::user_start: Child dup stops at %d - _layer=%p", i, _layer);
	      break;
	    }
	  }
	} // End of 'for' statement
	// Close _child_pids[1], down channel
	close(_child_pids[1]);
	_child_pids[1] = -1;
	// Close _parent_pids[0], down channel
	close(_parent_pids[0]);
	_parent_pids[0] = -1;
	
	process_background();
	loggers::get_instance().log("GeoNetworkingPort::user_start: Child terminates");
	std::_Exit(EXIT_SUCCESS);
      } else { // Parent process
	loggers::get_instance().log("GeoNetworkingPort::user_start: Parent process is running");
	// Close _pids[0], up channel
	close(_child_pids[0]);
	_child_pids[0] = -1;
	// Close _parent_pids[1], down channel
	close(_parent_pids[1]);
	_parent_pids[1] = -1;
	unsigned char buffer[2];
	
	bool ack = false;
	while (!ack) {
	  if ((read(_parent_pids[0], buffer, 1) > 0) && (buffer[0] == 0xAA)) {
	    loggers::get_instance().log("GeoNetworkingPort::user_start: Receive ack from child");
	    ack = true;
	  }
	} // End of 'while' statement
      }
    } else {
      _child = -1;
    }*/
  } // End of user_start method
garciay's avatar
garciay committed
  void GeoNetworkingPort::user_stop()
  {
    loggers::get_instance().log(">>> GeoNetworkingPort::user_stop");
    // TODO If timer mechanism is enought, remove fork code
    /*if (_child > 0) { // Parent process
      // Terminate child process
      loggers::get_instance().log("GeoNetworkingPort::user_stop: Stopping child process");
      unsigned char buffer[] = { 0xFF };
      write(_child_pids[1], buffer, 1);
      // And wait for the child ack
      bool ack = false;
      while (!ack) {
	if ((read(_parent_pids[0], buffer, 1) > 0) && (buffer[0] == 0xAA)) {
	  loggers::get_instance().log("GeoNetworkingPort::user_stop: Receive ack from child");
	  ack = true;
	}
      } // End of 'while' statement
      // Wait child process
      int status = -1;
      waitpid(_child, &status, WNOHANG); // TODO Check returned code
      loggers::get_instance().log("GeoNetworkingPort::user_stop: Child process ended [%d]", status);
      // Close _parent_pids[1], up channel
      close(_parent_pids[0]);
      _parent_pids[0] = -1;
      // Close _pids[1], down channel
      close(_child_pids[1]);
      _child_pids[1] = -1;
      // Reset child pid
      _child = -1;
      }*/
  } // End of user_stop method
garciay's avatar
garciay committed
  void GeoNetworkingPort::outgoing_send(const GeoNetworkingReq& send_par)
  {
    loggers::get_instance().log_msg(">>> GeoNetworkingPort::outgoing_send: payload=", send_par);
    
    float duration;
    loggers::get_instance().set_start_time(_time_key);
garciay's avatar
garciay committed
    static_cast<GeoNetworkingLayer *>(_layer)->sendMsg(send_par, _layer_params);
garciay's avatar
garciay committed
    loggers::get_instance().set_stop_time(_time_key, duration);
  }
garciay's avatar
garciay committed
  void GeoNetworkingPort::receiveMsg (const LibItsGeoNetworking__TestSystem::GeoNetworkingInd& p_ind, const Params& p_params) {
    loggers::get_instance().log_msg(">>> GeoNetworkingPort::receive_msg: ", p_ind);
    // Sanity check
    if (!p_ind.is_bound()) {
      return;
    }
    // TODO If timer mechanism is enought, remove fork code
    /*if (_child == 0) { // Bacgound task processing, ignore it
      return;
    */
garciay's avatar
garciay committed

    // Update location table
    if (p_ind.msgIn().basicHeader().version() == 0) { // Non secured mode
      const LibItsGeoNetworking__TypesAndValues::GnNonSecuredPacket& p = p_ind.msgIn().gnPacket().packet();
      const LibItsGeoNetworking__TypesAndValues::HeaderTST& htst = p.commonHeader().headerTST();
      if (htst.ischosen(LibItsGeoNetworking__TypesAndValues::HeaderTST::ALT_lsHdr)) { // Location service
	const LibItsGeoNetworking__TypesAndValues::LsHeaderType& ls = htst.lsHdr();
	if (ls.headerSubType() == LibItsGeoNetworking__TypesAndValues::HeaderSubTypeLs::e__lsReply) { // Update the Test System Location Table
	  const LibItsGeoNetworking__TypesAndValues::ExtendedHeader& ex = p.extendedHeader();
	  if (ex.ischosen(LibItsGeoNetworking__TypesAndValues::ExtendedHeader::ALT_lsReplyHeader)) {
	    const LibItsGeoNetworking__TypesAndValues::LongPosVector& sopv = ex.lsReplyHeader().srcPosVector();
	    loggers::get_instance().user_msg("GeoNetworkingPort::receive_msg: Update LocationTable: ", sopv);	    
	    // TODO Add a LocationTable class to manage it
	  } // else, discard packet
	} // else, discard packet
      } // else, discard packet
    } // TODO else security mode

    // TODO Add beacon filter for StartPassBeaconing/Stop
    
garciay's avatar
garciay committed
    incoming_message(p_ind);
  }
  // TODO If timer mechanism is enought, remove fork code
  /*void GeoNetworkingPort::process_background() {
    loggers::get_instance().log(">>> GeoNetworkingPort::process_background");

    std::chrono::milliseconds expiry(1000); // Default is set to 1 second
    unsigned long long ms;
    unsigned char buffer[512];
    bool terminate = false;
    // Child process ready, send an ack (0xAA)
    buffer[0] = 0xAA;
    write(_parent_pids[1], buffer, 1);
    while (!terminate) {
      int result = read(_child_pids[0], buffer, 512);
      if (result > 0) {
	loggers::get_instance().log("GeoNetworkingPort::process_background: receive %d bytes", result);
	OCTETSTRING os(result, buffer); // TODO For debug, to be removed
	loggers::get_instance().log_to_hexa("GeoNetworkingPort::process_background: ", os);
	// Decode it
	switch (buffer[0]) {
	case 0x01:
	  {
	    std::string s((const char *)(buffer + 1), result - 1);
	    loggers::get_instance().log("GeoNetworkingPort::process_background: %s", s.c_str());
	    _layer = LayerStackBuilder::GetInstance()->createLayerStack(s.c_str());
	    static_cast<GeoNetworkingLayer *>(_layer)->addUpperPort(this);
	  }
	  break;
	case 0xFF:
	  terminate = true;
	  break;
	default:
	  // Discard it
	  break;
	} // End of 'switch' statement
	buffer[0] = 0xAA;
	write(_parent_pids[1], buffer, 1);
      }
      if (_layer != NULL) {
	static_cast<GeoNetworkingLayer *>(_layer)->send_beacon();	  
	// Timer
	ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() + expiry.count();
	loggers::get_instance().log("GeoNetworkingPort::process_background: Start timer: %ld", ms);
	while (ms > static_cast<unsigned long long>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()));
	loggers::get_instance().log("GeoNetworkingPort::process_background: After timer");
      }
    } // End of 'while' statement
    if (_layer != NULL) {
      delete _layer;
      _layer = NULL;
    }
    // Close _pids[1], up channel
    close(_child_pids[0]);
    _child_pids[0] = -1;
    // Close _parent_pids[1], down channel
    close(_parent_pids[1]);
    _parent_pids[1] = -1;
    
    loggers::get_instance().log("<<< GeoNetworkingPort::process_background");    } */// End of process_background method
  
/*void GeoNetworkingPort::timer_irq_sigalrm_handler(int sig, siginfo_t *si, void *uc) {
    loggers::get_instance().log("GeoNetworkingPort::timer_irq_sigalrm_handler: Caught signal %d\n", sig);

    static_cast<GeoNetworkingLayer *>(static_cast<GeoNetworkingPort *>(si->si_value.sival_ptr)->_layer)->send_beacon();
    }*/ // End of method timer_irq_sigalrm_handler
  
} /* end of namespace */