<commit_before>/*
 * GeoIP C library binding for nodejs
 *
 * Licensed under the GNU LGPL 2.1 license
 */

#include "org.h"
#include "global.h"

Persistent<FunctionTemplate> geoip::Org::constructor_template;

void geoip::Org::Init(Handle<Object> target)
{
  HandleScope scope;

  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  constructor_template = Persistent<FunctionTemplate>::New(t);
  constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
  constructor_template->SetClassName(String::NewSymbol("geoip"));

  NODE_SET_PROTOTYPE_METHOD(constructor_template, "lookup", lookup);
  NODE_SET_PROTOTYPE_METHOD(constructor_template, "lookupSync", lookupSync);
  NODE_SET_PROTOTYPE_METHOD(constructor_template, "update", update);
  //NODE_SET_PROTOTYPE_METHOD(constructor_template, "close", close);
  target->Set(String::NewSymbol("Org"), constructor_template->GetFunction());
}

/*
   geoip::Org::Org()
   {
   }

   geoip::Org::~Org()
   {
   }
   */

Handle<Value> geoip::Org::New(const Arguments& args)
{
  HandleScope scope;

  Org *o = new Org();

  String::Utf8Value file_str(args[0]->ToString());
  const char * file_cstr = ToCString(file_str);
  //Local<String> path_str = args[0]->ToString();
  //char path_cstr[path_str->Length()];
  //path_str->WriteAscii(path_cstr);
  bool cache_on = args[1]->ToBoolean()->Value();

  o->db = GeoIP_open(file_cstr, cache_on?GEOIP_MEMORY_CACHE:GEOIP_STANDARD);

  if (o->db != NULL) {
    // Successfully opened the file, return 1 (true)
    o->db_edition = GeoIP_database_edition(o->db);
    if (o->db_edition == GEOIP_ORG_EDITION ||
        o->db_edition == GEOIP_ASNUM_EDITION ||
        o->db_edition == GEOIP_ISP_EDITION) {
      o->Wrap(args.This());
      return scope.Close(args.This());
    } else {
      GeoIP_delete(o->db);	// free()'s the gi reference & closes its fd
      o->db = NULL;
      return scope.Close(ThrowException(String::New("Error: Not valid org database")));
    }
  } else {
    return scope.Close(ThrowException(String::New("Error: Cannot open database")));
  }
}

Handle<Value> geoip::Org::lookupSync(const Arguments &args) {
  HandleScope scope;

  Local<String> host_str = args[0]->ToString();
  Local<Value> data;
  char host_cstr[host_str->Length()];
  host_str->WriteAscii(host_cstr);
  Org* o = ObjectWrap::Unwrap<geoip::Org>(args.This());

  uint32_t ipnum = _GeoIP_lookupaddress(host_cstr);
  if (ipnum <= 0) {
    return scope.Close(Null());
  }

  char *org = GeoIP_org_by_ipnum(o->db, ipnum);
  if (org == NULL) {
    return scope.Close(Null());
  }

  data = String::New(_GeoIP_iso_8859_1__utf8(org));
  return scope.Close(data);
}

Handle<Value> geoip::Org::lookup(const Arguments& args)
{
  HandleScope scope;

  REQ_FUN_ARG(1, cb);

  Org *o = ObjectWrap::Unwrap<geoip::Org>(args.This());
  Local<String> host_str = args[0]->ToString();
  char host_cstr[host_str->Length()];
  host_str->WriteAscii(host_cstr);

  org_baton_t *baton = new org_baton_t();
  baton->o = o;
  baton->ipnum = _GeoIP_lookupaddress(host_cstr);
  baton->cb = Persistent<Function>::New(cb);

  uv_work_t *req = new uv_work_t;
  req->data = baton;

  uv_queue_work(uv_default_loop(), req, EIO_Org, EIO_AfterOrg);

  return scope.Close(Undefined());
}

void geoip::Org::EIO_Org(uv_work_t *req)
{
  org_baton_t *baton = static_cast<org_baton_t *>(req->data);

  if (baton->ipnum <= 0) {
    baton->org = NULL;
  }

  baton->org = GeoIP_org_by_ipnum(baton->o->db, baton->ipnum);
}

void geoip::Org::EIO_AfterOrg(uv_work_t *req)
{
  HandleScope scope;

  org_baton_t *baton = static_cast<org_baton_t *>(req->data);

  Handle<Value> argv[2];

  if (baton->org == NULL) {
    argv[0] = Exception::Error(String::New("Data not found"));
    argv[1] = Null();
  } else {
    Local<String> data = String::New(_GeoIP_iso_8859_1__utf8(baton->org));

    argv[0] = Null();
    argv[1] = data;
  }

  TryCatch try_catch;
  baton->cb->Call(Context::GetCurrent()->Global(), 2, argv);

  // Cleanup
  baton->cb.Dispose();
  delete baton;
  delete req;

  if (try_catch.HasCaught()) {
    FatalException(try_catch);
  }
}

Handle<Value> geoip::Org::update(const Arguments &args) {
  Locker locker();

  HandleScope scope;

  Org* o = ObjectWrap::Unwrap<Org>(args.This());

  String::Utf8Value file_str(args[0]->ToString());
  const char * file_cstr = ToCString(file_str);

  bool cache_on = args[1]->ToBoolean()->Value();

  o->db = GeoIP_open(file_cstr, cache_on?GEOIP_MEMORY_CACHE:GEOIP_STANDARD);

  if (o->db != NULL) {
    o->db_edition = GeoIP_database_edition(o->db);
   if (o->db_edition == GEOIP_ORG_EDITION ||
       o->db_edition == GEOIP_ASNUM_EDITION ||
       o->db_edition == GEOIP_ISP_EDITION) {
      return scope.Close(True());
    } else {
      GeoIP_delete(o->db);	// free()'s the gi reference & closes its fd
      o->db = NULL;
      return scope.Close(ThrowException(String::New("Error: Not valid organization database")));
    }
  } else {
    return scope.Close(ThrowException(String::New("Error: Cannot open database")));
  }

 Unlocker unlocker();
}

void geoip::Org::close(const Arguments &args) {
  Org* o = ObjectWrap::Unwrap<geoip::Org>(args.This());
  GeoIP_delete(o->db);	// free()'s the gi reference & closes its fd
  o->db = NULL;
  HandleScope scope;	// Stick this down here since it seems to segfault when on top?
}
<commit_msg>reduce leakage in geoip::Org, still leaky<commit_after>/*
 * GeoIP C library binding for nodejs
 *
 * Licensed under the GNU LGPL 2.1 license
 */

#include "org.h"
#include "global.h"

Persistent<FunctionTemplate> geoip::Org::constructor_template;

void geoip::Org::Init(Handle<Object> target)
{
  HandleScope scope;

  Local<FunctionTemplate> t = FunctionTemplate::New(New);
  constructor_template = Persistent<FunctionTemplate>::New(t);
  constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
  constructor_template->SetClassName(String::NewSymbol("geoip"));

  NODE_SET_PROTOTYPE_METHOD(constructor_template, "lookup", lookup);
  NODE_SET_PROTOTYPE_METHOD(constructor_template, "lookupSync", lookupSync);
  NODE_SET_PROTOTYPE_METHOD(constructor_template, "update", update);
  //NODE_SET_PROTOTYPE_METHOD(constructor_template, "close", close);
  target->Set(String::NewSymbol("Org"), constructor_template->GetFunction());
}

/*
   geoip::Org::Org()
   {
   }

   geoip::Org::~Org()
   {
   }
   */

Handle<Value> geoip::Org::New(const Arguments& args)
{
  HandleScope scope;

  Org *o = new Org();

  String::Utf8Value file_str(args[0]->ToString());
  const char * file_cstr = ToCString(file_str);
  //Local<String> path_str = args[0]->ToString();
  //char path_cstr[path_str->Length()];
  //path_str->WriteAscii(path_cstr);
  bool cache_on = args[1]->ToBoolean()->Value();

  o->db = GeoIP_open(file_cstr, cache_on?GEOIP_MEMORY_CACHE:GEOIP_STANDARD);

  if (o->db != NULL) {
    // Successfully opened the file, return 1 (true)
    o->db_edition = GeoIP_database_edition(o->db);
    if (o->db_edition == GEOIP_ORG_EDITION ||
        o->db_edition == GEOIP_ASNUM_EDITION ||
        o->db_edition == GEOIP_ISP_EDITION) {
      o->Wrap(args.This());
      return scope.Close(args.This());
    } else {
      GeoIP_delete(o->db);	// free()'s the gi reference & closes its fd
      o->db = NULL;
      return scope.Close(ThrowException(String::New("Error: Not valid org database")));
    }
  } else {
    return scope.Close(ThrowException(String::New("Error: Cannot open database")));
  }
}

Handle<Value> geoip::Org::lookupSync(const Arguments &args) {
  HandleScope scope;

  Local<String> host_str = args[0]->ToString();
  Local<Value> data;
  char host_cstr[host_str->Length()];
  host_str->WriteAscii(host_cstr);
  Org* o = ObjectWrap::Unwrap<geoip::Org>(args.This());

  uint32_t ipnum = _GeoIP_lookupaddress(host_cstr);
  if (ipnum <= 0) {
    return scope.Close(Null());
  }

  char *org = GeoIP_org_by_ipnum(o->db, ipnum);
  if (org == NULL) {
    return scope.Close(Null());
  }

  data = String::New(_GeoIP_iso_8859_1__utf8(org));

  delete org;
  return scope.Close(data);
}

Handle<Value> geoip::Org::lookup(const Arguments& args)
{
  HandleScope scope;

  REQ_FUN_ARG(1, cb);

  Org *o = ObjectWrap::Unwrap<geoip::Org>(args.This());
  Local<String> host_str = args[0]->ToString();
  char host_cstr[host_str->Length()];
  host_str->WriteAscii(host_cstr);

  org_baton_t *baton = new org_baton_t();
  baton->o = o;
  baton->ipnum = _GeoIP_lookupaddress(host_cstr);
  baton->cb = Persistent<Function>::New(cb);

  uv_work_t *req = new uv_work_t;
  req->data = baton;

  uv_queue_work(uv_default_loop(), req, EIO_Org, EIO_AfterOrg);

  return scope.Close(Undefined());
}

void geoip::Org::EIO_Org(uv_work_t *req)
{
  org_baton_t *baton = static_cast<org_baton_t *>(req->data);

  if (baton->ipnum <= 0) {
    baton->org = NULL;
  }

  baton->org = GeoIP_org_by_ipnum(baton->o->db, baton->ipnum);
}

void geoip::Org::EIO_AfterOrg(uv_work_t *req)
{
  HandleScope scope;

  org_baton_t *baton = static_cast<org_baton_t *>(req->data);

  Handle<Value> argv[2];

  if (baton->org == NULL) {
    argv[0] = Exception::Error(String::New("Data not found"));
    argv[1] = Null();
  } else {
    Local<String> data = String::New(_GeoIP_iso_8859_1__utf8(baton->org));

    argv[0] = Null();
    argv[1] = data;
  }

  TryCatch try_catch;
  baton->cb->Call(Context::GetCurrent()->Global(), 2, argv);

  // Cleanup
  baton->cb.Dispose();
  delete baton;
  delete req;

  if (try_catch.HasCaught()) {
    FatalException(try_catch);
  }
}

