Commit 95494388 authored by garciay's avatar garciay
Browse files

Layers ongoing

parent 487062a3
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#include <vector>

#include "Params.hh"
#include "loggers.hh"

class OCTETSTRING;

@@ -23,7 +24,14 @@ class Layer {
    virtual void receiveData(const OCTETSTRING& data, const Params& info) {};

  protected:
    void toAllLayers(std::vector<Layer*>&layers, const OCTETSTRING& data, const Params& info) {};
    inline void toAllLayers(std::vector<Layer*>&layers, const OCTETSTRING& data, const Params& info) {
      //      loggers::loggers::log_msg(">>> Layer::toAllLayer: ", data);
      loggers::loggers::log(">>> Layer::toAllLayer: %d", layers.size());
      for (std::vector<Layer*>::const_iterator it = layers.cbegin(); it != layers.cend(); ++it) {
          Layer * p = *it;
          p->receiveData(data, info);
      } // End of 'for' statement
    };
    inline void toAllUpperLayers(const OCTETSTRING& data, const Params& info) { toAllLayers(upperLayers, data, info); }
    inline void toAllLowerLayers(const OCTETSTRING& data, const Params& info) { toAllLayers(upperLayers, data, info); }
    inline void receiveToAllLayers(const OCTETSTRING& data, const Params& info) { toAllLayers(upperLayers, data, info); }
+13 −0
Original line number Diff line number Diff line
@@ -13,6 +13,19 @@ void EthernetLayer::sendData(const OCTETSTRING& data, const Params& params) {
}

void EthernetLayer::receiveData(const OCTETSTRING& data, const Params& info) {
    loggers::loggers::log_msg(">>> EthernetLayer::receiveData: ", data);
    // Extract dest MAC Address
    OCTETSTRING dst = data << 6;
    loggers::loggers::log_msg("EthernetLayer::receiveData: dst: ", dst);
    // Extract source MAC Address
    OCTETSTRING src = data << 6;    
    loggers::loggers::log_msg("EthernetLayer::receiveData: src: ", src);
    // Extract ethertype
    OCTETSTRING type = data << 2;
    loggers::loggers::log_msg("EthernetLayer::receiveData: type: ", type);
    // Update params

    loggers::loggers::log_msg("<<< EthernetLayer::receiveData: ", data);   
}

class EthernetFactory: public LayerFactory {
+167 −23
Original line number Diff line number Diff line
#include "PORT.hh"
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <thread>
#include <chrono>

#include "Port.hh"

#include "PcapLayer.hh"
#include "loggers.hh"
@@ -8,22 +15,159 @@ PcapLayer::PcapLayer(const std::string & type, const std::string & param) : Pcap
  // Setup parameters
  Params::convert(_params, param);
  _params.log();
//    char error_buffer[64];
//    pcap_if_t devices = NULL;
//
//    if (pcap_findalldevs(devices, error_buffer) == -1) {
//        // Add throw exception
//    }
//
//    _pcap_h = pcap_get_selectable(_device);
  // Prepare capture processing
  char error_buffer[PCAP_ERRBUF_SIZE];
  std::map<std::string, std::string>::const_iterator it = _params.find(std::string("nic")); 
  if ((it != _params.end()) && !it->second.empty()) { // Use online capture
    // Fetch the network address and network mask
    /*bpf_u_int32 mask; // subnet mask
    bpf_u_int32 net; // ip address
    if (pcap_lookupnet(_params["nic"].c_str(), &net, &mask, error_buffer) != 0) {
      loggers::loggers::error("PcapLayer::PcapLayer: PcapLayer::PcapLayer: Failed to fetch newtork address for device %s", _params["nic"].c_str());
    }
    loggers::loggers::log("PcapLayer::PcapLayer: Device %s Network address: %d", _params["nic"].c_str(), net);*/
    // Open the device
    _device = pcap_open_live(_params["nic"].c_str(), 65536, 1, 1000, error_buffer); // TODO Replace hard coded values by PcapLayer::<constants>
    if (_device == NULL) {
      loggers::loggers::error("PcapLayer::PcapLayer: Failed to open device %s", _params["nic"].c_str());
    } // else, continue
    // Set non-blocking flag for the polling procedure
    if (pcap_setnonblock(_device, 1, error_buffer) != 0) {
      loggers::loggers::error("PcapLayer::PcapLayer: 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::loggers::error("PcapLayer::PcapLayer: Failed to get device handler");
    }
  } else {
    // Check file name
    it = _params.find(std::string("file"));
    if ((it != _params.end()) && !it->second.empty()) { // Use offline capture
      struct stat s = {0};
      if ((stat(_params["file"].c_str(), &s) != 0) || !S_ISREG(s.st_mode)) {
        loggers::loggers::error("PcapLayer::PcapLayer: Failed to acces PCAP file %s", _params["file"].c_str());
      }
      // File exist, open it
      _device = pcap_open_offline(_params["file"].c_str(), error_buffer);
      if (_device == NULL) {
        loggers::loggers::error("PcapLayer::PcapLayer: Failed to open PCAP file %s", error_buffer);	
      } // else, continue
      
    } else {
      loggers::loggers::error("PcapLayer::PcapLayer: Failed to open PCAP file %s", error_buffer);
    }
  }
  // Setup filter
  std::string filter;
  it = _params.find(std::string("filter"));
  if ((it != _params.end()) && !it->second.empty()) {
    filter = _params["filter"];
  } // else nothing to do
  loggers::loggers::log("PcapLayer::PcapLayer: Filter: %s", filter.c_str());
  if (!filter.empty()) {
    struct bpf_program f = {0};
    if (pcap_compile(_device, &f, filter.c_str(), 1, PCAP_NETMASK_UNKNOWN) != 0) {
      loggers::loggers::error("PcapLayer::PcapLayer: Failed to compile PCAP filter");
    }
    if (pcap_setfilter(_device, &f) != 0) {
      loggers::loggers::error("PcapLayer::PcapLayer: Failed to set PCAP filter");
    }
    pcap_freecode(&f);
  }
  // Pass the device file handler to the polling procedure
  if (_pcap_h != -1) {
    Handler_Add_Fd_Read(_pcap_h);
  } else {
    // Create a pipe
    if (pipe2(_fd, O_NONBLOCK) == -1) {
      loggers::loggers::error("PcapLayer::PcapLayer: Failed to create a pipe: %s", ::strerror(errno));
    }
    // Pass the pipe handler to the polling procedure
    loggers::loggers::log("PcapLayer::PcapLayer: Call handler with descriptor %d", _fd[0]);
    Handler_Add_Fd_Read(_fd[0]);
    if (pthread_create(&_thread_id, NULL, &PcapLayer::run, (void *)this) != 0) {
      loggers::loggers::error("PcapLayer::PcapLayer: Failed to compile PCAP filter");
    }
    // Start a working thread to dispatch packet to a pipe
    while (_running == FALSE) {
      std::this_thread::sleep_for(std::chrono::seconds(1));
    }
    loggers::loggers::log("<<< PcapLayer::PcapLayer");    
  }
} // End of ctor

PcapLayer::~PcapLayer() {
  loggers::loggers::log(">>> PcapLayer::~PcapLayer");
  if (_device != NULL) {
    if (_fd[0] != -1) { // TODO To be refined :-(
      _running = FALSE;
      // Wait for the working thread to terminate
      pthread_join(_thread_id, NULL);
      loggers::loggers::log("PcapLayer::~PcapLayer: Thread were stops");
      // Cleanup
      close(_fd[0]);
      close(_fd[1]);
    }
    pcap_close(_device);
  }
} // End of dtor

void * PcapLayer::run(void *p_this) {
  loggers::loggers::log(">>> PcapLayer::run: Class pointer: %p", p_this);
  PcapLayer& p = *static_cast<PcapLayer *>(p_this);
  p._running = TRUE;
  p._resume = TRUE;
  while (p._running) {
    if (p._resume == TRUE) {
      write(p._fd[1], "\n", 1);
      p._resume = FALSE;
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
  }
  loggers::loggers::log("<<< PcapLayer::run");
  return NULL;
}

void PcapLayer::sendData(const OCTETSTRING& data, const Params& params) {
  loggers::loggers::log_msg(">>> PcapLayer::sendData: ", data);
}

void PcapLayer::receiveData(const OCTETSTRING& data, const Params& info) {
void PcapLayer::receiveData(const OCTETSTRING& data, const Params& params) {
  //loggers::loggers::log(">>> PcapLayer::receiveData: Received %d bytes", data.lengthof());
  //loggers::loggers::log_to_hexa("Packet dump", data);
  // Pass the packet to the upper layers
  toAllUpperLayers(data, params);
}

void PcapLayer::Handle_Fd_Event_Readable(int fd) {
  //loggers::loggers::log(">>> PcapLayer::Handle_Fd_Event_Readable: %d", fd);
  
  struct 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::loggers::log("PcapLayer::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
      this->receiveData(OCTETSTRING(pkt_header->len, pkt_data), params);
    }
  } // else, skip the packet
  // Specific to offline mode
  if (_fd[0] != -1) { // Check if offline mode is used
    //loggers::loggers::log("PcapLayer::Handle_Fd_Event_Readable: Read pipe");
    char c[2];
    read(_fd[0], &c, 1);
    if (result == -2) { // End of file, therminate worker thread
      _running = FALSE;
    } else { // Get next packet
      loggers::loggers::log("PcapLayer::Handle_Fd_Event_Readable: pcap_next_ex failed: result=%d", result);
      _resume = TRUE;
    }
  } // else, nothing to do
}

class PcapFactory: public LayerFactory {
+18 −11
Original line number Diff line number Diff line
#pragma once

//#include <pcap.h>
#include <pthread.h>
#include <pcap/pcap.h>

#include "Layer.hh"
#include "Params.hh"
@@ -9,16 +10,22 @@ class PORT;

class PcapLayer : public PORT, public Layer {
  Params _params;
//    pcap_t *_device;
  pcap_t *_device;
  int _pcap_h;
  pthread_t _thread_id;
  bool _running;
  bool _resume;
  int _fd[2];

    virtual void Handle_Fd_Event_Readable(int fd) {};
  static void * run(void *p_this);
public:
    inline PcapLayer() : PORT("PcapLayer"), Layer(), _params(), /*_device(NULL),*/ _pcap_h(-1) {}
  inline PcapLayer() : PORT("PcapLayer"), Layer(), _params(), _device(NULL), _pcap_h(-1), _thread_id(-1), _running(FALSE), _resume(FALSE) { _fd[0] = -1; _fd[1] = -1; };
  PcapLayer(const std::string & type, const std::string & param);
    virtual ~PcapLayer() {}
  virtual ~PcapLayer();

  virtual void sendData(const OCTETSTRING& data, const Params& params);
  virtual void receiveData(const OCTETSTRING& data, const Params& info);
  
  void Handle_Fd_Event_Readable(int fd);
};