<commit_before>#include "n3rvservice.hpp"
#include <thread>

namespace n3rv {

  service::service(std::string name,
                   std::string service_class,
                   std::string controller_host,
                   int controller_port) {

        this->poll_timeout = 1000;

        this->ll = new logger(LOGLV_NORM);
        this->zctx = zmq::context_t(1);
        this->name = name;
        this->service_class = service_class;
        this->controller_host = controller_host;
        this->controller_port = controller_port;

        // Controller has 2 I/O channels: 1 for req/resp and one for multicast
        // (the later mostly for directory updates). Therefore, each service must
        // connect to the 2 of them.
        this->connections[CTLR_CH1].socket = new zmq::socket_t(this->zctx,ZMQ_REQ);
        this->connections[CTLR_CH2].socket = new zmq::socket_t(this->zctx,ZMQ_SUB);

        // Connects to controller on both channels.
        std::stringstream ss;
        ss << "tcp://" << controller_host << ":" << controller_port;

        this->ll->log(LOGLV_NORM, "Connecting to " + controller_host + " controller.." );
        this->connections[CTLR_CH1].socket->connect(ss.str().c_str());

        ss.str(std::string());
        ss.clear();

        ss << "tcp://" << controller_host << ":" << (controller_port + 1);
        this->connections[CTLR_CH2].socket->connect(ss.str().c_str());
        this->connections[CTLR_CH2].socket->setsockopt(ZMQ_SUBSCRIBE,"",0);

        // Attaches controller's channel 2 to directory updater callback.
        this->attach(CTLR_CH2,this->directory_update);

  }

  int service::connect(std::string name, int connection_type) {

    this->ll->log(LOGLV_NORM,"connecting to " + name);

    if (this->directory.find(name) != this->directory.end()) {

      n3rv::qserv s = this->directory[name];
      this->connections[name].socket = new zmq::socket_t(this->zctx, connection_type );
      std::stringstream ep;
      ep << "tcp://" << s.ip << ":" << s.port;
      this->connections[name].socket->connect(ep.str().c_str());

      //Adds sockopt if zmq socket type is ZMQ_SUB
      if (connection_type == ZMQ_SUB) {
        this->connections[name].socket->setsockopt(ZMQ_SUBSCRIBE,"",0);
      }

    }

    else {
      this->ll->log(LOGLV_WARN,"peer not found in directory, deferring connection..");
      n3rv::qdef cqd;
      cqd.name = name;
      cqd.socket_type = connection_type;
      this->deferred.emplace_back(cqd);
    }

  }

  int service::bind(std::string bind_name, std::string endpoint, int bind_type ) {
    this->connections[bind_name].socket = new zmq::socket_t(this->zctx, bind_type);
    this->connections[bind_name].socket->bind(endpoint.c_str());
  }

  int service::bind(std::string bind_name, std::string ip, int port , int bind_type ) {

    this->connections[bind_name].socket = new zmq::socket_t(this->zctx, bind_type);

    //Port Autobinding (if 0)
    if (port == 0) {

      srand(time(nullptr));
      port = rand() % 50000 + 10000;

      try {
        std::stringstream ep;
        ep << "tcp://" << ip << ":" << port;
        this->connections[bind_name].socket->bind(ep.str().c_str());
      }

      catch(const zmq::error_t& e) {
        return this->bind(bind_name,ip,0,bind_type);
      }

    }

    else {
      std::stringstream ep;
      ep << "tcp://" << ip << ":" << port;
      this->connections[bind_name].socket->bind(ep.str().c_str());
    }

    this->subscribe(bind_name, this->service_class, port);

  }

  service::~service() {

  }

  int service::initialize() {

  }

  void service::map_callbacks() {

  }

  zmq::pollitem_t* service::refresh_pollitems() {

    this->last_nconn = this->connections.size();
    this->last_connlist.clear();

    zmq::pollitem_t* items  = (zmq::pollitem_t*) malloc(sizeof(zmq::pollitem_t) * this->last_nconn );

    int i = 0;
    for(std::map<std::string, n3rv::qconn>::iterator iter = this->connections.begin();
        iter != this->connections.end();
        ++iter) {

      if (i >= last_nconn - 1 ) break;

      std::string k = iter->first;
      zmq::socket_t* s = iter->second.socket;

      if (k == CTLR_CH1) continue;

      this->last_connlist.emplace_back(k);

      //JEEEZZZZZ, that sucks !
      items[i].socket = static_cast<void*> (*s);
      items[i].fd = 0;
      items[i].events = ZMQ_POLLIN;
      items[i].revents = 0;
      i++;

    }

    return items;

  }

  int service::run() {

    zmq::message_t message;

    /** Main service loop, listens to open connections and forwards
     * the data to the correct handler.
     */
    while(1) {

      zmq::pollitem_t* items = this->refresh_pollitems();
      try {
        zmq::poll (items,this->last_connlist.size(), this->poll_timeout);
      }
      catch(const zmq::error_t& e) {}

       for (int j=0;j < this->last_connlist.size(); j++) {

         if (items[j].revents & ZMQ_POLLIN) {

            this->connections[this->last_connlist[j]].socket->recv(&message);

            if ( this->chmap.find(this->last_connlist[j]) != this->chmap.end() ) {
              (*this->chmap[this->last_connlist[j]])(this, &message);
            }
         }
       }

       this->hkloop();
    }

  }

  std::thread* service::run_async() {

    std::thread* t = new std::thread([this]() {  this->run(); });
    t->detach();
    return t;

  }

  int service::terminate() {

      for (auto n3sock: this->connections) {

        try {
          n3sock.second.socket->close();
        }
        catch (const zmq::error_t& e) {}
      }
      //this->zctx.destroy();
  }

  void service::hkloop() {

  }

  int service::attach(std::string connection_name, fctptr callback) {
    this->chmap[connection_name]  = callback;
  }

  int service::attach(std::string connection_name, std::string callback_name) {
    this->chmap[connection_name] = this->cbmap[callback_name];
  }

  int service::fetch_topology() {

      n3rv::message m;
      m.action = "topology";
      m.payload = "";
      this->send(CTLR_CH1,m,0);

      //fetches response
      zmq::message_t r1;
      this->connections[CTLR_CH1].socket->recv(&r1);

      char * rawmsg = (char*) calloc(r1.size()+1, sizeof(char)   );
      memcpy(rawmsg, r1.data(), r1.size() );
      std::string topo_resp = rawmsg;
      std::cout << topo_resp << std::endl;

      if (topo_resp != "ERR: NO TOPOLOGY") {
        topology* t = topology::parse(topo_resp);
        this->load_topology(t);
      }
      return 0;
  }

  int service::load_topology(std::string path) {
    topology* t = topology::load(path);
    this->load_topology(t);
  }

  int service::load_topology(topology* t) {

    std::map<std::string, int> zmq_sockmap;

    zmq_sockmap["ZMQ_PUB"] = ZMQ_PUB;
    zmq_sockmap["ZMQ_SUB"] = ZMQ_SUB;
    zmq_sockmap["ZMQ_REQ"] = ZMQ_REQ;
    zmq_sockmap["ZMQ_REP"] = ZMQ_REP;
    zmq_sockmap["ZMQ_XPUB"] = ZMQ_XPUB;
    zmq_sockmap["ZMQ_XSUB"] = ZMQ_XSUB;
    zmq_sockmap["ZMQ_XREQ"] = ZMQ_XREQ;
    zmq_sockmap["ZMQ_XREP"] = ZMQ_XREP;
    zmq_sockmap["ZMQ_PULL"] = ZMQ_PULL;
    zmq_sockmap["ZMQ_PUSH"] = ZMQ_PUSH;
    zmq_sockmap["ZMQ_DEALER"] = ZMQ_DEALER;
    zmq_sockmap["ZMQ_ROUTER"] = ZMQ_ROUTER;
    zmq_sockmap["ZMQ_PAIR"] = ZMQ_PAIR;

    for (auto& nmap : t->nodes) {

      auto& key = nmap.first;
      auto& n = nmap.second;

      if ( key == this->service_class  ) {

        for (auto& b: n.bindings) {
          this->bind(this->name + "." + b.name, "0.0.0.0", b.port, zmq_sockmap[b.type] );
        }

        for (auto& c: n.connections) {
          this->connect(c.name, zmq_sockmap[c.type]);
        }

        for (auto& cb: n.callbacks) {
          this->attach(cb.connection_name, cb.callback_name);
        }
        break;
      }
    }
  }

  int service::subscribe(std::string name, std::string sclass, int port) {

      n3rv::message m;

      m.sender = name;
      m.action = "subscribe";
      m.args.emplace_back(sclass);

      std::stringstream ss;
      ss << port;

      m.args.emplace_back(ss.str());
      m.payload = "";

      std::string to_send = serialize_msg(m);

      zmq::message_t req (to_send.size());
      memcpy (req.data(), to_send.data() , to_send.size());

      this->connections[CTLR_CH1].socket->send(req);

      //Waits for response
      zmq::message_t r1;
      this->connections[CTLR_CH1].socket->recv(&r1);
      return 0;

  }

  n3rv::qconn& service::get_connection(std::string connection_name) {
     return this->connections[connection_name];
  }

  int service::send(std::string connection_name, std::string& data, int flags = 0) {

    zmq::message_t msg(data.size());
    memcpy(msg.data(), data.data(), data.size());
    this->connections[connection_name].socket->send(msg);

    return 0;

  }

  int service::send(std::string connection_name, void* data, size_t size, int flags = 0) {

    zmq::message_t msg(size);
    memcpy(msg.data(), data, size);
    this->connections[connection_name].socket->send(msg);

    return 0;

  }

  int service::send(std::string connection_name, message& msg, int flags=0) {
    if (msg.sender == "") msg.sender = this->name;
    std::string msg_ser = serialize_msg(msg);
    return this->send(connection_name,msg_ser, flags);
  }

  int service::send(std::string connection_name, zmq::message_t* zmsg, int flags =0) {
    this->connections[connection_name].socket->send(*zmsg);
  }

