コード例 #1
0
ファイル: system.cpp プロジェクト: anrl/freeflow
// Creates a new port, adds it to the master port table, and
// returns a pointer to the new port.
Port*
create_port(Port::Type port_type, std::string const& args)
{
  // Create the port of given type with args in the master port table.
  Port* p = port_table.alloc(port_type, args);

  // Return a pointer to it.
  return p;
}
コード例 #2
0
ファイル: system.cpp プロジェクト: anrl/freeflow
namespace fp
{


Module_table     module_table;          // Flowpath module table.
Dataplane_table  dataplane_table;       // Flowpath data plane table.
Port_table       port_table;            // Flowpath port table.
Thread_pool      thread_pool(0, true);  // Flowpath thread pool.


// Creates a new port, adds it to the master port table, and
// returns a pointer to the new port.
Port*
create_port(Port::Type port_type, std::string const& args)
{
  // Create the port of given type with args in the master port table.
  Port* p = port_table.alloc(port_type, args);

  // Return a pointer to it.
  return p;
}


// Deletes the given port from the system port table.
void
delete_port(Port::Id id)
{
  if (port_table.find(id))
    port_table.dealloc(id);
}


// Creates a new data plane and returns a pointer to it. If the
// name already exists it throws an exception.
Dataplane*
create_dataplane(std::string const& name, std::string const& app)
{
  // Check if a dataplane with this name already exists.
  if (dataplane_table.find(name) != dataplane_table.end())
    throw std::string("Data plane name already exists");

  // Allocate the new data plane in the master data plane table.
  dataplane_table.insert({name, new Dataplane(name, app)});

  return dataplane_table.at(name);
}


// Deletes the given data plane from the system data plane table.
void
delete_dataplane(std::string const& name)
{
  auto dp = dataplane_table.find(name);
  if (dp != dataplane_table.end())
    dataplane_table.erase(dp);
  else
    throw std::string("Data plane name not in use");
}


// Loads the application at the given path. If it exists, throws a message.
// If the application does not exist, it creates the module and adds it to
// the module table.
void
load_application(std::string const& path)
{
  // Check if library from this path has already been loaded.
  if (module_table.find(path) != module_table.end())
    throw std::string("Application at '" + path + "' has already been loaded");

  // Register the path with the Application_library object.
  module_table.insert({path, new Application(path)});
}


// Unloads the given application. If it does not exist, throws a message.
void
unload_application(std::string const& path)
{
  auto app = module_table.find(path);
  // Check if library from this path has already been loaded.
  if (app != module_table.end())
    throw std::string("Application at '" + path + "' is not loaded.");

  // Remove the application from the module table.
  module_table.erase(app);
}


} // end namespace fp
コード例 #3
0
ファイル: system.cpp プロジェクト: anrl/freeflow
// Deletes the given port from the system port table.
void
delete_port(Port::Id id)
{
  if (port_table.find(id))
    port_table.dealloc(id);
}
コード例 #4
0
ファイル: port_tcp.cpp プロジェクト: lovejavaee/freeflow
namespace fp
{

extern Port_table port_table;


const int INIT_BUFF_SIZE = 2048;


// TCP Port constructor. Parses the TCP address and port from
// the input string given, allocates a new internal ID.
Port_tcp::Port_tcp(Port::Id id, std::string const& bind, std::string const& name)
  : Port(id, name)
{
  auto idx = bind.find(':');
  // Check length of address.
  if (idx == std::string::npos)
    throw std::string("bad address form");

  std::string addr = bind.substr(0, idx);
  std::string port = bind.substr(idx + 1, bind.length());
  // Set the address, if given. Otherwise it is set to INADDR_ANY.
  if (addr.length() > 0) {
    if (inet_pton(AF_INET, addr.c_str(), &src_addr_) < 0)
      perror("set socket address failed");
  }
  else {
    src_addr_.sin_family = AF_INET;
    src_addr_.sin_addr.s_addr = htons(INADDR_ANY);
  }

  // Check length of port arg.
  if (port.length() < 2)
    throw std::string("bad port form");

  // Set the port.
  int p = std::stoi(port, nullptr);
  src_addr_.sin_port = htons(p);

  // Create the socket.
  if ((sock_fd_ = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    perror(std::string("port[" + std::to_string(id_) + "] socket").c_str());
    throw std::string("Port_tcp::Ctor");
  }

  // Additional socket options.
  int optval = 1;
  setsockopt(sock_fd_, SOL_SOCKET, SO_REUSEADDR, (const void*)&optval,
    sizeof(int));
}


// UDP Port destructor. Releases the allocated ID.
Port_tcp::~Port_tcp()
{ }


// Read a packet from the input buffer.
Context*
Port_tcp::recv()
{
  if (config_.down)
    throw std::string("Port down");

  char buff[INIT_BUFF_SIZE];
  // Receive data.
  int bytes = read(io_fd_, buff, INIT_BUFF_SIZE);

  if (bytes < 0) {
    perror(std::string("port[" + std::to_string(id_) + "] recvfrom").c_str());
    return nullptr;
  }

  // If we receive a 0-byte packet, the dest has closed.
  // Set the port config to reflect this and return nullptr.
  if (bytes == 0) {
    config_.down = 1;
    throw std::string("Connection closed");
    return nullptr;
  }

  // Copy the buffer so that we guarantee that we don't
  // accidentally overwrite it when we have multiple
  // readers.
  //
  // TODO: We should probably have a better buffer management
  // framework so that we don't have to copy each time we
  // create a packet.
  Packet* pkt = packet_create((unsigned char*)buff, bytes, 0, nullptr, FP_BUF_ALLOC);
  // TODO: We should call functions which ask the application
  // for the maximum desired number of headers and fields
  // that can be extracted so we can produce a context
  // which takes up a minimal amount of space.
  // And probably move these to become global values instead
  // of locals to reduce function calls.
  //
  // NOTE: This should be done in the config() function? Or it could just be done
  // at link time when we are giving definitions to other unknowns.
  int max_headers = 0;
  int max_fields = 0;
  return new Context(pkt, id_, id_, 0, max_headers, max_fields);
}


// Write a packet to the output buffer.
int
Port_tcp::send()
{
  // Check that this port is usable.
  if (config_.down)
    throw("port down");
  int bytes = 0;

  // Get the next packet.
  Context* cxt = nullptr;
  while ((cxt = tx_queue_.dequeue())) {
    // Send the packet.
    int l_bytes = write(io_fd_, cxt->packet_->buf_.data_, cxt->packet_->size_);

    if (bytes < 0)
      continue;

    // TODO: What do we do if we send 0 bytes?
    if (bytes == 0)
      continue;

    // Destroy the packet data.
    packet_destroy(cxt->packet_);

    // Destroy the packet context.
    delete cxt;

    bytes += l_bytes;
  }
  // Return number of bytes sent.
  return bytes;
}


// Open the port. Creates a socket and binds it to the
// sockaddr data member.
int
Port_tcp::open()
{
  // Bind the socket to its address.
  if (::bind(sock_fd_, (struct sockaddr*)&src_addr_, sizeof(src_addr_)) < 0) {
    perror(std::string("port[" + std::to_string(id_) + "] bind").c_str());
    return -1;
  }

  // Set the socket to be non-blocking.
  int flags = fcntl(sock_fd_, F_GETFL, 0);
  fcntl(sock_fd_, F_SETFL, flags | O_NONBLOCK);

  // Put the socket into a listening state.
  listen(sock_fd_, 10);

  return 0;
}


// Close the port (socket).
void
Port_tcp::close()
{
  ::close((int)sock_fd_);
}


// TCP Port thread work function. Expects the internal port id to be passed
// as an argument, which is used to drive that port.
void*
tcp_work_fn(void* arg)
{
  // Grab a pointer to the port object you are driving.
  Port_tcp* self = (Port_tcp*)port_table.find(*((int*)arg));

  // Setup epoll.
  struct epoll_event event, event_list[10];
  struct sockaddr_in addr = self->dst_addr_;
  socklen_t slen = sizeof(addr);
  int sock_fd, conn_fd, epoll_fd, res;
  sock_fd = self->sock_fd_;

  if ((epoll_fd = epoll_create1(0)) == -1)
    perror(std::string("port[" + std::to_string(self->id()) +
      "] epoll_create").c_str());
  // Listen for input events.
  event.events = EPOLLIN | EPOLLET;
  event.data.fd = sock_fd;

  if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock_fd, &event) == -1)
    perror(std::string("port[" + std::to_string(self->id()) +
      "] epoll_ctl_add").c_str());