Handle<Value> geoip::Org::update(const Arguments &args) {
  Locker locker();

  HandleScope scope;

  Org* o = ObjectWrap::Unwrap<Org>(args.This());

  String::Utf8Value file_str(args[0]->ToString());
  const char * file_cstr = ToCString(file_str);

  bool cache_on = args[1]->ToBoolean()->Value();

  o->db = GeoIP_open(file_cstr, cache_on?GEOIP_MEMORY_CACHE:GEOIP_STANDARD);

  if (o->db != NULL) {
    o->db_edition = GeoIP_database_edition(o->db);
   if (o->db_edition == GEOIP_ORG_EDITION ||
       o->db_edition == GEOIP_ASNUM_EDITION ||
       o->db_edition == GEOIP_ISP_EDITION) {
      return scope.Close(True());
    } else {
      GeoIP_delete(o->db);	// free()'s the gi reference & closes its fd
      o->db = NULL;
      return scope.Close(ThrowException(String::New("Error: Not valid organization database")));
    }
  } else {
    return scope.Close(ThrowException(String::New("Error: Cannot open database")));
  }

 Unlocker unlocker();
}

void geoip::Org::close(const Arguments &args) {
  Org* o = ObjectWrap::Unwrap<geoip::Org>(args.This());
  GeoIP_delete(o->db);	// free()'s the gi reference & closes its fd
  o->db = NULL;
  HandleScope scope;	// Stick this down here since it seems to segfault when on top?
}
<|endoftext|>


<commit_before>#include <mos/gfx/assets.hpp>
#include <cstring>
#include <filesystem/path.h>
#include <fstream>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/io.hpp>
#include <glm/gtx/matrix_decompose.hpp>
#include <mos/util.hpp>
#include <iostream>

namespace mos {
namespace gfx {
using namespace nlohmann;

Assets::Assets(const std::string directory) : directory_(directory) {}

Assets::~Assets() {}

Model Assets::model_value(const std::string &base_path, const json &value) {
  auto name = value.value("name", "");
  auto mesh_name = std::string("");
  if (!value["mesh"].is_null()) {
    mesh_name = value.value("mesh", "");
  }
  std::string material_name = "";
  if (!value["material"].is_null()) {
    material_name = value.value("material", "");
  }

  auto transform = jsonarray_to_mat4(value["transform"]);

  auto created_model = Model(
      name, mesh(base_path + mesh_name),
      transform,
      material(base_path + material_name));

  for (auto &m : value["children"]) {
	  std::string t = m;
    created_model.models.push_back(model(base_path + t));
  }
  return created_model;
}

Model Assets::model(const std::string &path) {
  std::cout << "Loading: " << path << std::endl;
  filesystem::path fpath = path;
  auto doc = json::parse(mos::text(directory_ + path));

  return model_value(fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/", doc);
}

Animation Assets::animation(const std::string &path) {
  auto doc = json::parse(mos::text(directory_ + path));
  auto frame_rate = doc["frame_rate"];
  std::map<unsigned int, std::shared_ptr<Mesh const>> keyframes;

  for (auto &keyframe : doc["keyframes"]) {
    auto key = keyframe["key"];
    auto mesh_path = keyframe["mesh"];
    keyframes.insert({key, mesh(mesh_path)});
  }
  Animation animation(keyframes, frame_rate);
  return animation;
}

std::shared_ptr<Mesh> Assets::mesh(const std::string &path) {
  if (meshes_.find(path) == meshes_.end()) {
    meshes_.insert(MeshPair(path, Mesh::load(directory_ + path)));
  }
  return meshes_.at(path);
}

std::shared_ptr<Texture2D>
Assets::texture(const std::string &path,
                      const bool color_data,
                      const bool mipmaps,
                      const Texture2D::Wrap &wrap) {
  if (!path.empty()) {
    if (textures_.find(path) == textures_.end()) {
      textures_.insert(TexturePair(path, Texture2D::load(directory_ + path, color_data, mipmaps, wrap)));
    }
    return textures_.at(path);
  } else {
    return std::shared_ptr<Texture2D>(nullptr);
  }
}

Material Assets::material(const std::string &path) {
  if (path.empty()) {
    return Material();
  } else {
    filesystem::path fpath = path;
    auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

    if (fpath.extension() == "material") {
      auto value = json::parse(mos::text(directory_ + fpath.str()));

      auto read_texture = [&](const std::string &name, const bool color_data = true) {
        std::string file_name = "";
        if (!value[name].is_null()) {
          file_name = value[name];
        }
        auto tex = file_name.empty() ? texture("") : texture(base_path + file_name, color_data);
        return tex;
      };

      auto albedo_map = read_texture("albedo_map");
      auto emission_map = read_texture("emission_map");
      auto normal_map = read_texture("normal_map");
      if (normal_map) {
        if (normal_map->format == Texture::Format::SRGB){
          normal_map->format = Texture::Format::RGB;
        }
        else if (normal_map->format == Texture::Format::SRGBA){
          normal_map->format = Texture::Format::RGBA;
        }
        //normal_map->format = normal_map->format == Texture::Format::SRGB ? Texture::Format::RGB : Texture::Format::RGBA;
      }
      auto metallic_map = read_texture("metallic_map");
      auto roughness_map = read_texture("roughness_map");
      auto ambient_occlusion_map = read_texture("ambient_occlusion_map");

      auto diffuse = glm::vec3(value["albedo"][0], value["albedo"][1], value["albedo"][2]);
      auto opacity = value["opacity"];
      auto roughness = value["roughness"];
      auto metallic = value["metallic"];
      auto emission = glm::vec3(value["emission"][0], value["emission"][1], value["emission"][2]);
      auto ambient_occlusion = value["ambient_occlusion"];
      return Material(albedo_map,
                      emission_map,
                      normal_map,
                      metallic_map,
                      roughness_map,
                      ambient_occlusion_map,
                      diffuse,
                      opacity,
                      roughness,
                      metallic,
                      emission);
    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
          " file format is not supported.");
    }
  }
}

Light Assets::light(const std::string &path) {
  if (path.empty()) {
    return Light();
  } else {
    filesystem::path fpath = path;
    auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

    if (fpath.extension() == "light") {
      auto value = json::parse(mos::text(directory_ + fpath.str()));

      auto transform = jsonarray_to_mat4(value["transform"]);
      auto position = glm::vec3(transform[3]);
      auto center = position + glm::vec3(transform * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));

	  std::string t = value["light"];
      auto data_value = json::parse(mos::text(directory_ + t));

      auto color = glm::vec3(data_value["color"][0],
                             data_value["color"][1],
                             data_value["color"][2]);
      auto strength = data_value["strength"];
      auto size = data_value["size"];
      auto blend = value["blend"];

      return Light(position,
                      center,
                      size,
                      color,
                      strength);
    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
          " file format is not supported.");
    }
  }
}

EnvironmentLight Assets::environment_light(const std::string &path) {
  filesystem::path fpath = path;
  auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

  if (fpath.extension() == "environment_light") {
    auto value = json::parse(mos::text(directory_ + fpath.str()));

    auto transform = jsonarray_to_mat4(value["transform"]);

    auto position = glm::vec3(transform[3]);

    glm::vec3 scale;
    glm::quat rotation;
    glm::vec3 translation;
    glm::vec3 skew;
    glm::vec4 perspective;
    glm::decompose(transform, scale, rotation, translation, skew, perspective);

    auto extent = float(value["extent"]) * scale;
    auto strength = value.value("strength", 1.0f);
    auto resolution = value.value("resolution", 128.0f);

    return EnvironmentLight(position,
                 extent,
                 strength,
                 glm::uvec2(resolution));
  } else {
    throw std::runtime_error(path.substr(path.find_last_of(".")) +
        " file format is not supported.");
  }
}

void Assets::clear_unused() {
  for (auto it = textures_.begin(); it != textures_.end();) {
    if (it->second.use_count() <= 1) {
      textures_.erase(it++);
    } else {
      ++it;
    }
  }
  for (auto it = meshes_.begin(); it != meshes_.end();) {
    if (it->second.use_count() <= 1) {
      meshes_.erase(it++);
    } else {
      ++it;
    }
  }
}
std::string Assets::directory() const {
  return directory_;
}

}
}
<commit_msg>Assset fix.<commit_after>#include <mos/gfx/assets.hpp>
#include <cstring>
#include <filesystem/path.h>
#include <fstream>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/io.hpp>
#include <glm/gtx/matrix_decompose.hpp>
#include <mos/util.hpp>
#include <iostream>