  int service::check_deferred() {

    this->ll->log(n3rv::LOGLV_XDEBUG,"checking deferred list..");
    std::vector<n3rv::qdef> deferred_iter(this->deferred);

    int res = 0;
    for (auto def: deferred_iter) {
      if (this->directory.find(def.name) != this->directory.end()) {

        this->ll->log(n3rv::LOGLV_NORM,"reconnecting to " + def.name);
        this->connect(def.name, def.socket_type);
        this->deferred.erase(this->deferred.begin() + res);

        res++;
      }
    }
    return res;
  }

  void* service::directory_update(void* objref, zmq::message_t* dirmsg) {

    service* self = (service*) objref;

    self->ll->log(LOGLV_DEBUG,"updating Directory..");
    std::string dirstring((char*) dirmsg->data(), dirmsg->size());
    self->directory = parse_directory(dirstring);
    self->check_deferred();

  }

  void service::set_poll_timeout(int poll_timeout) {
    this->poll_timeout = poll_timeout;
  }

}<commit_msg>directory parsing: use of static_cast instead of C cast (more proper)<commit_after>#include "n3rvservice.hpp"
#include <thread>

namespace n3rv {

  service::service(std::string name,
                   std::string service_class,
                   std::string controller_host,
                   int controller_port) {

        this->poll_timeout = 1000;

        this->ll = new logger(LOGLV_NORM);
        this->zctx = zmq::context_t(1);
        this->name = name;
        this->service_class = service_class;
        this->controller_host = controller_host;
        this->controller_port = controller_port;

        // Controller has 2 I/O channels: 1 for req/resp and one for multicast
        // (the later mostly for directory updates). Therefore, each service must
        // connect to the 2 of them.
        this->connections[CTLR_CH1].socket = new zmq::socket_t(this->zctx,ZMQ_REQ);
        this->connections[CTLR_CH2].socket = new zmq::socket_t(this->zctx,ZMQ_SUB);

        // Connects to controller on both channels.
        std::stringstream ss;
        ss << "tcp://" << controller_host << ":" << controller_port;

        this->ll->log(LOGLV_NORM, "Connecting to " + controller_host + " controller.." );
        this->connections[CTLR_CH1].socket->connect(ss.str().c_str());

        ss.str(std::string());
        ss.clear();

        ss << "tcp://" << controller_host << ":" << (controller_port + 1);
        this->connections[CTLR_CH2].socket->connect(ss.str().c_str());
        this->connections[CTLR_CH2].socket->setsockopt(ZMQ_SUBSCRIBE,"",0);

        // Attaches controller's channel 2 to directory updater callback.
        this->attach(CTLR_CH2,this->directory_update);

  }

  int service::connect(std::string name, int connection_type) {

    this->ll->log(LOGLV_NORM,"connecting to " + name);

    if (this->directory.find(name) != this->directory.end()) {

      n3rv::qserv s = this->directory[name];
      this->connections[name].socket = new zmq::socket_t(this->zctx, connection_type );
      std::stringstream ep;
      ep << "tcp://" << s.ip << ":" << s.port;
      this->connections[name].socket->connect(ep.str().c_str());

      //Adds sockopt if zmq socket type is ZMQ_SUB
      if (connection_type == ZMQ_SUB) {
        this->connections[name].socket->setsockopt(ZMQ_SUBSCRIBE,"",0);
      }

    }

    else {
      this->ll->log(LOGLV_WARN,"peer not found in directory, deferring connection..");
      n3rv::qdef cqd;
      cqd.name = name;
      cqd.socket_type = connection_type;
      this->deferred.emplace_back(cqd);
    }

  }

  int service::bind(std::string bind_name, std::string endpoint, int bind_type ) {
    this->connections[bind_name].socket = new zmq::socket_t(this->zctx, bind_type);
    this->connections[bind_name].socket->bind(endpoint.c_str());
  }

  int service::bind(std::string bind_name, std::string ip, int port , int bind_type ) {

    this->connections[bind_name].socket = new zmq::socket_t(this->zctx, bind_type);

    //Port Autobinding (if 0)
    if (port == 0) {

      srand(time(nullptr));
      port = rand() % 50000 + 10000;

      try {
        std::stringstream ep;
        ep << "tcp://" << ip << ":" << port;
        this->connections[bind_name].socket->bind(ep.str().c_str());
      }

      catch(const zmq::error_t& e) {
        return this->bind(bind_name,ip,0,bind_type);
      }

    }

    else {
      std::stringstream ep;
      ep << "tcp://" << ip << ":" << port;
      this->connections[bind_name].socket->bind(ep.str().c_str());
    }

    this->subscribe(bind_name, this->service_class, port);

  }

  service::~service() {

  }

  int service::initialize() {

  }

  void service::map_callbacks() {

  }

  zmq::pollitem_t* service::refresh_pollitems() {

    this->last_nconn = this->connections.size();
    this->last_connlist.clear();

    zmq::pollitem_t* items  = (zmq::pollitem_t*) malloc(sizeof(zmq::pollitem_t) * this->last_nconn );

    int i = 0;
    for(std::map<std::string, n3rv::qconn>::iterator iter = this->connections.begin();
        iter != this->connections.end();
        ++iter) {

      if (i >= last_nconn - 1 ) break;

      std::string k = iter->first;
      zmq::socket_t* s = iter->second.socket;

      if (k == CTLR_CH1) continue;

      this->last_connlist.emplace_back(k);

      //JEEEZZZZZ, that sucks !
      items[i].socket = static_cast<void*> (*s);
      items[i].fd = 0;
      items[i].events = ZMQ_POLLIN;
      items[i].revents = 0;
      i++;

    }

    return items;

  }

  int service::run() {

    zmq::message_t message;

    /** Main service loop, listens to open connections and forwards
     * the data to the correct handler.
     */
    while(1) {

      zmq::pollitem_t* items = this->refresh_pollitems();
      try {
        zmq::poll (items,this->last_connlist.size(), this->poll_timeout);
      }
      catch(const zmq::error_t& e) {}

       for (int j=0;j < this->last_connlist.size(); j++) {

         if (items[j].revents & ZMQ_POLLIN) {

            this->connections[this->last_connlist[j]].socket->recv(&message);

            if ( this->chmap.find(this->last_connlist[j]) != this->chmap.end() ) {
              (*this->chmap[this->last_connlist[j]])(this, &message);
            }
         }
       }

       this->hkloop();
    }

  }

  std::thread* service::run_async() {

    std::thread* t = new std::thread([this]() {  this->run(); });
    t->detach();
    return t;

  }

  int service::terminate() {

      for (auto n3sock: this->connections) {

        try {
          n3sock.second.socket->close();
        }
        catch (const zmq::error_t& e) {}
      }
      //this->zctx.destroy();
  }

  void service::hkloop() {

  }

  int service::attach(std::string connection_name, fctptr callback) {
    this->chmap[connection_name]  = callback;
  }

  int service::attach(std::string connection_name, std::string callback_name) {
    this->chmap[connection_name] = this->cbmap[callback_name];
  }

  int service::fetch_topology() {

      n3rv::message m;
      m.action = "topology";
      m.payload = "";
      this->send(CTLR_CH1,m,0);

      //fetches response
      zmq::message_t r1;
      this->connections[CTLR_CH1].socket->recv(&r1);

      char * rawmsg = (char*) calloc(r1.size()+1, sizeof(char)   );
      memcpy(rawmsg, r1.data(), r1.size() );
      std::string topo_resp = rawmsg;
      std::cout << topo_resp << std::endl;

      if (topo_resp != "ERR: NO TOPOLOGY") {
        topology* t = topology::parse(topo_resp);
        this->load_topology(t);
      }
      return 0;
  }

  int service::load_topology(std::string path) {
    topology* t = topology::load(path);
    this->load_topology(t);
  }

  int service::load_topology(topology* t) {

    std::map<std::string, int> zmq_sockmap;

    zmq_sockmap["ZMQ_PUB"] = ZMQ_PUB;
    zmq_sockmap["ZMQ_SUB"] = ZMQ_SUB;
    zmq_sockmap["ZMQ_REQ"] = ZMQ_REQ;
    zmq_sockmap["ZMQ_REP"] = ZMQ_REP;
    zmq_sockmap["ZMQ_XPUB"] = ZMQ_XPUB;
    zmq_sockmap["ZMQ_XSUB"] = ZMQ_XSUB;
    zmq_sockmap["ZMQ_XREQ"] = ZMQ_XREQ;
    zmq_sockmap["ZMQ_XREP"] = ZMQ_XREP;
    zmq_sockmap["ZMQ_PULL"] = ZMQ_PULL;
    zmq_sockmap["ZMQ_PUSH"] = ZMQ_PUSH;
    zmq_sockmap["ZMQ_DEALER"] = ZMQ_DEALER;
    zmq_sockmap["ZMQ_ROUTER"] = ZMQ_ROUTER;
    zmq_sockmap["ZMQ_PAIR"] = ZMQ_PAIR;

    for (auto& nmap : t->nodes) {

      auto& key = nmap.first;
      auto& n = nmap.second;

      if ( key == this->service_class  ) {

        for (auto& b: n.bindings) {
          this->bind(this->name + "." + b.name, "0.0.0.0", b.port, zmq_sockmap[b.type] );
        }

        for (auto& c: n.connections) {
          this->connect(c.name, zmq_sockmap[c.type]);
        }

        for (auto& cb: n.callbacks) {
          this->attach(cb.connection_name, cb.callback_name);
        }
        break;
      }
    }
  }

  int service::subscribe(std::string name, std::string sclass, int port) {

      n3rv::message m;

      m.sender = name;
      m.action = "subscribe";
      m.args.emplace_back(sclass);

      std::stringstream ss;
      ss << port;

      m.args.emplace_back(ss.str());
      m.payload = "";

      std::string to_send = serialize_msg(m);

      zmq::message_t req (to_send.size());
      memcpy (req.data(), to_send.data() , to_send.size());

      this->connections[CTLR_CH1].socket->send(req);

      //Waits for response
      zmq::message_t r1;
      this->connections[CTLR_CH1].socket->recv(&r1);
      return 0;

  }

