Compare Revisions

The credentials to download the source code are:
 Username: svnusers
 Password: svnusers

Ignore whitespace Rev 3320 → Rev 3321

/branches/STF525/ccsrc/Protocols/Pcap/pcap_layer.hh
1,71 → 1,5
/*!
* \file pcap_layer.hh
* \brief Header file for ITS Pcap port layer.
* \author ETSI STF525
* \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 <thread>
#include <mutex>
#include <pcap/pcap.h>
 
#include "t_layer.hh"
#include "params.hh"
 
class PORT; //! Forward declaration of TITAN class
 
/*!
* \class pcap_layer
* \brief This class provides description of ITS PCAP port protocol layer
*/
class pcap_layer : public layer, public PORT {
params _params; //! Layer parameters
pcap_t* _device; //! Device handle
int _pcap_h; //! PCAP instance handle
std::thread* _thread; //! Thread handle, used to read PCAP file instead of NIC, used in file mode
bool _running; //! Set to true when the thread is running, used in file mode
std::mutex _resume; //! \todo
pcap_dumper_t* _sent_file; //! Write file handle to save sent packet, used in file mode
std::string _time_key; //! \todo
int _fd[2]; //! \todo
 
static void* run(void* p_this);
public:
void* thread(void);
public: //! \publicsection
/*!
* \brief Specialised constructor
* Create a new instance of the pcap_layer class
* \param[in] p_type \todo
* \param[in] p_param \todo
*/
pcap_layer(const std::string& p_type, const std::string& param);
/*!
* \brief Default destructor
*/
virtual ~pcap_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& data, params& 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& data, params& info);
void Handle_Fd_Event_Readable(int fd);
};
#if defined (__CYGWIN__)
#include "pcap_cygwin_layer.hh"
#else
#include "pcap_linux_layer.hh"
#endif
/branches/STF525/ccsrc/Protocols/Pcap/pcap_linux_layer.cc
0,0 → 1,195
#if !defined (__CYGWIN__)
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <chrono>
#include <sstream>
#include <iomanip>
 
#include <Port.hh>
 
#include "pcap_layer_factory.hh"
 
#include "loggers.hh"
 
static const char* _hexDigits = "0123456789ABCDEF";
static char * _bin2hex(char * hex, size_t hlen, const char * bin, size_t blen)
{
const unsigned char *b, *e;
char * s;
 
// sanity check
if (hlen >= 0 && hlen < blen * 2) return NULL;
 
b = (const unsigned char *)bin;
e = b + blen - 1;
s = hex + blen * 2;
if (s < hex + hlen) *s = 0;
for (; b <= e; e--){
*(--s) = _hexDigits[(*e) & 0xF];
*(--s) = _hexDigits[(*e) >> 4];
}
return hex + blen * 2;
}
 
 
pcap_layer::pcap_layer(const std::string& p_type, const std::string& param)
: layer(p_type), PORT(p_type.c_str()), _params(), _device(NULL), _pcap_h(-1),
_time_key("pcap_layer::Handle_Fd_Event_Readable")
{
char error_buffer[PCAP_ERRBUF_SIZE];
params::const_iterator it;
std::string nic;
 
loggers::get_instance().log(">>> pcap_layer::pcap_layer: %s, %s", to_string().c_str(), param.c_str());
// Setup parameters
params::convert(_params, param);
// Prepare capture processing
it = _params.find(params::nic);
if ((it == _params.end()) || it->second.empty()) { // Use online capture
loggers::get_instance().error("pcap_layer::pcap_layer: NIC name must be specified");
return;
}
 
nic = _params[params::nic];
{
bpf_u_int32 net, mask; // ip address and subnet mask
if (pcap_lookupnet(nic.c_str(), &net, &mask, error_buffer) != 0) {
loggers::get_instance().error("pcap_layer::pcap_layer: Failed to fetch newtork address for device %s", nic.c_str());
}else{
loggers::get_instance().log("pcap_layer::pcap_layer: Device %s Network address: %d", nic.c_str(), net);
}
}
// Open the device
_device = pcap_open_live(nic.c_str(), 65536, 1, 100, error_buffer); // TODO Replace hard coded values by pcap_layer::<constants>
if (_device == NULL) {
loggers::get_instance().error("pcap_layer::pcap_layer: Failed to open device %s", nic.c_str());
return;
} // else, continue
// Set non-blocking flag for the polling procedure
if (pcap_setnonblock(_device, 1, error_buffer) != 0) {
loggers::get_instance().error("pcap_layer::pcap_layer: Failed to set blocking mode: %s", error_buffer);
}
// Retrieve the device file handler
_pcap_h = pcap_get_selectable_fd(_device);
if (_pcap_h == -1) {
loggers::get_instance().error("pcap_layer::pcap_layer: Failed to get device handler");
}
 
// Setup filter
std::string filter = "";
std::string mac_src;
it = _params.find(params::mac_src);
if (it != _params.end()) { // Use online capture
mac_src = it->second;
}else{
// detect MAC address of NIC
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
nic.copy(ifr.ifr_name, sizeof(ifr.ifr_name));
if (ioctl(_pcap_h, SIOCGIFHWADDR, &ifr) == -1) {
loggers::get_instance().error("pcap_layer::pcap_layer: Failed to get device MAC address");
}else{
char buf[13];
*_bin2hex(buf, sizeof(buf), ifr.ifr_hwaddr.sa_data, 6) = 0;
mac_src = buf;
loggers::get_instance().user("pcap_layer::pcap_layer: local MAC is %s", mac_src.c_str());
}
}
 
// Accept ITS broadcasted messages
std::string mac_bc;
it = _params.find(params::mac_bc);
if (it != _params.end() && !it->second.empty())
mac_bc = it->second;
else
mac_bc = "ffffffffffff";
 
if(mac_bc == mac_src || mac_src.empty())
filter = "ether dst " + mac_bc;
else
filter = "( ether dst " + mac_bc + " or ether dst " + mac_src + " )";
 
if(! mac_src.empty())
// Reject ITS messages sent by this component
filter += " and not ether src " + mac_src;
 
// Add user defined filter
it = _params.find(std::string("filter"));
if ((it != _params.end()) && !it->second.empty()) {
filter += std::string(" ") + it->second;
}
// Log final PCAP filter
loggers::get_instance().user("pcap_layer::pcap_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_layer::pcap_layer: Failed to compile PCAP filter");
}else{
if (pcap_setfilter(_device, &f) != 0) {
loggers::get_instance().error("pcap_layer::pcap_layer: Failed to set PCAP filter");
}
}
pcap_freecode(&f);
}
 