namespace mos {
namespace gfx {
using namespace nlohmann;

Assets::Assets(const std::string directory) : directory_(directory) {}

Assets::~Assets() {}

Model Assets::model_value(const std::string &base_path, const json &value) {
  auto name = value.value("name", "");
  auto mesh_name = std::string("");
  if (!value["mesh"].is_null()) {
    mesh_name = value.value("mesh", "");
  }
  std::string material_name = "";
  if (!value["material"].is_null()) {
    material_name = value.value("material", "");
  }

  auto transform = jsonarray_to_mat4(value["transform"]);

  auto created_model = Model(
      name, mesh(base_path + mesh_name),
      transform,
      material(base_path + material_name));

  for (auto &m : value["children"]) {
    filesystem::path t = std::string(m);
    if(t.extension() == "model") {
      created_model.models.push_back(model(base_path + t.str()));
    }
  }
  return created_model;
}

Model Assets::model(const std::string &path) {
  std::cout << "Loading: " << path << std::endl;
  filesystem::path fpath = path;
  auto doc = json::parse(mos::text(directory_ + path));

  return model_value(fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/", doc);
}

Animation Assets::animation(const std::string &path) {
  auto doc = json::parse(mos::text(directory_ + path));
  auto frame_rate = doc["frame_rate"];
  std::map<unsigned int, std::shared_ptr<Mesh const>> keyframes;

  for (auto &keyframe : doc["keyframes"]) {
    auto key = keyframe["key"];
    auto mesh_path = keyframe["mesh"];
    keyframes.insert({key, mesh(mesh_path)});
  }
  Animation animation(keyframes, frame_rate);
  return animation;
}

std::shared_ptr<Mesh> Assets::mesh(const std::string &path) {
  if (meshes_.find(path) == meshes_.end()) {
    meshes_.insert(MeshPair(path, Mesh::load(directory_ + path)));
  }
  return meshes_.at(path);
}

std::shared_ptr<Texture2D>
Assets::texture(const std::string &path,
                      const bool color_data,
                      const bool mipmaps,
                      const Texture2D::Wrap &wrap) {
  if (!path.empty()) {
    if (textures_.find(path) == textures_.end()) {
      textures_.insert(TexturePair(path, Texture2D::load(directory_ + path, color_data, mipmaps, wrap)));
    }
    return textures_.at(path);
  } else {
    return std::shared_ptr<Texture2D>(nullptr);
  }
}

Material Assets::material(const std::string &path) {
  if (path.empty()) {
    return Material();
  } else {
    filesystem::path fpath = path;
    auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

    if (fpath.extension() == "material") {
      auto value = json::parse(mos::text(directory_ + fpath.str()));

      auto read_texture = [&](const std::string &name, const bool color_data = true) {
        std::string file_name = "";
        if (!value[name].is_null()) {
          file_name = value[name];
        }
        auto tex = file_name.empty() ? texture("") : texture(base_path + file_name, color_data);
        return tex;
      };

      auto albedo_map = read_texture("albedo_map");
      auto emission_map = read_texture("emission_map");
      auto normal_map = read_texture("normal_map");
      if (normal_map) {
        if (normal_map->format == Texture::Format::SRGB){
          normal_map->format = Texture::Format::RGB;
        }
        else if (normal_map->format == Texture::Format::SRGBA){
          normal_map->format = Texture::Format::RGBA;
        }
        //normal_map->format = normal_map->format == Texture::Format::SRGB ? Texture::Format::RGB : Texture::Format::RGBA;
      }
      auto metallic_map = read_texture("metallic_map");
      auto roughness_map = read_texture("roughness_map");
      auto ambient_occlusion_map = read_texture("ambient_occlusion_map");

      auto diffuse = glm::vec3(value["albedo"][0], value["albedo"][1], value["albedo"][2]);
      auto opacity = value["opacity"];
      auto roughness = value["roughness"];
      auto metallic = value["metallic"];
      auto emission = glm::vec3(value["emission"][0], value["emission"][1], value["emission"][2]);
      auto ambient_occlusion = value["ambient_occlusion"];
      return Material(albedo_map,
                      emission_map,
                      normal_map,
                      metallic_map,
                      roughness_map,
                      ambient_occlusion_map,
                      diffuse,
                      opacity,
                      roughness,
                      metallic,
                      emission);
    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
          " file format is not supported.");
    }
  }
}

Light Assets::light(const std::string &path) {
  if (path.empty()) {
    return Light();
  } else {
    filesystem::path fpath = path;
    auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

    if (fpath.extension() == "light") {
      auto value = json::parse(mos::text(directory_ + fpath.str()));

      auto transform = jsonarray_to_mat4(value["transform"]);
      auto position = glm::vec3(transform[3]);
      auto center = position + glm::vec3(transform * glm::vec4(0.0f, 0.0f, -1.0f, 0.0f));

	  std::string t = value["light"];
      auto data_value = json::parse(mos::text(directory_ + t));

      auto color = glm::vec3(data_value["color"][0],
                             data_value["color"][1],
                             data_value["color"][2]);
      auto strength = data_value["strength"];
      auto size = data_value["size"];
      auto blend = value["blend"];

      return Light(position,
                      center,
                      size,
                      color,
                      strength);
    } else {
      throw std::runtime_error(path.substr(path.find_last_of(".")) +
          " file format is not supported.");
    }
  }
}

EnvironmentLight Assets::environment_light(const std::string &path) {
  filesystem::path fpath = path;
  auto base_path = fpath.parent_path().empty() ? "" : fpath.parent_path().str() + "/";

  if (fpath.extension() == "environment_light") {
    auto value = json::parse(mos::text(directory_ + fpath.str()));

    auto transform = jsonarray_to_mat4(value["transform"]);

    auto position = glm::vec3(transform[3]);

    glm::vec3 scale;
    glm::quat rotation;
    glm::vec3 translation;
    glm::vec3 skew;
    glm::vec4 perspective;
    glm::decompose(transform, scale, rotation, translation, skew, perspective);

    auto extent = float(value["extent"]) * scale;
    auto strength = value.value("strength", 1.0f);
    auto resolution = value.value("resolution", 128.0f);

    return EnvironmentLight(position,
                 extent,
                 strength,
                 glm::uvec2(resolution));
  } else {
    throw std::runtime_error(path.substr(path.find_last_of(".")) +
        " file format is not supported.");
  }
}

void Assets::clear_unused() {
  for (auto it = textures_.begin(); it != textures_.end();) {
    if (it->second.use_count() <= 1) {
      textures_.erase(it++);
    } else {
      ++it;
    }
  }
  for (auto it = meshes_.begin(); it != meshes_.end();) {
    if (it->second.use_count() <= 1) {
      meshes_.erase(it++);
    } else {
      ++it;
    }
  }
}
std::string Assets::directory() const {
  return directory_;
}

}
}
<|endoftext|>


<commit_before>#include "./anchor_force.h"
#include <Eigen/Core>
#include "./label_state.h"

namespace Forces
{
AnchorForce::AnchorForce() : Force(0.01f)
{
}

Eigen::Vector2f AnchorForce::calculate(LabelState &label,
                                       std::vector<LabelState> &labels,
                                       const LabellerFrameData &frameData)
{
  return (label.anchorPosition2D - label.labelPosition2D).normalized() * weight;
}
}  // namespace Forces
<commit_msg>Adapt anchor force according to Stadler et al.<commit_after>#include "./anchor_force.h"
#include <Eigen/Core>
#include "./label_state.h"

namespace Forces
{
AnchorForce::AnchorForce() : Force(0.01f)
{
}

Eigen::Vector2f AnchorForce::calculate(LabelState &label,
                                       std::vector<LabelState> &labels,
                                       const LabellerFrameData &frameData)
{
  const float epsilon = 0.01f;
  Eigen::Vector2f diff = label.anchorPosition2D - label.labelPosition2D;
  float distance = diff.norm();
  float d = std::max(epsilon, distance);
  float factor = d > 0.2f ? 1.0f : 0.0f;
  return (d - 2 + 1/d) * factor * diff.normalized() * frameData.frameTime;
}
}  // namespace Forces
<|endoftext|>


<commit_before>#include <v8.h>
#include <node.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/time.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <assert.h>
#include "node_defs.h"

using namespace v8;
using namespace node;
using namespace std;

// This ICMP code was written by somebody else
// Slight modifications were made by me to remove logging/integrate with V8
// Found it on a forum - no license was attached.
// Will try to google for it again later
uint16_t in_cksum(uint16_t *addr, unsigned len);

#define DEFDATALEN  (64-ICMP_MINLEN)  /* default data length */
#define MAXIPLEN  60
#define MAXICMPLEN  76
#define MAXPACKET (65536 - 60 - ICMP_MINLEN)/* max packet size */