  n3rv::qconn& service::get_connection(std::string connection_name) {
     return this->connections[connection_name];
  }

  int service::send(std::string connection_name, std::string& data, int flags = 0) {

    zmq::message_t msg(data.size());
    memcpy(msg.data(), data.data(), data.size());
    this->connections[connection_name].socket->send(msg);

    return 0;

  }

  int service::send(std::string connection_name, void* data, size_t size, int flags = 0) {

    zmq::message_t msg(size);
    memcpy(msg.data(), data, size);
    this->connections[connection_name].socket->send(msg);

    return 0;

  }

  int service::send(std::string connection_name, message& msg, int flags=0) {
    if (msg.sender == "") msg.sender = this->name;
    std::string msg_ser = serialize_msg(msg);
    return this->send(connection_name,msg_ser, flags);
  }

  int service::send(std::string connection_name, zmq::message_t* zmsg, int flags =0) {
    this->connections[connection_name].socket->send(*zmsg);
  }

  int service::check_deferred() {

    this->ll->log(n3rv::LOGLV_XDEBUG,"checking deferred list..");
    std::vector<n3rv::qdef> deferred_iter(this->deferred);

    int res = 0;
    for (auto def: deferred_iter) {
      if (this->directory.find(def.name) != this->directory.end()) {

        this->ll->log(n3rv::LOGLV_NORM,"reconnecting to " + def.name);
        this->connect(def.name, def.socket_type);
        this->deferred.erase(this->deferred.begin() + res);

        res++;
      }
    }
    return res;
  }

  void* service::directory_update(void* objref, zmq::message_t* dirmsg) {

    service* self = (service*) objref;

    self->ll->log(LOGLV_DEBUG,"updating Directory..");
    std::string dirstring(static_cast<char*>(dirmsg->data()), dirmsg->size());
    self->directory = parse_directory(dirstring);
    self->check_deferred();

  }

  void service::set_poll_timeout(int poll_timeout) {
    this->poll_timeout = poll_timeout;
  }

}<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#define DEBUG
#define DEBUG2

#include <net/tcp/tcp.hpp>
#include <net/tcp/packet.hpp>
#include <statman>

using namespace std;
using namespace net;
using namespace net::tcp;

TCP::TCP(IPStack& inet) :
  bytes_rx_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.bytes_rx").get_uint64()},
  bytes_tx_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.bytes_tx").get_uint64()},
  packets_rx_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.packets_rx").get_uint64()},
  packets_tx_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.packets_tx").get_uint64()},
  incoming_connections_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.incoming_connections").get_uint64()},
  outgoing_connections_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.outgoing_connections").get_uint64()},
  connection_attempts_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.connection_attempts").get_uint64()},
  packets_dropped_{Statman::get().create(Stat::UINT32, inet.ifname() + ".tcp.packets_dropped").get_uint32()},
  inet_(inet),
  listeners_(),
  connections_(),
  writeq(),
  MAX_SEG_LIFETIME(30s)
{
  inet.on_transmit_queue_available({this, &TCP::process_writeq});
}

/*
  Note: There is different approaches to how to handle listeners & connections.
  Need to discuss and decide for the best one.

  Best solution(?):
  Preallocate a pool with listening connections.
  When threshold is reach, remove/add new ones, similar to TCP window.

  Current solution:
  Simple.
*/
Listener& TCP::bind(const port_t port) {
  // Already a listening socket.
  Listeners::const_iterator it = listeners_.find(port);
  if(it != listeners_.cend()) {
    throw TCPException{"Port is already taken."};
  }
  auto& listener = listeners_.emplace(port,
    std::make_unique<tcp::Listener>(*this, port)
    ).first->second;
  debug("<TCP::bind> Bound to port %i \n", port);
  return *listener;

  /*auto& listener = (listeners_.emplace(std::piecewise_construct,
    std::forward_as_tuple(port),
    std::forward_as_tuple(*this, port))
    ).first->second;
  debug("<TCP::bind> Bound to port %i \n", port);

  return listener;*/
}

bool TCP::unbind(const port_t port) {
  auto it = listeners_.find(port);
  if(LIKELY(it != listeners_.end())) {
    auto listener = std::move(it->second);
    listener->close();
    Ensures(listeners_.find(port) == listeners_.end());
    return true;
  }
  return false;
}

/*
  Active open a new connection to the given remote.

  @WARNING: Callback is added when returned (TCP::connect(...).onSuccess(...)),
  and open() is called before callback is added.
*/
Connection_ptr TCP::connect(Socket remote) {
  auto port = next_free_port();
  auto connection = add_connection(port, remote);
  connection->open(true);
  return connection;
}

/*
  Active open a new connection to the given remote.
*/
void TCP::connect(Socket remote, Connection::ConnectCallback callback) {
  auto port = next_free_port();
  auto connection = add_connection(port, remote);
  connection->on_connect(callback).open(true);
}

void TCP::insert_connection(Connection_ptr conn)
{
  connections_.emplace(
      std::piecewise_construct,
      std::forward_as_tuple(conn->local_port(), conn->remote()),
      std::forward_as_tuple(conn));
  // add to writeq if it has any jobs
  if (conn->has_doable_job()) {
    writeq.push_back(conn);
    // try to flush
    this->kick();
  }
}

seq_t TCP::generate_iss() {
  // Do something to get a iss.
  return rand();
}

/*
  TODO: Check if there is any ports free.
*/
port_t TCP::next_free_port() {

  current_ephemeral_ = (current_ephemeral_ == 0) ? current_ephemeral_ + 1025 : current_ephemeral_ + 1;

  // Avoid giving a port that is bound to a service.
  while(listeners_.find(current_ephemeral_) != listeners_.end())
    current_ephemeral_++;

  return current_ephemeral_;
}

/*
  Expensive look up if port is in use.
*/
bool TCP::port_in_use(const port_t port) const {
  if(listeners_.find(port) != listeners_.end())
    return true;

  for(auto conn : connections_) {
    if(conn.first.first == port)
      return true;
  }
  return false;
}

uint16_t TCP::checksum(const tcp::Packet& packet)
{
  short tcp_length = packet.tcp_length();

  Pseudo_header pseudo_hdr;
  pseudo_hdr.saddr.whole = packet.src().whole;
  pseudo_hdr.daddr.whole = packet.dst().whole;
  pseudo_hdr.zero = 0;
  pseudo_hdr.proto = IP4::IP4_TCP;
  pseudo_hdr.tcp_length = htons(tcp_length);

  union Sum{
    uint32_t whole;
    uint16_t part[2];
  } sum;

  sum.whole = 0;

  // Compute sum of pseudo header
  for (uint16_t* it = (uint16_t*)&pseudo_hdr; it < (uint16_t*)&pseudo_hdr + sizeof(pseudo_hdr)/2; it++)
    sum.whole += *it;

  // Compute sum of header and data
  Header* tcp_hdr = &packet.tcp_header();
  for (uint16_t* it = (uint16_t*)tcp_hdr; it < (uint16_t*)tcp_hdr + tcp_length/2; it++)
    sum.whole+= *it;

  // The odd-numbered case
  bool odd = (tcp_length & 1);
  sum.whole += (odd) ? ((uint8_t*)tcp_hdr)[tcp_length - 1] << 16 : 0;

  sum.whole = (uint32_t)sum.part[0] + sum.part[1];
  sum.part[0] += sum.part[1];

  return ~sum.whole;
}

void TCP::bottom(net::Packet_ptr packet_ptr) {
  // Stat increment packets received
  packets_rx_++;

  // Translate into a TCP::Packet. This will be used inside the TCP-scope.
  auto packet = static_unique_ptr_cast<net::tcp::Packet>(std::move(packet_ptr));
  debug2("<TCP::bottom> TCP Packet received - Source: %s, Destination: %s \n",
        packet->source().to_string().c_str(), packet->destination().to_string().c_str());

  // Stat increment bytes received
  bytes_rx_ += packet->tcp_data_length();

  // Validate checksum
  if (UNLIKELY(checksum(*packet) != 0)) {
    debug("<TCP::bottom> TCP Packet Checksum != 0 \n");
    drop(*packet);
    return;
  }

  Connection::Tuple tuple { packet->dst_port(), packet->source() };

  // Try to find the receiver
  auto conn_it = connections_.find(tuple);

  // Connection found
  if (conn_it != connections_.end()) {
    debug("<TCP::bottom> Connection found: %s \n", conn_it->second->to_string().c_str());
    conn_it->second->segment_arrived(std::move(packet));
    return;
  }

  // No open connection found, find listener on port
  Listeners::iterator listener_it = listeners_.find(packet->dst_port());
  debug("<TCP::bottom> No connection found - looking for listener..\n");
  // Listener found => Create listening Connection
  if (LIKELY(listener_it != listeners_.end())) {
    auto& listener = listener_it->second;
    debug("<TCP::bottom> Listener found: %s\n", listener->to_string().c_str());
    listener->segment_arrived(std::move(packet));
    debug2("<TCP::bottom> Listener done with packet\n");
    return;
  }

  drop(*packet);
}

void TCP::process_writeq(size_t packets) {
  debug("<TCP::process_writeq> size=%u p=%u\n", writeq.size(), packets);
  // foreach connection who wants to write
  while(packets and !writeq.empty()) {
    debug("<TCP::process_writeq> Processing writeq size=%u, p=%u\n", writeq.size(), packets);
    auto conn = writeq.front();
    writeq.pop_back();
    conn->offer(packets);
    conn->set_queued(false);
  }
}