  // Run while the FD is valid.
  while (fcntl(sock_fd, F_GETFD) != EBADF) {
    res = epoll_wait(epoll_fd, event_list, 10, 1000);

    // Receive messages/report errors.
    if (res < 0) {
      perror(std::string("port[" + std::to_string(self->id()) +
        "]").c_str());
      continue;
    }
    else {
      for (int i = 0; i < res; i++) {
        if (event_list[i].data.fd == sock_fd) {
          // We have a new connection coming in.
          conn_fd = accept(sock_fd, (struct sockaddr*)&addr, &slen);
          if (conn_fd == -1) {
            perror(std::string("port[" + std::to_string(self->id()) +
              "]").c_str());
            continue;
          }
          else {
            // Set the socket to be non-blocking.
            int flags = fcntl(conn_fd, F_GETFL, 0);
            fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
            // Add to the epoll set.
            event.events = EPOLLIN | EPOLLET;
            event.data.fd = conn_fd;
            if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &event) == -1)
              perror(std::string("port[" + std::to_string(self->id()) +
                "]").c_str());
          }
        }
        else {
          // A message from a known client has been received. Process it.
          self->io_fd_ = event_list[i].data.fd;
          Context* cxt = self->recv();
          thread_pool.assign(new Task("pipeline", cxt));
        }
      }
    }
    // Send any packets buffered for TX.
    self->send();
  }
  return 0;
}


} // end namespace fp
コード例 #5
0
ファイル: port_tcp.cpp プロジェクト: lovejavaee/freeflow
// TCP Port thread work function. Expects the internal port id to be passed
// as an argument, which is used to drive that port.
void*
tcp_work_fn(void* arg)
{
  // Grab a pointer to the port object you are driving.
  Port_tcp* self = (Port_tcp*)port_table.find(*((int*)arg));

  // Setup epoll.
  struct epoll_event event, event_list[10];
  struct sockaddr_in addr = self->dst_addr_;
  socklen_t slen = sizeof(addr);
  int sock_fd, conn_fd, epoll_fd, res;
  sock_fd = self->sock_fd_;

  if ((epoll_fd = epoll_create1(0)) == -1)
    perror(std::string("port[" + std::to_string(self->id()) +
      "] epoll_create").c_str());
  // Listen for input events.
  event.events = EPOLLIN | EPOLLET;
  event.data.fd = sock_fd;

  if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock_fd, &event) == -1)
    perror(std::string("port[" + std::to_string(self->id()) +
      "] epoll_ctl_add").c_str());

  // Run while the FD is valid.
  while (fcntl(sock_fd, F_GETFD) != EBADF) {
    res = epoll_wait(epoll_fd, event_list, 10, 1000);

    // Receive messages/report errors.
    if (res < 0) {
      perror(std::string("port[" + std::to_string(self->id()) +
        "]").c_str());
      continue;
    }
    else {
      for (int i = 0; i < res; i++) {
        if (event_list[i].data.fd == sock_fd) {
          // We have a new connection coming in.
          conn_fd = accept(sock_fd, (struct sockaddr*)&addr, &slen);
          if (conn_fd == -1) {
            perror(std::string("port[" + std::to_string(self->id()) +
              "]").c_str());
            continue;
          }
          else {
            // Set the socket to be non-blocking.
            int flags = fcntl(conn_fd, F_GETFL, 0);
            fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
            // Add to the epoll set.
            event.events = EPOLLIN | EPOLLET;
            event.data.fd = conn_fd;
            if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &event) == -1)
              perror(std::string("port[" + std::to_string(self->id()) +
                "]").c_str());
          }
        }
        else {
          // A message from a known client has been received. Process it.
          self->io_fd_ = event_list[i].data.fd;
          Context* cxt = self->recv();
          thread_pool.assign(new Task("pipeline", cxt));
        }
      }
    }
    // Send any packets buffered for TX.
    self->send();
  }
  return 0;
}