int ping(const char* targ)
{

  int s, i, cc, packlen, datalen = DEFDATALEN;
  struct hostent *hp;
  struct sockaddr_in to, from;
  struct ip *ip;
  u_char *packet, outpack[MAXPACKET];
  char hnamebuf[MAXHOSTNAMELEN];
  string hostname;
  struct icmp *icp;
  int ret, fromlen, hlen;
  fd_set rfds;
  struct timeval tv;
  int retval;
  struct timeval start, end;
  int end_t;
  bool cont = true;

  to.sin_family = AF_INET;

  // try to convert as dotted decimal address, else if that fails assume it's a hostname
  to.sin_addr.s_addr = inet_addr(targ);
  if (to.sin_addr.s_addr != (u_int)-1)
    hostname = string(targ);
  else
  {
    hp = gethostbyname(targ);
    if (!hp)
    {
      return -1;
    }
    to.sin_family = hp->h_addrtype;
    bcopy(hp->h_addr, (caddr_t)&to.sin_addr, hp->h_length);
    strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
    hostname = hnamebuf;
  }
  packlen = datalen + MAXIPLEN + MAXICMPLEN;
  if ( (packet = (u_char *)malloc((u_int)packlen)) == NULL)
  {
    cerr << "malloc error\n";
    return -1;
  }

  if ( (s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
  {
    perror("socket"); /* probably not running as superuser */
    return -1;
  }

  icp = (struct icmp *)outpack;
  icp->icmp_type = ICMP_ECHO;
  icp->icmp_code = 0;
  icp->icmp_cksum = 0;
  icp->icmp_seq = 12345;  /* seq and id must be reflected */
  icp->icmp_id = getpid();

  cc = datalen + ICMP_MINLEN;
  icp->icmp_cksum = in_cksum((unsigned short *)icp,cc);

  gettimeofday(&start, NULL);

  i = sendto(s, (char *)outpack, cc, 0, (struct sockaddr*)&to, (socklen_t)sizeof(struct sockaddr_in));
  if (i < 0 || i != cc)
  {
    if (i < 0)
      perror("sendto error");
  }

  // Watch stdin (fd 0) to see when it has input.
  FD_ZERO(&rfds);
  FD_SET(s, &rfds);
  // Wait up to one seconds.
  tv.tv_sec = 1;
  tv.tv_usec = 0;

  while(cont)
  {
    retval = select(s+1, &rfds, NULL, NULL, &tv);
    if (retval == -1)
    {
      perror("select()");
      return -1;
    }
    else if (retval)
    {
      fromlen = sizeof(sockaddr_in);
      if ( (ret = recvfrom(s, (char *)packet, packlen, 0,(struct sockaddr *)&from, (socklen_t*)&fromlen)) < 0)
      {
        perror("recvfrom error");
        return -1;
      }

      // Check the IP header
      ip = (struct ip *)((char*)packet);
      hlen = sizeof( struct ip );
      if (ret < (hlen + ICMP_MINLEN))
      {
        return -1;
      }

      // Now the ICMP part
      icp = (struct icmp *)(packet + hlen);
      if (icp->icmp_type == ICMP_ECHOREPLY)
      {
        if (icp->icmp_seq != 12345)
        {
          continue;
        }
        if (icp->icmp_id != getpid())
        {
          continue;
        }
        cont = false;
      }
      else
      {
        continue;
      }

      gettimeofday(&end, NULL);
      end_t = 1000000*(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec);

      if(end_t < 1)
        end_t = 1;

      return end_t;
    }
    else
    {
      return 0;
    }
  }
  return 0;
}

uint16_t in_cksum(uint16_t *addr, unsigned len)
{
  uint16_t answer = 0;
  /*
   * Our algorithm is simple, using a 32 bit accumulator (sum), we add
   * sequential 16 bit words to it, and at the end, fold back all the
   * carry bits from the top 16 bits into the lower 16 bits.
   */
  uint32_t sum = 0;
  while (len > 1)  {
    sum += *addr++;
    len -= 2;
  }

  // mop up an odd byte, if necessary
  if (len == 1) {
    *(unsigned char *)&answer = *(unsigned char *)addr ;
    sum += answer;
  }

  // add back carry outs from top 16 bits to low 16 bits
  sum = (sum >> 16) + (sum & 0xffff); // add high 16 to low 16
  sum += (sum >> 16); // add carry
  answer = ~sum; // truncate to 16 bits
  return answer;
}

Handle<Value> Ping(const Arguments &args)
{
    HandleScope scope;

    // Check args
    ARG_CHECK_STRING(0, 'host');
    ARG_CHECK_OPTIONAL_FUNCTION(1, 'callback');

    String::Utf8Value host(args[0]->ToString());
    const char* ac = *host;

    // Do ping
    int ret;
    Unlocker ul;
    ret = ping(ac);
    Locker l;
    Handle<Boolean> res;
    if (ret > 0) {
        res = True();
    } else {
        res = False();
    }

    if (args.Length() > 1){
      //Set up callback
      Local<Function> cb = Local<Function>::Cast(args[1]);
      unsigned cbargc = 1;
      Handle<Value> cbargv[cbargc];
      cbargv[0] = res;

      //Run callback
      cb->Call(Context::GetCurrent()->Global(), cbargc, cbargv);
      return scope.Close(Undefined());
    } else {
      return scope.Close(res);
    }
}

extern "C" {
    static void init (Handle<Object> target)
    {
        HandleScope scope;
        target->Set(NODE_SYMBOL("ping"), FunctionTemplate::New(Ping)->GetFunction());
    }

    NODE_MODULE(pinger, init);
}<commit_msg>Patched to return resolved IP of host that returned the ping<commit_after>#include <v8.h>
#include <node.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/time.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream>
#include <assert.h>
#include "node_defs.h"

using namespace v8;
using namespace node;
using namespace std;

typedef struct {
  int ret;
  in_addr ip;
} PingResponse;

// This ICMP code was written by somebody else
// Slight modifications were made by me to remove logging/integrate with V8
// Found it on a forum - no license was attached.
// Will try to google for it again later
uint16_t in_cksum(uint16_t *addr, unsigned len);

#define DEFDATALEN  (64-ICMP_MINLEN)  /* default data length */
#define MAXIPLEN  60
#define MAXICMPLEN  76
#define MAXPACKET (65536 - 60 - ICMP_MINLEN)/* max packet size */

PingResponse ping(const char* targ)
{

  int s, i, cc, packlen, datalen = DEFDATALEN;
  struct hostent *hp;
  struct sockaddr_in to, from;
  struct ip *ip;
  u_char *packet, outpack[MAXPACKET];
  char hnamebuf[MAXHOSTNAMELEN];
  string hostname;
  struct icmp *icp;
  int fromlen, hlen;
  PingResponse ret;
  fd_set rfds;
  struct timeval tv;
  int retval;
  struct timeval start, end;
  int end_t;
  bool cont = true;

  to.sin_family = AF_INET;

  // try to convert as dotted decimal address, else if that fails assume it's a hostname
  to.sin_addr.s_addr = inet_addr(targ);
  if (to.sin_addr.s_addr != (u_int)-1)
  {
    hostname = string(targ);
    ret.ip = to.sin_addr;
  }
  else
  {
    hp = gethostbyname(targ);
    if (!hp)
    {
      ret.ret = -1;
      return ret;
    }
    to.sin_family = hp->h_addrtype;
    bcopy(hp->h_addr, (caddr_t)&to.sin_addr, hp->h_length);
    ret.ip = to.sin_addr;
    strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
    hostname = hnamebuf;
  }
  packlen = datalen + MAXIPLEN + MAXICMPLEN;
  if ( (packet = (u_char *)malloc((u_int)packlen)) == NULL)
  {
    cerr << "malloc error\n";
    ret.ret = -1;
    return ret;
  }

  if ( (s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
  {
    perror("socket"); /* probably not running as superuser */
    ret.ret = -1;
    return ret;
  }

  icp = (struct icmp *)outpack;
  icp->icmp_type = ICMP_ECHO;
  icp->icmp_code = 0;
  icp->icmp_cksum = 0;
  icp->icmp_seq = 12345;  /* seq and id must be reflected */
  icp->icmp_id = getpid();

  cc = datalen + ICMP_MINLEN;
  icp->icmp_cksum = in_cksum((unsigned short *)icp,cc);

  gettimeofday(&start, NULL);

  i = sendto(s, (char *)outpack, cc, 0, (struct sockaddr*)&to, (socklen_t)sizeof(struct sockaddr_in));
  if (i < 0 || i != cc)
  {
    if (i < 0)
      perror("sendto error");
  }

  // Watch stdin (fd 0) to see when it has input.
  FD_ZERO(&rfds);
  FD_SET(s, &rfds);
  // Wait up to one seconds.
  tv.tv_sec = 1;
  tv.tv_usec = 0;

  while(cont)
  {
    retval = select(s+1, &rfds, NULL, NULL, &tv);
    if (retval == -1)
    {
      perror("select()");
      ret.ret = -1;
      return ret;
    }
    else if (retval)
    {
      fromlen = sizeof(sockaddr_in);
      if ( (ret.ret = recvfrom(s, (char *)packet, packlen, 0,(struct sockaddr *)&from, (socklen_t*)&fromlen)) < 0)
      {
        perror("recvfrom error");
        ret.ret = -1;
        return ret;
      }

      // Check the IP header
      ip = (struct ip *)((char*)packet);
      hlen = sizeof( struct ip );
      if (ret.ret < (hlen + ICMP_MINLEN))
      {
        ret.ret = -1;
        return ret;
      }

      // Now the ICMP part
      icp = (struct icmp *)(packet + hlen);
      if (icp->icmp_type == ICMP_ECHOREPLY)
      {
        if (icp->icmp_seq != 12345)
        {
          continue;
        }
        if (icp->icmp_id != getpid())
        {
          continue;
        }
        cont = false;
      }
      else
      {
        continue;
      }

      gettimeofday(&end, NULL);
      end_t = 1000000*(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec);

      if(end_t < 1)
        end_t = 1;

      ret.ret = end_t;
      return ret;
    }
    else
    {
      ret.ret = 0;
      return ret;
    }
  }
  ret.ret = 0;
  return ret;
}

uint16_t in_cksum(uint16_t *addr, unsigned len)
{
  uint16_t answer = 0;
  /*
   * Our algorithm is simple, using a 32 bit accumulator (sum), we add
   * sequential 16 bit words to it, and at the end, fold back all the
   * carry bits from the top 16 bits into the lower 16 bits.
   */
  uint32_t sum = 0;
  while (len > 1)  {
    sum += *addr++;
    len -= 2;
  }

  // mop up an odd byte, if necessary
  if (len == 1) {
    *(unsigned char *)&answer = *(unsigned char *)addr ;
    sum += answer;
  }

  // add back carry outs from top 16 bits to low 16 bits
  sum = (sum >> 16) + (sum & 0xffff); // add high 16 to low 16
  sum += (sum >> 16); // add carry
  answer = ~sum; // truncate to 16 bits
  return answer;
}

Handle<Value> Ping(const Arguments &args)
{
    HandleScope scope;

    // Check args
    ARG_CHECK_STRING(0, 'host');
    ARG_CHECK_OPTIONAL_FUNCTION(1, 'callback');

    String::Utf8Value host(args[0]->ToString());
    const char* ac = *host;

    // Do ping
    PingResponse ret;
    Unlocker ul;
    ret = ping(ac);
    Locker l;
    Handle<Boolean> res;
    if (ret.ret > 0) {
        res = True();
    } else {
        res = False();
    }

    if (args.Length() > 1){
      //Set up callback
      Local<Function> cb = Local<Function>::Cast(args[1]);
      unsigned cbargc = 3;
      Handle<Value> cbargv[cbargc];
      cbargv[0] = res;
      cbargv[1] = Local<Value>::New(Number::New(ret.ret));
      char* host = inet_ntoa(ret.ip);
      cbargv[2] = Local<Value>::New(String::New(host));
      //Run callback
      cb->Call(Context::GetCurrent()->Global(), cbargc, cbargv);
      return scope.Close(Undefined());
    } else {
      return scope.Close(res);
    }
}

extern "C" {
    static void init (Handle<Object> target)
    {
        HandleScope scope;
        target->Set(NODE_SYMBOL("ping"), FunctionTemplate::New(Ping)->GetFunction());
    }

    NODE_MODULE(pinger, init);
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "config.h"
#include <assert.h>
#include <poll.h>
#include <fcntl.h>

#include <memcached/engine.h>
#include <memcached/protocol_binary.h>

#include "ep_engine.h"

class BinaryMessage {
public:
    BinaryMessage() : size(0) {
        data.rawBytes = NULL;
    }

    BinaryMessage(const protocol_binary_request_header &h) throw (std::runtime_error)
        : size(ntohl(h.request.bodylen) + sizeof(h.bytes))
    {
        // verify the internal
        if (h.request.magic != PROTOCOL_BINARY_REQ &&
            h.request.magic != PROTOCOL_BINARY_RES) {
            throw std::runtime_error("Invalid package detected on the wire");
        }
        data.rawBytes = new char[size];
        memcpy(data.rawBytes, reinterpret_cast<const char*>(&h),
               sizeof(h.bytes));
    }

    virtual ~BinaryMessage() {
        delete []data.rawBytes;
    }

    size_t size;
    union {
        protocol_binary_request_header *req;
        protocol_binary_request_tap_no_extras *tap;
        protocol_binary_request_tap_connect *tap_connect;
        protocol_binary_request_tap_mutation *mutation;
        protocol_binary_request_tap_delete *remove;
        protocol_binary_request_tap_flush *flush;
        protocol_binary_request_tap_opaque *opaque;
        protocol_binary_request_tap_vbucket_set *vs;
        char *rawBytes;
    } data;
};

class TapConnectBinaryMessage : public BinaryMessage {
public:
    TapConnectBinaryMessage(const std::string &id, uint32_t flags,
                            uint64_t backfill) {
        size = sizeof(data.tap_connect->bytes) + id.length();
        if (flags & TAP_CONNECT_FLAG_BACKFILL) {
            size += sizeof(backfill);
        }
        data.rawBytes = new char[size];
        data.req->request.magic = PROTOCOL_BINARY_REQ;
        data.req->request.opcode = PROTOCOL_BINARY_CMD_TAP_CONNECT;
        data.req->request.keylen = ntohs(static_cast<uint16_t>(id.length()));
        data.req->request.extlen = 4;
        data.req->request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        data.req->request.vbucket = 0;
        uint32_t bodylen = size - sizeof(data.req->bytes);
        data.req->request.bodylen = htonl(bodylen);;
        data.req->request.opaque = 0xcafecafe;
        data.req->request.cas = 0;
        data.tap_connect->message.body.flags = htonl(flags);
        char *ptr = data.rawBytes + sizeof(data.tap_connect->bytes);
        memcpy(ptr, id.c_str(), id.length());
        ptr += id.length();

        if (flags & TAP_CONNECT_FLAG_BACKFILL) {
            backfill = htonll(backfill);
            memcpy(ptr, &backfill, sizeof(backfill));
        }
    }
};

void TapClientConnection::resolve(void) throw (std::runtime_error) {
    if (ai == NULL) {
        struct addrinfo hints;
        std::memset(&hints, 0, sizeof(hints));
        hints.ai_flags = AI_PASSIVE;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_family = AF_UNSPEC;

        std::string host = peer;
        std::string port = "11211";
        ssize_t s = host.find(":");
        if (s != -1) {
            port = host.substr(s + 1);
            host = host.substr(0, s);
        }

        int error = getaddrinfo(host.c_str(), port.c_str(), &hints, &ai);
        if (error != 0) {
            std::stringstream ss;
            ss << "getaddrinfo(): "
               << (error != EAI_SYSTEM) ? gai_strerror(error) : strerror(error);
            throw std::runtime_error(ss.str());
        }
    }
}

void TapClientConnection::createSocket() throw (std::runtime_error) {
    for (struct addrinfo *next= ai; next; next= next->ai_next) {
        if ((sock = socket(ai->ai_family, SOCK_STREAM,
                           ai->ai_protocol)) != -1) {
            break;
        }
    }

    if (sock == -1) {
        throw std::runtime_error("Failed to create socket");
    }

    int fl;
    if ((fl = fcntl(sock, F_GETFL, 0)) < 0) {
        std::stringstream msg;
        msg << "Failed to get current flags: " << strerror(errno);
        throw std::runtime_error(msg.str());
    }

    if ((fl & O_NONBLOCK) != O_NONBLOCK) {
        if (fcntl(sock, F_SETFL, fl | O_NONBLOCK) < 0) {
            std::stringstream msg;
            msg << "Failed to enable O_NONBLOCK: " << strerror(errno);
            throw std::runtime_error(msg.str());
        }
    }
}

bool TapClientConnection::connect() throw (std::runtime_error) {
    // create socket and make it nonblocking
    if (!connected) {
        resolve();
        if (sock == -1) {
            createSocket();
        }

        while (::connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
            if (errno == EINPROGRESS || errno == EALREADY) {
                return false;
            } else if (errno == EISCONN) {
                TapConnectBinaryMessage msg(tapId, flags, backfillage);
                connected = true;
                if (send(sock, msg.data.rawBytes, msg.size, 0) !=
                    static_cast<ssize_t>(msg.size)) {
                    // It's unlikely that we're not able to send that few
                    // bytes, so just retry if it happens..
                    setFailed();
                    return false;
                }
                return true;
            } else if (errno != EINTR) {
                /* A real problem occured */
                std::stringstream msg;
                msg << "Failed to connect: " << strerror(errno);
                throw std::runtime_error(msg.str());
            }
        }
    }

    return true;
}

void TapClientConnection::run() {
    LockHolder lh(mutex);
    while (!terminate) {
        lh.unlock();
        try {
            if (retry_interval == 0) {
                if (connect()) {
                    consume();
                }
            } else {
                --retry_interval;
            }

            if (connected) {
                wait(POLLIN);
            } else if (sock == -1) {
                wait(0);
            } else {
                if (!wait(POLLOUT)) {
                    --connect_timeout;
                    if (connect_timeout == 0) {
                        setFailed();
                        if (!shouldRetry()) {
                            terminate = true;
                        }
                    }
                }
            }
        } catch (std::runtime_error &e) {
            std::stringstream msg;
            msg << "An exception occured in the tap stream: " << e.what()
                << std::endl;
            getLogger()->log(EXTENSION_LOG_DEBUG, NULL, msg.str().c_str());
            setFailed();
        }
        lh.lock();
    }

    if (connected) {
        (void)close(sock);
        sock = -1;
        connected = false;
    }

    running = false;
    zombie = true;
}

bool TapClientConnection::wait(short mask) throw (std::runtime_error) {
    struct pollfd fds[1];
    fds[0].fd = sock;
    fds[0].events = mask;
    int error = poll(fds, 1, 1000);

    if (error != 1 || fds[0].revents & POLLERR) {
        if (fds[0].revents & POLLERR) {
            int err;
            socklen_t len = sizeof(err);
            (void)getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len);
            std::stringstream msg;
            msg << "Error on TAP client stream: ";
            if (err == 0) {
                msg << errno;
            } else {
                msg << err;
            }
            (void)close(sock);
            sock = -1;
            throw std::runtime_error(msg.str());
        }

        return false;
    }

    return true;
}

void TapClientConnection::apply() {
    /* Call the tap notify function!! */
    protocol_binary_request_tap_no_extras *tap = message->data.tap;
    uint16_t nengine = ntohs(tap->message.body.tap.enginespecific_length);
    uint16_t tap_flags = ntohs(tap->message.body.tap.flags);
    uint32_t seqno = ntohl(tap->message.header.request.opaque);
    uint8_t ttl = tap->message.body.tap.ttl;
    char *engine_specific = message->data.rawBytes + sizeof(tap->bytes);
    char *key = engine_specific + nengine;
    uint16_t nkey = ntohs(tap->message.header.request.keylen);
    char *data = key + nkey;
    uint32_t fl = 0;
    uint32_t exptime = 0;
    uint32_t ndata = ntohl(tap->message.header.request.bodylen) - nengine - nkey - 8;
    uint16_t vbucket = ntohs(tap->message.header.request.vbucket);
    uint64_t cas = ntohll(tap->message.header.request.cas);
    tap_event_t event = TAP_OPAQUE;
    bool ignore = false;

    switch (tap->message.header.request.opcode) {
    case PROTOCOL_BINARY_CMD_TAP_MUTATION:
        event = TAP_MUTATION;
        break;
    case PROTOCOL_BINARY_CMD_TAP_DELETE:
        event = TAP_DELETION;
        break;
    case PROTOCOL_BINARY_CMD_TAP_FLUSH:
        event = TAP_FLUSH;
        break;
    case PROTOCOL_BINARY_CMD_TAP_OPAQUE:
        event = TAP_OPAQUE;
        break;
    case PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET:
        event = TAP_VBUCKET_SET;
        break;
    default:
        ignore = true;
    }

    if (ignore) {
        getLogger()->log(EXTENSION_LOG_DEBUG, NULL,
                         "Ignoring unknown packet on tap stream: 0x%02x\n",
                         static_cast<unsigned int>(tap->message.header.request.opcode));
    } else {
        if (event == TAP_MUTATION) {
            protocol_binary_request_tap_mutation *mutation;
            mutation = message->data.mutation;
            fl = ntohl(mutation->message.body.item.flags);
            exptime = ntohl(mutation->message.body.item.expiration);
            key += 8;
            data += 8;
            ndata -= 8;
        }

        ENGINE_ERROR_CODE ret;
        ret = engine->tapNotify(NULL,
                                engine_specific, nengine,
                                ttl - 1, tap_flags, event, seqno,
                                key, nkey, fl, exptime,
                                cas, data, ndata, vbucket);

        switch (ret) {
        case ENGINE_SUCCESS:
            break;
        case ENGINE_DISCONNECT:
            terminate = true;
            // FALLTHROUGH
        default:
            getLogger()->log(EXTENSION_LOG_DEBUG, NULL,
                             "tapNotify returned: %d\n", static_cast<int>(ret));
        }

        if (ret == ENGINE_DISCONNECT) {
            terminate = true;
        }
    }
}

void TapClientConnection::consume() {
    LockHolder lh(mutex);
    do {
        lh.unlock();
        char *dst;
        size_t nbytes;
        ssize_t nr;

        if (message == NULL) {
            dst = reinterpret_cast<char*>(&header) + offset;
            nbytes = sizeof(header.bytes) - offset;
        } else {
            dst = message->data.rawBytes + sizeof(header.bytes) + offset;
            nbytes = ntohl(header.request.bodylen) - offset;
        }

        if ((nr = recv(sock, dst, nbytes, 0)) == -1) {
            switch (errno) {
            case EINTR:
                break;
            case EWOULDBLOCK:
                return;
            default:
                std::stringstream msg;
                msg << "Failed to read from socket: " << strerror(errno);
                throw std::runtime_error(msg.str());
            }
        } else if (nr == 0) {
            throw std::runtime_error("stream closed");
        }

        offset += nr;
        if (nr == static_cast<ssize_t>(nbytes)) {
            // we got everything..
            offset = 0;
            if (message == NULL) {
                message = new BinaryMessage(header);
            } else {
                /* Call the tap notify function!! */
                apply();
                delete message;
                message = NULL;
            }
        }

        lh.lock();
    } while (!terminate);
}

void* tapClientConnectionMain(void *arg)
{
    TapClientConnection *conn = reinterpret_cast<TapClientConnection*>(arg);
    conn->run();
    return NULL;
}
<commit_msg>Fixed incorrect handling of EINTR in tapclient<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include "config.h"
#include <assert.h>
#include <poll.h>
#include <fcntl.h>

#include <memcached/engine.h>
#include <memcached/protocol_binary.h>

#include "ep_engine.h"

class BinaryMessage {
public:
    BinaryMessage() : size(0) {
        data.rawBytes = NULL;
    }

    BinaryMessage(const protocol_binary_request_header &h) throw (std::runtime_error)
        : size(ntohl(h.request.bodylen) + sizeof(h.bytes))
    {
        // verify the internal
        if (h.request.magic != PROTOCOL_BINARY_REQ &&
            h.request.magic != PROTOCOL_BINARY_RES) {
            throw std::runtime_error("Invalid package detected on the wire");
        }
        data.rawBytes = new char[size];
        memcpy(data.rawBytes, reinterpret_cast<const char*>(&h),
               sizeof(h.bytes));
    }

    virtual ~BinaryMessage() {
        delete []data.rawBytes;
    }

    size_t size;
    union {
        protocol_binary_request_header *req;
        protocol_binary_request_tap_no_extras *tap;
        protocol_binary_request_tap_connect *tap_connect;
        protocol_binary_request_tap_mutation *mutation;
        protocol_binary_request_tap_delete *remove;
        protocol_binary_request_tap_flush *flush;
        protocol_binary_request_tap_opaque *opaque;
        protocol_binary_request_tap_vbucket_set *vs;
        char *rawBytes;
    } data;
};

class TapConnectBinaryMessage : public BinaryMessage {
public:
    TapConnectBinaryMessage(const std::string &id, uint32_t flags,
                            uint64_t backfill) {
        size = sizeof(data.tap_connect->bytes) + id.length();
        if (flags & TAP_CONNECT_FLAG_BACKFILL) {
            size += sizeof(backfill);
        }
        data.rawBytes = new char[size];
        data.req->request.magic = PROTOCOL_BINARY_REQ;
        data.req->request.opcode = PROTOCOL_BINARY_CMD_TAP_CONNECT;
        data.req->request.keylen = ntohs(static_cast<uint16_t>(id.length()));
        data.req->request.extlen = 4;
        data.req->request.datatype = PROTOCOL_BINARY_RAW_BYTES;
        data.req->request.vbucket = 0;
        uint32_t bodylen = size - sizeof(data.req->bytes);
        data.req->request.bodylen = htonl(bodylen);;
        data.req->request.opaque = 0xcafecafe;
        data.req->request.cas = 0;
        data.tap_connect->message.body.flags = htonl(flags);
        char *ptr = data.rawBytes + sizeof(data.tap_connect->bytes);
        memcpy(ptr, id.c_str(), id.length());
        ptr += id.length();

        if (flags & TAP_CONNECT_FLAG_BACKFILL) {
            backfill = htonll(backfill);
            memcpy(ptr, &backfill, sizeof(backfill));
        }
    }
};

void TapClientConnection::resolve(void) throw (std::runtime_error) {
    if (ai == NULL) {
        struct addrinfo hints;
        std::memset(&hints, 0, sizeof(hints));
        hints.ai_flags = AI_PASSIVE;
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_family = AF_UNSPEC;

        std::string host = peer;
        std::string port = "11211";
        ssize_t s = host.find(":");
        if (s != -1) {
            port = host.substr(s + 1);
            host = host.substr(0, s);
        }

        int error = getaddrinfo(host.c_str(), port.c_str(), &hints, &ai);
        if (error != 0) {
            std::stringstream ss;
            ss << "getaddrinfo(): "
               << (error != EAI_SYSTEM) ? gai_strerror(error) : strerror(error);
            throw std::runtime_error(ss.str());
        }
    }
}

void TapClientConnection::createSocket() throw (std::runtime_error) {
    for (struct addrinfo *next= ai; next; next= next->ai_next) {
        if ((sock = socket(ai->ai_family, SOCK_STREAM,
                           ai->ai_protocol)) != -1) {
            break;
        }
    }

    if (sock == -1) {
        throw std::runtime_error("Failed to create socket");
    }

    int fl;
    if ((fl = fcntl(sock, F_GETFL, 0)) < 0) {
        std::stringstream msg;
        msg << "Failed to get current flags: " << strerror(errno);
        throw std::runtime_error(msg.str());
    }

    if ((fl & O_NONBLOCK) != O_NONBLOCK) {
        if (fcntl(sock, F_SETFL, fl | O_NONBLOCK) < 0) {
            std::stringstream msg;
            msg << "Failed to enable O_NONBLOCK: " << strerror(errno);
            throw std::runtime_error(msg.str());
        }
    }
}

bool TapClientConnection::connect() throw (std::runtime_error) {
    // create socket and make it nonblocking
    if (!connected) {
        resolve();
        if (sock == -1) {
            createSocket();
        }

        while (::connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
            if (errno == EINPROGRESS || errno == EALREADY) {
                return false;
            } else if (errno == EISCONN) {
                TapConnectBinaryMessage msg(tapId, flags, backfillage);
                connected = true;
                if (send(sock, msg.data.rawBytes, msg.size, 0) !=
                    static_cast<ssize_t>(msg.size)) {
                    // It's unlikely that we're not able to send that few
                    // bytes, so just retry if it happens..
                    setFailed();
                    return false;
                }
                return true;
            } else if (errno != EINTR) {
                /* A real problem occured */
                std::stringstream msg;
                msg << "Failed to connect: " << strerror(errno);
                throw std::runtime_error(msg.str());
            }
        }
    }

    return true;
}

void TapClientConnection::run() {
    LockHolder lh(mutex);
    while (!terminate) {
        lh.unlock();
        try {
            if (retry_interval == 0) {
                if (connect()) {
                    consume();
                }
            } else {
                --retry_interval;
            }

            if (connected) {
                wait(POLLIN);
            } else if (sock == -1) {
                wait(0);
            } else {
                if (!wait(POLLOUT)) {
                    --connect_timeout;
                    if (connect_timeout == 0) {
                        setFailed();
                        if (!shouldRetry()) {
                            terminate = true;
                        }
                    }
                }
            }
        } catch (std::runtime_error &e) {
            std::stringstream msg;
            msg << "An exception occured in the tap stream: " << e.what()
                << std::endl;
            getLogger()->log(EXTENSION_LOG_DEBUG, NULL, msg.str().c_str());
            setFailed();
        }
        lh.lock();
    }

    if (connected) {
        (void)close(sock);
        sock = -1;
        connected = false;
    }

    running = false;
    zombie = true;
}

bool TapClientConnection::wait(short mask) throw (std::runtime_error) {
    struct pollfd fds[1];
    fds[0].fd = sock;
    fds[0].events = mask;
    int error = poll(fds, 1, 1000);

    if (error != 1 || fds[0].revents & POLLERR) {
        if (fds[0].revents & POLLERR) {
            int err;
            socklen_t len = sizeof(err);
            (void)getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len);
            std::stringstream msg;
            msg << "Error on TAP client stream: ";
            if (err == 0) {
                msg << errno;
            } else {
                msg << err;
            }
            (void)close(sock);
            sock = -1;
            throw std::runtime_error(msg.str());
        }

        return false;
    }

    return true;
}

void TapClientConnection::apply() {
    /* Call the tap notify function!! */
    protocol_binary_request_tap_no_extras *tap = message->data.tap;
    uint16_t nengine = ntohs(tap->message.body.tap.enginespecific_length);
    uint16_t tap_flags = ntohs(tap->message.body.tap.flags);
    uint32_t seqno = ntohl(tap->message.header.request.opaque);
    uint8_t ttl = tap->message.body.tap.ttl;
    char *engine_specific = message->data.rawBytes + sizeof(tap->bytes);
    char *key = engine_specific + nengine;
    uint16_t nkey = ntohs(tap->message.header.request.keylen);
    char *data = key + nkey;
    uint32_t fl = 0;
    uint32_t exptime = 0;
    uint32_t ndata = ntohl(tap->message.header.request.bodylen) - nengine - nkey - 8;
    uint16_t vbucket = ntohs(tap->message.header.request.vbucket);
    uint64_t cas = ntohll(tap->message.header.request.cas);
    tap_event_t event = TAP_OPAQUE;
    bool ignore = false;

    switch (tap->message.header.request.opcode) {
    case PROTOCOL_BINARY_CMD_TAP_MUTATION:
        event = TAP_MUTATION;
        break;
    case PROTOCOL_BINARY_CMD_TAP_DELETE:
        event = TAP_DELETION;
        break;
    case PROTOCOL_BINARY_CMD_TAP_FLUSH:
        event = TAP_FLUSH;
        break;
    case PROTOCOL_BINARY_CMD_TAP_OPAQUE:
        event = TAP_OPAQUE;
        break;
    case PROTOCOL_BINARY_CMD_TAP_VBUCKET_SET:
        event = TAP_VBUCKET_SET;
        break;
    default:
        ignore = true;
    }

    if (ignore) {
        getLogger()->log(EXTENSION_LOG_DEBUG, NULL,
                         "Ignoring unknown packet on tap stream: 0x%02x\n",
                         static_cast<unsigned int>(tap->message.header.request.opcode));
    } else {
        if (event == TAP_MUTATION) {
            protocol_binary_request_tap_mutation *mutation;
            mutation = message->data.mutation;
            fl = ntohl(mutation->message.body.item.flags);
            exptime = ntohl(mutation->message.body.item.expiration);
            key += 8;
            data += 8;
            ndata -= 8;
        }

        ENGINE_ERROR_CODE ret;
        ret = engine->tapNotify(NULL,
                                engine_specific, nengine,
                                ttl - 1, tap_flags, event, seqno,
                                key, nkey, fl, exptime,
                                cas, data, ndata, vbucket);

        switch (ret) {
        case ENGINE_SUCCESS:
            break;
        case ENGINE_DISCONNECT:
            terminate = true;
            // FALLTHROUGH
        default:
            getLogger()->log(EXTENSION_LOG_DEBUG, NULL,
                             "tapNotify returned: %d\n", static_cast<int>(ret));
        }

        if (ret == ENGINE_DISCONNECT) {
            terminate = true;
        }
    }
}

void TapClientConnection::consume() {
    LockHolder lh(mutex);
    do {
        lh.unlock();
        char *dst;
        size_t nbytes;
        ssize_t nr;

        if (message == NULL) {
            dst = reinterpret_cast<char*>(&header) + offset;
            nbytes = sizeof(header.bytes) - offset;
        } else {
            dst = message->data.rawBytes + sizeof(header.bytes) + offset;
            nbytes = ntohl(header.request.bodylen) - offset;
        }

        if ((nr = recv(sock, dst, nbytes, 0)) == -1) {
            switch (errno) {
            case EINTR:
                break;
            case EWOULDBLOCK:
                return;
            default:
                std::stringstream msg;
                msg << "Failed to read from socket: " << strerror(errno);
                throw std::runtime_error(msg.str());
            }
        } else if (nr == 0) {
            throw std::runtime_error("stream closed");
        } else {
            offset += nr;
            if (nr == static_cast<ssize_t>(nbytes)) {
                // we got everything..
                offset = 0;
                if (message == NULL) {
                    message = new BinaryMessage(header);
                } else {
                    /* Call the tap notify function!! */
                    apply();
                    delete message;
                    message = NULL;
                }
            }
        }

        lh.lock();
    } while (!terminate);
}

void* tapClientConnectionMain(void *arg)
{
    TapClientConnection *conn = reinterpret_cast<TapClientConnection*>(arg);
    conn->run();
    return NULL;
}
<|endoftext|>


<commit_before>/* Copyright (C) 2005-2011, Thorvald Natvig <thorvald@natvig.com>

   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

   - Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   - Neither the name of the Mumble Developers nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "mumble_pch.hpp"

#include "Overlay.h"

#include "OverlayClient.h"
#include "Channel.h"
#include "ClientUser.h"
#include "Database.h"
#include "Global.h"
#include "GlobalShortcut.h"
#include "MainWindow.h"
#include "Message.h"
#include "OverlayText.h"
#include "RichTextEditor.h"
#include "ServerHandler.h"
#include "User.h"
#include "WebFetch.h"

OverlayAppInfo::OverlayAppInfo(QString name, QIcon icon) {
	qsDisplayName = name;
	qiIcon = icon;
}

OverlayMouse::OverlayMouse(QGraphicsItem *p) : QGraphicsPixmapItem(p) {
}

bool OverlayMouse::contains(const QPointF &) const {
	return false;
}

bool OverlayMouse::collidesWithPath(const QPainterPath &, Qt::ItemSelectionMode) const {
	return false;
}

OverlayGroup::OverlayGroup() : QGraphicsItem() {
}

int OverlayGroup::type() const {
	return Type;
}

void OverlayGroup::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {
}

QRectF OverlayGroup::boundingRect() const {
	QRectF qr;
	foreach(const QGraphicsItem *item, childItems())
		if (item->isVisible())
			qr |= item->boundingRect().translated(item->pos());

	return qr;
}

Overlay::Overlay() : QObject() {
	d = NULL;

	platformInit();
	forceSettings();

	qlsServer = new QLocalServer(this);
	QString pipepath;
#ifdef Q_OS_WIN
	pipepath = QLatin1String("MumbleOverlayPipe");
#else
	pipepath = QDir::home().absoluteFilePath(QLatin1String(".MumbleOverlayPipe"));
	{
		QFile f(pipepath);
		if (f.exists()) {
			qWarning() << "Overlay: Removing old socket on" << pipepath;
			f.remove();
		}
	}
#endif

	if (! qlsServer->listen(pipepath)) {
		QMessageBox::warning(NULL, QLatin1String("Mumble"), tr("Failed to create communication with overlay at %2: %1. No overlay will be available.").arg(Qt::escape(qlsServer->errorString()), Qt::escape(pipepath)), QMessageBox::Ok, QMessageBox::NoButton);
	} else {
		qWarning() << "Overlay: Listening on" << qlsServer->fullServerName();
		connect(qlsServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
	}

	QMetaObject::connectSlotsByName(this);
}

Overlay::~Overlay() {
	setActive(false);
	delete d;

	// Need to be deleted first, since destructor references lingering QLocalSockets
	foreach(OverlayClient *oc, qlClients)
		delete oc;
}

void Overlay::newConnection() {
	while (true) {
		QLocalSocket *qls = qlsServer->nextPendingConnection();
		if (! qls)
			break;
		OverlayClient *oc = new OverlayClient(qls, this);
		qlClients << oc;

		connect(qls, SIGNAL(disconnected()), this, SLOT(disconnected()));
		connect(qls, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(error(QLocalSocket::LocalSocketError)));
	}
}

void Overlay::disconnected() {
	QLocalSocket *qls = qobject_cast<QLocalSocket *>(sender());
	foreach(OverlayClient *oc, qlClients) {
		if (oc->qlsSocket == qls) {
			qlClients.removeAll(oc);
			delete oc;
			return;
		}
	}
}

void Overlay::error(QLocalSocket::LocalSocketError) {
	disconnected();
}

bool Overlay::isActive() const {
	return ! qlClients.isEmpty();
}

void Overlay::toggleShow() {
	if (g.ocIntercept) {
		g.ocIntercept->hideGui();
	} else {
		foreach(OverlayClient *oc, qlClients) {
			if (oc->uiPid) {
#if defined(Q_OS_WIN)
				HWND hwnd = GetForegroundWindow();
				DWORD pid = 0;
				GetWindowThreadProcessId(hwnd, &pid);
				if (pid != oc->uiPid)
					continue;
#elif defined(Q_OS_MAC)
				pid_t pid = 0;
				ProcessSerialNumber psn;
				GetFrontProcess(&psn);
				GetProcessPID(&psn, &pid);
				if (pid != oc->uiPid)
					continue;
#if 0
				// Fullscreen only.
				if (! CGDisplayIsCaptured(CGMainDisplayID()))
					continue;
#endif
#endif
				oc->showGui();
				return;
			}
		}
	}
}

void Overlay::forceSettings() {
	foreach(OverlayClient *oc, qlClients) {
		oc->reset();
	}

	updateOverlay();
}

void Overlay::verifyTexture(ClientUser *cp, bool allowupdate) {
	qsQueried.remove(cp->uiSession);

	ClientUser *self = ClientUser::get(g.uiSession);
	allowupdate = allowupdate && self && self->cChannel->isLinked(cp->cChannel);

	if (allowupdate && ! cp->qbaTextureHash.isEmpty() && cp->qbaTexture.isEmpty())
		cp->qbaTexture = Database::blob(cp->qbaTextureHash);

	if (! cp->qbaTexture.isEmpty()) {
		bool valid = true;

		if (cp->qbaTexture.length() < static_cast<int>(sizeof(unsigned int))) {
			valid = false;
		} else if (qFromBigEndian<unsigned int>(reinterpret_cast<const unsigned char *>(cp->qbaTexture.constData())) == 600 * 60 * 4) {
			QByteArray qba = qUncompress(cp->qbaTexture);
			if (qba.length() != 600 * 60 * 4) {
				valid = false;
			} else {
				int width = 0;
				int height = 0;
				const unsigned int *ptr = reinterpret_cast<const unsigned int *>(qba.constData());

				// If we have an alpha only part on the right side of the image ignore it
				for (int y=0;y<60;++y) {
					for (int x=0;x<600; ++x) {
						if (ptr[y*600+x] & 0xff000000) {
							if (x > width)
								width = x;
							if (y > height)
								height = y;
						}
					}
				}

				// Full size image? More likely image without alpha; fix it.
				if ((width == 599) && (height == 59)) {
					width = 0;
					height = 0;
					for (int y=0;y<60;++y) {
						for (int x=0;x<600; ++x) {
							if (ptr[y*600+x] & 0x00ffffff) {
								if (x > width)
									width = x;
								if (y > height)
									height = y;
							}
						}
					}
				}

				if (! width || ! height) {
					valid = false;
				} else {
					QImage img = QImage(width+1, height+1, QImage::Format_ARGB32);
					{
						QImage srcimg(reinterpret_cast<const uchar *>(qba.constData()), 600, 60, QImage::Format_ARGB32);

						QPainter imgp(&img);
						img.fill(0);
						imgp.setRenderHint(QPainter::Antialiasing);
						imgp.setRenderHint(QPainter::TextAntialiasing);
						imgp.setBackground(QColor(0,0,0,0));
						imgp.setCompositionMode(QPainter::CompositionMode_Source);
						imgp.drawImage(0, 0, srcimg);
					}
					cp->qbaTexture = QByteArray();

					QBuffer qb(& cp->qbaTexture);
					qb.open(QIODevice::WriteOnly);
					QImageWriter qiw(&qb, "png");
					qiw.write(img);

					cp->qbaTextureFormat = QString::fromLatin1("png").toUtf8();
				}
			}
		} else {
			QBuffer qb(& cp->qbaTexture);
			qb.open(QIODevice::ReadOnly);

			QImageReader qir;
			qir.setAutoDetectImageFormat(false);

			QByteArray fmt;
			if (RichTextImage::isValidImage(cp->qbaTexture, fmt)) {
				qir.setFormat(fmt);
				qir.setDevice(&qb);
				if (! qir.canRead() || (qir.size().width() > 1024) || (qir.size().height() > 1024)) {
					valid = false;
				} else {
					cp->qbaTextureFormat = qir.format();
					QImage qi = qir.read();
					valid = ! qi.isNull();
				}
			} else {
				valid = false;
			}
		}
		if (! valid) {
			cp->qbaTexture = QByteArray();
			cp->qbaTextureHash = QByteArray();
		}
	}

	if (allowupdate)
		updateOverlay();
}

typedef QPair<QString, quint32> qpChanCol;

void Overlay::updateOverlay() {
	if (! g.uiSession)
		qsQueried.clear();

	if (qlClients.isEmpty())
		return;

	qsQuery.clear();

	foreach(OverlayClient *oc, qlClients) {
		if (! oc->update()) {
			qWarning() << "Overlay: Dead client detected. PID" << oc->uiPid << oc->qsProcessName;
			qlClients.removeAll(oc);
			oc->scheduleDelete();
			break;
		}
	}

	if (! qsQuery.isEmpty()) {
		MumbleProto::RequestBlob mprb;
		foreach(unsigned int session, qsQuery) {
			qsQueried.insert(session);
			mprb.add_session_texture(session);
		}
		g.sh->sendMessage(mprb);
	}
}

void Overlay::requestTexture(ClientUser *cu) {
	if (cu->qbaTexture.isEmpty() && ! qsQueried.contains(cu->uiSession)) {
		cu->qbaTexture=Database::blob(cu->qbaTextureHash);
		if (cu->qbaTexture.isEmpty())
			qsQuery.insert(cu->uiSession);
		else
			verifyTexture(cu, false);
	}
}
<commit_msg>Fix compilation of Overlay.cpp. It was accidentally broken by fd782c3c.<commit_after>/* Copyright (C) 2005-2011, Thorvald Natvig <thorvald@natvig.com>

   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

   - Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   - Neither the name of the Mumble Developers nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "mumble_pch.hpp"

#include "Overlay.h"

#include "OverlayClient.h"
#include "Channel.h"
#include "ClientUser.h"
#include "Database.h"
#include "Global.h"
#include "GlobalShortcut.h"
#include "MainWindow.h"
#include "Message.h"
#include "OverlayText.h"
#include "RichTextEditor.h"
#include "ServerHandler.h"
#include "User.h"
#include "WebFetch.h"

OverlayAppInfo::OverlayAppInfo(QString name, QIcon icon) {
	qsDisplayName = name;
	qiIcon = icon;
}

OverlayMouse::OverlayMouse(QGraphicsItem *p) : QGraphicsPixmapItem(p) {
}

bool OverlayMouse::contains(const QPointF &) const {
	return false;
}

bool OverlayMouse::collidesWithPath(const QPainterPath &, Qt::ItemSelectionMode) const {
	return false;
}

OverlayGroup::OverlayGroup() : QGraphicsItem() {
}

int OverlayGroup::type() const {
	return Type;
}

void OverlayGroup::paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) {
}

QRectF OverlayGroup::boundingRect() const {
	QRectF qr;
	foreach(const QGraphicsItem *item, childItems())
		if (item->isVisible())
			qr |= item->boundingRect().translated(item->pos());

	return qr;
}

Overlay::Overlay() : QObject() {
	d = NULL;

	platformInit();
	forceSettings();

	qlsServer = new QLocalServer(this);
	QString pipepath;
#ifdef Q_OS_WIN
	pipepath = QLatin1String("MumbleOverlayPipe");
#else
	pipepath = QDir::home().absoluteFilePath(QLatin1String(".MumbleOverlayPipe"));
	{
		QFile f(pipepath);
		if (f.exists()) {
			qWarning() << "Overlay: Removing old socket on" << pipepath;
			f.remove();
		}
	}
#endif

	if (! qlsServer->listen(pipepath)) {
		QMessageBox::warning(NULL, QLatin1String("Mumble"), tr("Failed to create communication with overlay at %2: %1. No overlay will be available.").arg(Qt::escape(qlsServer->errorString()), Qt::escape(pipepath)), QMessageBox::Ok, QMessageBox::NoButton);
	} else {
		qWarning() << "Overlay: Listening on" << qlsServer->fullServerName();
		connect(qlsServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
	}

	QMetaObject::connectSlotsByName(this);
}

Overlay::~Overlay() {
	setActive(false);
	delete d;

	// Need to be deleted first, since destructor references lingering QLocalSockets
	foreach(OverlayClient *oc, qlClients)
		delete oc;
}

void Overlay::newConnection() {
	while (true) {
		QLocalSocket *qls = qlsServer->nextPendingConnection();
		if (! qls)
			break;
		OverlayClient *oc = new OverlayClient(qls, this);
		qlClients << oc;

		connect(qls, SIGNAL(disconnected()), this, SLOT(disconnected()));
		connect(qls, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(error(QLocalSocket::LocalSocketError)));
	}
}

void Overlay::disconnected() {
	QLocalSocket *qls = qobject_cast<QLocalSocket *>(sender());
	foreach(OverlayClient *oc, qlClients) {
		if (oc->qlsSocket == qls) {
			qlClients.removeAll(oc);
			delete oc;
			return;
		}
	}
}

void Overlay::error(QLocalSocket::LocalSocketError) {
	disconnected();
}

bool Overlay::isActive() const {
	return ! qlClients.isEmpty();
}

void Overlay::toggleShow() {
	if (g.ocIntercept) {
		g.ocIntercept->hideGui();
	} else {
		foreach(OverlayClient *oc, qlClients) {
			if (oc->uiPid) {
#if defined(Q_OS_WIN)
				HWND hwnd = GetForegroundWindow();
				DWORD pid = 0;
				GetWindowThreadProcessId(hwnd, &pid);
				if (pid != oc->uiPid)
					continue;
#elif defined(Q_OS_MAC)
				pid_t pid = 0;
				ProcessSerialNumber psn;
				GetFrontProcess(&psn);
				GetProcessPID(&psn, &pid);
				if (pid != oc->uiPid)
					continue;
#if 0
				// Fullscreen only.
				if (! CGDisplayIsCaptured(CGMainDisplayID()))
					continue;
#endif
#endif
				oc->showGui();
				return;
			}
		}
	}
}

void Overlay::forceSettings() {
	foreach(OverlayClient *oc, qlClients) {
		oc->reset();
	}

	updateOverlay();
}

void Overlay::verifyTexture(ClientUser *cp, bool allowupdate) {
	qsQueried.remove(cp->uiSession);

	ClientUser *self = ClientUser::get(g.uiSession);
	allowupdate = allowupdate && self && self->cChannel->isLinked(cp->cChannel);

	if (allowupdate && ! cp->qbaTextureHash.isEmpty() && cp->qbaTexture.isEmpty())
		cp->qbaTexture = Database::blob(cp->qbaTextureHash);

	if (! cp->qbaTexture.isEmpty()) {
		bool valid = true;

		if (cp->qbaTexture.length() < static_cast<int>(sizeof(unsigned int))) {
			valid = false;
		} else if (qFromBigEndian<unsigned int>(reinterpret_cast<const unsigned char *>(cp->qbaTexture.constData())) == 600 * 60 * 4) {
			QByteArray qba = qUncompress(cp->qbaTexture);
			if (qba.length() != 600 * 60 * 4) {
				valid = false;
			} else {
				int width = 0;
				int height = 0;
				const unsigned int *ptr = reinterpret_cast<const unsigned int *>(qba.constData());

				// If we have an alpha only part on the right side of the image ignore it
				for (int y=0;y<60;++y) {
					for (int x=0;x<600; ++x) {
						if (ptr[y*600+x] & 0xff000000) {
							if (x > width)
								width = x;
							if (y > height)
								height = y;
						}
					}
				}

				// Full size image? More likely image without alpha; fix it.
				if ((width == 599) && (height == 59)) {
					width = 0;
					height = 0;
					for (int y=0;y<60;++y) {
						for (int x=0;x<600; ++x) {
							if (ptr[y*600+x] & 0x00ffffff) {
								if (x > width)
									width = x;
								if (y > height)
									height = y;
							}
						}
					}
				}

				if (! width || ! height) {
					valid = false;
				} else {
					QImage img = QImage(width+1, height+1, QImage::Format_ARGB32);
					{
						QImage srcimg(reinterpret_cast<const uchar *>(qba.constData()), 600, 60, QImage::Format_ARGB32);

						QPainter imgp(&img);
						img.fill(0);
						imgp.setRenderHint(QPainter::Antialiasing);
						imgp.setRenderHint(QPainter::TextAntialiasing);
						imgp.setBackground(QColor(0,0,0,0));
						imgp.setCompositionMode(QPainter::CompositionMode_Source);
						imgp.drawImage(0, 0, srcimg);
					}
					cp->qbaTexture = QByteArray();

					QBuffer qb(& cp->qbaTexture);
					qb.open(QIODevice::WriteOnly);
					QImageWriter qiw(&qb, "png");
					qiw.write(img);

					cp->qbaTextureFormat = QString::fromLatin1("png").toUtf8();
				}
			}
		} else {
			QBuffer qb(& cp->qbaTexture);
			qb.open(QIODevice::ReadOnly);

			QImageReader qir;
			qir.setAutoDetectImageFormat(false);

			QByteArray fmt;
			if (RichTextImage::isValidImage(cp->qbaTexture, fmt)) {
				qir.setFormat(fmt);
				qir.setDevice(&qb);
				if (! qir.canRead() || (qir.size().width() > 1024) || (qir.size().height() > 1024)) {
					valid = false;
				} else {
					cp->qbaTextureFormat = qir.format();
					QImage qi = qir.read();
					valid = ! qi.isNull();
				}
			} else {
				valid = false;
			}
		}
		if (! valid) {
			cp->qbaTexture = QByteArray();
			cp->qbaTextureHash = QByteArray();
		}
	}

	if (allowupdate)
		updateOverlay();
}

typedef QPair<QString, quint32> qpChanCol;

void Overlay::updateOverlay() {
	if (! g.uiSession)
		qsQueried.clear();

	if (qlClients.isEmpty())
		return;

	qsQuery.clear();

	foreach(OverlayClient *oc, qlClients) {
		if (! oc->update()) {
			qWarning() << "Overlay: Dead client detected. PID" << oc->uiPid << oc->qsExecutablePath;
			qlClients.removeAll(oc);
			oc->scheduleDelete();
			break;
		}
	}

	if (! qsQuery.isEmpty()) {
		MumbleProto::RequestBlob mprb;
		foreach(unsigned int session, qsQuery) {
			qsQueried.insert(session);
			mprb.add_session_texture(session);
		}
		g.sh->sendMessage(mprb);
	}
}

void Overlay::requestTexture(ClientUser *cu) {
	if (cu->qbaTexture.isEmpty() && ! qsQueried.contains(cu->uiSession)) {
		cu->qbaTexture=Database::blob(cu->qbaTextureHash);
		if (cu->qbaTexture.isEmpty())
			qsQuery.insert(cu->uiSession);
		else
			verifyTexture(cu, false);
	}
}
<|endoftext|>


<commit_before>/**
 * @file /home/ryan/programming/atl/test/atl.cpp
 * @author Ryan Domigan <ryan_domigan@sutdents@uml.edu>
 * Created on Aug 05, 2015
 *
 * Regression tests for integrated behaviour:
 * - repl like calls
 * - loading form a file
 */

#include <gtest/gtest.h>
#include <fstream>
#include <sstream>
#include <atl.hpp>
#include <iterator>

using namespace atl;

struct AtlTest : public ::testing::Test {
	Atl atl;
    AtlTest() : atl() {}
};

TEST_F(AtlTest, test_string_stream)
{
	std::stringstream content
		(";; used to test atl.cpp\n"
		 "(define-value foo (\\ (a) (print-int (add2 a 3))))");
	atl.stream(content);
	atl.string_("(foo 2)");
}

TEST_F(AtlTest, test_loaded_file)
{
	std::ifstream file("./simple.atl");
	atl.stream(file);
	atl.string_("(foo 2)");
}

TEST_F(AtlTest, test_multiline_stream)
{
	std::stringstream content
		("(define-value foo (\\ (a b) (add2 (add2 a 2) b)))\n"
		 "\n"
		 "(define-value bar (\\ (a b) (add2 (add2 a 3) b)))");
	atl.stream(content);
	ASSERT_EQ((unwrap<Fixnum>(atl.string_("(bar 2 3)")).value),
	          8);
}

TEST_F(AtlTest, test_file_contents)
{
	std::ifstream file("./simple.atl");
	std::string content((istreambuf_iterator<char>(file)),
	                    istreambuf_iterator<char>());

	atl.string_(content);
	atl.string_("(foo 2)");
}
<commit_msg>Automate atl.cpp tests<commit_after>/**
 * @file /home/ryan/programming/atl/test/atl.cpp
 * @author Ryan Domigan <ryan_domigan@sutdents@uml.edu>
 * Created on Aug 05, 2015
 *
 * Regression tests for integrated behaviour:
 * - repl like calls
 * - loading form a file
 */

#include <gtest/gtest.h>
#include <fstream>
#include <sstream>
#include <atl.hpp>
#include <iterator>

using namespace atl;

struct AtlTest : public ::testing::Test {
	Atl atl;
    AtlTest() : atl() {}
};

TEST_F(AtlTest, test_string_stream)
{
	std::stringstream output;
	atl.set_stdout(output);

	std::stringstream content
		(";; used to test atl.cpp\n"
		 "(define-value foo (\\ (a) (print-int (add2 a 3))))");
	atl.stream(content);
	atl.string_("(foo 2)");

	ASSERT_EQ(output.str(), "5\n");
}

TEST_F(AtlTest, test_loaded_file)
{
	std::stringstream output;
	atl.set_stdout(output);

	std::ifstream file("./simple.atl");
	atl.stream(file);
	atl.string_("(foo 2)");

	ASSERT_EQ(output.str(), "5\n");
}

TEST_F(AtlTest, test_multiline_stream)
{
	std::stringstream content
		("(define-value foo (\\ (a b) (add2 (add2 a 2) b)))\n"
		 "\n"
		 "(define-value bar (\\ (a b) (add2 (add2 a 3) b)))");
	atl.stream(content);
	ASSERT_EQ((unwrap<Fixnum>(atl.string_("(bar 2 3)")).value),
	          8);
}

TEST_F(AtlTest, test_file_contents)
{
	std::ifstream file("./simple.atl");
	std::string content((istreambuf_iterator<char>(file)),
	                    istreambuf_iterator<char>());

	atl.string_(content);
	atl.string_("(foo 2)");
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <node/coinstats.h>

#include <coins.h>
#include <hash.h>
#include <serialize.h>
#include <validation.h>
#include <uint256.h>
#include <util/system.h>

#include <map>

static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
{
    assert(!outputs.empty());
    ss << hash;
    ss << VARINT(outputs.begin()->second.nHeight * 2 + outputs.begin()->second.fCoinBase ? 1u : 0u);
    stats.nTransactions++;
    for (const auto& output : outputs) {
        ss << VARINT(output.first + 1);
        ss << output.second.out.scriptPubKey;
        ss << VARINT_MODE(output.second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
        stats.nTransactionOutputs++;
        stats.nTotalAmount += output.second.out.nValue;
        stats.nBogoSize += 32 /* txid */ + 4 /* vout index */ + 4 /* height + coinbase */ + 8 /* amount */ +
                           2 /* scriptPubKey len */ + output.second.out.scriptPubKey.size() /* scriptPubKey */;
    }
    ss << VARINT(0u);
}

//! Calculate statistics about the unspent transaction output set
bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, const std::function<void()>& interruption_point)
{
    stats = CCoinsStats();
    std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
    assert(pcursor);

    CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
    stats.hashBlock = pcursor->GetBestBlock();
    {
        LOCK(cs_main);
        stats.nHeight = LookupBlockIndex(stats.hashBlock)->nHeight;
    }
    ss << stats.hashBlock;
    uint256 prevkey;
    std::map<uint32_t, Coin> outputs;
    while (pcursor->Valid()) {
        interruption_point();
        COutPoint key;
        Coin coin;
        if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
            if (!outputs.empty() && key.hash != prevkey) {
                ApplyStats(stats, ss, prevkey, outputs);
                outputs.clear();
            }
            prevkey = key.hash;
            outputs[key.n] = std::move(coin);
            stats.coins_count++;
        } else {
            return error("%s: unable to read value", __func__);
        }
        pcursor->Next();
    }
    if (!outputs.empty()) {
        ApplyStats(stats, ss, prevkey, outputs);
    }
    stats.hashSerialized = ss.GetHash();
    stats.nDiskSize = view->EstimateSize();
    return true;
}
<commit_msg>refactor: Extract GetBogoSize function<commit_after>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <node/coinstats.h>

#include <coins.h>
#include <hash.h>
#include <serialize.h>
#include <uint256.h>
#include <util/system.h>
#include <validation.h>

#include <map>

static uint64_t GetBogoSize(const CScript& scriptPubKey)
{
    return 32 /* txid */ +
           4 /* vout index */ +
           4 /* height + coinbase */ +
           8 /* amount */ +
           2 /* scriptPubKey len */ +
           scriptPubKey.size() /* scriptPubKey */;
}

static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
{
    assert(!outputs.empty());
    ss << hash;
    ss << VARINT(outputs.begin()->second.nHeight * 2 + outputs.begin()->second.fCoinBase ? 1u : 0u);
    stats.nTransactions++;
    for (const auto& output : outputs) {
        ss << VARINT(output.first + 1);
        ss << output.second.out.scriptPubKey;
        ss << VARINT_MODE(output.second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
        stats.nTransactionOutputs++;
        stats.nTotalAmount += output.second.out.nValue;
        stats.nBogoSize += GetBogoSize(output.second.out.scriptPubKey);
    }
    ss << VARINT(0u);
}

//! Calculate statistics about the unspent transaction output set
bool GetUTXOStats(CCoinsView* view, CCoinsStats& stats, const std::function<void()>& interruption_point)
{
    stats = CCoinsStats();
    std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
    assert(pcursor);

    CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
    stats.hashBlock = pcursor->GetBestBlock();
    {
        LOCK(cs_main);
        stats.nHeight = LookupBlockIndex(stats.hashBlock)->nHeight;
    }
    ss << stats.hashBlock;
    uint256 prevkey;
    std::map<uint32_t, Coin> outputs;
    while (pcursor->Valid()) {
        interruption_point();
        COutPoint key;
        Coin coin;
        if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
            if (!outputs.empty() && key.hash != prevkey) {
                ApplyStats(stats, ss, prevkey, outputs);
                outputs.clear();
            }
            prevkey = key.hash;
            outputs[key.n] = std::move(coin);
            stats.coins_count++;
        } else {
            return error("%s: unable to read value", __func__);
        }
        pcursor->Next();
    }
    if (!outputs.empty()) {
        ApplyStats(stats, ss, prevkey, outputs);
    }
    stats.hashSerialized = ss.GetHash();
    stats.nDiskSize = view->EstimateSize();
    return true;
}
<|endoftext|>