size_t TCP::send(Connection_ptr conn, const char* buffer, size_t n) {
  size_t written{0};
  auto packets = inet_.transmit_queue_available();

  debug2("<TCP::send> Send request for %u bytes\n", n);

  if(packets > 0) {
    written += conn->send(buffer, n, packets);
  }
  // if connection still can send (means there wasn't enough packets)
  // only requeue if not already queued
  if(!packets and conn->can_send() and !conn->is_queued()) {
    debug("<TCP::send> %s queued\n", conn->to_string().c_str());
    writeq.push_back(conn);
    conn->set_queued(true);
  }

  return written;
}

/*
  Show all connections for TCP as a string.

  Format:
  [Protocol][Recv][Send][Local][Remote][State]

  TODO: Make sure Recv, Send, In, Out is correct and add them to output. Also, alignment?
*/
string TCP::to_string() const {
  // Write all connections in a cute list.
  stringstream ss;
  ss << "LISTENERS:\n" << "Port\t" << "Queued\n";
  for(auto& listen_it : listeners_) {
    auto& l = listen_it.second;
    ss << l->port() << "\t" << l->syn_queue_size() << "\n";
  }
  ss << "\nCONNECTIONS:\n" <<  "Proto\tRecv\tSend\tIn\tOut\tLocal\t\t\tRemote\t\t\tState\n";
  for(auto& con_it : connections_) {
    auto& c = *(con_it.second);
    ss << "tcp4\t"
       << " " << "\t" << " " << "\t"
       << " " << "\t" << " " << "\t"
       << c.local().to_string() << "\t\t" << c.remote().to_string() << "\t\t"
       << c.state().to_string() << "\n";
  }
  return ss.str();
}

Connection_ptr TCP::add_connection(port_t local_port, Socket remote) {
  // Stat increment number of outgoing connections
  outgoing_connections_++;

  auto& conn = (connections_.emplace(
      Connection::Tuple{ local_port, remote },
      std::make_shared<Connection>(*this, local_port, remote))
    ).first->second;
  conn->_on_cleanup({this, &TCP::close_connection});
  return conn;
}

void TCP::add_connection(tcp::Connection_ptr conn) {
  // Stat increment number of incoming connections
  incoming_connections_++;

  debug("<TCP::add_connection> Connection added %s \n", conn->to_string().c_str());
  conn->_on_cleanup({this, &TCP::close_connection});
  connections_.emplace(conn->tuple(), conn);
}

void TCP::close_connection(tcp::Connection_ptr conn) {
  debug("<TCP::close_connection> Closing connection: %s \n", conn->to_string().c_str());
  connections_.erase(conn->tuple());
}

void TCP::close_listener(Listener& listener) {
  listeners_.erase(listener.port());
}

void TCP::drop(const tcp::Packet&) {
  // Stat increment packets dropped
  packets_dropped_++;

  debug("<TCP::drop> Packet dropped\n");
  //debug("<TCP::drop> Packet was dropped - no recipient: %s \n", packet->destination().to_string().c_str());
}

void TCP::transmit(tcp::Packet_ptr packet) {
  // Generate checksum.
  packet->set_checksum(TCP::checksum(*packet));
  debug2("<TCP::transmit> %s\n", packet->to_string().c_str());

  // Stat increment bytes transmitted and packets transmitted
  bytes_tx_ += packet->tcp_data_length();
  packets_tx_++;

  _network_layer_out(std::move(packet));
}
<commit_msg>tcp: No longer attempt to add back to writeq after manual insertion<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2016 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#define DEBUG
#define DEBUG2

#include <net/tcp/tcp.hpp>
#include <net/tcp/packet.hpp>
#include <statman>

using namespace std;
using namespace net;
using namespace net::tcp;

TCP::TCP(IPStack& inet) :
  bytes_rx_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.bytes_rx").get_uint64()},
  bytes_tx_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.bytes_tx").get_uint64()},
  packets_rx_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.packets_rx").get_uint64()},
  packets_tx_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.packets_tx").get_uint64()},
  incoming_connections_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.incoming_connections").get_uint64()},
  outgoing_connections_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.outgoing_connections").get_uint64()},
  connection_attempts_{Statman::get().create(Stat::UINT64, inet.ifname() + ".tcp.connection_attempts").get_uint64()},
  packets_dropped_{Statman::get().create(Stat::UINT32, inet.ifname() + ".tcp.packets_dropped").get_uint32()},
  inet_(inet),
  listeners_(),
  connections_(),
  writeq(),
  MAX_SEG_LIFETIME(30s)
{
  inet.on_transmit_queue_available({this, &TCP::process_writeq});
}

/*
  Note: There is different approaches to how to handle listeners & connections.
  Need to discuss and decide for the best one.

  Best solution(?):
  Preallocate a pool with listening connections.
  When threshold is reach, remove/add new ones, similar to TCP window.

  Current solution:
  Simple.
*/
Listener& TCP::bind(const port_t port) {
  // Already a listening socket.
  Listeners::const_iterator it = listeners_.find(port);
  if(it != listeners_.cend()) {
    throw TCPException{"Port is already taken."};
  }
  auto& listener = listeners_.emplace(port,
    std::make_unique<tcp::Listener>(*this, port)
    ).first->second;
  debug("<TCP::bind> Bound to port %i \n", port);
  return *listener;

  /*auto& listener = (listeners_.emplace(std::piecewise_construct,
    std::forward_as_tuple(port),
    std::forward_as_tuple(*this, port))
    ).first->second;
  debug("<TCP::bind> Bound to port %i \n", port);

  return listener;*/
}

bool TCP::unbind(const port_t port) {
  auto it = listeners_.find(port);
  if(LIKELY(it != listeners_.end())) {
    auto listener = std::move(it->second);
    listener->close();
    Ensures(listeners_.find(port) == listeners_.end());
    return true;
  }
  return false;
}

/*
  Active open a new connection to the given remote.

  @WARNING: Callback is added when returned (TCP::connect(...).onSuccess(...)),
  and open() is called before callback is added.
*/
Connection_ptr TCP::connect(Socket remote) {
  auto port = next_free_port();
  auto connection = add_connection(port, remote);
  connection->open(true);
  return connection;
}

/*
  Active open a new connection to the given remote.
*/
void TCP::connect(Socket remote, Connection::ConnectCallback callback) {
  auto port = next_free_port();
  auto connection = add_connection(port, remote);
  connection->on_connect(callback).open(true);
}

void TCP::insert_connection(Connection_ptr conn)
{
  connections_.emplace(
      std::piecewise_construct,
      std::forward_as_tuple(conn->local_port(), conn->remote()),
      std::forward_as_tuple(conn));
}

seq_t TCP::generate_iss() {
  // Do something to get a iss.
  return rand();
}

/*
  TODO: Check if there is any ports free.
*/
port_t TCP::next_free_port() {

  current_ephemeral_ = (current_ephemeral_ == 0) ? current_ephemeral_ + 1025 : current_ephemeral_ + 1;

  // Avoid giving a port that is bound to a service.
  while(listeners_.find(current_ephemeral_) != listeners_.end())
    current_ephemeral_++;

  return current_ephemeral_;
}

/*
  Expensive look up if port is in use.
*/
bool TCP::port_in_use(const port_t port) const {
  if(listeners_.find(port) != listeners_.end())
    return true;

  for(auto conn : connections_) {
    if(conn.first.first == port)
      return true;
  }
  return false;
}

uint16_t TCP::checksum(const tcp::Packet& packet)
{
  short tcp_length = packet.tcp_length();

  Pseudo_header pseudo_hdr;
  pseudo_hdr.saddr.whole = packet.src().whole;
  pseudo_hdr.daddr.whole = packet.dst().whole;
  pseudo_hdr.zero = 0;
  pseudo_hdr.proto = IP4::IP4_TCP;
  pseudo_hdr.tcp_length = htons(tcp_length);

  union Sum{
    uint32_t whole;
    uint16_t part[2];
  } sum;

  sum.whole = 0;

  // Compute sum of pseudo header
  for (uint16_t* it = (uint16_t*)&pseudo_hdr; it < (uint16_t*)&pseudo_hdr + sizeof(pseudo_hdr)/2; it++)
    sum.whole += *it;

  // Compute sum of header and data
  Header* tcp_hdr = &packet.tcp_header();
  for (uint16_t* it = (uint16_t*)tcp_hdr; it < (uint16_t*)tcp_hdr + tcp_length/2; it++)
    sum.whole+= *it;

  // The odd-numbered case
  bool odd = (tcp_length & 1);
  sum.whole += (odd) ? ((uint8_t*)tcp_hdr)[tcp_length - 1] << 16 : 0;

  sum.whole = (uint32_t)sum.part[0] + sum.part[1];
  sum.part[0] += sum.part[1];

  return ~sum.whole;
}

void TCP::bottom(net::Packet_ptr packet_ptr) {
  // Stat increment packets received
  packets_rx_++;

  // Translate into a TCP::Packet. This will be used inside the TCP-scope.
  auto packet = static_unique_ptr_cast<net::tcp::Packet>(std::move(packet_ptr));
  debug2("<TCP::bottom> TCP Packet received - Source: %s, Destination: %s \n",
        packet->source().to_string().c_str(), packet->destination().to_string().c_str());

  // Stat increment bytes received
  bytes_rx_ += packet->tcp_data_length();

  // Validate checksum
  if (UNLIKELY(checksum(*packet) != 0)) {
    debug("<TCP::bottom> TCP Packet Checksum != 0 \n");
    drop(*packet);
    return;
  }

  Connection::Tuple tuple { packet->dst_port(), packet->source() };

  // Try to find the receiver
  auto conn_it = connections_.find(tuple);

  // Connection found
  if (conn_it != connections_.end()) {
    debug("<TCP::bottom> Connection found: %s \n", conn_it->second->to_string().c_str());
    conn_it->second->segment_arrived(std::move(packet));
    return;
  }

  // No open connection found, find listener on port
  Listeners::iterator listener_it = listeners_.find(packet->dst_port());
  debug("<TCP::bottom> No connection found - looking for listener..\n");
  // Listener found => Create listening Connection
  if (LIKELY(listener_it != listeners_.end())) {
    auto& listener = listener_it->second;
    debug("<TCP::bottom> Listener found: %s\n", listener->to_string().c_str());
    listener->segment_arrived(std::move(packet));
    debug2("<TCP::bottom> Listener done with packet\n");
    return;
  }

  drop(*packet);
}