// Pass the device file handler to the polling procedure
Handler_Add_Fd_Read(_pcap_h);
} // End of ctor
 
pcap_layer::~pcap_layer() {
loggers::get_instance().log(">>> pcap_layer::~pcap_layer");
 
if (_device != NULL) {
pcap_close(_device);
}
} // End of dtor
 
 
void pcap_layer::send_data(OCTETSTRING& data, params& params) {
loggers::get_instance().log_msg(">>> pcap_layer::send_data: ", data);
 
if (pcap_sendpacket(_device, static_cast<const unsigned char *>(data), data.lengthof()) == -1) {
loggers::get_instance().error("pcap_layer::send_data: Failed to send packet: %s", pcap_geterr(_device));
}
}
 
void pcap_layer::receive_data(OCTETSTRING& data, params& params) {
loggers::get_instance().log(">>> pcap_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_layer::Handle_Fd_Event_Readable(int fd) {
//loggers::get_instance().log(">>> pcap_layer::Handle_Fd_Event_Readable: %d", fd);
 
pcap_pkthdr *pkt_header;
const u_char *pkt_data;
int result = pcap_next_ex(_device, &pkt_header, &pkt_data);
if (result == 1) { // Succeed
if (pkt_header->caplen > 14) { // Reject too small packet
//loggers::get_instance().log("pcap_layer::Handle_Fd_Event_Readable: %.6d - %d", pkt_header->ts.tv_usec, pkt_header->len);
// Fill parameters from PCAP layer
params params;
params.insert(std::pair<std::string, std::string>(std::string("timestamp"), std::to_string(pkt_header->ts.tv_usec)));
// Process the packet at this layer
OCTETSTRING os(pkt_header->caplen, pkt_data);
//loggers::get_instance().log_to_hexa("pcap_layer::Handle_Fd_Event_Readable: ", os);
// TODO Case of caplen != len !!!
float duration;
loggers::get_instance().set_start_time(_time_key);
this->receive_data(os, params); // TODO Check execution time for decoding operation
loggers::get_instance().set_stop_time(_time_key, duration);
}
} // else, skip the packet
}
 
pcap_layer_factory pcap_layer_factory::_f;
 
#endif // !CYGWIN
Property changes:
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+URL Id
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: ccsrc/Protocols/Pcap/pcap_linux_layer.hh
===================================================================
--- ccsrc/Protocols/Pcap/pcap_linux_layer.hh (nonexistent)
+++ ccsrc/Protocols/Pcap/pcap_linux_layer.hh (revision 3321)
@@ -0,0 +1,62 @@
+/*!
+ * \file pcap_layer.hh
+ * \brief Header file for ITS Pcap port layer.
+ * \author ETSI STF525
+ * \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 <pcap/pcap.h>
+
+#include "t_layer.hh"
+#include "params.hh"
+
+class PORT; //! Forward declaration of TITAN class
+
+/*!
+ * \class pcap_layer
+ * \brief This class provides description of ITS PCAP port protocol layer
+ */
+class pcap_layer : public layer, public PORT {
+ params _params; //! Layer parameters
+ pcap_t* _device; //! Device handle
+ int _pcap_h; //! PCAP instance handle
+ pcap_dumper_t* _sent_file; //! Write file handle to save sent packet, used in file mode
+ std::string _time_key; //! \todo
+
+public: //! \publicsection
+ /*!
+ * \brief Specialised constructor
+ * Create a new instance of the pcap_layer class
+ * \param[in] p_type \todo
+ * \param[in] p_param \todo
+ */
+ pcap_layer(const std::string& p_type, const std::string& param);
+ /*!
+ * \brief Default destructor
+ */
+ virtual ~pcap_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& data, params& 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& data, params& info);
+
+ void Handle_Fd_Event_Readable(int fd);
+};
/ccsrc/Protocols/Pcap/pcap_linux_layer.hh
Property changes:
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+URL Id
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property