diff --git a/ccsrc/Framework/include/params.hh b/ccsrc/Framework/include/params.hh index bc683cfe98daed266062f38488ccb8722c3bc5e1..9dc4b61c9f62d2e5e61e6b9e9a35a62a0e9843a2 100644 --- a/ccsrc/Framework/include/params.hh +++ b/ccsrc/Framework/include/params.hh @@ -35,6 +35,10 @@ public: //! \publicsection static const std::string& nic; //! Network Interface Card parameter name + static const std::string& ip_src; //! Source IP address parameter name + static const std::string& ip_dst; //! Destination IP address parameter name + static const std::string& ip_proto; //! IP proto parameter name + static const std::string& server; //! Remote server address (e.g. www.etsi.org) static const std::string& port; //! Remote server port. Default: 80 static const std::string& use_ssl; //! Set to 1 to use SSL to communicate with the HTTP server. Default: false diff --git a/ccsrc/Framework/src/params.cc b/ccsrc/Framework/src/params.cc index a18371414d5992bb40be3c8733784f0666d323cf..bc4ebb8d166da75dcb147c8d53efd7d5cd78cfb1 100644 --- a/ccsrc/Framework/src/params.cc +++ b/ccsrc/Framework/src/params.cc @@ -28,6 +28,10 @@ const std::string& params::filter = std::string("filter"); const std::string& params::nic = std::string("nic"); +const std::string& params::ip_src = std::string("ip_src"); +const std::string& params::ip_dst = std::string("ip_dst"); +const std::string& params::ip_proto = std::string("ip_proto"); + const std::string& params::server = std::string("server"); const std::string& params::port = std::string("port"); const std::string& params::use_ssl = std::string("use_ssl"); diff --git a/ccsrc/Protocols/IP/ip_offline_layer.cc b/ccsrc/Protocols/IP/ip_offline_layer.cc new file mode 100644 index 0000000000000000000000000000000000000000..30702104f344830766148413541a706ed4f58bb0 --- /dev/null +++ b/ccsrc/Protocols/IP/ip_offline_layer.cc @@ -0,0 +1,73 @@ +#include "ip_offline_layer_factory.hh" + +#include "loggers.hh" + +ip_offline_layer::ip_offline_layer(const std::string& p_type, const std::string& p_param) : layer(p_type), _params() { + loggers::get_instance().log(">>> ip_offline_layer::ip_offline_layer: '%s', %s", to_string().c_str(), p_param.c_str()); + // Setup parameters + params::convert(_params, p_param); +} + +void ip_offline_layer::send_data(OCTETSTRING& p_data, params& p_params) { + loggers::get_instance().log_msg(">>> ip_offline_layer::send_data: ", p_data); + + //OCTETSTRING ip; + // FIXME FSCOM: To be done + loggers::get_instance().error("ip_offline_layer::send_data: Not implemented. On;ly for offline mode"); + //ip += p_data; + //send_to_all_layers(ip, static_cast<params&>(p_params)); +} + +void ip_offline_layer::receive_data(OCTETSTRING& p_data, params& p_params) { + loggers::get_instance().log_msg(">>> ip_offline_layer::receive_data: ", p_data); + + // Version + uint8_t v = static_cast<const uint8_t>(*p_data); + OCTETSTRING version = int2oct(1, v >> 4); + loggers::get_instance().log_msg("ip_offline_layer::receive_data: verion: ", version); + // Length in bytes + uint8_t length = (v & 0x0f) * 4; + loggers::get_instance().log("ip_offline_layer::receive_data: length: %d", length); + // DSF + OCTETSTRING dsf = OCTETSTRING(1, 1 + static_cast<const uint8_t *>(p_data)); + loggers::get_instance().log_msg("ip_offline_layer::receive_data: dsf: ", dsf); + // Total Length + OCTETSTRING total_length = OCTETSTRING(2, 2 + static_cast<const uint8_t*>(p_data)); + loggers::get_instance().log_msg("ip_offline_layer::receive_data: total_length: ", total_length); + // Identification + OCTETSTRING id = OCTETSTRING(2, 4 + static_cast<const uint8_t*>(p_data)); + loggers::get_instance().log_msg("ip_offline_layer::receive_data: id: ", id); + // Flags + OCTETSTRING flags = OCTETSTRING(2, 6 + static_cast<const uint8_t*>(p_data)); + loggers::get_instance().log_msg("ip_offline_layer::receive_data: id: ", flags); + // TTL + OCTETSTRING ttl = OCTETSTRING(1, 8 + static_cast<const uint8_t*>(p_data)); + loggers::get_instance().log_msg("ip_offline_layer::receive_data: ttl: ", ttl); + // Protocol + OCTETSTRING protocol = OCTETSTRING(1, 9 + static_cast<const uint8_t*>(p_data)); + loggers::get_instance().log_msg("ip_offline_layer::receive_data: protocol: ", protocol); + // checksum + OCTETSTRING checksum = OCTETSTRING(2, 10 + static_cast<const uint8_t*>(p_data)); + loggers::get_instance().log_msg("ip_offline_layer::receive_data: checksum: ", checksum); + // src + OCTETSTRING src = OCTETSTRING(4, 12 + static_cast<const uint8_t*>(p_data)); + loggers::get_instance().log_msg("ip_offline_layer::receive_data: src: ", src); + // dst + OCTETSTRING dst = OCTETSTRING(4, 16 + static_cast<const uint8_t*>(p_data)); + loggers::get_instance().log_msg("ip_offline_layer::receive_data: dst: ", dst); + + OCTETSTRING data = OCTETSTRING(p_data.lengthof() - length, length + static_cast<const uint8_t *>(p_data)); + loggers::get_instance().log_msg("ip_offline_layer::receive_data: payload for upper layer:", data); + + // Update params + CHARSTRING s = oct2str(dst); + p_params.insert(std::pair<std::string, std::string>(params::ip_dst, std::string(static_cast<const char *>(s)))); + s = oct2str(src); + p_params.insert(std::pair<std::string, std::string>(params::ip_src, std::string(static_cast<const char *>(s)))); + s = oct2str(protocol); + p_params.insert(std::pair<std::string, std::string>(params::ip_proto, std::string(static_cast<const char *>(s)))); + + receive_to_all_layers(data, static_cast<params&>(p_params)); +} + +ip_offline_layer_factory ip_offline_layer_factory::_f; diff --git a/ccsrc/Protocols/IP/ip_offline_layer.hh b/ccsrc/Protocols/IP/ip_offline_layer.hh new file mode 100644 index 0000000000000000000000000000000000000000..3b31a80e65ead80e68f0e39c78835cc775dacde8 --- /dev/null +++ b/ccsrc/Protocols/IP/ip_offline_layer.hh @@ -0,0 +1,48 @@ +/*! + * \file ip_offline_layer.hh + * \brief Header file for ITS IP protocol layer definition. + * \author ETSI TTF T041 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include "params.hh" +#include "t_layer.hh" + +class ip_offline_layer : public layer { + params _params; //! Layer parameters + +public: //! \publicsection + /*! + * \brief Specialised constructor + * Create a new instance of the ip_offline_layer class + * \param[in] p_type \todo + * \param[in] p_param \todo + */ + ip_offline_layer(const std::string& p_type, const std::string& p_param); + /*! + * \brief Default destructor + */ + virtual ~ip_offline_layer(){}; + + /*! + * \virtual + * \fn void send_data(OCTETSTRING& data, params& p_params); + * \brief Send bytes formated data to the lower layers + * \param[in] p_data The data to be sent + * \param[in] p_params Some parameters to overwrite default value of the lower layers parameters + */ + virtual void send_data(OCTETSTRING& p_data, params& p_params); + /*! + * \virtual + * \fn void receive_data(OCTETSTRING& data, params& p_params); + * \brief Receive bytes formated data from the lower layers + * \param[in] p_data The bytes formated data received + * \param[in] p_params Some lower layers parameters values when data was received + */ + virtual void receive_data(OCTETSTRING& p_data, params& p_params); +}; // End of class ip_offline_layer diff --git a/ccsrc/Protocols/IP/ip_offline_layer_factory.hh b/ccsrc/Protocols/IP/ip_offline_layer_factory.hh new file mode 100644 index 0000000000000000000000000000000000000000..9a408415b36886fb40343dcf3bc023de83629037 --- /dev/null +++ b/ccsrc/Protocols/IP/ip_offline_layer_factory.hh @@ -0,0 +1,42 @@ +/*! + * \file ip_offline_layer_factory.hh + * \brief Header file for ITS Ethernet protocol layer factory. + * \author ETSI TTF T041 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include "layer_stack_builder.hh" + +#include "ip_offline_layer.hh" + +/*! + * \class ip_offline_layer_factory + * \brief This class provides a factory class to create an ip_offline_layer class instance + */ +class ip_offline_layer_factory : public layer_factory { + static ip_offline_layer_factory _f; //! Reference to the unique instance of this class +public: //! \publicsection + /*! + * \brief Default constructor + * Create a new instance of the ip_offline_layer_factory class + * \remark The ETH layer identifier is ETH + */ + ip_offline_layer_factory() { + // register factory + layer_stack_builder::register_layer_factory("IP_OFFLINE", this); + }; + /*! + * \fn layer* create_layer(const std::string& type, const std::string& param); + * \brief Create the layers stack based on the provided layers stack description + * \param[in] p_type The provided layers stack description + * \param[in] p_params Optional parameters + * \return 0 on success, -1 otherwise + * \inline + */ + inline virtual layer *create_layer(const std::string& p_type, const std::string& p_param) { return new ip_offline_layer(p_type, p_param); }; +}; // End of class ip_offline_layer_factory diff --git a/ccsrc/Protocols/IP/module.mk b/ccsrc/Protocols/IP/module.mk new file mode 100644 index 0000000000000000000000000000000000000000..d53608b8ba96269fc58381b726346300cc7b5760 --- /dev/null +++ b/ccsrc/Protocols/IP/module.mk @@ -0,0 +1,3 @@ +sources := ip_offline_layer.cc +includes := . + diff --git a/ccsrc/Protocols/Pcap/pcap_offline_layer.cc b/ccsrc/Protocols/Pcap/pcap_offline_layer.cc index e400f53033215b6d52594aecaba5090c4a68ea67..2530f7d0f2d538dae324faecdc02d1ec6b487d3d 100644 --- a/ccsrc/Protocols/Pcap/pcap_offline_layer.cc +++ b/ccsrc/Protocols/Pcap/pcap_offline_layer.cc @@ -1,227 +1,236 @@ -#if defined(__CYGWIN__) -#define _GNU_SOURCE -#endif -#include <chrono> -#include <errno.h> -#include <fcntl.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <Port.hh> - -#include "pcap_offline_layer_factory.hh" - -#include "loggers.hh" - -#include <pcap.h> - -#ifdef __CYGWIN__ -typedef struct { - bpf_int32 tv_sec; /* seconds */ - bpf_int32 tv_usec; /* microseconds */ -} pcap_o_timeval; - -typedef struct pcap_o_pkthdr { - pcap_o_timeval ts; /* time stamp */ - bpf_u_int32 caplen; /* length of portion present */ - bpf_u_int32 len; /* length this packet (off wire) */ -} pcap_o_pkthdr; -#else -typedef struct pcap_pkthdr pcap_o_pkthdr; -typedef struct timeval pcap_o_timeval; -#endif - -pcap_offline_layer::pcap_offline_layer(const std::string& p_type, const std::string& param) - : layer(p_type), PORT(p_type.c_str()), _params(), _device(NULL), _running(FALSE), _time_key("pcap_offline_layer::Handle_Fd_Event_Readable") { - loggers::get_instance().log(">>> pcap_offline_layer::pcap_offline_layer: '%s', %s", p_type.c_str(), param.c_str()); - params::convert(_params, param); - - _o_params.insert(std::pair<std::string, std::string>(std::string("timestamp"), std::string())); - - char error_buffer[PCAP_ERRBUF_SIZE]; - params::const_iterator it; - - it = _params.find(std::string("realtime")); - _realtime = ((it != _params.end()) && !it->second.empty()); - - it = _params.find(std::string("loop")); - _loop = ((it != _params.end()) && !it->second.empty()); - - it = _params.find(std::string("file")); - if ((it != _params.end()) && !it->second.empty()) { - const std::string& file = it->second; - _device = pcap_open_offline(file.c_str(), error_buffer); - if (_device) { - - // Add user defined filter - it = _params.find(params::filter); - if ((it != _params.end()) && !it->second.empty()) { - const std::string& filter = it->second; - // Log final PCAP filter - loggers::get_instance().user("pcap_offline_layer::pcap_offline_layer: Filter: '%s'", filter.c_str()); - struct bpf_program f = {0}; - if (pcap_compile(_device, &f, filter.c_str(), 1, PCAP_NETMASK_UNKNOWN) != 0) { - loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to compile PCAP filter"); - } else { - if (pcap_setfilter(_device, &f) != 0) { - loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to set PCAP filter"); - } - } - pcap_freecode(&f); - } - - // create pipe and run thread - if (pipe2(_fd, O_NONBLOCK) == -1) { - loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to create a pipe: '%s'", ::strerror(errno)); - } - // Pass the pipe handler to the polling procedure - loggers::get_instance().log("pcap_offline_layer::pcap_offline_layer: Call handler with descriptor %d", _fd[0]); - Handler_Add_Fd_Read(_fd[0]); - // Create the offline reader thread - _thread = new std::thread(&pcap_offline_layer::run, (void *)this); - if (_thread == NULL) { - loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to start offline thread"); - } - while (_running == FALSE) { - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } - // Thread was started - loggers::get_instance().log("<<< pcap_offline_layer::pcap_offline_layer"); - } - } -} // End of ctor - -pcap_offline_layer::~pcap_offline_layer() { - loggers::get_instance().log(">>> pcap_offline_layer::~pcap_offline_layer"); - - if (_device != NULL) { - if (_thread != NULL) { - _running = FALSE; - // Wait for the working thread to terminate - _thread->join(); - loggers::get_instance().log("pcap_offline_layer::~pcap_offline_layer: Thread were stops"); - // Cleanup - delete _thread; - close(_fd[0]); - close(_fd[1]); - } - pcap_close(_device); - } -} // End of dtor - -void *pcap_offline_layer::run(void *p_this) { - pcap_offline_layer &p = *static_cast<pcap_offline_layer *>(p_this); - return p.thread(); -} - -static long timeval_diff(const pcap_o_timeval &x, const pcap_o_timeval &y) { - pcap_o_timeval z = y; - /* Perform the carry for the later subtraction by updating y. */ - if (x.tv_usec < y.tv_usec) { - int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1; - z.tv_usec -= 1000000 * nsec; - z.tv_sec += nsec; - } - if (x.tv_usec - z.tv_usec > 1000000) { - int nsec = (x.tv_usec - z.tv_usec) / 1000000; - z.tv_usec += 1000000 * nsec; - z.tv_sec -= nsec; - } - - return (x.tv_sec - z.tv_sec) * 1000 + ((x.tv_usec - z.tv_usec) / 1000); -} - -void *pcap_offline_layer::thread() { - pcap_o_pkthdr *pkt_header; - pcap_o_pkthdr lh; - const u_char * pkt_data; - uint8_t pkt_count = 0; - - // loggers::get_instance().log(">>> pcap_offline_layer::run"); - - memset(&lh, 0, sizeof(lh)); - - _running = TRUE; - - int delay = 1000; - params::const_iterator it; - it = _params.find(std::string("delay")); - if (it != _params.cend()) { - delay = std::stoi(it->second); - } - - // wait a bit before sending first packet - std::this_thread::sleep_for(std::chrono::milliseconds(delay)); - - while (_running) { // Loop while _running flag is up - // get next frame - int result = pcap_next_ex(_device, (struct pcap_pkthdr **)&pkt_header, &pkt_data); - if (result == 2) { - if (_loop) { - - } else { - _running = FALSE; - return NULL; - } - } - if (_realtime) { - // wait for next packet timestamp - if (lh.ts.tv_sec | lh.ts.tv_usec) { - long diff = timeval_diff(pkt_header->ts, lh.ts); - if (diff > 0) { - loggers::get_instance().log("<<< pcap_offline_layer::run: Wait %d msec", diff); - std::this_thread::sleep_for(std::chrono::milliseconds(diff)); - loggers::get_instance().log("<<< pcap_offline_layer::run: Wait done"); - } - } - } - while (_running && !_resume.try_lock()) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - lh = *pkt_header; -#if 0 - { - char buf[128]; - std::time_t t = pkt_header->ts.tv_sec; - std::tm * pt = std::localtime( &t ); - t = std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", pt); - std::sprintf(buf+t, ".%06ld", pkt_header->ts.tv_usec); - _o_params["timestamp"] = std::string(buf); - } -#else - _o_params["timestamp"] = std::to_string(pkt_header->ts.tv_usec); -#endif - _o_data = OCTETSTRING(pkt_header->len, pkt_data); - write(_fd[1], &pkt_count, 1); - pkt_count++; - } - - // loggers::get_instance().log("<<< pcap_offline_layer::run"); - return NULL; -} - -void pcap_offline_layer::send_data(OCTETSTRING &data, params ¶ms) { - loggers::get_instance().log("pcap_offline_layer::send_data: Offline mode, operation was skipped"); -} - -void pcap_offline_layer::receive_data(OCTETSTRING &data, params ¶ms) { - loggers::get_instance().log(">>> pcap_offline_layer::receive_data: Received %d bytes", data.lengthof()); - loggers::get_instance().log_to_hexa("Packet dump", data); - - // Pass the packet to the upper layers - receive_to_all_layers(data, params); -} - -void pcap_offline_layer::Handle_Fd_Event_Readable(int fd) { - // loggers::get_instance().log(">>> pcap_offline_layer::Handle_Fd_Event_Readable: %d", fd); - char c[2]; - float duration; - // Process the packet at this layer - loggers::get_instance().set_start_time(_time_key); - this->receive_data(_o_data, _o_params); - loggers::get_instance().set_stop_time(_time_key, duration); - read(_fd[0], &c, 1); - _resume.unlock(); -} - -pcap_offline_layer_factory pcap_offline_layer_factory::_f; +#if defined(__CYGWIN__) +#define _GNU_SOURCE +#endif +#include <chrono> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <Port.hh> + +#include "pcap_offline_layer_factory.hh" + +#include "loggers.hh" + +#include <pcap.h> + +#ifdef __CYGWIN__ +typedef struct { + bpf_int32 tv_sec; /* seconds */ + bpf_int32 tv_usec; /* microseconds */ +} pcap_o_timeval; + +typedef struct pcap_o_pkthdr { + pcap_o_timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ +} pcap_o_pkthdr; +#else +typedef struct pcap_pkthdr pcap_o_pkthdr; +typedef struct timeval pcap_o_timeval; +#endif + +pcap_offline_layer::pcap_offline_layer(const std::string& p_type, const std::string& param) + : layer(p_type), PORT(p_type.c_str()), _params(), _device(NULL), _running(FALSE), _time_key("pcap_offline_layer::Handle_Fd_Event_Readable") { + loggers::get_instance().log(">>> pcap_offline_layer::pcap_offline_layer: '%s', %s", p_type.c_str(), param.c_str()); + params::convert(_params, param); + + _o_params.insert(std::pair<std::string, std::string>(std::string("timestamp"), std::string())); + + char error_buffer[PCAP_ERRBUF_SIZE]; + params::const_iterator it; + + it = _params.find(std::string("realtime")); + _realtime = ((it != _params.end()) && !it->second.empty()); + + it = _params.find(std::string("loop")); + _loop = ((it != _params.end()) && !it->second.empty()); + + it = _params.find(std::string("file")); + if ((it != _params.end()) && !it->second.empty()) { + const std::string& file = it->second; + _device = pcap_open_offline(file.c_str(), error_buffer); + if (_device) { + + // Add user defined filter + it = _params.find(params::filter); + if ((it != _params.end()) && !it->second.empty()) { + const std::string& filter = it->second; + // Log final PCAP filter + loggers::get_instance().user("pcap_offline_layer::pcap_offline_layer: Filter: '%s'", filter.c_str()); + struct bpf_program f = {0}; + if (pcap_compile(_device, &f, filter.c_str(), 1, PCAP_NETMASK_UNKNOWN) != 0) { + loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to compile PCAP filter"); + } else { + if (pcap_setfilter(_device, &f) != 0) { + loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to set PCAP filter"); + } + } + pcap_freecode(&f); + } + + // create pipe and run thread + if (pipe2(_fd, O_NONBLOCK) == -1) { + loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to create a pipe: '%s'", ::strerror(errno)); + } + // Pass the pipe handler to the polling procedure + loggers::get_instance().log("pcap_offline_layer::pcap_offline_layer: Call handler with descriptor %d", _fd[0]); + Handler_Add_Fd_Read(_fd[0]); + // Create the offline reader thread + _thread = new std::thread(&pcap_offline_layer::run, (void *)this); + if (_thread == NULL) { + loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to start offline thread"); + } + while (_running == FALSE) { + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + // Thread was started + loggers::get_instance().log("<<< pcap_offline_layer::pcap_offline_layer"); + } else { + loggers::get_instance().error("pcap_offline_layer::pcap_offline_layer: Failed to create device: '%s'", error_buffer); + } + } +} // End of ctor + +pcap_offline_layer::~pcap_offline_layer() { + loggers::get_instance().log(">>> pcap_offline_layer::~pcap_offline_layer"); + + if (_device != NULL) { + if (_thread != NULL) { + _running = FALSE; + // Wait for the working thread to terminate + _thread->join(); + loggers::get_instance().log("pcap_offline_layer::~pcap_offline_layer: Thread were stops"); + // Cleanup + delete _thread; + close(_fd[0]); + close(_fd[1]); + } + pcap_close(_device); + } +} // End of dtor + +void *pcap_offline_layer::run(void *p_this) { + pcap_offline_layer &p = *static_cast<pcap_offline_layer *>(p_this); + return p.thread(); +} + +static long timeval_diff(const pcap_o_timeval &x, const pcap_o_timeval &y) { + pcap_o_timeval z = y; + /* Perform the carry for the later subtraction by updating y. */ + if (x.tv_usec < y.tv_usec) { + int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1; + z.tv_usec -= 1000000 * nsec; + z.tv_sec += nsec; + } + if (x.tv_usec - z.tv_usec > 1000000) { + int nsec = (x.tv_usec - z.tv_usec) / 1000000; + z.tv_usec += 1000000 * nsec; + z.tv_sec -= nsec; + } + + return (x.tv_sec - z.tv_sec) * 1000 + ((x.tv_usec - z.tv_usec) / 1000); +} + +void *pcap_offline_layer::thread() { + pcap_o_pkthdr *pkt_header; + pcap_o_pkthdr lh; + const u_char * pkt_data; + uint8_t pkt_count = 0; + + // loggers::get_instance().log(">>> pcap_offline_layer::run"); + + memset(&lh, 0, sizeof(lh)); + + _running = TRUE; + + int delay = 1000; + params::const_iterator it; + it = _params.find(std::string("delay")); + if (it != _params.cend()) { + delay = std::stoi(it->second); + } + + // wait a bit before sending first packet + std::this_thread::sleep_for(std::chrono::milliseconds(delay)); + + while (_running) { // Loop while _running flag is up + // get next frame + int result = pcap_next_ex(_device, (struct pcap_pkthdr **)&pkt_header, &pkt_data); + if (result == 2) { + if (_loop) { + + } else { + _running = FALSE; + return NULL; + } + } + if (_realtime) { + // wait for next packet timestamp + if (lh.ts.tv_sec | lh.ts.tv_usec) { + long diff = timeval_diff(pkt_header->ts, lh.ts); + if (diff > 0) { + loggers::get_instance().log("<<< pcap_offline_layer::run: Wait %d msec", diff); + std::this_thread::sleep_for(std::chrono::milliseconds(diff)); + loggers::get_instance().log("<<< pcap_offline_layer::run: Wait done"); + } + } + } + while (_running && !_resume.try_lock()) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + lh = *pkt_header; +#if 0 + { + char buf[128]; + std::time_t t = pkt_header->ts.tv_sec; + std::tm * pt = std::localtime( &t ); + t = std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", pt); + std::sprintf(buf+t, ".%06ld", pkt_header->ts.tv_usec); + _o_params["timestamp"] = std::string(buf); + } +#else + _o_params["timestamp"] = std::to_string(pkt_header->ts.tv_usec); +#endif + _o_data = OCTETSTRING(pkt_header->len, pkt_data); + write(_fd[1], &pkt_count, 1); + pkt_count++; + } + + // loggers::get_instance().log("<<< pcap_offline_layer::run"); + return NULL; +} + +void pcap_offline_layer::send_data(OCTETSTRING &data, params ¶ms) { + loggers::get_instance().log("pcap_offline_layer::send_data: Offline mode, operation was skipped"); +} + +void pcap_offline_layer::receive_data(OCTETSTRING &data, params ¶ms) { + loggers::get_instance().log(">>> pcap_offline_layer::receive_data: Received %d bytes", data.lengthof()); + + const uint8_t *p = static_cast<const uint8_t*>(data); + if ((*p == 0x00) && ((*(p + 1) == 0x00) || (*(p + 1) == 0x04))) { // Linux PCAP header to be skipped + // It's up to the user to know the protocol (IPv4/IPv6) and the source MAC address + loggers::get_instance().log_to_hexa("Skipping Linux PCAP header.", data); + data = OCTETSTRING(data.lengthof() - 16, 16 + static_cast<const uint8_t*>(data)); + } + + // Pass the packet to the upper layers + loggers::get_instance().log_to_hexa("Packet dump", data); + receive_to_all_layers(data, params); +} + +void pcap_offline_layer::Handle_Fd_Event_Readable(int fd) { + // loggers::get_instance().log(">>> pcap_offline_layer::Handle_Fd_Event_Readable: %d", fd); + char c[2]; + float duration; + // Process the packet at this layer + loggers::get_instance().set_start_time(_time_key); + this->receive_data(_o_data, _o_params); + loggers::get_instance().set_stop_time(_time_key, duration); + read(_fd[0], &c, 1); + _resume.unlock(); +} + +pcap_offline_layer_factory pcap_offline_layer_factory::_f; diff --git a/ccsrc/Protocols/Sctp/module.mk b/ccsrc/Protocols/Sctp/module.mk new file mode 100644 index 0000000000000000000000000000000000000000..a711a9f7a32ff24187d8cb9001c440474612ae70 --- /dev/null +++ b/ccsrc/Protocols/Sctp/module.mk @@ -0,0 +1,2 @@ +sources := sctp_layer.cc sctp_offline_layer.cc +includes := . diff --git a/ccsrc/Protocols/Sctp/sctp_layer.cc b/ccsrc/Protocols/Sctp/sctp_layer.cc new file mode 100644 index 0000000000000000000000000000000000000000..3b53bd33602a7dfa8419adf47da5f1a9226bc1a9 --- /dev/null +++ b/ccsrc/Protocols/Sctp/sctp_layer.cc @@ -0,0 +1,285 @@ +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <chrono> + +#include "sctp_layer_factory.hh" + +#include "loggers.hh" + +sctp_layer::sctp_layer(const std::string& p_type, const std::string& param) : layer(p_type), SSL_Socket(), PORT(p_type.c_str()), _params(), _client_id{-1}, _time_key("sctp_layer::Handle_Fd_Event_Readable"), _reconnect_on_send{false} { + loggers::get_instance().log(">>> sctp_layer::sctp_layer (1): '%s', %s", to_string().c_str(), param.c_str()); + // Setup parameters + params::convert(_params, param); + _params.log(); + + init(); } + +sctp_layer::sctp_layer(const std::string& p_type, const params & param) : layer(p_type), SSL_Socket(), PORT(p_type.c_str()), _params(), _client_id{-1}, _time_key("sctp_layer::Handle_Fd_Event_Readable"), _reconnect_on_send{false} { + loggers::get_instance().log(">>> sctp_layer::sctp_layer (2): '%s'", to_string().c_str()); + // Setup parameters + _params = param; + + init(); +} + +void sctp_layer::init() { + loggers::get_instance().log(">>> sctp_layer::init"); + + set_ip_proto(IPPROTO_SCTP); + + set_socket_debugging(false); + params::const_iterator it = _params.find(params::debug); + if (it == _params.cend()) { + _params.insert(std::pair<std::string, std::string>(std::string("debug"), "0")); + } else if (it->second.compare("1") == 0) { + set_socket_debugging(true); + } + bool server_mode = false; + it = _params.find(params::server_mode); + if (it != _params.cend()) { + server_mode = (1 == std::stoi(it->second)); + } else { + _params.insert(std::pair<std::string, std::string>(std::string("server_mode"), "0")); + } + it = _params.find(params::server); + if (it == _params.cend()) { + _params.insert(std::pair<std::string, std::string>(std::string("server"), "127.0.0.1")); // TODO Try using params::server instead of std::string("server") + } + if (!parameter_set(remote_address_name(), _params[params::server].c_str())) { + loggers::get_instance().warning("sctp_layer::set_parameter: Unprocessed parameter: 'remote_address_name()'"); + } + bool ssl_mode = false; + it = _params.find(params::use_ssl); + if (it == _params.cend()) { + _params.insert(std::pair<std::string, std::string>(std::string("use_ssl"), "0")); + } else if (it->second.compare("1") == 0) { + _params.insert(std::pair<std::string, std::string>(std::string("use_ssl"), "1")); + ssl_mode = true; + } + set_ssl_use_ssl(ssl_mode); + it = _params.find(params::port); + if (it == _params.cend()) { + if (_params[params::use_ssl].compare("0") == 0) { // Use standard SCTP port + _params.insert(std::pair<std::string, std::string>(std::string("port"), "13")); + } else { // Use standard HTTPS port + _params.insert(std::pair<std::string, std::string>(std::string("port"), "22")); + } + } + if (!parameter_set(remote_port_name(), _params[params::port].c_str())) { + loggers::get_instance().warning("sctp_layer::set_parameter: Unprocessed parameter: '%s'", params::port.c_str()); + } + it = _params.find(params::local_port); + if (it == _params.cend()) { + if (_params[params::use_ssl].compare("0") == 0) { // Use standard SCTP port + _params.insert(std::pair<std::string, std::string>(std::string("local_port"), "13")); + } else { // Use standard HTTPS local_port + _params.insert(std::pair<std::string, std::string>(std::string("local_port"), "22")); + } + } + if (!parameter_set(local_port_name(), _params[params::local_port].c_str())) { + loggers::get_instance().warning("sctp_layer::set_parameter: Unprocessed parameter: '%s'", params::local_port.c_str()); + } + + it = _params.find(params::local_server); + if (it == _params.cend()) { + _params.insert(std::pair<std::string, std::string>(std::string("local_server"), "0.0.0.0")); + } + if (!parameter_set(local_address_name(), _params[params::local_server].c_str())) { + loggers::get_instance().warning("sctp_layer::set_parameter: Unprocessed parameter: '%s'", params::local_server.c_str()); + } + + parameter_set(use_connection_ASPs_name(), (!server_mode) ? "yes" : "no"); + loggers::get_instance().warning("sctp_layer::set_parameter: Limit to one simultanneous accepted connection (server_backlog == 1)"); + parameter_set(server_backlog_name(), "1"); // Limit to one simultanneous accepted connection + loggers::get_instance().log("sctp_layer::init: server_mode=%x", server_mode); + set_server_mode(server_mode); + if (server_mode) { // Apply default values or specified ones + parameter_set(local_port_name(), _params[params::local_port].c_str()); + parameter_set(local_address_name(), _params[params::local_server].c_str()); + } + if (ssl_mode) { // Add certificate bundle + // Check mutual authentication param + _params.insert(std::pair<std::string, std::string>(std::string("mutual_tls"), "0")); + parameter_set(ssl_verifycertificate_name(), "no"); + it = _params.find(params::mutual_auth); + if (it != _params.cend()) { + if (_params[params::mutual_auth].compare("1") == 0) { // Use mutual authentication + parameter_set(ssl_verifycertificate_name(), "yes"); + _params.insert(std::pair<std::string, std::string>(std::string("mutual_tls"), "1")); + } + } + // Set trusted CA file + it = _params.find(params::trusted_ca_list); + if (it != _params.cend()) { + parameter_set(ssl_trustedCAlist_file_name(), it->second.c_str()); + } else { + // Use Let's Encrypt to generate your certificates + // https://manpages.ubuntu.com/manpages/impish/en/man1/certbot.1.html + loggers::get_instance().error("sctp_layer::set_parameter: Trusted CA list is required for TLS"); + } + // Set additional certificates + it = _params.find(params::privkey); + if (it != _params.cend()) { + parameter_set(ssl_private_key_file_name(), it->second.c_str()); + } else { + // Use Let's Encrypt to generate your certificates + // https://manpages.ubuntu.com/manpages/impish/en/man1/certbot.1.html + loggers::get_instance().error("sctp_layer::set_parameter: Certificate private key is required for TLS"); + } + it = _params.find(params::certificate); + if (it != _params.cend()) { + parameter_set(ssl_certificate_file_name(), it->second.c_str()); + } else { + // Use Let's Encrypt to generate your certificates + // https://manpages.ubuntu.com/manpages/impish/en/man1/certbot.1.html + loggers::get_instance().error("sctp_layer::set_parameter: Certificate is required for TLS"); + } + } + set_ttcn_buffer_usercontrol(false); + set_handle_half_close(true); + + map_user(); + + parameter_set(client_TCP_reconnect_name(), "yes"); + + if (server_mode == 0) { + loggers::get_instance().log("sctp_layer::init: Establish connection: '%s'/%s", _params[params::server].c_str(), _params[params::port].c_str()); + open_client_connection(_params[params::server].c_str(), _params[params::port].c_str(), NULL, NULL); + } +} + +sctp_layer::~sctp_layer() { + loggers::get_instance().log(">>> sctp_layer::~sctp_layer: %d", _client_id); + if (_client_id != -1) { + remove_client(_client_id); + } + + unmap_user(); +} + +void sctp_layer::Handle_Fd_Event(int fd, boolean is_readable, boolean is_writable, boolean is_error) +{ + loggers::get_instance().log(">>> sctp_layer::Handle_Fd_Event: %d - _client_id: %d", fd, _client_id); + Handle_Socket_Event(fd, is_readable, is_writable, is_error); + log_debug("<<< sctp_layer::Handle_Fd_Event"); +} + +void sctp_layer::Handle_Timeout(double time_since_last_call) +{ + loggers::get_instance().log(">>> sctp_layer::Handle_Timeout: %f", time_since_last_call); + Handle_Timeout_Event(time_since_last_call); + loggers::get_instance().log("<<< sctp_layer::Handle_Timeout"); +} + +void sctp_layer::send_data(OCTETSTRING& data, params& params) { + loggers::get_instance().log_msg(">>> sctp_layer::send_data: ", data); + + loggers::get_instance().log("sctp_layer::send_data: SSL mode: %x", get_ssl_use_ssl()); + loggers::get_instance().log("sctp_layer::send_data: server_mode: '%s'", _params[params::server_mode].c_str()); + loggers::get_instance().log("sctp_layer::send_data: peer_list_get_nr_of_peers: %d", peer_list_get_nr_of_peers()); + + if ((_params[params::server_mode].compare("0") == 0) && (peer_list_get_nr_of_peers() == 0)) { + // Reconnect (e.g. HTTP connection lost + loggers::get_instance().log("sctp_layer::send_data: Re-establish connection: '%s'/%s", _params[params::server].c_str(), _params[params::port].c_str()); + open_client_connection(_params[params::server].c_str(), _params[params::port].c_str(), NULL, NULL); + } + send_outgoing(static_cast<const uint8_t*>(data), data.lengthof(), _client_id); +} + +void sctp_layer::receive_data(OCTETSTRING& data, params& params) { + loggers::get_instance().log_msg(">>> sctp_layer::receive_data: ", data); + + receive_to_all_layers(data, params); +} + +void sctp_layer::message_incoming(const uint8_t* message_buffer, int length, int client_id) { + loggers::get_instance().log(">>> sctp_layer::message_incoming"); + loggers::get_instance().log_to_hexa("sctp_layer::message_incoming: ", message_buffer, length); + + float duration; + loggers::get_instance().set_start_time(_time_key); + OCTETSTRING data(length, message_buffer); + params params; + params.insert(std::pair<std::string, std::string>( + std::string("timestamp"), + std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()))); + this->receive_data(data, params); // TODO Check execution time for decoding operation + params::const_iterator it = params.find(std::string("Buffurizing")); + if (it != params.end()) { + loggers::get_instance().log("sctp_layer::message_incoming: Buffurizing requested"); + } + loggers::get_instance().set_stop_time(_time_key, duration); +} + +void sctp_layer::client_connection_opened(int p_client_id) +{ + loggers::get_instance().log(">>> sctp_layer::client_connection_opened - _client_id: %d: %d", p_client_id, _client_id); +} + +bool sctp_layer::add_user_data(int p_client_id) +{ + loggers::get_instance().log(">>> sctp_layer::add_user_data: %d - _client_id: %d", p_client_id, _client_id); + _client_id = p_client_id; + if (_params[params::use_ssl].compare("0") == 0) { + loggers::get_instance().log("sctp_layer::add_user_data: Non secured mode"); + return Abstract_Socket::add_user_data(p_client_id); + } + loggers::get_instance().log("sctp_layer::add_user_data: SSL mode"); + return SSL_Socket::add_user_data(p_client_id); +} + +int sctp_layer::send_message_on_fd(int p_client_id, const uint8_t * message_buffer, int length_of_message) +{ + loggers::get_instance().log(">>> sctp_layer::send_message_on_fd: %d", p_client_id); + + if(get_user_data(p_client_id)) { + loggers::get_instance().log("sctp_layer::send_message_on_fd: SSL mode"); + return SSL_Socket::send_message_on_fd(p_client_id, message_buffer, length_of_message); + } + + loggers::get_instance().log("sctp_layer::send_message_on_fd: Non secured mode"); + return Abstract_Socket::send_message_on_fd(p_client_id, message_buffer, length_of_message); +} + +int sctp_layer::send_message_on_nonblocking_fd(int p_client_id, const uint8_t * message_buffer, int length_of_message) +{ + loggers::get_instance().log(">>> sctp_layer::send_message_on_nonblocking_fd: %d", p_client_id); + + if(get_user_data(p_client_id)) { + loggers::get_instance().log("sctp_layer::send_message_on_nonblocking_fd: SSL mode"); + return SSL_Socket::send_message_on_nonblocking_fd(p_client_id, message_buffer, length_of_message); + } + + loggers::get_instance().log("sctp_layer::send_message_on_nonblocking_fd: Non secured mode"); + return Abstract_Socket::send_message_on_nonblocking_fd(p_client_id, message_buffer, length_of_message); +} + +int sctp_layer::receive_message_on_fd(int p_client_id) +{ + loggers::get_instance().log(">>> sctp_layer::receive_message_on_fd: %d", p_client_id); + + if(get_user_data(p_client_id)) { + // INFO: it is assumed that only SSL_Socket assigns user data to each peer + loggers::get_instance().log("sctp_layer::receive_message_on_fd: SSL mode"); + return SSL_Socket::receive_message_on_fd(p_client_id); + } + + loggers::get_instance().log("sctp_layer::receive_message_on_fd: Non secured mode"); + if (_params[std::string("sctp_fragmented")].compare("1") == 0) { + sleep(4); // FIXME When HTTP paquet is fragmented into several TCP packets, a timer is required. This is a Q&D solution + } + return Abstract_Socket::receive_message_on_fd(p_client_id); +} + +void sctp_layer::peer_disconnected(int p_client_id) +{ + loggers::get_instance().log(">>> sctp_layer::peer_disconnected: %d", p_client_id); + + Abstract_Socket::peer_disconnected(p_client_id); + _client_id = -1; +} + +sctp_layer_factory sctp_layer_factory::_f; + diff --git a/ccsrc/Protocols/Sctp/sctp_layer.hh b/ccsrc/Protocols/Sctp/sctp_layer.hh new file mode 100644 index 0000000000000000000000000000000000000000..8b91550eecb94ee5749a881b5643dbf017a766cf --- /dev/null +++ b/ccsrc/Protocols/Sctp/sctp_layer.hh @@ -0,0 +1,108 @@ +/*! + * \file sctp_layer.hh + * \brief Header file for ITS TCP socket based protocol port layer. + * \author ETSI TTF T041 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include "layer.hh" + +using namespace std; // Required for isnan() +#include "Abstract_Socket.hh" + +class PORT; //! Forward declaration of TITAN class + +/*! + * \class sctp_layer + * \brief This class provides description of ITS TCP port protocol layer + */ +class sctp_layer : public layer, public SSL_Socket, public PORT { + params _params; //! Layer parameters + int _client_id; //! Connection identifier + std::string _time_key; //! \todo + bool _reconnect_on_send; //! Set to true if connection shall be done when sending data. Otherwise, connection is established by the \see constructor + +public: //! \publicsection + //sctp_layer(): PORT("TCP") {}; + /*! + * \brief Specialised constructor + * Create a new instance of the sctp_layer class + * \param[in] p_type \todo + * \param[in] p_param \todo + */ + sctp_layer(const std::string& p_type, const std::string& p_param); + /*! + * \brief Specialised constructor + * Create a new instance of the sctp_layer class + * \param[in] p_type \todo + * \param[in] p_param \todo + */ + sctp_layer(const std::string& p_type, const params &p_param); + /*! + * \brief Default destructor + * \remark If \see _reconnect_on_send is set to false, the disconnection is done by the destructor + */ + virtual ~sctp_layer(); + + /*! + * \virtual + * \fn void send_data(OCTETSTRING& data, params& params); + * \brief Send bytes formated data to the lower layers + * \param[in] p_data The data to be sent + * \param[in] p_params Some parameters to overwrite default value of the lower layers parameters + * \virtual + */ + virtual void send_data(OCTETSTRING &data, params ¶ms); + /*! + * \virtual + * \fn void receive_data(OCTETSTRING& data, params& params); + * \brief Receive bytes formated data from the lower layers + * \param[in] p_data The bytes formated data received + * \param[in] p_params Some lower layers parameters values when data was received + */ + virtual void receive_data(OCTETSTRING &data, params &info); + + /*! + * \virtual + * \fn void message_incoming(const unsigned char* message_buffer, int length, int client_id = -1); + * \brief Receive bytes formated data from the lower layers + * \param[in] p_buffer The bytes formated data received + * \param[in] p_length The number of bytes received + * \param[in] p_client_id The connection identifier.Default: -1 + */ + virtual void message_incoming(const unsigned char *p_buffer, int p_length, int p_client_id = -1); + +protected: //! \protectedsection + void init(); + + void Add_Fd_Read_Handler(int fd) { Handler_Add_Fd_Read(fd); }; + void Add_Fd_Write_Handler(int fd) { Handler_Add_Fd_Write(fd); }; + void Remove_Fd_Read_Handler(int fd) { Handler_Remove_Fd_Read(fd); }; + void Remove_Fd_Write_Handler(int fd) { Handler_Remove_Fd_Write(fd); }; + void Remove_Fd_All_Handlers(int fd) { Handler_Remove_Fd(fd); }; + void Handler_Uninstall() { Uninstall_Handler(); } + void Timer_Set_Handler(double call_interval, boolean is_timeout = TRUE, boolean call_anyway = TRUE, boolean is_periodic = TRUE) { + Handler_Set_Timer(call_interval, is_timeout, call_anyway, is_periodic); + }; + + const char *remote_address_name() { return params::server.c_str(); }; + const char *remote_port_name() { return params::port.c_str(); }; + const char *socket_debugging_name() { return params::debug.c_str(); }; + const char *ssl_use_ssl_name() { return params::use_ssl.c_str(); }; + + void client_connection_opened(int p_client_id); + bool add_user_data(int p_client_id); + int send_message_on_fd(int p_client_id, const unsigned char *message_buffer, int length_of_message); + int send_message_on_nonblocking_fd(int client_id, const unsigned char *message_buffer, int length_of_message); + int receive_message_on_fd(int p_client_id); + void peer_disconnected(int p_client_id); + +private: //! \privatesection + void Handle_Fd_Event(int fd, boolean is_readable, boolean is_writable, boolean is_error); + void Handle_Timeout(double time_since_last_call); +}; // End of class sctp_layer diff --git a/ccsrc/Protocols/Sctp/sctp_layer_factory.hh b/ccsrc/Protocols/Sctp/sctp_layer_factory.hh new file mode 100644 index 0000000000000000000000000000000000000000..59fa0f68402f4fa8a91ed8dd895799c548c82ef6 --- /dev/null +++ b/ccsrc/Protocols/Sctp/sctp_layer_factory.hh @@ -0,0 +1,41 @@ +/*! + * \file sctp_layer_factory.hh + * \brief Header file for ITS TCP socket based protocol layer factory. + * \author ETSI TTF T010 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include "layer_stack_builder.hh" + +#include "sctp_layer.hh" + +/*! + * \class sctp_layer_factory + * \brief This class provides a factory class to create an sctp_layer class instance + */ +class sctp_layer_factory : public layer_factory { + static sctp_layer_factory _f; //! Reference to the unique instance of this class +public: //! \publicsection + /*! + * \brief Default constructor + * Create a new instance of the sctp_layer class + * \remark The TCP socket based layer identifier is TCP + */ + sctp_layer_factory() { + // Register factory + layer_stack_builder::register_layer_factory("SCTP", this); + }; + /*! + * \fn layer* create_layer(const std::string& type, const std::string& param); + * \brief Create the layers stack based on the provided layers stack description + * \param[in] p_type The provided layers stack description + * \param[in] p_params Optional parameters + * \return 0 on success, -1 otherwise + */ + inline virtual layer *create_layer(const std::string& p_type, const std::string& p_param) { return new sctp_layer(p_type, p_param); }; +}; // End of class sctp_layer_factory diff --git a/ccsrc/Protocols/Sctp/sctp_offline_layer.cc b/ccsrc/Protocols/Sctp/sctp_offline_layer.cc new file mode 100644 index 0000000000000000000000000000000000000000..c6dbccb7d22bfdf598e312093ab9751e4f3f3d7d --- /dev/null +++ b/ccsrc/Protocols/Sctp/sctp_offline_layer.cc @@ -0,0 +1,118 @@ +#include <chrono> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "sctp_offline_layer_factory.hh" + +#include "loggers.hh" + +sctp_offline_layer::sctp_offline_layer(const std::string& p_type, const std::string& param) + : layer(p_type), _params(), _time_key("sctp_offline_layer::Handle_Fd_Event_Readable") { + loggers::get_instance().log(">>> sctp_offline_layer::sctp_offline_layer: '%s', %s", p_type.c_str(), param.c_str()); + params::convert(_params, param); + + _o_params.insert(std::pair<std::string, std::string>(std::string("timestamp"), std::string())); + +} // End of ctor + +sctp_offline_layer::~sctp_offline_layer() { + loggers::get_instance().log(">>> sctp_offline_layer::~sctp_offline_layer"); +} // End of dtor + + +void sctp_offline_layer::send_data(OCTETSTRING &p_data, params &p_params) { + loggers::get_instance().log_msg(">>> sctp_offline_layer::send_data: ", p_data); + + //OCTETSTRING sctp; + // FIXME FSCOM: To be done + loggers::get_instance().error("sctp_offline_layer::send_data: Not implemented. On;ly for offline mode"); + //sctp += p_data; + //send_to_all_layers(sctp, static_cast<params&>(p_params)); +} + +void sctp_offline_layer::receive_data(OCTETSTRING &p_data, params &p_params) { + loggers::get_instance().log(">>> sctp_offline_layer::receive_data: Received %d bytes", p_data.lengthof()); + loggers::get_instance().log_to_hexa("Packet dump", p_data); + + // Source port + OCTETSTRING src_port = OCTETSTRING(2, static_cast<const uint8_t *>(p_data)); + loggers::get_instance().log_msg("sctp_offline_layer::receive_data: src_port: ", src_port); + // Dst port + OCTETSTRING dst_port = OCTETSTRING(2, 2 + static_cast<const uint8_t *>(p_data)); + loggers::get_instance().log_msg("sctp_offline_layer::receive_data: dst_port: ", dst_port); + // Verification tag + OCTETSTRING vtag = OCTETSTRING(4, 4 + static_cast<const uint8_t *>(p_data)); + loggers::get_instance().log_msg("sctp_offline_layer::receive_data: vtag: ", vtag); + // checksum + OCTETSTRING checksum = OCTETSTRING(4, 8 + static_cast<const uint8_t*>(p_data)); + loggers::get_instance().log_msg("sctp_offline_layer::receive_data: checksum: ", checksum); + // Chunk + OCTETSTRING chunk = OCTETSTRING(p_data.lengthof() - 12, 12 + static_cast<const uint8_t*>(p_data)); + loggers::get_instance().log_msg("sctp_offline_layer::receive_data: chunk: ", chunk); + + OCTETSTRING payload(0, nullptr); + process_chunk(chunk, p_params, payload); + if (payload.lengthof() == 0) { + loggers::get_instance().log("sctp_offline_layer::receive_data: SCTP chunk, skip it"); + return; + } + + // Update params + // CHARSTRING s = oct2str(dst); + // p_params.insert(std::pair<std::string, std::string>(params::ip_dst, std::string(static_cast<const char *>(s)))); + // s = oct2str(src); + // p_params.insert(std::pair<std::string, std::string>(params::ip_src, std::string(static_cast<const char *>(s)))); + // s = oct2str(protocol); + // p_params.insert(std::pair<std::string, std::string>(params::ip_proto, std::string(static_cast<const char *>(s)))); + // Pass the packet to the upper layers + receive_to_all_layers(payload, p_params); +} + +void sctp_offline_layer::process_chunk(const OCTETSTRING& p_chunk, params &p_params, OCTETSTRING& p_payload) { + loggers::get_instance().log_msg(">>> sctp_offline_layer::process_chunk: ", p_chunk); + + const uint8_t* p = static_cast<const uint8_t*>(p_chunk); // Chunk type + switch (static_cast<const uint8_t>(*p)) { + case 0x00: { // DATA chunk + p += 2; // Skip Chunk type + Chunk flag + // Chunk length + uint16_t l = (*p << 8 | *(p + 1)) & 0xffff; + loggers::get_instance().log("sctp_offline_layer::receive_data: l: %d", l); + p += 2; + + p += 4; // Skip Transmission sequence number + + // Stream identifier + OCTETSTRING stream_id = OCTETSTRING(2, p); + loggers::get_instance().log_msg("sctp_offline_layer::receive_data: stream_id: ", stream_id); + p += 2; + // Stream sequence number + OCTETSTRING stream_num = OCTETSTRING(2, p); + loggers::get_instance().log_msg("sctp_offline_layer::receive_data: stream_num: ", stream_num); + p += 2; + // Protocol + uint32_t protocol = (*p << 24 | *(p + 1) << 16 | *(p + 2) << 8 | *(p + 3)) & 0xffffffff; + loggers::get_instance().log("sctp_offline_layer::receive_data: protocol: %d", protocol); + p += 4; + loggers::get_instance().log("sctp_offline_layer::receive_data: pointer offset: %d", (uint32_t)(p - static_cast<const uint8_t*>(p_chunk))); + p_payload = OCTETSTRING(p_chunk.lengthof() - (uint32_t)(p - static_cast<const uint8_t*>(p_chunk)), p); + } + break; + case 0x01: // INIT chunk + break; + case 0x02: // INIT_ACK chunk + break; + case 0x0a: // COOKIE_ECHO chunk + break; + case 0x0b: // COOKIE_ACK chunk + break; + default: // + loggers::get_instance().warning("sctp_offline_layer::send_data: Unprocessed chunk: 0x%02x", *p); + } + + loggers::get_instance().log_msg("<<< sctp_offline_layer::process_chunk: p_payload: ", p_payload); +} + +sctp_offline_layer_factory sctp_offline_layer_factory::_f; diff --git a/ccsrc/Protocols/Sctp/sctp_offline_layer.hh b/ccsrc/Protocols/Sctp/sctp_offline_layer.hh new file mode 100644 index 0000000000000000000000000000000000000000..c78204b3865a5b6718fc3190ae436b4abce31a54 --- /dev/null +++ b/ccsrc/Protocols/Sctp/sctp_offline_layer.hh @@ -0,0 +1,76 @@ +/*! + * \file sctp_offline_layer.hh + * \brief Header file for offline Sctp layer. + * \author ETSI TTF T041 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include "params.hh" +#include "t_layer.hh" + +#include <Octetstring.hh> + +/*! + * \class sctp_offline_layer + * \brief This class provides description of offline Sctp layer protocol layer + */ +class sctp_offline_layer : public layer { + params _params; //! Layer parameters + + params _o_params; + OCTETSTRING _o_data; + + std::string _time_key; + + static void *run(void *p_this); + +public: + void *thread(void); + +public: //! \publicsection + /*! + * \brief Specialised constructor + * Create a new instance of the sctp_offline_layer class + * \param[in] p_type \todo + * \param[in] p_param \todo + */ + sctp_offline_layer(const std::string& p_type, const std::string& param); + /*! + * \brief Default destructor + */ + virtual ~sctp_offline_layer(); + + /*! + * \virtual + * \fn void send_data(OCTETSTRING& data, params& params); + * \brief Send bytes formated data to the lower layers + * \param[in] p_data The data to be sent + * \param[in] p_params Some parameters to overwrite default value of the lower layers parameters + */ + virtual void send_data(OCTETSTRING &p_data, params &p_params); + /*! + * \virtual + * \fn void receive_data(OCTETSTRING& data, params& params); + * \brief Receive bytes formated data from the lower layers + * \param[in] p_data The bytes formated data received + * \param[in] p_params Some lower layers parameters values when data was received + */ + virtual void receive_data(OCTETSTRING &p_data, params &p_params); + +private: //! \privatesection + /*! + * \fn void process_chunk(const OCTETSTRING& p_chunk, OCTETSTRING& p_payload); + * \brief Process SCTP chunk and extrat the payload if the chunck is of DATA type + * \param[in] p_data The bytes formated data received + * \param[inout] p_params Some lower layers parameters values when data was received + * \param[out] p_payload The payload if the chunck is of DATA type, unchanged otherwise + */ + void process_chunk(const OCTETSTRING& p_chunk, params &p_params, OCTETSTRING& p_payload); + + void Handle_Fd_Event_Readable(int fd); +}; diff --git a/ccsrc/Protocols/Sctp/sctp_offline_layer_factory.hh b/ccsrc/Protocols/Sctp/sctp_offline_layer_factory.hh new file mode 100644 index 0000000000000000000000000000000000000000..dda767420f816082f3b848fae4c3771ad00bbb20 --- /dev/null +++ b/ccsrc/Protocols/Sctp/sctp_offline_layer_factory.hh @@ -0,0 +1,42 @@ +/*! + * \file sctp_offline_layer_factory.hh + * \brief Header file for Sctp layer factory. + * \author ETSI TTF T041 + * \copyright ETSI Copyright Notification + * No part may be reproduced except as authorized by written permission. + * The copyright and the foregoing restriction extend to reproduction in all media. + * All rights reserved. + * \version 0.1 + */ +#pragma once + +#include "layer_stack_builder.hh" + +#include "sctp_offline_layer.hh" + +/*! + * \class sctp_offline_layer_factory + * \brief This class provides a factory class to create an sctp_offline_layer class instance + */ +class sctp_offline_layer_factory : public layer_factory { + static sctp_offline_layer_factory _f; //! Reference to the unique instance of this class +public: //! \publicsection + /*! + * \brief Default constructor + * Create a new instance of the udp_layer_factory class + * \remark The SCTP layer identifier is SCTP + */ + sctp_offline_layer_factory() { + // register factory + layer_stack_builder::register_layer_factory("SCTP_FILE", this); + }; + /*! + * \fn layer* create_layer(const std::string& type, const std::string& param); + * \brief Create the layers stack based on the provided layers stack description + * \param[in] p_type The provided layers stack description + * \param[in] p_params Optional parameters + * \return 0 on success, -1 otherwise + * \inline + */ + inline virtual layer *create_layer(const std::string& p_type, const std::string& p_param) { return new sctp_offline_layer(p_type, p_param); }; +}; // End of class sctp_offline_layer_factory