void TCP::process_writeq(size_t packets) {
  debug("<TCP::process_writeq> size=%u p=%u\n", writeq.size(), packets);
  // foreach connection who wants to write
  while(packets and !writeq.empty()) {
    debug("<TCP::process_writeq> Processing writeq size=%u, p=%u\n", writeq.size(), packets);
    auto conn = writeq.front();
    writeq.pop_back();
    conn->offer(packets);
    conn->set_queued(false);
  }
}

size_t TCP::send(Connection_ptr conn, const char* buffer, size_t n) {
  size_t written{0};
  auto packets = inet_.transmit_queue_available();

  debug2("<TCP::send> Send request for %u bytes\n", n);

  if(packets > 0) {
    written += conn->send(buffer, n, packets);
  }
  // if connection still can send (means there wasn't enough packets)
  // only requeue if not already queued
  if(!packets and conn->can_send() and !conn->is_queued()) {
    debug("<TCP::send> %s queued\n", conn->to_string().c_str());
    writeq.push_back(conn);
    conn->set_queued(true);
  }

  return written;
}

/*
  Show all connections for TCP as a string.

  Format:
  [Protocol][Recv][Send][Local][Remote][State]

  TODO: Make sure Recv, Send, In, Out is correct and add them to output. Also, alignment?
*/
string TCP::to_string() const {
  // Write all connections in a cute list.
  stringstream ss;
  ss << "LISTENERS:\n" << "Port\t" << "Queued\n";
  for(auto& listen_it : listeners_) {
    auto& l = listen_it.second;
    ss << l->port() << "\t" << l->syn_queue_size() << "\n";
  }
  ss << "\nCONNECTIONS:\n" <<  "Proto\tRecv\tSend\tIn\tOut\tLocal\t\t\tRemote\t\t\tState\n";
  for(auto& con_it : connections_) {
    auto& c = *(con_it.second);
    ss << "tcp4\t"
       << " " << "\t" << " " << "\t"
       << " " << "\t" << " " << "\t"
       << c.local().to_string() << "\t\t" << c.remote().to_string() << "\t\t"
       << c.state().to_string() << "\n";
  }
  return ss.str();
}

Connection_ptr TCP::add_connection(port_t local_port, Socket remote) {
  // Stat increment number of outgoing connections
  outgoing_connections_++;

  auto& conn = (connections_.emplace(
      Connection::Tuple{ local_port, remote },
      std::make_shared<Connection>(*this, local_port, remote))
    ).first->second;
  conn->_on_cleanup({this, &TCP::close_connection});
  return conn;
}

void TCP::add_connection(tcp::Connection_ptr conn) {
  // Stat increment number of incoming connections
  incoming_connections_++;

  debug("<TCP::add_connection> Connection added %s \n", conn->to_string().c_str());
  conn->_on_cleanup({this, &TCP::close_connection});
  connections_.emplace(conn->tuple(), conn);
}

void TCP::close_connection(tcp::Connection_ptr conn) {
  debug("<TCP::close_connection> Closing connection: %s \n", conn->to_string().c_str());
  connections_.erase(conn->tuple());
}

void TCP::close_listener(Listener& listener) {
  listeners_.erase(listener.port());
}

void TCP::drop(const tcp::Packet&) {
  // Stat increment packets dropped
  packets_dropped_++;

  debug("<TCP::drop> Packet dropped\n");
  //debug("<TCP::drop> Packet was dropped - no recipient: %s \n", packet->destination().to_string().c_str());
}

void TCP::transmit(tcp::Packet_ptr packet) {
  // Generate checksum.
  packet->set_checksum(TCP::checksum(*packet));
  debug2("<TCP::transmit> %s\n", packet->to_string().c_str());

  // Stat increment bytes transmitted and packets transmitted
  bytes_tx_ += packet->tcp_data_length();
  packets_tx_++;

  _network_layer_out(std::move(packet));
}
<|endoftext|>


<commit_before>#include"Board.hpp"

namespace neuro {

	void advanceInDirection(Coordinates & coord, int dir) {
		switch ( dir ) {
			case 0:
			case 2:
				coord.first += (coord.second % 2 == 0) : 0 ? 1;
				break;
			case 3:
			case 5:
				coord.first += (coord.second % 2 == 0) : -1 ? 0;
				break;
			case 1:
				coord.first += 1;
				break;
			case 4:
				coord.first += -1;
				break;
		}
		switch ( dir ) {
			case 0:
			case 5:
				coord.second += -1;
				break;
			case 1:
			case 4:
				coord.second += 0;
				break;
			case 2:
			case 3:
				coord.second += 1;
				break;
		}
	}

	Board::Board( BoardDescription desc ) : fields(desc) {
		width = fields.size();
		if ( width == 0 ) {
			height = 0;
		} else {
			height = fields[0].size();
		}
	}

	FieldType Board::getFieldDescription(Coordinates coord) const {
		if ( insideBoard(coord) ) {
			return fields[coord.first][coord.second];
		} else {
			return FieldType::NO_FIELD;
		}
	}

	std::list<TileP> Board::getTiles(Coordinates coord) const {
		if ( insideBoard(coord) ) {
			return tiles[coord.first][coord.second];
		} else {
			return std::list<TileP>();
		}
	}

	Coordinates Board::findTile(TileP tile) const {
		Coordinates result(-1, -1);
		for ( int x = 0; x < static_cast<int>( tiles.size() ); x++ ) {
			for ( int y = 0; y < static_cast<int>( tiles[x].size() ); y++ ) {
				for ( TileP tp : tiles[x][y] ) {
					if ( tp == tile ) {
						result.first = x;
						result.second = y;
						return result;
					}
				}
			}
		}
		return result;
	}

	std::list<TileP> Board::getSolidTilesInDirection(Coordinates coord, int dir) const {
		std::list<TileP> result;
		int xMod, yMod;
		coord.first += xMod;
		coord.second += yMod;
		while ( insideBoard(coord) ) {
			for ( TileP tp : tiles[coord.first][coord.second] ) {
				if ( tp->isSolid() ) {
					result.push_back( tp );
					break;
				}
			}
			advanceInDirection(coord, dir);
		}
		return result;
	}

	bool Board::placeTile( Coordinates coord, TileP tile ) {
		if ( insideBoard(coord) ) {
			if ( getFieldDescription(coord) != FieldType::NO_FIELD ) {
				// No more validation, assume the game validates; maybe validation later?
				tiles[coord.first][coord.second].push_front(tile);
				sigModified(*this);
				return true;
			}
		}
		return false;
	}

	bool Board::removeTile(TileP tile) {
		Coordinates toRem = findTile(tile);
		if ( toRem.first == -1 ) {
			return false;
		} else {
			tiles[toRem.first][toRem.second].remove(tile);
			sigModified(*this);
			return true;
		}
	}

}
<commit_msg>Fixed broken ternary operators and cleaned up unneeded variables<commit_after>#include"Board.hpp"

namespace neuro {

	void advanceInDirection(Coordinates & coord, int dir) {
		switch ( dir ) {
			case 0:
			case 2:
				coord.first += (coord.second % 2 == 0) ? 0 : 1;
				break;
			case 3:
			case 5:
				coord.first += (coord.second % 2 == 0) ? -1 : 0;
				break;
			case 1:
				coord.first += 1;
				break;
			case 4:
				coord.first += -1;
				break;
		}
		switch ( dir ) {
			case 0:
			case 5:
				coord.second += -1;
				break;
			case 1:
			case 4:
				coord.second += 0;
				break;
			case 2:
			case 3:
				coord.second += 1;
				break;
		}
	}

	Board::Board( BoardDescription desc ) : fields(desc) {
		width = fields.size();
		if ( width == 0 ) {
			height = 0;
		} else {
			height = fields[0].size();
		}
	}

	FieldType Board::getFieldDescription(Coordinates coord) const {
		if ( insideBoard(coord) ) {
			return fields[coord.first][coord.second];
		} else {
			return FieldType::NO_FIELD;
		}
	}

	std::list<TileP> Board::getTiles(Coordinates coord) const {
		if ( insideBoard(coord) ) {
			return tiles[coord.first][coord.second];
		} else {
			return std::list<TileP>();
		}
	}

	Coordinates Board::findTile(TileP tile) const {
		Coordinates result(-1, -1);
		for ( int x = 0; x < static_cast<int>( tiles.size() ); x++ ) {
			for ( int y = 0; y < static_cast<int>( tiles[x].size() ); y++ ) {
				for ( TileP tp : tiles[x][y] ) {
					if ( tp == tile ) {
						result.first = x;
						result.second = y;
						return result;
					}
				}
			}
		}
		return result;
	}

	std::list<TileP> Board::getSolidTilesInDirection(Coordinates coord, int dir) const {
		std::list<TileP> result;
		advanceInDirection(coord, dir);
		while ( insideBoard(coord) ) {
			for ( TileP tp : tiles[coord.first][coord.second] ) {
				if ( tp->isSolid() ) {
					result.push_back( tp );
					break;
				}
			}
			advanceInDirection(coord, dir);
		}
		return result;
	}

	bool Board::placeTile( Coordinates coord, TileP tile ) {
		if ( insideBoard(coord) ) {
			if ( getFieldDescription(coord) != FieldType::NO_FIELD ) {
				// No more validation, assume the game validates; maybe validation later?
				tiles[coord.first][coord.second].push_front(tile);
				sigModified(*this);
				return true;
			}
		}
		return false;
	}

	bool Board::removeTile(TileP tile) {
		Coordinates toRem = findTile(tile);
		if ( toRem.first == -1 ) {
			return false;
		} else {
			tiles[toRem.first][toRem.second].remove(tile);
			sigModified(*this);
			return true;
		}
	}

}
<|endoftext|>


<commit_before>/*******************************************************************************
* Copyright 2017-2018 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#pragma once

#include <chrono>
#include <cmath>
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

namespace ngraph
{
    class Node;
    class Function;
    class NodeMap;
    class stopwatch;

    namespace runtime
    {
        class Backend;
        class Value;
    }

    std::string to_cplusplus_sourcecode_literal(bool val);

    template <typename T>
    std::string join(const T& v, const std::string& sep = ", ")
    {
        std::ostringstream ss;
        for (const auto& x : v)
        {
            if (&x != &*(v.begin()))
            {
                ss << sep;
            }
            ss << x;
        }
        return ss.str();
    }

    template <typename T>
    static std::string vector_to_string(const T& v)
    {
        std::ostringstream os;
        os << "[ " << ngraph::join(v) << " ]";
        return os.str();
    }

    template <typename U, typename T>
    bool contains(const U& container, const T& obj)
    {
        bool rc = false;
        for (auto o : container)
        {
            if (o == obj)
            {
                rc = true;
                break;
            }
        }
        return rc;
    }

    template <typename U, typename T>
    bool contains_key(const U& container, const T& obj)
    {
        bool rc = false;
        for (auto o : container)
        {
            if (o.first == obj)
            {
                rc = true;
                break;
            }
        }
        return rc;
    }

    template <typename U, typename T>
    void remove_from(U& container, const T& obj)
    {
        auto it = container.find(obj);
        if (it != container.end())
        {
            container.erase(it);
        }
    }

    size_t hash_combine(const std::vector<size_t>& list);
    void dump(std::ostream& out, const void*, size_t);

    std::string to_lower(const std::string& s);
    std::string trim(const std::string& s);
    std::vector<std::string> split(const std::string& s, char delimiter, bool trim = false);

    class stopwatch
    {
    public:
        void start()
        {
            if (m_active == false)
            {
                m_total_count++;
                m_active = true;
                m_start_time = m_clock.now();
            }
        }

        void stop()
        {
            if (m_active == true)
            {
                auto end_time = m_clock.now();
                m_last_time = end_time - m_start_time;
                m_total_time += m_last_time;
                m_active = false;
            }
        }

        size_t get_call_count() const { return m_total_count; }
        size_t get_seconds() const { return get_nanoseconds() / 1e9; }
        size_t get_milliseconds() const { return get_nanoseconds() / 1e6; }
        size_t get_microseconds() const { return get_nanoseconds() / 1e3; }
        size_t get_nanoseconds() const
        {
            if (m_active)
            {
                return (m_clock.now() - m_start_time).count();
            }
            else
            {
                return m_last_time.count();
            }
        }

        size_t get_total_seconds() const { return get_total_nanoseconds() / 1e9; }
        size_t get_total_milliseconds() const { return get_total_nanoseconds() / 1e6; }
        size_t get_total_microseconds() const { return get_total_nanoseconds() / 1e3; }
        size_t get_total_nanoseconds() const { return m_total_time.count(); }
    private:
        std::chrono::high_resolution_clock m_clock;
        std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
        bool m_active = false;
        std::chrono::nanoseconds m_total_time =
            std::chrono::high_resolution_clock::duration::zero();
        std::chrono::nanoseconds m_last_time;
        size_t m_total_count = 0;
    };

    /// Parses a string containing a literal of the underlying type.
    template <typename T>
    T parse_string(const std::string& s)
    {
        T result;
        std::stringstream ss;

        ss << s;
        ss >> result;

        // Check that (1) parsing succeeded and (2) the entire string was used.
        if (ss.fail() || ss.rdbuf()->in_avail() != 0)
        {
            throw std::runtime_error("Could not parse literal '" + s + "'");
        }

        return result;
    }

    /// template specializations for float and double to handle INFINITY, -INFINITY
    /// and NaN values.
    template <>
    float parse_string<float>(const std::string& s);
    template <>
    double parse_string<double>(const std::string& s);

    /// Parses a list of strings containing literals of the underlying type.
    template <typename T>
    std::vector<T> parse_string(const std::vector<std::string>& ss)
    {
        std::vector<T> result;

        for (auto s : ss)
        {
            result.push_back(parse_string<T>(s));
        }

        return result;
    }

    template <typename T>
    T ceil_div(const T& x, const T& y)
    {
        return (x == 0 ? 0 : (1 + (x - 1) / y));
    }

    template <typename T>
    T subtract_or_zero(T x, T y)
    {
        return y > x ? 0 : x - y;
    }

    template <typename T, bool (*func)(T)>
    void check_fp_values(const char* name, const T* array, size_t n)
    {
        bool (*fPtr)(T) = &std::isinf;
        const char* cerr_type = fPtr == func ? "Inf" : "NaN";
        for (size_t i = 0; i < n; i++)
        {
            if (func(array[i]))
            {
                throw std::runtime_error(std::string("Discovered ") + cerr_type + " in '" + name +
                                         "'");
            }
        }
    }

    template void
        check_fp_values<float, std::isinf>(const char* name, const float* array, size_t n);
    template void
        check_fp_values<float, std::isnan>(const char* name, const float* array, size_t n);
    template void
        check_fp_values<double, std::isinf>(const char* name, const double* array, size_t n);
    template void
        check_fp_values<double, std::isnan>(const char* name, const double* array, size_t n);

    void* aligned_alloc(size_t alignment, size_t size);
    void aligned_free(void*);
    size_t round_up(size_t size, size_t alignment);

    /*
    * Return type struct for cache_fprop, with the modified fprop and bprop
    * functions
    * and a list of the nodes that have been appended to fprop output/bprop
    * input
    */
    struct FpropCache
    {
        std::shared_ptr<Function> fprop;
        std::shared_ptr<Function> bprop;
        std::vector<std::shared_ptr<Node>> fprop_output_nodes;
        std::shared_ptr<NodeMap> node_param_map;
    };

    /**
    * This utility takes forward-propogation and back-propagation functions
    * and turns them into clone functions where the intermediate values of
    * the forward prop are added to the output of fprop and the input of the bprop
    * to avoid repeat calcualtions.
    * The last argument is the adjoints coming into the bprop function, the output
    * bprop function will have these nodes as the first N input parameters
    **/
    FpropCache cache_fprop(std::shared_ptr<Function> fprop,
                           std::shared_ptr<Function> bprop,
                           std::vector<std::shared_ptr<Node>> adjoints);
} // end namespace ngraph
<commit_msg>Remove unnecessary static specifier that triggers warnings (#737)<commit_after>/*******************************************************************************
* Copyright 2017-2018 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#pragma once

#include <chrono>
#include <cmath>
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

namespace ngraph
{
    class Node;
    class Function;
    class NodeMap;
    class stopwatch;

    namespace runtime
    {
        class Backend;
        class Value;
    }

    std::string to_cplusplus_sourcecode_literal(bool val);

    template <typename T>
    std::string join(const T& v, const std::string& sep = ", ")
    {
        std::ostringstream ss;
        for (const auto& x : v)
        {
            if (&x != &*(v.begin()))
            {
                ss << sep;
            }
            ss << x;
        }
        return ss.str();
    }

    template <typename T>
    std::string vector_to_string(const T& v)
    {
        std::ostringstream os;
        os << "[ " << ngraph::join(v) << " ]";
        return os.str();
    }

    template <typename U, typename T>
    bool contains(const U& container, const T& obj)
    {
        bool rc = false;
        for (auto o : container)
        {
            if (o == obj)
            {
                rc = true;
                break;
            }
        }
        return rc;
    }

    template <typename U, typename T>
    bool contains_key(const U& container, const T& obj)
    {
        bool rc = false;
        for (auto o : container)
        {
            if (o.first == obj)
            {
                rc = true;
                break;
            }
        }
        return rc;
    }

    template <typename U, typename T>
    void remove_from(U& container, const T& obj)
    {
        auto it = container.find(obj);
        if (it != container.end())
        {
            container.erase(it);
        }
    }

    size_t hash_combine(const std::vector<size_t>& list);
    void dump(std::ostream& out, const void*, size_t);

    std::string to_lower(const std::string& s);
    std::string trim(const std::string& s);
    std::vector<std::string> split(const std::string& s, char delimiter, bool trim = false);

    class stopwatch
    {
    public:
        void start()
        {
            if (m_active == false)
            {
                m_total_count++;
                m_active = true;
                m_start_time = m_clock.now();
            }
        }

        void stop()
        {
            if (m_active == true)
            {
                auto end_time = m_clock.now();
                m_last_time = end_time - m_start_time;
                m_total_time += m_last_time;
                m_active = false;
            }
        }

        size_t get_call_count() const { return m_total_count; }
        size_t get_seconds() const { return get_nanoseconds() / 1e9; }
        size_t get_milliseconds() const { return get_nanoseconds() / 1e6; }
        size_t get_microseconds() const { return get_nanoseconds() / 1e3; }
        size_t get_nanoseconds() const
        {
            if (m_active)
            {
                return (m_clock.now() - m_start_time).count();
            }
            else
            {
                return m_last_time.count();
            }
        }

        size_t get_total_seconds() const { return get_total_nanoseconds() / 1e9; }
        size_t get_total_milliseconds() const { return get_total_nanoseconds() / 1e6; }
        size_t get_total_microseconds() const { return get_total_nanoseconds() / 1e3; }
        size_t get_total_nanoseconds() const { return m_total_time.count(); }
    private:
        std::chrono::high_resolution_clock m_clock;
        std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
        bool m_active = false;
        std::chrono::nanoseconds m_total_time =
            std::chrono::high_resolution_clock::duration::zero();
        std::chrono::nanoseconds m_last_time;
        size_t m_total_count = 0;
    };

    /// Parses a string containing a literal of the underlying type.
    template <typename T>
    T parse_string(const std::string& s)
    {
        T result;
        std::stringstream ss;

        ss << s;
        ss >> result;

        // Check that (1) parsing succeeded and (2) the entire string was used.
        if (ss.fail() || ss.rdbuf()->in_avail() != 0)
        {
            throw std::runtime_error("Could not parse literal '" + s + "'");
        }

        return result;
    }

    /// template specializations for float and double to handle INFINITY, -INFINITY
    /// and NaN values.
    template <>
    float parse_string<float>(const std::string& s);
    template <>
    double parse_string<double>(const std::string& s);

    /// Parses a list of strings containing literals of the underlying type.
    template <typename T>
    std::vector<T> parse_string(const std::vector<std::string>& ss)
    {
        std::vector<T> result;

        for (auto s : ss)
        {
            result.push_back(parse_string<T>(s));
        }

        return result;
    }

    template <typename T>
    T ceil_div(const T& x, const T& y)
    {
        return (x == 0 ? 0 : (1 + (x - 1) / y));
    }

    template <typename T>
    T subtract_or_zero(T x, T y)
    {
        return y > x ? 0 : x - y;
    }

    template <typename T, bool (*func)(T)>
    void check_fp_values(const char* name, const T* array, size_t n)
    {
        bool (*fPtr)(T) = &std::isinf;
        const char* cerr_type = fPtr == func ? "Inf" : "NaN";
        for (size_t i = 0; i < n; i++)
        {
            if (func(array[i]))
            {
                throw std::runtime_error(std::string("Discovered ") + cerr_type + " in '" + name +
                                         "'");
            }
        }
    }

    template void
        check_fp_values<float, std::isinf>(const char* name, const float* array, size_t n);
    template void
        check_fp_values<float, std::isnan>(const char* name, const float* array, size_t n);
    template void
        check_fp_values<double, std::isinf>(const char* name, const double* array, size_t n);
    template void
        check_fp_values<double, std::isnan>(const char* name, const double* array, size_t n);

    void* aligned_alloc(size_t alignment, size_t size);
    void aligned_free(void*);
    size_t round_up(size_t size, size_t alignment);

    /*
    * Return type struct for cache_fprop, with the modified fprop and bprop
    * functions
    * and a list of the nodes that have been appended to fprop output/bprop
    * input
    */
    struct FpropCache
    {
        std::shared_ptr<Function> fprop;
        std::shared_ptr<Function> bprop;
        std::vector<std::shared_ptr<Node>> fprop_output_nodes;
        std::shared_ptr<NodeMap> node_param_map;
    };

    /**
    * This utility takes forward-propogation and back-propagation functions
    * and turns them into clone functions where the intermediate values of
    * the forward prop are added to the output of fprop and the input of the bprop
    * to avoid repeat calcualtions.
    * The last argument is the adjoints coming into the bprop function, the output
    * bprop function will have these nodes as the first N input parameters
    **/
    FpropCache cache_fprop(std::shared_ptr<Function> fprop,
                           std::shared_ptr<Function> bprop,
                           std::vector<std::shared_ptr<Node>> adjoints);
} // end namespace ngraph
<|endoftext|>


<commit_before>#include "object/array.h"
#include "object/argument.h"
#include "object/function.h"

#include "libs/array/sort.h" // ArraySort
#include "libs/array/join.h" // ArrayJoin
#include "libs/array/push-pop.h"
#include "libs/array/reverse.h"
#include "libs/array/concat.h"
#include "libs/array/shift-unshift.h"
#include "libs/array/map.h"
#include "libs/array/slice.h"

namespace grok {
namespace obj {

std::shared_ptr<Object> ArrayConstructor(std::shared_ptr<Argument> Args)
{
    auto This = Args->GetProperty("this");
    if (Args->Size() == 0) {
        This->Reset(CreateArray(0));
    } else if (Args->Size() >= 1) {
        auto sz = Args->At(0);

        if (IsJSNumber(sz)) {
            auto num = sz->as<JSNumber>()->GetNumber();
            This->Reset(CreateArray(num));
        }
        auto Arr = CreateArray(0);
        auto A = Arr->as<JSArray>();
        for (auto Arg : *Args) {
            A->Push(Arg);
        }
        This->Reset(Arr);
    }
    return CreateUndefinedObject();
}

JSObject::Value JSArray::GetProperty(const JSObject::Name &name)
{
    if (name == "length") {
        return CreateJSNumber(Size());
    }
    return JSObject::GetProperty(name);
}

std::shared_ptr<Object> CreateArray(size_t size)
{
    auto ptr = std::make_shared<JSArray>();
    ptr->Resize(size);
    DefineInternalObjectProperties(ptr.get());

    // a.sort()
    auto S = std::make_shared<Function>(grok::libs::ArraySort);
    S->SetNonWritable();
    S->SetNonEnumerable();
    S->SetParams({ "pred" });
    ptr->AddProperty(std::string("sort"), std::make_shared<Object>(S));

    // a.join()
    S = std::make_shared<Function>(grok::libs::ArrayJoin);
    S->SetNonWritable();
    S->SetNonEnumerable();
    S->SetParams({ "sep" });
    ptr->AddProperty(std::string("join"), std::make_shared<Object>(S));

    // a.push
    S = std::make_shared<Function>(grok::libs::ArrayPush);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("push"), std::make_shared<Object>(S));

    // a.pop
    S = std::make_shared<Function>(grok::libs::ArrayPop);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("pop"), std::make_shared<Object>(S));

    // a.reverse
    S = std::make_shared<Function>(grok::libs::ArrayReverse);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("reverse"), std::make_shared<Object>(S));

    // a.concat
    S = std::make_shared<Function>(grok::libs::ArrayConcat);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("concat"), std::make_shared<Object>(S));

    // a.shift
    S = std::make_shared<Function>(grok::libs::ArrayShift);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("shift"), std::make_shared<Object>(S));

    // a.unshift
    S = std::make_shared<Function>(grok::libs::ArrayUnshift);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("unshift"), std::make_shared<Object>(S));

    // a.map
    S = std::make_shared<Function>(grok::libs::ArrayMap);
    S->SetNonWritable();
    S->SetParams({ "callback" });
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("map"), std::make_shared<Object>(S));

    // a.slice
    S = std::make_shared<Function>(grok::libs::ArraySlice);
    S->SetNonWritable();
    S->SetParams({ "start", "end" });
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("slice"), std::make_shared<Object>(S));

    auto Wrap = std::make_shared<Object>(ptr);
    return Wrap;
}

}
}
<commit_msg>Moved Array constructor to libs/array/array_constructor.h<commit_after>#include "object/array.h"
#include "object/argument.h"
#include "object/function.h"

#include "libs/array/sort.h" // ArraySort
#include "libs/array/join.h" // ArrayJoin
#include "libs/array/push-pop.h"
#include "libs/array/reverse.h"
#include "libs/array/concat.h"
#include "libs/array/shift-unshift.h"
#include "libs/array/map.h"
#include "libs/array/slice.h"

namespace grok {
namespace obj {

JSObject::Value JSArray::GetProperty(const JSObject::Name &name)
{
    if (name == "length") {
        return CreateJSNumber(Size());
    }
    return JSObject::GetProperty(name);
}

std::shared_ptr<Object> CreateArray(size_t size)
{
    auto ptr = std::make_shared<JSArray>();
    ptr->Resize(size);
    DefineInternalObjectProperties(ptr.get());

    // a.sort()
    auto S = std::make_shared<Function>(grok::libs::ArraySort);
    S->SetNonWritable();
    S->SetNonEnumerable();
    S->SetParams({ "pred" });
    ptr->AddProperty(std::string("sort"), std::make_shared<Object>(S));

    // a.join()
    S = std::make_shared<Function>(grok::libs::ArrayJoin);
    S->SetNonWritable();
    S->SetNonEnumerable();
    S->SetParams({ "sep" });
    ptr->AddProperty(std::string("join"), std::make_shared<Object>(S));

    // a.push
    S = std::make_shared<Function>(grok::libs::ArrayPush);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("push"), std::make_shared<Object>(S));

    // a.pop
    S = std::make_shared<Function>(grok::libs::ArrayPop);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("pop"), std::make_shared<Object>(S));

    // a.reverse
    S = std::make_shared<Function>(grok::libs::ArrayReverse);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("reverse"), std::make_shared<Object>(S));

    // a.concat
    S = std::make_shared<Function>(grok::libs::ArrayConcat);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("concat"), std::make_shared<Object>(S));

    // a.shift
    S = std::make_shared<Function>(grok::libs::ArrayShift);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("shift"), std::make_shared<Object>(S));

    // a.unshift
    S = std::make_shared<Function>(grok::libs::ArrayUnshift);
    S->SetNonWritable();
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("unshift"), std::make_shared<Object>(S));

    // a.map
    S = std::make_shared<Function>(grok::libs::ArrayMap);
    S->SetNonWritable();
    S->SetParams({ "callback" });
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("map"), std::make_shared<Object>(S));

    // a.slice
    S = std::make_shared<Function>(grok::libs::ArraySlice);
    S->SetNonWritable();
    S->SetParams({ "start", "end" });
    S->SetNonEnumerable();
    ptr->AddProperty(std::string("slice"), std::make_shared<Object>(S));

    auto Wrap = std::make_shared<Object>(ptr);
    return Wrap;
}

}
}
<|endoftext|>


<commit_before>/*
 * Filter an istream through a piped program.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "pipe_filter.hxx"
#include "http_response.hxx"
#include "format.h"
#include "stopwatch.hxx"
#include "istream_stopwatch.hxx"
#include "strmap.hxx"
#include "pool.hxx"
#include "istream/istream.hxx"
#include "spawn/ChildOptions.hxx"
#include "spawn/IstreamSpawn.hxx"
#include "spawn/Prepared.hxx"
#include "PrefixLogger.hxx"
#include "util/ConstBuffer.hxx"
#include "util/djbhash.h"
#include "util/Error.hxx"

#include <daemon/log.h>

#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

static const char *
append_etag(struct pool *pool, const char *in, const char *suffix)
{
    size_t length;

    if (*in != '"')
        /* simple concatenation */
        return p_strcat(pool, in, suffix, nullptr);

    length = strlen(in + 1);
    if (in[length] != '"')
        return p_strcat(pool, in, suffix, nullptr);

    return p_strncat(pool, in, length, suffix, strlen(suffix),
                     "\"", (size_t)1, nullptr);
}

static const char *
make_pipe_etag(struct pool *pool, const char *in,
               const char *path,
               ConstBuffer<const char *> args,
               ConstBuffer<const char *> env)
{
    char suffix[10] = {'-'};

    /* build hash from path and arguments */
    unsigned hash = djb_hash_string(path);

    for (auto i : args)
        hash ^= djb_hash_string(i);

    for (auto i : env)
        hash ^= djb_hash_string(i);

    format_uint32_hex_fixed(suffix + 1, hash);
    suffix[9] = 0;

    /* append the hash to the old ETag */
    return append_etag(pool, in, suffix);
}

void
pipe_filter(SpawnService &spawn_service, EventLoop &event_loop,
            struct pool *pool, const char *path,
            ConstBuffer<const char *> args,
            const ChildOptions &options,
            http_status_t status, StringMap &&headers, Istream *body,
            HttpResponseHandler &handler)
{
    const char *etag;

    if (body == nullptr) {
        /* if the resource does not have a body (which is different
           from Content-Length:0), don't filter it */
        handler.InvokeResponse(status, std::move(headers), nullptr);
        return;
    }

    assert(!http_status_is_empty(status));

    auto *stopwatch = stopwatch_new(pool, path);

    const auto prefix_logger = CreatePrefixLogger(event_loop, IgnoreError());

    PreparedChildProcess p;
    p.stderr_fd = prefix_logger.second;
    p.Append(path);
    for (auto i : args)
        p.Append(i);

    GError *error = nullptr;
    if (!options.CopyTo(p, true, nullptr, &error)) {
        DeletePrefixLogger(prefix_logger.first);
        handler.InvokeError(error);
        return;
    }

    Istream *response;
    pid_t pid = SpawnChildProcess(event_loop, pool, path, body, &response,
                                  std::move(p),
                                  spawn_service, &error);
    if (prefix_logger.second >= 0)
        close(prefix_logger.second);
    if (pid < 0) {
        DeletePrefixLogger(prefix_logger.first);
        handler.InvokeError(error);
        return;
    }

    if (prefix_logger.first != nullptr)
        PrefixLoggerSetPid(*prefix_logger.first, pid);

    stopwatch_event(stopwatch, "fork");

    etag = headers.Get("etag");
    if (etag != nullptr) {
        /* we cannot pass the original ETag to the client, because the
           pipe has modified the resource (which is what the pipe is
           all about) - append a digest value to the ETag, which is
           built from the program path and its arguments */

        etag = make_pipe_etag(pool, etag, path, args,
                              options.env);
        assert(etag != nullptr);

        headers.Set("etag", etag);
    }

    response = istream_stopwatch_new(*pool, *response, stopwatch);

    handler.InvokeResponse(status, std::move(headers), response);
}
<commit_msg>pipe_filter: fix double close() bug<commit_after>/*
 * Filter an istream through a piped program.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "pipe_filter.hxx"
#include "http_response.hxx"
#include "format.h"
#include "stopwatch.hxx"
#include "istream_stopwatch.hxx"
#include "strmap.hxx"
#include "pool.hxx"
#include "istream/istream.hxx"
#include "spawn/ChildOptions.hxx"
#include "spawn/IstreamSpawn.hxx"
#include "spawn/Prepared.hxx"
#include "PrefixLogger.hxx"
#include "util/ConstBuffer.hxx"
#include "util/djbhash.h"
#include "util/Error.hxx"

#include <daemon/log.h>

#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

static const char *
append_etag(struct pool *pool, const char *in, const char *suffix)
{
    size_t length;

    if (*in != '"')
        /* simple concatenation */
        return p_strcat(pool, in, suffix, nullptr);

    length = strlen(in + 1);
    if (in[length] != '"')
        return p_strcat(pool, in, suffix, nullptr);

    return p_strncat(pool, in, length, suffix, strlen(suffix),
                     "\"", (size_t)1, nullptr);
}

static const char *
make_pipe_etag(struct pool *pool, const char *in,
               const char *path,
               ConstBuffer<const char *> args,
               ConstBuffer<const char *> env)
{
    char suffix[10] = {'-'};

    /* build hash from path and arguments */
    unsigned hash = djb_hash_string(path);

    for (auto i : args)
        hash ^= djb_hash_string(i);

    for (auto i : env)
        hash ^= djb_hash_string(i);

    format_uint32_hex_fixed(suffix + 1, hash);
    suffix[9] = 0;

    /* append the hash to the old ETag */
    return append_etag(pool, in, suffix);
}

void
pipe_filter(SpawnService &spawn_service, EventLoop &event_loop,
            struct pool *pool, const char *path,
            ConstBuffer<const char *> args,
            const ChildOptions &options,
            http_status_t status, StringMap &&headers, Istream *body,
            HttpResponseHandler &handler)
{
    const char *etag;

    if (body == nullptr) {
        /* if the resource does not have a body (which is different
           from Content-Length:0), don't filter it */
        handler.InvokeResponse(status, std::move(headers), nullptr);
        return;
    }

    assert(!http_status_is_empty(status));

    auto *stopwatch = stopwatch_new(pool, path);

    const auto prefix_logger = CreatePrefixLogger(event_loop, IgnoreError());

    PreparedChildProcess p;
    p.stderr_fd = prefix_logger.second;
    p.Append(path);
    for (auto i : args)
        p.Append(i);

    GError *error = nullptr;
    if (!options.CopyTo(p, true, nullptr, &error)) {
        DeletePrefixLogger(prefix_logger.first);
        handler.InvokeError(error);
        return;
    }

    Istream *response;
    pid_t pid = SpawnChildProcess(event_loop, pool, path, body, &response,
                                  std::move(p),
                                  spawn_service, &error);
    if (pid < 0) {
        DeletePrefixLogger(prefix_logger.first);
        handler.InvokeError(error);
        return;
    }

    if (prefix_logger.first != nullptr)
        PrefixLoggerSetPid(*prefix_logger.first, pid);

    stopwatch_event(stopwatch, "fork");

    etag = headers.Get("etag");
    if (etag != nullptr) {
        /* we cannot pass the original ETag to the client, because the
           pipe has modified the resource (which is what the pipe is
           all about) - append a digest value to the ETag, which is
           built from the program path and its arguments */

        etag = make_pipe_etag(pool, etag, path, args,
                              options.env);
        assert(etag != nullptr);

        headers.Set("etag", etag);
    }

    response = istream_stopwatch_new(*pool, *response, stopwatch);

    handler.InvokeResponse(status, std::move(headers), response);
}
<|endoftext|>


<commit_before>// Copyright 2014 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>
#include <string>
#include <vector>
#include <exception>
#include <fstream>
#include <iomanip>
#include <limits>
#include <ctime>

#include <ArgumentList.hpp>
#include <Observation.hpp>
#include <utils.hpp>
#include <Shifts.hpp>

int main(int argc, char *argv[]) {
  unsigned int padding = 0;
  AstroData::Observation observation;

  try {
    isa::utils::ArgumentList args(argc, argv);
    padding = args.getSwitchArgument< unsigned int >("-padding");
    observation.setFrequencyRange(args.getSwitchArgument< unsigned int >("-channels"), args.getSwitchArgument< float >("-min_freq"), args.getSwitchArgument< float >("-channel_bandwidth"));
    observation.setNrSamplesPerSecond(args.getSwitchArgument< unsigned int >("-samples"));
    observation.setDMRange(args.getSwitchArgument< unsigned int >("-dms"), args.getSwitchArgument< float >("-dm_first"), args.getSwitchArgument< float >("-dm_step"));
	} catch  ( isa::utils::SwitchNotFound &err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }catch ( std::exception &err ) {
    std::cerr << "Usage: " << argv[0] << " -padding ... -min_freq ... -channel_bandwidth ... -channels ... -samples ... -dms ... -dm_first ... -dm_step ..." << std::endl;
		return 1;
	}

  std::vector< float > * shifts = PulsarSearch::getShifts(observation, padding);

  for ( unsigned int channel = 0; channel < observation.getNrChannels(); channel++ ) {
    std::cout << shifts->at(channel) << " ";
  }
  std::cout << std::endl;

	return 0;
}

<commit_msg>Refactoring.<commit_after>// Copyright 2014 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>
#include <string>
#include <vector>
#include <exception>
#include <fstream>
#include <iomanip>
#include <limits>
#include <ctime>

#include <ArgumentList.hpp>
#include <Observation.hpp>
#include <utils.hpp>
#include <Shifts.hpp>

int main(int argc, char *argv[]) {
  unsigned int padding = 0;
  AstroData::Observation observation;

  try {
    isa::utils::ArgumentList args(argc, argv);
    padding = args.getSwitchArgument< unsigned int >("-padding");
    observation.setFrequencyRange(args.getSwitchArgument< unsigned int >("-subbands"), args.getSwitchArgument< unsigned int >("-channels"), args.getSwitchArgument< float >("-min_freq"), args.getSwitchArgument< float >("-channel_bandwidth"));
    observation.setNrSamplesPerSecond(args.getSwitchArgument< unsigned int >("-samples"));
    observation.setDMRange(args.getSwitchArgument< unsigned int >("-dms"), args.getSwitchArgument< float >("-dm_first"), args.getSwitchArgument< float >("-dm_step"));
	} catch  ( isa::utils::SwitchNotFound &err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }catch ( std::exception &err ) {
    std::cerr << "Usage: " << argv[0] << " -padding ... -min_freq ... -channel_bandwidth ... -subbands ... -channels ... -samples ... -dms ... -dm_first ... -dm_step ..." << std::endl;
		return 1;
	}

  std::vector< float > * shifts = PulsarSearch::getShifts(observation, padding);

  for ( unsigned int channel = 0; channel < observation.getNrChannels(); channel++ ) {
    std::cout << shifts->at(channel) << " ";
  }
  std::cout << std::endl;

	return 0;
}

<|endoftext|>