<commit_before>/*
 * Copyright (c) 2012, 2013 Aldebaran Robotics. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the COPYING file.
 */

#include <fstream>
#include <cstdlib>

#include <qi/application.hpp>
#include <qi/qi.hpp>
#include <qi/os.hpp>
#include <qi/log.hpp>
#include <qi/path.hpp>
#include <src/sdklayout.hpp>
#include <numeric>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>

#include "filesystem.hpp"
#include "utils.hpp"
#include "path_conf.hpp"

#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
#ifdef _WIN32
#include <windows.h>
#endif

qiLogCategory("qi.Application");

namespace qi {
  static int         globalArgc = -1;
  static char**      globalArgv = 0;
  static bool        globalInitialized = false;
  static bool        globalTerminated = false;

  static std::string globalName;
  static std::vector<std::string>* globalArguments;
  static std::string globalPrefix;
  static std::string globalProgram;

  typedef std::vector<boost::function<void()> > FunctionList;
  static FunctionList* globalAtExit = 0;
  static FunctionList* globalAtEnter = 0;
  static FunctionList* globalAtStop = 0;

  static boost::condition_variable globalCond;

  static boost::asio::io_service*             globalIoService = 0;
  static boost::thread*                       globalIoThread = 0;
  static boost::asio::io_service::work*       globalIoWork = 0;
  static std::list<boost::asio::signal_set*>* globalSignalSet = 0;

  static void readPathConf()
  {
    std::string prefix = ::qi::path::sdkPrefix();
    std::set<std::string> toAdd =  ::qi::path::detail::parseQiPathConf(prefix);
    std::set<std::string>::const_iterator it;
    for (it = toAdd.begin(); it != toAdd.end(); ++it) {
      ::qi::path::detail::addOptionalSdkPrefix(it->c_str());
    }
  }

  static void stop_io_service()
  {
    qiLogVerbose() << "Unregistering all signal handlers.";
    //dont call ioservice->stop, just remove all events for the ioservice
    //deleting the object holding the run() method from quitting
    delete globalIoWork;
    globalIoWork = 0;

    if (globalSignalSet) {
      std::list<boost::asio::signal_set*>::iterator it;
      for (it = globalSignalSet->begin(); it != globalSignalSet->end(); ++it) {
        (*it)->cancel();
        delete *it;
      }
      delete globalSignalSet;
      globalSignalSet = 0;
    }
    if (globalIoThread) {
      //wait for the ioservice to terminate
      if (boost::this_thread::get_id() != globalIoThread->get_id())
        globalIoThread->join();
      //we are sure run has stopped so we can delete the io service
      delete globalIoService;
      delete globalIoThread;
      globalIoThread = 0;
      globalIoService = 0;
    }
  }

  static void run_io_service()
  {
    qi::os::setCurrentThreadName("appioservice");
    globalIoService->run();
  }

  static void stop_handler(int signal_number) {
    static int  count_int = 0;
    static int count_term = 0;
    int sigcount = 0;
    if (signal_number == SIGINT) {
      count_int++;
      sigcount = count_int;
    }
    else if (signal_number == SIGTERM) {
      count_term++;
      sigcount = count_term;
    }
    switch (sigcount) {
      case 1:
        qiLogInfo() << "Sending the stop command...";
        //register the signal again to call exit the next time if stop did not succeed
        Application::atSignal(boost::bind<void>(&stop_handler, _1), signal_number);
        // Stop might immediately trigger application destruction, so it has
        // to go after atSignal.
        Application::stop();
        return;
      default:
        //even for SIGTERM this is an error, so return 1.
        qiLogInfo() << "signal " << signal_number << " received a second time, calling exit(1).";
        exit(1);
        return;
    }
  }

  static void signal_handler(const boost::system::error_code& error, int signal_number, boost::function<void (int)> fun)
  {
    //when cancel is called the signal handler is raised with an error. catch it!
    if (!error) {
      fun(signal_number);
    }
  }

  bool Application::atSignal(boost::function<void (int)> func, int signal)
  {
    if (!globalIoService)
    {
      globalIoService = new boost::asio::io_service;
      // Prevent run from exiting
      globalIoWork = new boost::asio::io_service::work(*globalIoService);
      // Start io_service in a thread. It will call our handlers.
      globalIoThread = new boost::thread(&run_io_service);
      // We want signal handlers to work as late as possible.
      ::atexit(&stop_io_service);
      globalSignalSet = new std::list<boost::asio::signal_set*>;
    }

    boost::asio::signal_set *sset = new boost::asio::signal_set(*globalIoService, signal);
    sset->async_wait(boost::bind(signal_handler, _1, _2, func));
    globalSignalSet->push_back(sset);
    return true;
  }

  template<typename T> static T& lazyGet(T* & ptr)
  {
    if (!ptr)
      ptr = new T;
    return *ptr;
  }

  static std::string guess_app_from_path(int argc, const char *argv[])
  {
    boost::filesystem::path execPath(argv[0], qi::unicodeFacet());
    execPath = boost::filesystem::system_complete(execPath).make_preferred();
    execPath = boost::filesystem::path(detail::normalizePath(execPath.string(qi::unicodeFacet())), qi::unicodeFacet());

    //arg0 does not exists, or is not a program (directory)
    if (!boost::filesystem::exists(execPath) || boost::filesystem::is_directory(execPath))
    {
      std::string filename = execPath.filename().string(qi::unicodeFacet());
      std::string envPath = qi::os::getenv("PATH");
      size_t begin = 0;
#ifndef _WIN32
      size_t end = envPath.find(":", begin);
#else
      size_t end = envPath.find(";", begin);
#endif
      while (end != std::string::npos)
      {
        std::string realPath = "";

        realPath = envPath.substr(begin, end - begin);
        boost::filesystem::path p(realPath, qi::unicodeFacet());
        p /= filename;
        p = boost::filesystem::system_complete(p).make_preferred();
        p = boost::filesystem::path(detail::normalizePath(p.string(qi::unicodeFacet())), qi::unicodeFacet());

        if (boost::filesystem::exists(p) && !boost::filesystem::is_directory(p))
          return p.string(qi::unicodeFacet());

        begin = end + 1;
#ifndef _WIN32
        end = envPath.find(":", begin);
#else
        end = envPath.find(";", begin);
#endif
      }
    }
    else
      return execPath.string(qi::unicodeFacet());
    return std::string();
  }

  static void initApp(int& argc, char ** &argv)
  {
    readPathConf();
    if (globalInitialized)
      throw std::logic_error("Application was already initialized");
    globalInitialized = true;
    globalArgc = argc;
    globalArgv = argv;
    std::vector<std::string>& args = lazyGet(globalArguments);
    args.clear();
    for (int i=0; i<argc; ++i)
      args.push_back(argv[i]);

    FunctionList& fl = lazyGet(globalAtEnter);
    qiLogDebug() << "Executing " << fl.size() << " atEnter handlers";
    for (FunctionList::iterator i = fl.begin(); i!= fl.end(); ++i)
      (*i)();
    fl.clear();
    argc = Application::argc();
    argv = globalArgv;
  }

  Application::Application(int& argc, char ** &argv)
  {
    initApp(argc, argv);
  }

  Application::Application(const std::string &name, int& argc, char ** &argv)
  {
    globalName = name;
    initApp(argc, argv);
  }

  void* Application::loadModule(const std::string& moduleName, int flags)
  {
    void* handle = os::dlopen(moduleName.c_str(), flags);
    if (!handle)
    {
      qiLogDebug() << "dlopen failed with " << os::dlerror();
    }
    else
    {
      qiLogDebug() << "Loadmodule " << handle;
    }
    // Reprocess atEnter list in case the module had AT_ENTER
    FunctionList& fl = lazyGet(globalAtEnter);
    qiLogDebug() << "Executing " << fl.size() << " atEnter handlers";
    for (FunctionList::iterator i = fl.begin(); i!= fl.end(); ++i)
      (*i)();
    fl.clear();
    return handle;
  }

  void Application::unloadModule(void* handle)
  {
    os::dlclose(handle);
  }

  Application::~Application()
  {
    FunctionList& fl = lazyGet(globalAtExit);
    for (FunctionList::iterator i = fl.begin(); i!= fl.end(); ++i)
      (*i)();
    globalCond.notify_all();
    globalTerminated = true;
  }

  static void initSigIntSigTermCatcher() {
    bool signalInit = false;

    if (!signalInit) {
      qiLogVerbose() << "Registering SIGINT/SIGTERM handler within qi::Application";
      // kill with no signal sends TERM, control-c sends INT.
      Application::atSignal(boost::bind(&stop_handler, _1), SIGTERM);
      Application::atSignal(boost::bind(&stop_handler, _1), SIGINT);
      signalInit = true;
    }
  }

  void Application::run()
  {
    //run is called, so we catch sigint/sigterm, the default implementation call Application::stop that
    //will make this loop exit.
    initSigIntSigTermCatcher();

    // We just need a barrier, so no need to share the mutex
    boost::mutex m;
    boost::unique_lock<boost::mutex> l(m);
    globalCond.wait(l);
    l.unlock();
  }

  void Application::stop()
  {
    globalCond.notify_all();
    FunctionList& fl = lazyGet(globalAtStop);
    qiLogDebug() << "Executing " << fl.size() << " atStop handlers";
    for (FunctionList::iterator i = fl.begin(); i!= fl.end(); ++i)
      (*i)();
  }

  void Application::setName(const std::string &name)
  {
    globalName = name;
  }

  std::string Application::name()
  {
    return globalName;
  }

  void Application::setArguments(const std::vector<std::string>& args)
  {
    globalArgc = static_cast<int>(args.size());
    lazyGet(globalArguments) = args;
    globalArgv = new char*[args.size() + 1];
    for (unsigned i=0; i<args.size(); ++i)
      globalArgv[i] = strdup(args[i].c_str());
    globalArgv[args.size()] = 0;
  }

  void Application::setArguments(int argc, char** argv)
  {
    globalArgc = argc;
    globalArgv = argv;
    std::vector<std::string>& args = lazyGet(globalArguments);
    args.resize(argc);
    for (int i=0; i<argc; ++i)
      args[i] = argv[i];
  }

  bool Application::initialized()
  {
    return globalInitialized;
  }

  bool Application::terminated()
  {
    return globalTerminated;
  }

  int Application::argc()
  {
    return globalArgc;
  }

  const char** Application::argv()
  {
    return (const char**)globalArgv;
  }

  bool Application::atEnter(boost::function<void()> func)
  {
    qiLogDebug() << "atEnter";
    lazyGet(globalAtEnter).push_back(func);
    return true;
  }

  bool Application::atExit(boost::function<void()> func)
  {
    lazyGet(globalAtExit).push_back(func);
    return true;
  }

  bool Application::atStop(boost::function<void()> func)
  {
    //If the client call atStop, it mean it will handle the proper destruction
    //of the program by itself. So here we catch SigInt/SigTerm to call Application::stop
    //and let the developer properly stop the application as needed.
    initSigIntSigTermCatcher();
    lazyGet(globalAtStop).push_back(func);
    return true;
  }

  const std::vector<std::string>& Application::arguments()
  {
    return lazyGet(globalArguments);
  }

/*
  http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
  Some OS-specific interfaces:
  Mac OS X: _NSGetExecutablePath() (man 3 dyld)
  Linux   : readlink /proc/self/exe
  Solaris : getexecname()
  FreeBSD : sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1
  BSD with procfs: readlink /proc/curproc/file
  Windows : GetModuleFileName() with hModule = NULL

  The portable (but less reliable) method is to use argv[0].
  Although it could be set to anything by the calling program,
  by convention it is set to either a path name of the executable
  or a name that was found using $PATH.

  Some shells, including bash and ksh, set the environment variable "_"
  to the full path of the executable before it is executed. In that case
  you can use getenv("_") to get it. However this is unreliable because
  not all shells do this, and it could be set to anything or be left over
  from a parent process which did not change it before executing your program.
*/
  const char *Application::program()
  {
    try
    {
      if (!globalProgram.empty())
        return globalProgram.c_str();

#ifdef __APPLE__
      {
        char *fname = (char *)malloc(PATH_MAX);
        uint32_t sz = PATH_MAX;
        fname[0] = 0;
        int ret;
        ret = _NSGetExecutablePath(fname, &sz);
        if (ret == 0)
        {
          globalProgram = fname;
          globalProgram = detail::normalizePath(globalProgram);
        }
        else
        {
          globalProgram = guess_app_from_path(::qi::Application::argc(),
            ::qi::Application::argv());
        }
        free(fname);
      }
#elif __linux__
      boost::filesystem::path p("/proc/self/exe");
      boost::filesystem::path fname = boost::filesystem::read_symlink(p);

      if (!boost::filesystem::is_empty(fname))
        globalProgram = fname.string().c_str();
      else
        globalProgram = guess_app_from_path(::qi::Application::argc(),
          ::qi::Application::argv());
#elif _WIN32
      WCHAR fname[MAX_PATH];
      int ret = GetModuleFileNameW(NULL, fname, MAX_PATH);
      if (ret > 0)
      {
        fname[ret] = '\0';
        boost::filesystem::path programPath(fname, qi::unicodeFacet());
        globalProgram = programPath.string(qi::unicodeFacet());
      }
      else
      {
        // GetModuleFileName failed, trying to guess from argc, argv...
        globalProgram = guess_app_from_path(::qi::Application::argc(),
          ::qi::Application::argv());
      }
#else
      globalProgram = guess_app_from_path(::qi::Application::argc(),
        ::qi::Application::argv());
#endif
      return globalProgram.c_str();
    }
    catch (...)
    {
      return NULL;
    }
  }

  int argc()
  {
    return Application::argc();
  }

  const char** argv()
  {
    return Application::argv();
  }

  //this is not threadsafe
  void init(int& argc, char**& argv)
  {
    static qi::Application *app = 0;

    qiLogError() << "qi::init() is deprecated, use qi::Application";
    if (!app)
      app = new qi::Application(argc, argv);
  }
}
<commit_msg>Revert "Move dlopen fail log from verbose to debug"<commit_after>/*
 * Copyright (c) 2012, 2013 Aldebaran Robotics. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the COPYING file.
 */

#include <fstream>
#include <cstdlib>

#include <qi/application.hpp>
#include <qi/qi.hpp>
#include <qi/os.hpp>
#include <qi/log.hpp>
#include <qi/path.hpp>
#include <src/sdklayout.hpp>
#include <numeric>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>

#include "filesystem.hpp"
#include "utils.hpp"
#include "path_conf.hpp"

#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
#ifdef _WIN32
#include <windows.h>
#endif

qiLogCategory("qi.Application");

namespace qi {
  static int         globalArgc = -1;
  static char**      globalArgv = 0;
  static bool        globalInitialized = false;
  static bool        globalTerminated = false;

  static std::string globalName;
  static std::vector<std::string>* globalArguments;
  static std::string globalPrefix;
  static std::string globalProgram;

  typedef std::vector<boost::function<void()> > FunctionList;
  static FunctionList* globalAtExit = 0;
  static FunctionList* globalAtEnter = 0;
  static FunctionList* globalAtStop = 0;

  static boost::condition_variable globalCond;

  static boost::asio::io_service*             globalIoService = 0;
  static boost::thread*                       globalIoThread = 0;
  static boost::asio::io_service::work*       globalIoWork = 0;
  static std::list<boost::asio::signal_set*>* globalSignalSet = 0;

  static void readPathConf()
  {
    std::string prefix = ::qi::path::sdkPrefix();
    std::set<std::string> toAdd =  ::qi::path::detail::parseQiPathConf(prefix);
    std::set<std::string>::const_iterator it;
    for (it = toAdd.begin(); it != toAdd.end(); ++it) {
      ::qi::path::detail::addOptionalSdkPrefix(it->c_str());
    }
  }

  static void stop_io_service()
  {
    qiLogVerbose() << "Unregistering all signal handlers.";
    //dont call ioservice->stop, just remove all events for the ioservice
    //deleting the object holding the run() method from quitting
    delete globalIoWork;
    globalIoWork = 0;

    if (globalSignalSet) {
      std::list<boost::asio::signal_set*>::iterator it;
      for (it = globalSignalSet->begin(); it != globalSignalSet->end(); ++it) {
        (*it)->cancel();
        delete *it;
      }
      delete globalSignalSet;
      globalSignalSet = 0;
    }
    if (globalIoThread) {
      //wait for the ioservice to terminate
      if (boost::this_thread::get_id() != globalIoThread->get_id())
        globalIoThread->join();
      //we are sure run has stopped so we can delete the io service
      delete globalIoService;
      delete globalIoThread;
      globalIoThread = 0;
      globalIoService = 0;
    }
  }

  static void run_io_service()
  {
    qi::os::setCurrentThreadName("appioservice");
    globalIoService->run();
  }

  static void stop_handler(int signal_number) {
    static int  count_int = 0;
    static int count_term = 0;
    int sigcount = 0;
    if (signal_number == SIGINT) {
      count_int++;
      sigcount = count_int;
    }
    else if (signal_number == SIGTERM) {
      count_term++;
      sigcount = count_term;
    }
    switch (sigcount) {
      case 1:
        qiLogInfo() << "Sending the stop command...";
        //register the signal again to call exit the next time if stop did not succeed
        Application::atSignal(boost::bind<void>(&stop_handler, _1), signal_number);
        // Stop might immediately trigger application destruction, so it has
        // to go after atSignal.
        Application::stop();
        return;
      default:
        //even for SIGTERM this is an error, so return 1.
        qiLogInfo() << "signal " << signal_number << " received a second time, calling exit(1).";
        exit(1);
        return;
    }
  }

  static void signal_handler(const boost::system::error_code& error, int signal_number, boost::function<void (int)> fun)
  {
    //when cancel is called the signal handler is raised with an error. catch it!
    if (!error) {
      fun(signal_number);
    }
  }

  bool Application::atSignal(boost::function<void (int)> func, int signal)
  {
    if (!globalIoService)
    {
      globalIoService = new boost::asio::io_service;
      // Prevent run from exiting
      globalIoWork = new boost::asio::io_service::work(*globalIoService);
      // Start io_service in a thread. It will call our handlers.
      globalIoThread = new boost::thread(&run_io_service);
      // We want signal handlers to work as late as possible.
      ::atexit(&stop_io_service);
      globalSignalSet = new std::list<boost::asio::signal_set*>;
    }

    boost::asio::signal_set *sset = new boost::asio::signal_set(*globalIoService, signal);
    sset->async_wait(boost::bind(signal_handler, _1, _2, func));
    globalSignalSet->push_back(sset);
    return true;
  }

  template<typename T> static T& lazyGet(T* & ptr)
  {
    if (!ptr)
      ptr = new T;
    return *ptr;
  }

  static std::string guess_app_from_path(int argc, const char *argv[])
  {
    boost::filesystem::path execPath(argv[0], qi::unicodeFacet());
    execPath = boost::filesystem::system_complete(execPath).make_preferred();
    execPath = boost::filesystem::path(detail::normalizePath(execPath.string(qi::unicodeFacet())), qi::unicodeFacet());

    //arg0 does not exists, or is not a program (directory)
    if (!boost::filesystem::exists(execPath) || boost::filesystem::is_directory(execPath))
    {
      std::string filename = execPath.filename().string(qi::unicodeFacet());
      std::string envPath = qi::os::getenv("PATH");
      size_t begin = 0;
#ifndef _WIN32
      size_t end = envPath.find(":", begin);
#else
      size_t end = envPath.find(";", begin);
#endif
      while (end != std::string::npos)
      {
        std::string realPath = "";

        realPath = envPath.substr(begin, end - begin);
        boost::filesystem::path p(realPath, qi::unicodeFacet());
        p /= filename;
        p = boost::filesystem::system_complete(p).make_preferred();
        p = boost::filesystem::path(detail::normalizePath(p.string(qi::unicodeFacet())), qi::unicodeFacet());

        if (boost::filesystem::exists(p) && !boost::filesystem::is_directory(p))
          return p.string(qi::unicodeFacet());

        begin = end + 1;
#ifndef _WIN32
        end = envPath.find(":", begin);
#else
        end = envPath.find(";", begin);
#endif
      }
    }
    else
      return execPath.string(qi::unicodeFacet());
    return std::string();
  }

  static void initApp(int& argc, char ** &argv)
  {
    readPathConf();
    if (globalInitialized)
      throw std::logic_error("Application was already initialized");
    globalInitialized = true;
    globalArgc = argc;
    globalArgv = argv;
    std::vector<std::string>& args = lazyGet(globalArguments);
    args.clear();
    for (int i=0; i<argc; ++i)
      args.push_back(argv[i]);

    FunctionList& fl = lazyGet(globalAtEnter);
    qiLogDebug() << "Executing " << fl.size() << " atEnter handlers";
    for (FunctionList::iterator i = fl.begin(); i!= fl.end(); ++i)
      (*i)();
    fl.clear();
    argc = Application::argc();
    argv = globalArgv;
  }

  Application::Application(int& argc, char ** &argv)
  {
    initApp(argc, argv);
  }

  Application::Application(const std::string &name, int& argc, char ** &argv)
  {
    globalName = name;
    initApp(argc, argv);
  }

  void* Application::loadModule(const std::string& moduleName, int flags)
  {
    void* handle = os::dlopen(moduleName.c_str(), flags);
    if (!handle)
    {
      qiLogVerbose() << "dlopen failed with " << os::dlerror();
    }
    else
    {
      qiLogDebug() << "Loadmodule " << handle;
    }
    // Reprocess atEnter list in case the module had AT_ENTER
    FunctionList& fl = lazyGet(globalAtEnter);
    qiLogDebug() << "Executing " << fl.size() << " atEnter handlers";
    for (FunctionList::iterator i = fl.begin(); i!= fl.end(); ++i)
      (*i)();
    fl.clear();
    return handle;
  }

  void Application::unloadModule(void* handle)
  {
    os::dlclose(handle);
  }

  Application::~Application()
  {
    FunctionList& fl = lazyGet(globalAtExit);
    for (FunctionList::iterator i = fl.begin(); i!= fl.end(); ++i)
      (*i)();
    globalCond.notify_all();
    globalTerminated = true;
  }

  static void initSigIntSigTermCatcher() {
    bool signalInit = false;

    if (!signalInit) {
      qiLogVerbose() << "Registering SIGINT/SIGTERM handler within qi::Application";
      // kill with no signal sends TERM, control-c sends INT.
      Application::atSignal(boost::bind(&stop_handler, _1), SIGTERM);
      Application::atSignal(boost::bind(&stop_handler, _1), SIGINT);
      signalInit = true;
    }
  }

  void Application::run()
  {
    //run is called, so we catch sigint/sigterm, the default implementation call Application::stop that
    //will make this loop exit.
    initSigIntSigTermCatcher();

    // We just need a barrier, so no need to share the mutex
    boost::mutex m;
    boost::unique_lock<boost::mutex> l(m);
    globalCond.wait(l);
    l.unlock();
  }

  void Application::stop()
  {
    globalCond.notify_all();
    FunctionList& fl = lazyGet(globalAtStop);
    qiLogDebug() << "Executing " << fl.size() << " atStop handlers";
    for (FunctionList::iterator i = fl.begin(); i!= fl.end(); ++i)
      (*i)();
  }

  void Application::setName(const std::string &name)
  {
    globalName = name;
  }

  std::string Application::name()
  {
    return globalName;
  }

  void Application::setArguments(const std::vector<std::string>& args)
  {
    globalArgc = static_cast<int>(args.size());
    lazyGet(globalArguments) = args;
    globalArgv = new char*[args.size() + 1];
    for (unsigned i=0; i<args.size(); ++i)
      globalArgv[i] = strdup(args[i].c_str());
    globalArgv[args.size()] = 0;
  }

  void Application::setArguments(int argc, char** argv)
  {
    globalArgc = argc;
    globalArgv = argv;
    std::vector<std::string>& args = lazyGet(globalArguments);
    args.resize(argc);
    for (int i=0; i<argc; ++i)
      args[i] = argv[i];
  }

  bool Application::initialized()
  {
    return globalInitialized;
  }

  bool Application::terminated()
  {
    return globalTerminated;
  }

  int Application::argc()
  {
    return globalArgc;
  }

  const char** Application::argv()
  {
    return (const char**)globalArgv;
  }

  bool Application::atEnter(boost::function<void()> func)
  {
    qiLogDebug() << "atEnter";
    lazyGet(globalAtEnter).push_back(func);
    return true;
  }

  bool Application::atExit(boost::function<void()> func)
  {
    lazyGet(globalAtExit).push_back(func);
    return true;
  }

  bool Application::atStop(boost::function<void()> func)
  {
    //If the client call atStop, it mean it will handle the proper destruction
    //of the program by itself. So here we catch SigInt/SigTerm to call Application::stop
    //and let the developer properly stop the application as needed.
    initSigIntSigTermCatcher();
    lazyGet(globalAtStop).push_back(func);
    return true;
  }

  const std::vector<std::string>& Application::arguments()
  {
    return lazyGet(globalArguments);
  }

/*
  http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
  Some OS-specific interfaces:
  Mac OS X: _NSGetExecutablePath() (man 3 dyld)
  Linux   : readlink /proc/self/exe
  Solaris : getexecname()
  FreeBSD : sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1
  BSD with procfs: readlink /proc/curproc/file
  Windows : GetModuleFileName() with hModule = NULL

  The portable (but less reliable) method is to use argv[0].
  Although it could be set to anything by the calling program,
  by convention it is set to either a path name of the executable
  or a name that was found using $PATH.

  Some shells, including bash and ksh, set the environment variable "_"
  to the full path of the executable before it is executed. In that case
  you can use getenv("_") to get it. However this is unreliable because
  not all shells do this, and it could be set to anything or be left over
  from a parent process which did not change it before executing your program.
*/
  const char *Application::program()
  {
    try
    {
      if (!globalProgram.empty())
        return globalProgram.c_str();

#ifdef __APPLE__
      {
        char *fname = (char *)malloc(PATH_MAX);
        uint32_t sz = PATH_MAX;
        fname[0] = 0;
        int ret;
        ret = _NSGetExecutablePath(fname, &sz);
        if (ret == 0)
        {
          globalProgram = fname;
          globalProgram = detail::normalizePath(globalProgram);
        }
        else
        {
          globalProgram = guess_app_from_path(::qi::Application::argc(),
            ::qi::Application::argv());
        }
        free(fname);
      }
#elif __linux__
      boost::filesystem::path p("/proc/self/exe");
      boost::filesystem::path fname = boost::filesystem::read_symlink(p);

      if (!boost::filesystem::is_empty(fname))
        globalProgram = fname.string().c_str();
      else
        globalProgram = guess_app_from_path(::qi::Application::argc(),
          ::qi::Application::argv());
#elif _WIN32
      WCHAR fname[MAX_PATH];
      int ret = GetModuleFileNameW(NULL, fname, MAX_PATH);
      if (ret > 0)
      {
        fname[ret] = '\0';
        boost::filesystem::path programPath(fname, qi::unicodeFacet());
        globalProgram = programPath.string(qi::unicodeFacet());
      }
      else
      {
        // GetModuleFileName failed, trying to guess from argc, argv...
        globalProgram = guess_app_from_path(::qi::Application::argc(),
          ::qi::Application::argv());
      }
#else
      globalProgram = guess_app_from_path(::qi::Application::argc(),
        ::qi::Application::argv());
#endif
      return globalProgram.c_str();
    }
    catch (...)
    {
      return NULL;
    }
  }

  int argc()
  {
    return Application::argc();
  }

  const char** argv()
  {
    return Application::argv();
  }

  //this is not threadsafe
  void init(int& argc, char**& argv)
  {
    static qi::Application *app = 0;

    qiLogError() << "qi::init() is deprecated, use qi::Application";
    if (!app)
      app = new qi::Application(argc, argv);
  }
}
<|endoftext|>


<commit_before>#include <node.h>

#include <stdint.h>
#include <cstring>
#include <string>

#include "../argon2/include/argon2.h"
#include "argon2_node.h"

namespace NodeArgon2 {

template<class T = uint32_t>
T fromJust(v8::Local<v8::Value> info) {
    return Nan::To<T>(info).FromJust();
}

using size_type = std::string::size_type;

enum OBJECTS {
    RESERVED = 0,
    THIS_OBJ,
    RESOLVE,
    REJECT,
};

constexpr uint32_t log(uint64_t number, uint64_t base = 2u)
{
    return (number > 1) ? 1u + log(number / base, base) : 0u;
}

constexpr size_type base64Length(size_type length)
{
    return ((length + 2u) / 3u) * 4u;
}

size_type encodedLength(size_type hashLength, size_type saltLength)
{
    /* statically calculate maximum encoded hash length */
    constexpr size_type extraLength = sizeof "$argon2x$m=,t=,p=$$" +
        log(static_cast<uint64_t>(ARGON2_MAX_MEMORY) + 1u, 10u) +
        log(static_cast<uint64_t>(ARGON2_MAX_TIME) + 1u, 10u) +
        log(static_cast<uint64_t>(ARGON2_MAX_LANES) + 1u, 10u);

    return extraLength + base64Length(hashLength) + base64Length(saltLength);
}

HashWorker::HashWorker(std::string&& plain, std::string&& salt,
        uint32_t l, uint32_t t, uint32_t m, uint32_t p, argon2_type a, bool raw):
    Nan::AsyncWorker{nullptr}, plain{std::move(plain)}, salt{std::move(salt)},
    hash_length{l}, time_cost{t}, memory_cost{m}, parallelism{p}, type{a}, raw{raw}
{ }

void HashWorker::Execute()
{
    int result;

    if (raw) {
        output.reset(new char[hash_length]);

        result = argon2_hash(time_cost, 1u << memory_cost, parallelism,
                plain.c_str(), plain.size(), salt.c_str(), salt.size(), output.get(),
                hash_length, nullptr, 0, type, ARGON2_VERSION_NUMBER);
    } else {
        const auto ENCODED_LEN = encodedLength(hash_length, salt.size());
        output.reset(new char[ENCODED_LEN]);

        result = argon2_hash(time_cost, 1u << memory_cost, parallelism,
                plain.c_str(), plain.size(), salt.c_str(), salt.size(), nullptr,
                hash_length, output.get(), ENCODED_LEN, type, ARGON2_VERSION_NUMBER);
    }

    if (result != ARGON2_OK) {
        /* LCOV_EXCL_START */
        SetErrorMessage(argon2_error_message(result));
        /* LCOV_EXCL_STOP */
    }
}

void HashWorker::HandleOKCallback()
{
    using namespace v8;
    using std::strlen;

    Nan::HandleScope scope;

    if (raw) {
        Local<Value> argv[] = {Nan::NewBuffer(output.release(), hash_length).ToLocalChecked()};
        Nan::MakeCallback(GetFromPersistent(THIS_OBJ).As<Object>(),
            GetFromPersistent(RESOLVE).As<Function>(), 1, argv);
    } else {
        Local<Value> argv[] = {Nan::Encode(output.get(), strlen(output.get()))};
        Nan::MakeCallback(GetFromPersistent(THIS_OBJ).As<Object>(),
            GetFromPersistent(RESOLVE).As<Function>(), 1, argv);
    }
}

/* LCOV_EXCL_START */
void HashWorker::HandleErrorCallback()
{
    using namespace v8;

    Nan::HandleScope scope;

    Local<Value> argv[] = {Nan::New(ErrorMessage()).ToLocalChecked()};
    Nan::MakeCallback(GetFromPersistent(THIS_OBJ).As<Object>(),
            GetFromPersistent(REJECT).As<Function>(), 1, argv);
}
/* LCOV_EXCL_STOP */

NAN_METHOD(Hash) {
    using namespace node;
    using namespace v8;

    assert(info.Length() >= 5);

    const auto plain = Nan::To<Object>(info[0]).ToLocalChecked();
    const auto salt = Nan::To<Object>(info[1]).ToLocalChecked();
    const auto options = Nan::To<Object>(info[2]).ToLocalChecked();

    const auto getArg = [&](const char* key) {
        auto localKey = Nan::New(key).ToLocalChecked();
        return Nan::Get(options, localKey).ToLocalChecked();
    };

    auto worker = new HashWorker{
            {Buffer::Data(plain), Buffer::Length(plain)},
            {Buffer::Data(salt), Buffer::Length(salt)},
            fromJust(getArg("hashLength")), fromJust(getArg("timeCost")),
            fromJust(getArg("memoryCost")), fromJust(getArg("parallelism")),
            argon2_type(fromJust(getArg("type"))), fromJust<bool>(getArg("raw"))
            };

    worker->SaveToPersistent(THIS_OBJ, info.This());
    worker->SaveToPersistent(RESOLVE, Local<Function>::Cast(info[3]));
    worker->SaveToPersistent(REJECT, Local<Function>::Cast(info[4]));

    Nan::AsyncQueueWorker(worker);
}

VerifyWorker::VerifyWorker(std::string&& hash, std::string&& plain):
    Nan::AsyncWorker{nullptr}, hash{std::move(hash)}, plain{std::move(plain)}
{ }

void VerifyWorker::Execute()
{
    argon2_type type;

    if(hash.at(7) == 'd') {
        type = Argon2_d;
    }
    else if(hash.at(8) == 'd') {
        type = Argon2_id;
    }
    else {
        type = Argon2_i;
    }

    auto result = argon2_verify(hash.c_str(), plain.c_str(), plain.size(), type);

    switch (result) {
        case ARGON2_OK:
        case ARGON2_VERIFY_MISMATCH:
            output = result == ARGON2_OK;
            break;
        default:
            /* LCOV_EXCL_START */
            SetErrorMessage(argon2_error_message(result));
            break;
            /* LCOV_EXCL_STOP */
    }
}

void VerifyWorker::HandleOKCallback()
{
    using namespace v8;

    Nan::HandleScope scope;

    Local<Value> argv[] = {Nan::New(output)};
    Nan::MakeCallback(GetFromPersistent(THIS_OBJ).As<Object>(),
            GetFromPersistent(RESOLVE).As<Function>(), 1, argv);
}

/* LCOV_EXCL_START */
void VerifyWorker::HandleErrorCallback()
{
    using namespace v8;

    Nan::HandleScope scope;

    Local<Value> argv[] = {Nan::New(ErrorMessage()).ToLocalChecked()};
    Nan::MakeCallback(GetFromPersistent(THIS_OBJ).As<Object>(),
            GetFromPersistent(REJECT).As<Function>(), 1, argv);
}
/* LCOV_EXCL_STOP */

NAN_METHOD(Verify) {
    using namespace node;
    using namespace v8;

    assert(info.Length() >= 4);

    const auto hash = Nan::To<Object>(info[0]).ToLocalChecked();
    const auto plain = Nan::To<Object>(info[1]).ToLocalChecked();

    auto worker = new VerifyWorker{{Buffer::Data(hash), Buffer::Length(hash)},
            {Buffer::Data(plain), Buffer::Length(plain)}};

    worker->SaveToPersistent(THIS_OBJ, info.This());
    worker->SaveToPersistent(RESOLVE, Local<Function>::Cast(info[2]));
    worker->SaveToPersistent(REJECT, Local<Function>::Cast(info[3]));

    Nan::AsyncQueueWorker(worker);
}

NAN_MODULE_INIT(init) {
    using namespace v8;

    auto limits = Nan::New<Object>();

    const auto setMaxMin = [&](const char* name, uint32_t max, uint32_t min) {
        auto obj = Nan::New<Object>();
        Nan::Set(obj, Nan::New("max").ToLocalChecked(), Nan::New<Number>(max));
        Nan::Set(obj, Nan::New("min").ToLocalChecked(), Nan::New<Number>(min));
        Nan::Set(limits, Nan::New(name).ToLocalChecked(), obj);
    };

    setMaxMin("hashLength", ARGON2_MAX_OUTLEN, ARGON2_MIN_OUTLEN);
    setMaxMin("memoryCost", log(ARGON2_MAX_MEMORY), log(ARGON2_MIN_MEMORY));
    setMaxMin("timeCost", ARGON2_MAX_TIME, ARGON2_MIN_TIME);
    setMaxMin("parallelism", ARGON2_MAX_LANES, ARGON2_MIN_LANES);

    Nan::Set(target, Nan::New("limits").ToLocalChecked(), limits);
    Nan::Export(target, "hash", Hash);
    Nan::Export(target, "verify", Verify);
}

}

NODE_MODULE(argon2_lib, NodeArgon2::init);
<commit_msg>Fix encoded length reserved space<commit_after>#include <node.h>

#include <stdint.h>
#include <cstring>
#include <string>

#include "../argon2/include/argon2.h"
#include "argon2_node.h"

namespace NodeArgon2 {

template<class T = uint32_t>
T fromJust(v8::Local<v8::Value> info) {
    return Nan::To<T>(info).FromJust();
}

using size_type = std::string::size_type;

enum OBJECTS {
    RESERVED = 0,
    THIS_OBJ,
    RESOLVE,
    REJECT,
};

constexpr uint32_t log(uint64_t number, uint64_t base = 2u)
{
    return (number > 1) ? 1u + log(number / base, base) : 0u;
}

constexpr size_type base64Length(size_type length)
{
    return ((length + 2u) / 3u) * 4u;
}

size_type encodedLength(size_type hashLength, size_type saltLength)
{
    /* statically calculate maximum encoded hash length */
    constexpr size_type extraLength = sizeof "$argon2xx$v=$m=,t=,p=$$" +
        log(static_cast<uint64_t>(ARGON2_VERSION_NUMBER) + 1u, 10u) +
        log(static_cast<uint64_t>(ARGON2_MAX_MEMORY) + 1u, 10u) +
        log(static_cast<uint64_t>(ARGON2_MAX_TIME) + 1u, 10u) +
        log(static_cast<uint64_t>(ARGON2_MAX_LANES) + 1u, 10u);

    return extraLength + base64Length(hashLength) + base64Length(saltLength);
}

HashWorker::HashWorker(std::string&& plain, std::string&& salt,
        uint32_t l, uint32_t t, uint32_t m, uint32_t p, argon2_type a, bool raw):
    Nan::AsyncWorker{nullptr}, plain{std::move(plain)}, salt{std::move(salt)},
    hash_length{l}, time_cost{t}, memory_cost{m}, parallelism{p}, type{a}, raw{raw}
{ }

void HashWorker::Execute()
{
    int result;

    if (raw) {
        output.reset(new char[hash_length]);

        result = argon2_hash(time_cost, 1u << memory_cost, parallelism,
                plain.c_str(), plain.size(), salt.c_str(), salt.size(), output.get(),
                hash_length, nullptr, 0, type, ARGON2_VERSION_NUMBER);
    } else {
        const auto ENCODED_LEN = encodedLength(hash_length, salt.size());
        output.reset(new char[ENCODED_LEN]);

        result = argon2_hash(time_cost, 1u << memory_cost, parallelism,
                plain.c_str(), plain.size(), salt.c_str(), salt.size(), nullptr,
                hash_length, output.get(), ENCODED_LEN, type, ARGON2_VERSION_NUMBER);
    }

    if (result != ARGON2_OK) {
        /* LCOV_EXCL_START */
        SetErrorMessage(argon2_error_message(result));
        /* LCOV_EXCL_STOP */
    }
}

void HashWorker::HandleOKCallback()
{
    using namespace v8;
    using std::strlen;

    Nan::HandleScope scope;

    if (raw) {
        Local<Value> argv[] = {Nan::NewBuffer(output.release(), hash_length).ToLocalChecked()};
        Nan::MakeCallback(GetFromPersistent(THIS_OBJ).As<Object>(),
            GetFromPersistent(RESOLVE).As<Function>(), 1, argv);
    } else {
        Local<Value> argv[] = {Nan::Encode(output.get(), strlen(output.get()))};
        Nan::MakeCallback(GetFromPersistent(THIS_OBJ).As<Object>(),
            GetFromPersistent(RESOLVE).As<Function>(), 1, argv);
    }
}

/* LCOV_EXCL_START */
void HashWorker::HandleErrorCallback()
{
    using namespace v8;

    Nan::HandleScope scope;

    Local<Value> argv[] = {Nan::New(ErrorMessage()).ToLocalChecked()};
    Nan::MakeCallback(GetFromPersistent(THIS_OBJ).As<Object>(),
            GetFromPersistent(REJECT).As<Function>(), 1, argv);
}
/* LCOV_EXCL_STOP */

NAN_METHOD(Hash) {
    using namespace node;
    using namespace v8;

    assert(info.Length() >= 5);

    const auto plain = Nan::To<Object>(info[0]).ToLocalChecked();
    const auto salt = Nan::To<Object>(info[1]).ToLocalChecked();
    const auto options = Nan::To<Object>(info[2]).ToLocalChecked();

    const auto getArg = [&](const char* key) {
        auto localKey = Nan::New(key).ToLocalChecked();
        return Nan::Get(options, localKey).ToLocalChecked();
    };

    auto worker = new HashWorker{
            {Buffer::Data(plain), Buffer::Length(plain)},
            {Buffer::Data(salt), Buffer::Length(salt)},
            fromJust(getArg("hashLength")), fromJust(getArg("timeCost")),
            fromJust(getArg("memoryCost")), fromJust(getArg("parallelism")),
            argon2_type(fromJust(getArg("type"))), fromJust<bool>(getArg("raw"))
            };

    worker->SaveToPersistent(THIS_OBJ, info.This());
    worker->SaveToPersistent(RESOLVE, Local<Function>::Cast(info[3]));
    worker->SaveToPersistent(REJECT, Local<Function>::Cast(info[4]));

    Nan::AsyncQueueWorker(worker);
}

VerifyWorker::VerifyWorker(std::string&& hash, std::string&& plain):
    Nan::AsyncWorker{nullptr}, hash{std::move(hash)}, plain{std::move(plain)}
{ }

void VerifyWorker::Execute()
{
    argon2_type type;

    if(hash.at(7) == 'd') {
        type = Argon2_d;
    }
    else if(hash.at(8) == 'd') {
        type = Argon2_id;
    }
    else {
        type = Argon2_i;
    }

    auto result = argon2_verify(hash.c_str(), plain.c_str(), plain.size(), type);

    switch (result) {
        case ARGON2_OK:
        case ARGON2_VERIFY_MISMATCH:
            output = result == ARGON2_OK;
            break;
        default:
            /* LCOV_EXCL_START */
            SetErrorMessage(argon2_error_message(result));
            break;
            /* LCOV_EXCL_STOP */
    }
}

void VerifyWorker::HandleOKCallback()
{
    using namespace v8;

    Nan::HandleScope scope;

    Local<Value> argv[] = {Nan::New(output)};
    Nan::MakeCallback(GetFromPersistent(THIS_OBJ).As<Object>(),
            GetFromPersistent(RESOLVE).As<Function>(), 1, argv);
}

/* LCOV_EXCL_START */
void VerifyWorker::HandleErrorCallback()
{
    using namespace v8;

    Nan::HandleScope scope;

    Local<Value> argv[] = {Nan::New(ErrorMessage()).ToLocalChecked()};
    Nan::MakeCallback(GetFromPersistent(THIS_OBJ).As<Object>(),
            GetFromPersistent(REJECT).As<Function>(), 1, argv);
}
/* LCOV_EXCL_STOP */

NAN_METHOD(Verify) {
    using namespace node;
    using namespace v8;

    assert(info.Length() >= 4);

    const auto hash = Nan::To<Object>(info[0]).ToLocalChecked();
    const auto plain = Nan::To<Object>(info[1]).ToLocalChecked();

    auto worker = new VerifyWorker{{Buffer::Data(hash), Buffer::Length(hash)},
            {Buffer::Data(plain), Buffer::Length(plain)}};

    worker->SaveToPersistent(THIS_OBJ, info.This());
    worker->SaveToPersistent(RESOLVE, Local<Function>::Cast(info[2]));
    worker->SaveToPersistent(REJECT, Local<Function>::Cast(info[3]));

    Nan::AsyncQueueWorker(worker);
}

NAN_MODULE_INIT(init) {
    using namespace v8;

    auto limits = Nan::New<Object>();

    const auto setMaxMin = [&](const char* name, uint32_t max, uint32_t min) {
        auto obj = Nan::New<Object>();
        Nan::Set(obj, Nan::New("max").ToLocalChecked(), Nan::New<Number>(max));
        Nan::Set(obj, Nan::New("min").ToLocalChecked(), Nan::New<Number>(min));
        Nan::Set(limits, Nan::New(name).ToLocalChecked(), obj);
    };

    setMaxMin("hashLength", ARGON2_MAX_OUTLEN, ARGON2_MIN_OUTLEN);
    setMaxMin("memoryCost", log(ARGON2_MAX_MEMORY), log(ARGON2_MIN_MEMORY));
    setMaxMin("timeCost", ARGON2_MAX_TIME, ARGON2_MIN_TIME);
    setMaxMin("parallelism", ARGON2_MAX_LANES, ARGON2_MIN_LANES);

    Nan::Set(target, Nan::New("limits").ToLocalChecked(), limits);
    Nan::Export(target, "hash", Hash);
    Nan::Export(target, "verify", Verify);
}

}

NODE_MODULE(argon2_lib, NodeArgon2::init);
<|endoftext|>


<commit_before>// Copyright (C) 2012-2016 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include <autowiring/CoreJob.h>
#include THREAD_HEADER

class CoreJobTest:
  public testing::Test
{};

TEST_F(CoreJobTest, VerifySimpleProperties) {
  AutoRequired<CoreJob> jb;
  AutoCurrentContext ctxt;

  ASSERT_FALSE(ctxt->IsInitiated()) << "CoreJob reported it could receive events before its enclosing context was created";

  // Create a thread which will delay for acceptance, and then quit:
  std::mutex lock;
  std::condition_variable cv;
  auto done = std::make_shared<bool>(false);
  std::thread t([&] {
    ctxt->DelayUntilInitiated();

    (std::lock_guard<std::mutex>)lock,
    *done = true,
    cv.notify_all();
  });

  auto wait = [&] (std::chrono::milliseconds timeout) {
    std::unique_lock<std::mutex> lk(lock);
    return cv.wait_for(lk, timeout, [&] { return *done; });
  };

  // Verify that this thread doesn't back out right away:
  ASSERT_FALSE(wait(std::chrono::milliseconds(10))) << "CoreJob did not block a client who was waiting for its readiness to accept dispatchers";

  // Now start the context and verify that certain properties changed as anticipated:
  ctxt->Initiate();
  ASSERT_TRUE(ctxt->DelayUntilInitiated()) << "CoreJob did not correctly delay for dispatch acceptance";

  // Verify that the blocked thread has become unblocked and quits properly:
  ASSERT_TRUE(wait(std::chrono::seconds(1))) << "CoreJob did not correctly signal a blocked thread that it was ready to accept dispatchers";

  ctxt->SignalShutdown(true);
  t.join();
}

TEST_F(CoreJobTest, VerifySimpleSubmission) {
  AutoRequired<CoreJob> jb;

  auto myFlag = std::make_shared<bool>(false);
  *jb += [myFlag] {
    *myFlag = true;
  };

  // Kickoff, signal for a shutdown to take place, and then verify the flag
  AutoCurrentContext ctxt;
  ctxt->Initiate();
  ctxt->SignalShutdown(true);
  ASSERT_TRUE(*myFlag) << "CoreJob did not properly execute its thread";
}

TEST_F(CoreJobTest, VerifyTeardown) {
  AutoRequired<CoreJob> job;
  AutoCurrentContext ctxt;

  bool check1 = false;
  bool check2 = false;
  bool check3 = false;

  *job += [&check1] {
    std::this_thread::sleep_for(std::chrono::milliseconds(2));
    check1 = true;
  };
  *job += [&check2] {
    std::this_thread::sleep_for(std::chrono::milliseconds(2));
    check2 = true;
  };
  ctxt->Initiate();
  *job += [&check3] {
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
    check3 = true;
  };

  ctxt->SignalShutdown(true);
  ASSERT_TRUE(check1) << "Lambda 1 didn't finish";
  ASSERT_TRUE(check2) << "Lambda 2 didn't finish";
  ASSERT_TRUE(check3) << "Lambda 3 didn't finish";
}

TEST_F(CoreJobTest, AbandonedDispatchers) {
  auto v = std::make_shared<bool>(false);

  AutoRequired<CoreJob> cj;
  *cj += [v] { *v = true; };

  // Graceful shutdown on our enclosing context without starting it:
  AutoCurrentContext()->SignalShutdown(true);

  // Verify that all lambdas on the CoreThread got called as expected:
  ASSERT_FALSE(*v) << "Lambdas attached to a CoreJob should not be executed when the enclosing context is terminated without being started";
}

TEST_F(CoreJobTest, RecursiveAdd) {
  bool first = false;
  bool second = false;
  bool third = false;

  AutoRequired<CoreJob> cj;

  AutoCurrentContext()->Initiate();

  *cj += [&first,&second,&third, &cj] {
    first = true;
    *cj += [&first,&second,&third,&cj] {
      second = true;
      *cj += [&first,&second,&third,&cj] {
        third = true;
      };
      cj->Stop(true);
    };
  };

  cj->Wait();

  // Verify that all lambdas on the CoreThread got called as expected:
  ASSERT_TRUE(first) << "Appended lambda didn't set value";
  ASSERT_TRUE(second) << "Appended lambda didn't set value";
  ASSERT_TRUE(third) << "Appended lambda didn't set value";
}

TEST_F(CoreJobTest, RaceCondition) {
  AutoCurrentContext()->Initiate();

  for (int i=0; i<5; i++) {
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);
    AutoRequired<CoreJob> cj;
    ctxt->Initiate();

    bool first = false;
    bool second = false;

    *cj += [&first] {
      first = true;
    };

    std::this_thread::sleep_for(std::chrono::milliseconds(i));

    *cj += [&second, &cj] {
      second = true;
    };

    ctxt->SignalShutdown(true);

    ASSERT_TRUE(first) << "Failed after set value in lambda";
    ASSERT_TRUE(second) << "Failed to set value when delayed " << i << " milliseconds";
  }
}

TEST_F(CoreJobTest, CorrectlyAssignedCurrentContext) {
  AutoCurrentContext()->Initiate();
  AutoRequired<CoreJob> job;

  std::shared_ptr<CoreContext> ctxt;
  *job += [&ctxt] { ctxt = AutoCurrentContext(); };
  *job += [job] { job->Stop(true); };
  ASSERT_TRUE(job->WaitFor(std::chrono::seconds(5)));

  // Now verify that the job was run in the right thread context:
  ASSERT_EQ(AutoCurrentContext(), ctxt) << "Job lambda was not run with the correct CoreContext current";
}

TEST_F(CoreJobTest, RecursiveDeadlock) {
  // Create a CoreJob which will wait for a bit.  Then, delegate its deletion responsibility to the thread
  // itself, a
  AutoCreateContext ctxt;
  AutoRequired<CoreJob> cj(ctxt);
  *cj += [] {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  };
}
<commit_msg>Add test that pends from multiple threads at once<commit_after>// Copyright (C) 2012-2016 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include <autowiring/CoreJob.h>
#include THREAD_HEADER
#include ARRAY_HEADER

class CoreJobTest:
  public testing::Test
{};

TEST_F(CoreJobTest, VerifySimpleProperties) {
  AutoRequired<CoreJob> jb;
  AutoCurrentContext ctxt;

  ASSERT_FALSE(ctxt->IsInitiated()) << "CoreJob reported it could receive events before its enclosing context was created";

  // Create a thread which will delay for acceptance, and then quit:
  std::mutex lock;
  std::condition_variable cv;
  auto done = std::make_shared<bool>(false);
  std::thread t([&] {
    ctxt->DelayUntilInitiated();

    (std::lock_guard<std::mutex>)lock,
    *done = true,
    cv.notify_all();
  });

  auto wait = [&] (std::chrono::milliseconds timeout) {
    std::unique_lock<std::mutex> lk(lock);
    return cv.wait_for(lk, timeout, [&] { return *done; });
  };

  // Verify that this thread doesn't back out right away:
  ASSERT_FALSE(wait(std::chrono::milliseconds(10))) << "CoreJob did not block a client who was waiting for its readiness to accept dispatchers";

  // Now start the context and verify that certain properties changed as anticipated:
  ctxt->Initiate();
  ASSERT_TRUE(ctxt->DelayUntilInitiated()) << "CoreJob did not correctly delay for dispatch acceptance";

  // Verify that the blocked thread has become unblocked and quits properly:
  ASSERT_TRUE(wait(std::chrono::seconds(1))) << "CoreJob did not correctly signal a blocked thread that it was ready to accept dispatchers";

  ctxt->SignalShutdown(true);
  t.join();
}

TEST_F(CoreJobTest, VerifySimpleSubmission) {
  AutoRequired<CoreJob> jb;

  auto myFlag = std::make_shared<bool>(false);
  *jb += [myFlag] {
    *myFlag = true;
  };

  // Kickoff, signal for a shutdown to take place, and then verify the flag
  AutoCurrentContext ctxt;
  ctxt->Initiate();
  ctxt->SignalShutdown(true);
  ASSERT_TRUE(*myFlag) << "CoreJob did not properly execute its thread";
}

TEST_F(CoreJobTest, VerifyTeardown) {
  AutoRequired<CoreJob> job;
  AutoCurrentContext ctxt;

  bool check1 = false;
  bool check2 = false;
  bool check3 = false;

  *job += [&check1] {
    std::this_thread::sleep_for(std::chrono::milliseconds(2));
    check1 = true;
  };
  *job += [&check2] {
    std::this_thread::sleep_for(std::chrono::milliseconds(2));
    check2 = true;
  };
  ctxt->Initiate();
  *job += [&check3] {
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
    check3 = true;
  };

  ctxt->SignalShutdown(true);
  ASSERT_TRUE(check1) << "Lambda 1 didn't finish";
  ASSERT_TRUE(check2) << "Lambda 2 didn't finish";
  ASSERT_TRUE(check3) << "Lambda 3 didn't finish";
}

TEST_F(CoreJobTest, AbandonedDispatchers) {
  auto v = std::make_shared<bool>(false);

  AutoRequired<CoreJob> cj;
  *cj += [v] { *v = true; };

  // Graceful shutdown on our enclosing context without starting it:
  AutoCurrentContext()->SignalShutdown(true);

  // Verify that all lambdas on the CoreThread got called as expected:
  ASSERT_FALSE(*v) << "Lambdas attached to a CoreJob should not be executed when the enclosing context is terminated without being started";
}

TEST_F(CoreJobTest, RecursiveAdd) {
  bool first = false;
  bool second = false;
  bool third = false;

  AutoRequired<CoreJob> cj;

  AutoCurrentContext()->Initiate();

  *cj += [&first,&second,&third, &cj] {
    first = true;
    *cj += [&first,&second,&third,&cj] {
      second = true;
      *cj += [&first,&second,&third,&cj] {
        third = true;
      };
      cj->Stop(true);
    };
  };

  cj->Wait();

  // Verify that all lambdas on the CoreThread got called as expected:
  ASSERT_TRUE(first) << "Appended lambda didn't set value";
  ASSERT_TRUE(second) << "Appended lambda didn't set value";
  ASSERT_TRUE(third) << "Appended lambda didn't set value";
}

TEST_F(CoreJobTest, RaceCondition) {
  AutoCurrentContext()->Initiate();

  for (int i=0; i<5; i++) {
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);
    AutoRequired<CoreJob> cj;
    ctxt->Initiate();

    bool first = false;
    bool second = false;

    *cj += [&first] {
      first = true;
    };

    std::this_thread::sleep_for(std::chrono::milliseconds(i));

    *cj += [&second, &cj] {
      second = true;
    };

    ctxt->SignalShutdown(true);

    ASSERT_TRUE(first) << "Failed after set value in lambda";
    ASSERT_TRUE(second) << "Failed to set value when delayed " << i << " milliseconds";
  }
}

TEST_F(CoreJobTest, CorrectlyAssignedCurrentContext) {
  AutoCurrentContext()->Initiate();
  AutoRequired<CoreJob> job;

  std::shared_ptr<CoreContext> ctxt;
  *job += [&ctxt] { ctxt = AutoCurrentContext(); };
  *job += [job] { job->Stop(true); };
  ASSERT_TRUE(job->WaitFor(std::chrono::seconds(5)));

  // Now verify that the job was run in the right thread context:
  ASSERT_EQ(AutoCurrentContext(), ctxt) << "Job lambda was not run with the correct CoreContext current";
}

TEST_F(CoreJobTest, RecursiveDeadlock) {
  // Create a CoreJob which will wait for a bit.  Then, delegate its deletion responsibility to the thread
  // itself, a
  AutoCreateContext ctxt;
  AutoRequired<CoreJob> cj(ctxt);
  *cj += [] {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  };
}

TEST_F(CoreJobTest, PendFromMultipleThreads) {
  AutoCurrentContext ctxt;
  AutoRequired<CoreJob> cj;
  std::array<std::thread, 4> threads;
  const size_t times{ 256 };
  int counter{ 0 };

  for (size_t i = 0; i < threads.size(); i++) {
    threads[i] = std::thread([&] {
      ctxt->DelayUntilInitiated();
      for (int j = 0; j < times; j++) {
        *cj += [&counter] {
          counter++; // Should be updated exclusively in the CoreJob's thread
        };
      }
    });
  }
  ctxt->Initiate();
  for (size_t i = 0; i < threads.size(); i++) {
    threads[i].join();
  }
  ctxt->SignalShutdown(true);
  ASSERT_EQ(times*threads.size(), counter);
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/custom_handlers/protocol_handler_registry.h"

#include "base/memory/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/custom_handlers/protocol_handler.h"
#include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "content/browser/child_process_security_policy.h"
#include "net/base/network_delegate.h"
#include "net/url_request/url_request_redirect_job.h"

// ProtocolHandlerRegistry -----------------------------------------------------

ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile,
    Delegate* delegate)
  : profile_(profile),
    delegate_(delegate),
    enabled_(true) {
}

ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
  STLDeleteContainerPairSecondPointers(protocol_handlers_.begin(),
      protocol_handlers_.end());
  STLDeleteContainerPointers(ignored_protocol_handlers_.begin(),
      ignored_protocol_handlers_.end());
}

static void RemoveAndDelete(ProtocolHandlerMap& handlers,
    const std::string& scheme) {
  ProtocolHandlerMap::iterator p = handlers.find(scheme);
  if (p != handlers.end()) {
    ProtocolHandler* removed_handler = p->second;
    handlers.erase(p);
    delete removed_handler;
  }
}

void ProtocolHandlerRegistry::RegisterProtocolHandler(
    ProtocolHandler* handler) {
  DCHECK(CanSchemeBeOverridden(handler->protocol()));
  if (enabled_) {
    delegate_->RegisterExternalHandler(handler->protocol());
  }
  RemoveAndDelete(protocol_handlers_, handler->protocol());
  protocol_handlers_[handler->protocol()] = handler;
}

void ProtocolHandlerRegistry::IgnoreProtocolHandler(ProtocolHandler* handler) {
  ignored_protocol_handlers_.push_back(handler);
}

void ProtocolHandlerRegistry::Enable() {
  if (enabled_) {
    return;
  }
  enabled_ = true;
  for (ProtocolHandlerMap::const_iterator p = protocol_handlers_.begin();
      p != protocol_handlers_.end(); p++) {
    delegate_->RegisterExternalHandler(p->first);
  }
}

void ProtocolHandlerRegistry::Disable() {
  if (!enabled_) {
    return;
  }
  enabled_ = false;
  for (ProtocolHandlerMap::const_iterator p = protocol_handlers_.begin();
      p != protocol_handlers_.end(); p++) {
    delegate_->DeregisterExternalHandler(p->first);
  }
}

ProtocolHandlerList ProtocolHandlerRegistry::GetHandlersFromPref(
    const char* pref_name) {
  ProtocolHandlerList result;
  PrefService* prefs = profile_->GetPrefs();
  if (!prefs->HasPrefPath(pref_name)) {
    return result;
  }

  const ListValue* handlers = prefs->GetList(pref_name);
  if (handlers) {
    for (size_t i = 0; i < handlers->GetSize(); i++) {
      DictionaryValue* dict;
      handlers->GetDictionary(i, &dict);
      ProtocolHandler* handler = ProtocolHandler::CreateProtocolHandler(dict);
      if (handler) {
        result.push_back(handler);
      }
    }
  }
  return result;
}

void ProtocolHandlerRegistry::Load() {
  PrefService* prefs = profile_->GetPrefs();
  if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) {
    enabled_ = prefs->GetBoolean(prefs::kCustomHandlersEnabled);
  }
  ProtocolHandlerList registered_handlers =
    GetHandlersFromPref(prefs::kRegisteredProtocolHandlers);
  for (ProtocolHandlerList::iterator p = registered_handlers.begin();
      p != registered_handlers.end(); p++) {
    RegisterProtocolHandler(*p);
  }
  ProtocolHandlerList ignored_handlers =
    GetHandlersFromPref(prefs::kIgnoredProtocolHandlers);
  for (ProtocolHandlerList::iterator p = ignored_handlers.begin();
      p != ignored_handlers.end(); p++) {
    IgnoreProtocolHandler(*p);
  }
}

void ProtocolHandlerRegistry::RegisterHandlerFromValue(
    const DictionaryValue* value) {
  ProtocolHandler* handler = ProtocolHandler::CreateProtocolHandler(value);
  if (handler) {
    RegisterProtocolHandler(handler);
  }
}

void ProtocolHandlerRegistry::Save() {
  scoped_ptr<Value> registered_protocol_handlers(EncodeRegisteredHandlers());
  scoped_ptr<Value> ignored_protocol_handlers(EncodeIgnoredHandlers());
  scoped_ptr<Value> enabled(Value::CreateBooleanValue(enabled_));
  profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers,
      *registered_protocol_handlers);
  profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers,
      *ignored_protocol_handlers);
  profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled);
  profile_->GetPrefs()->ScheduleSavePersistentPrefs();
}

ProtocolHandler* ProtocolHandlerRegistry::GetHandlerFor(
    const std::string& scheme) const {
  ProtocolHandlerMap::const_iterator i = protocol_handlers_.find(scheme);
  return i == protocol_handlers_.end() ? NULL : i->second;
}

bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
    const std::string& scheme) const {
  return GetHandlerFor(scheme) != NULL ||
    !delegate_->IsExternalHandlerRegistered(scheme);
}

void ProtocolHandlerRegistry::GetHandledProtocols(
    std::vector<std::string>* output) {
  ProtocolHandlerMap::iterator p;
  for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); p++) {
    output->push_back(p->first);
  }
}

void ProtocolHandlerRegistry::RemoveHandlerFor(const std::string& scheme) {
  RemoveAndDelete(protocol_handlers_, scheme);
  net::URLRequest::RegisterProtocolFactory(scheme, NULL);
  Save();
}

void ProtocolHandlerRegistry::RemoveIgnoredHandler(ProtocolHandler* handler) {
  for (ProtocolHandlerList::iterator p = ignored_protocol_handlers_.begin();
      p != ignored_protocol_handlers_.end(); p++) {
    if (*handler == **p) {
      ProtocolHandler* removed_handler = *p;
      ignored_protocol_handlers_.erase(p);
      delete removed_handler;
      break;
    }
  }
}

bool ProtocolHandlerRegistry::IsRegistered(
    const ProtocolHandler* handler) const {
  ProtocolHandler* currentHandler = GetHandlerFor(handler->protocol());
  return currentHandler && *currentHandler == *handler;
}

bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler* handler) const {
  ProtocolHandlerList::const_iterator i;
  for (i = ignored_protocol_handlers_.begin();
      i != ignored_protocol_handlers_.end(); i++) {
    if (**i == *handler) {
      return true;
    }
  }
  return false;
}

bool ProtocolHandlerRegistry::IsHandledProtocol(
    const std::string& scheme) const {
  return GetHandlerFor(scheme);
}

net::URLRequestJob* ProtocolHandlerRegistry::Factory(net::URLRequest* request,
    const std::string& scheme) {
  return request->context()->network_delegate()->MaybeCreateURLRequestJob(
      request);
}

net::URLRequestJob* ProtocolHandlerRegistry::MaybeCreateJob(
    net::URLRequest* request) const {
  ProtocolHandler* handler = GetHandlerFor(request->url().scheme());

  if (!handler) {
    return NULL;
  }

  GURL translated_url(handler->TranslateUrl(request->url()));

  if (!translated_url.is_valid()) {
    return NULL;
  }

  return new net::URLRequestRedirectJob(request, translated_url);
}

Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
  ListValue* protocol_handlers = new ListValue();

  for (ProtocolHandlerMap::iterator i = protocol_handlers_.begin();
      i != protocol_handlers_.end(); ++i) {
    protocol_handlers->Append(i->second->Encode());
  }
  return protocol_handlers;
}

Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
  ListValue* handlers = new ListValue();

  for (ProtocolHandlerList::iterator i = ignored_protocol_handlers_.begin();
      i != ignored_protocol_handlers_.end(); ++i) {
    handlers->Append((*i)->Encode());
  }
  return handlers;
}

void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
    ProtocolHandler* handler) {
  RegisterProtocolHandler(handler);
  Save();
}

void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
    ProtocolHandler* handler) {
}

void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
    ProtocolHandler* handler) {
  IgnoreProtocolHandler(handler);
  Save();
}

void ProtocolHandlerRegistry::RegisterPrefs(PrefService* prefService) {
  prefService->RegisterListPref(prefs::kRegisteredProtocolHandlers);
  prefService->RegisterListPref(prefs::kIgnoredProtocolHandlers);
  prefService->RegisterBooleanPref(prefs::kCustomHandlersEnabled, true);
}

// Delegate --------------------------------------------------------------------

ProtocolHandlerRegistry::Delegate::~Delegate() {
}

void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler(
    const std::string& protocol) {
  ChildProcessSecurityPolicy* policy =
    ChildProcessSecurityPolicy::GetInstance();
  if (!policy->IsWebSafeScheme(protocol)) {
    policy->RegisterWebSafeScheme(protocol);
  }
  net::URLRequest::RegisterProtocolFactory(protocol,
      &ProtocolHandlerRegistry::Factory);
}

void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
    const std::string& protocol) {
  net::URLRequest::RegisterProtocolFactory(protocol, NULL);
}

bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered(
    const std::string& protocol) {
  return net::URLRequest::IsHandledProtocol(protocol);
}
<commit_msg>Make pointer to bool conversion explicit.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/custom_handlers/protocol_handler_registry.h"

#include "base/memory/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/custom_handlers/protocol_handler.h"
#include "chrome/browser/custom_handlers/register_protocol_handler_infobar_delegate.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "content/browser/child_process_security_policy.h"
#include "net/base/network_delegate.h"
#include "net/url_request/url_request_redirect_job.h"

// ProtocolHandlerRegistry -----------------------------------------------------

ProtocolHandlerRegistry::ProtocolHandlerRegistry(Profile* profile,
    Delegate* delegate)
  : profile_(profile),
    delegate_(delegate),
    enabled_(true) {
}

ProtocolHandlerRegistry::~ProtocolHandlerRegistry() {
  STLDeleteContainerPairSecondPointers(protocol_handlers_.begin(),
      protocol_handlers_.end());
  STLDeleteContainerPointers(ignored_protocol_handlers_.begin(),
      ignored_protocol_handlers_.end());
}

static void RemoveAndDelete(ProtocolHandlerMap& handlers,
    const std::string& scheme) {
  ProtocolHandlerMap::iterator p = handlers.find(scheme);
  if (p != handlers.end()) {
    ProtocolHandler* removed_handler = p->second;
    handlers.erase(p);
    delete removed_handler;
  }
}

void ProtocolHandlerRegistry::RegisterProtocolHandler(
    ProtocolHandler* handler) {
  DCHECK(CanSchemeBeOverridden(handler->protocol()));
  if (enabled_) {
    delegate_->RegisterExternalHandler(handler->protocol());
  }
  RemoveAndDelete(protocol_handlers_, handler->protocol());
  protocol_handlers_[handler->protocol()] = handler;
}

void ProtocolHandlerRegistry::IgnoreProtocolHandler(ProtocolHandler* handler) {
  ignored_protocol_handlers_.push_back(handler);
}

void ProtocolHandlerRegistry::Enable() {
  if (enabled_) {
    return;
  }
  enabled_ = true;
  for (ProtocolHandlerMap::const_iterator p = protocol_handlers_.begin();
      p != protocol_handlers_.end(); p++) {
    delegate_->RegisterExternalHandler(p->first);
  }
}

void ProtocolHandlerRegistry::Disable() {
  if (!enabled_) {
    return;
  }
  enabled_ = false;
  for (ProtocolHandlerMap::const_iterator p = protocol_handlers_.begin();
      p != protocol_handlers_.end(); p++) {
    delegate_->DeregisterExternalHandler(p->first);
  }
}

ProtocolHandlerList ProtocolHandlerRegistry::GetHandlersFromPref(
    const char* pref_name) {
  ProtocolHandlerList result;
  PrefService* prefs = profile_->GetPrefs();
  if (!prefs->HasPrefPath(pref_name)) {
    return result;
  }

  const ListValue* handlers = prefs->GetList(pref_name);
  if (handlers) {
    for (size_t i = 0; i < handlers->GetSize(); i++) {
      DictionaryValue* dict;
      handlers->GetDictionary(i, &dict);
      ProtocolHandler* handler = ProtocolHandler::CreateProtocolHandler(dict);
      if (handler) {
        result.push_back(handler);
      }
    }
  }
  return result;
}

void ProtocolHandlerRegistry::Load() {
  PrefService* prefs = profile_->GetPrefs();
  if (prefs->HasPrefPath(prefs::kCustomHandlersEnabled)) {
    enabled_ = prefs->GetBoolean(prefs::kCustomHandlersEnabled);
  }
  ProtocolHandlerList registered_handlers =
    GetHandlersFromPref(prefs::kRegisteredProtocolHandlers);
  for (ProtocolHandlerList::iterator p = registered_handlers.begin();
      p != registered_handlers.end(); p++) {
    RegisterProtocolHandler(*p);
  }
  ProtocolHandlerList ignored_handlers =
    GetHandlersFromPref(prefs::kIgnoredProtocolHandlers);
  for (ProtocolHandlerList::iterator p = ignored_handlers.begin();
      p != ignored_handlers.end(); p++) {
    IgnoreProtocolHandler(*p);
  }
}

void ProtocolHandlerRegistry::RegisterHandlerFromValue(
    const DictionaryValue* value) {
  ProtocolHandler* handler = ProtocolHandler::CreateProtocolHandler(value);
  if (handler) {
    RegisterProtocolHandler(handler);
  }
}

void ProtocolHandlerRegistry::Save() {
  scoped_ptr<Value> registered_protocol_handlers(EncodeRegisteredHandlers());
  scoped_ptr<Value> ignored_protocol_handlers(EncodeIgnoredHandlers());
  scoped_ptr<Value> enabled(Value::CreateBooleanValue(enabled_));
  profile_->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers,
      *registered_protocol_handlers);
  profile_->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers,
      *ignored_protocol_handlers);
  profile_->GetPrefs()->Set(prefs::kCustomHandlersEnabled, *enabled);
  profile_->GetPrefs()->ScheduleSavePersistentPrefs();
}

ProtocolHandler* ProtocolHandlerRegistry::GetHandlerFor(
    const std::string& scheme) const {
  ProtocolHandlerMap::const_iterator i = protocol_handlers_.find(scheme);
  return i == protocol_handlers_.end() ? NULL : i->second;
}

bool ProtocolHandlerRegistry::CanSchemeBeOverridden(
    const std::string& scheme) const {
  return GetHandlerFor(scheme) != NULL ||
    !delegate_->IsExternalHandlerRegistered(scheme);
}

void ProtocolHandlerRegistry::GetHandledProtocols(
    std::vector<std::string>* output) {
  ProtocolHandlerMap::iterator p;
  for (p = protocol_handlers_.begin(); p != protocol_handlers_.end(); p++) {
    output->push_back(p->first);
  }
}

void ProtocolHandlerRegistry::RemoveHandlerFor(const std::string& scheme) {
  RemoveAndDelete(protocol_handlers_, scheme);
  net::URLRequest::RegisterProtocolFactory(scheme, NULL);
  Save();
}

void ProtocolHandlerRegistry::RemoveIgnoredHandler(ProtocolHandler* handler) {
  for (ProtocolHandlerList::iterator p = ignored_protocol_handlers_.begin();
      p != ignored_protocol_handlers_.end(); p++) {
    if (*handler == **p) {
      ProtocolHandler* removed_handler = *p;
      ignored_protocol_handlers_.erase(p);
      delete removed_handler;
      break;
    }
  }
}

bool ProtocolHandlerRegistry::IsRegistered(
    const ProtocolHandler* handler) const {
  ProtocolHandler* currentHandler = GetHandlerFor(handler->protocol());
  return currentHandler && *currentHandler == *handler;
}

bool ProtocolHandlerRegistry::IsIgnored(const ProtocolHandler* handler) const {
  ProtocolHandlerList::const_iterator i;
  for (i = ignored_protocol_handlers_.begin();
      i != ignored_protocol_handlers_.end(); i++) {
    if (**i == *handler) {
      return true;
    }
  }
  return false;
}

bool ProtocolHandlerRegistry::IsHandledProtocol(
    const std::string& scheme) const {
  return GetHandlerFor(scheme) != NULL;
}

net::URLRequestJob* ProtocolHandlerRegistry::Factory(net::URLRequest* request,
    const std::string& scheme) {
  return request->context()->network_delegate()->MaybeCreateURLRequestJob(
      request);
}

net::URLRequestJob* ProtocolHandlerRegistry::MaybeCreateJob(
    net::URLRequest* request) const {
  ProtocolHandler* handler = GetHandlerFor(request->url().scheme());

  if (!handler) {
    return NULL;
  }

  GURL translated_url(handler->TranslateUrl(request->url()));

  if (!translated_url.is_valid()) {
    return NULL;
  }

  return new net::URLRequestRedirectJob(request, translated_url);
}

Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
  ListValue* protocol_handlers = new ListValue();

  for (ProtocolHandlerMap::iterator i = protocol_handlers_.begin();
      i != protocol_handlers_.end(); ++i) {
    protocol_handlers->Append(i->second->Encode());
  }
  return protocol_handlers;
}

Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
  ListValue* handlers = new ListValue();

  for (ProtocolHandlerList::iterator i = ignored_protocol_handlers_.begin();
      i != ignored_protocol_handlers_.end(); ++i) {
    handlers->Append((*i)->Encode());
  }
  return handlers;
}

void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
    ProtocolHandler* handler) {
  RegisterProtocolHandler(handler);
  Save();
}

void ProtocolHandlerRegistry::OnDenyRegisterProtocolHandler(
    ProtocolHandler* handler) {
}

void ProtocolHandlerRegistry::OnIgnoreRegisterProtocolHandler(
    ProtocolHandler* handler) {
  IgnoreProtocolHandler(handler);
  Save();
}

void ProtocolHandlerRegistry::RegisterPrefs(PrefService* prefService) {
  prefService->RegisterListPref(prefs::kRegisteredProtocolHandlers);
  prefService->RegisterListPref(prefs::kIgnoredProtocolHandlers);
  prefService->RegisterBooleanPref(prefs::kCustomHandlersEnabled, true);
}

// Delegate --------------------------------------------------------------------

ProtocolHandlerRegistry::Delegate::~Delegate() {
}

void ProtocolHandlerRegistry::Delegate::RegisterExternalHandler(
    const std::string& protocol) {
  ChildProcessSecurityPolicy* policy =
    ChildProcessSecurityPolicy::GetInstance();
  if (!policy->IsWebSafeScheme(protocol)) {
    policy->RegisterWebSafeScheme(protocol);
  }
  net::URLRequest::RegisterProtocolFactory(protocol,
      &ProtocolHandlerRegistry::Factory);
}

void ProtocolHandlerRegistry::Delegate::DeregisterExternalHandler(
    const std::string& protocol) {
  net::URLRequest::RegisterProtocolFactory(protocol, NULL);
}

bool ProtocolHandlerRegistry::Delegate::IsExternalHandlerRegistered(
    const std::string& protocol) {
  return net::URLRequest::IsHandledProtocol(protocol);
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014-2015 Darrell Wright
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files( the "Software" ), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <vector>

#include "nodepp_rfb.h"

namespace daw {
	namespace rfb {
		namespace impl {
			class RFBServerImpl {
				uint16_t m_width;
				uint16_t m_height;
				uint8_t m_bit_depth;
				std::vector<uint8_t> m_buffer;
			public:
				RFBServerImpl( uint16_t width, uint16_t height, uint8_t bit_depth, daw::nodepp::base::EventEmitter emitter ):
					m_width{ width },
					m_height{ height },
					m_bit_depth{ bit_depth },
					m_buffer( static_cast<size_t>(width*height*bit_depth), 0 ) {
				}

				uint16_t width( ) const {
					return m_width;
				}

				uint16_t height( ) const {
					return m_height;
				}

				Box get_area( uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2 ) {
					assert( y2 >= y1 );
					assert( x2 >= x1 );
					Box result;
					result.reserve( static_cast<size_t>(y2 - y1) );

					auto const width = x2 - x1;
					for( size_t n = y1; n < y2; ++n ) {
						auto p1 = m_buffer.begin( ) + (m_width*n) + x1;
						auto rng = daw::range::make_range( p1, p1 + width );
						result.push_back( rng );
					}
					return result;
				}
			};	// class RFBServerImpl
		}	// namespace impl
		namespace {
			constexpr uint8_t get_bit_depth( BitDepth::values bit_depth ) {
				return bit_depth == BitDepth::eight ? 8 : bit_depth == BitDepth::sixteen ? 16 : 32;
			}
		}	// namespace anonymous

		RFBServer::RFBServer( uint16_t width, uint16_t height, BitDepth::values depth, daw::nodepp::base::EventEmitter emitter ):
			m_impl( std::make_unique<impl::RFBServerImpl>( width, height, get_bit_depth( depth ), std::move( emitter ) ) ) {

		}

		RFBServer::~RFBServer( ) { }	// Empty but cannot use default.  The destructor on std::unique_ptr needs to know the full info for RFBServerImpl

		RFBServer::RFBServer( RFBServer && other ): m_impl( std::move( other.m_impl ) ) { }

		RFBServer & RFBServer::operator=( RFBServer && rhs ) {
			if( this != &rhs ) {
				m_impl = std::move( rhs.m_impl );
			}
			return *this;
		}

		uint16_t RFBServer::width( ) const {
			return m_impl->width( );
		}

		uint16_t RFBServer::height( ) const {
			return m_impl->height( );
		}

		void RFBServer::listen( uint16_t port ) {

		}

		void RFBServer::close( ) {

		}

		void RFBServer::on_key_event( std::function<void( bool key_down, uint32_t key )> callback ) {
		}

		void RFBServer::on_pointer_event( std::function<void( ButtonMask buttons, uint16_t x_position, uint16_t y_position )> callback ) {
		}

		void RFBServer::on_client_clipboard_text( std::function<void( boost::string_ref text )> callback ) {
		}

		Box RFBServer::get_area( uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2 ) {
			return m_impl->get_area( x1, y1, x2, y2 );
		}

		void RFBServer::update( ) {
		}
	}	// namespace rfb
}    // namespace daw
<commit_msg>Starting to add basic routines to update framebuffer<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014-2015 Darrell Wright
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files( the "Software" ), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <vector>

#include "nodepp_rfb.h"

namespace daw {
	namespace rfb {
		namespace impl {
			class RFBServerImpl {
				uint16_t m_width;
				uint16_t m_height;
				uint8_t m_bit_depth;
				std::vector<uint8_t> m_buffer;
			public:
				RFBServerImpl( uint16_t width, uint16_t height, uint8_t bit_depth, daw::nodepp::base::EventEmitter emitter ):
					m_width{ width },
					m_height{ height },
					m_bit_depth{ bit_depth },
					m_buffer( static_cast<size_t>(width*height*bit_depth), 0 ) {
				}

				uint16_t width( ) const {
					return m_width;
				}

				uint16_t height( ) const {
					return m_height;
				}

				Box get_area( uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2 ) {
					assert( y2 >= y1 );
					assert( x2 >= x1 );
					Box result;
					result.reserve( static_cast<size_t>(y2 - y1) );

					auto const width = x2 - x1;
					for( size_t n = y1; n < y2; ++n ) {
						auto p1 = m_buffer.data( ) + (m_width*n) + x1;
						auto rng = daw::range::make_range( p1, p1 + width );
						result.push_back( rng );
					}
					return result;
				}
			};	// class RFBServerImpl
		}	// namespace impl
		namespace {
			constexpr uint8_t get_bit_depth( BitDepth::values bit_depth ) {
				return bit_depth == BitDepth::eight ? 8 : bit_depth == BitDepth::sixteen ? 16 : 32;
			}
		}	// namespace anonymous

		RFBServer::RFBServer( uint16_t width, uint16_t height, BitDepth::values depth, daw::nodepp::base::EventEmitter emitter ):
			m_impl( std::make_unique<impl::RFBServerImpl>( width, height, get_bit_depth( depth ), std::move( emitter ) ) ) {

		}

		RFBServer::~RFBServer( ) { }	// Empty but cannot use default.  The destructor on std::unique_ptr needs to know the full info for RFBServerImpl

		RFBServer::RFBServer( RFBServer && other ): m_impl( std::move( other.m_impl ) ) { }

		RFBServer & RFBServer::operator=( RFBServer && rhs ) {
			if( this != &rhs ) {
				m_impl = std::move( rhs.m_impl );
			}
			return *this;
		}

		uint16_t RFBServer::width( ) const {
			return m_impl->width( );
		}

		uint16_t RFBServer::height( ) const {
			return m_impl->height( );
		}

		void RFBServer::listen( uint16_t port ) {

		}

		void RFBServer::close( ) {

		}

		void RFBServer::on_key_event( std::function<void( bool key_down, uint32_t key )> callback ) {
		}

		void RFBServer::on_pointer_event( std::function<void( ButtonMask buttons, uint16_t x_position, uint16_t y_position )> callback ) {
		}

		void RFBServer::on_client_clipboard_text( std::function<void( boost::string_ref text )> callback ) {
		}

		Box RFBServer::get_area( uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2 ) {
			return m_impl->get_area( x1, y1, x2, y2 );
		}

		void RFBServer::update( ) {
		}
	}	// namespace rfb
}    // namespace daw
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin.
 *
 * libbitcoin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef LIBBITCOIN_CONTAINER_SOURCE_HPP
#define LIBBITCOIN_CONTAINER_SOURCE_HPP

#include <algorithm>
#include <cstdint>
#include <boost/iostreams/categories.hpp>
#include <bitcoin/bitcoin/define.hpp>
#include <bitcoin/bitcoin/utility/assert.hpp>

namespace libbitcoin {

// modified from boost.iostreams example
// boost.org/doc/libs/1_55_0/libs/iostreams/doc/tutorial/container_source.html
template<typename Container, typename SourceType, typename CharType>
class BC_API container_source
{
public:
    typedef CharType char_type;
    typedef boost::iostreams::source_tag category;

    container_source(const Container& container)
      : container_(container), position_(0)
    {
        static_assert(sizeof(SourceType) == sizeof(CharType), "invalid size");
    }

    std::streamsize read(char_type* buffer, std::streamsize size)
    {
        const auto amount = container_.size() - position_;
        auto result = std::min(size, static_cast<std::streamsize>(amount));

        // TODO: use ios eof symbol (template-based).
        if (result <= 0)
            return -1;

        const auto value = static_cast<typename Container::size_type>(result);
        DEBUG_ONLY(const auto maximum =
            std::numeric_limits<typename Container::size_type>::max());
        BITCOIN_ASSERT(result < maximum);
        BITCOIN_ASSERT(position_ + value < maximum);
        const auto upperbound = position_ + value;
        std::copy(container_.begin() + position_,
            container_.begin() + upperbound, buffer);
        position_ = upperbound;
        return result;
    }

private:
    const Container& container_;
    typename Container::size_type position_;
};

template<typename Container>
using byte_source = container_source<Container, uint8_t, char>;

using data_source = boost::iostreams::stream<byte_source<data_chunk>>;

} // namespace libbitcoin

#endif

<commit_msg>Fix debug-only warning.<commit_after>/**
 * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin.
 *
 * libbitcoin is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef LIBBITCOIN_CONTAINER_SOURCE_HPP
#define LIBBITCOIN_CONTAINER_SOURCE_HPP

#include <algorithm>
#include <cstdint>
#include <boost/iostreams/categories.hpp>
#include <bitcoin/bitcoin/define.hpp>
#include <bitcoin/bitcoin/utility/assert.hpp>

namespace libbitcoin {

// modified from boost.iostreams example
// boost.org/doc/libs/1_55_0/libs/iostreams/doc/tutorial/container_source.html
template<typename Container, typename SourceType, typename CharType>
class BC_API container_source
{
public:
    typedef CharType char_type;
    typedef boost::iostreams::source_tag category;

    container_source(const Container& container)
      : container_(container), position_(0)
    {
        static_assert(sizeof(SourceType) == sizeof(CharType), "invalid size");
    }

    std::streamsize read(char_type* buffer, std::streamsize size)
    {
        const auto amount = container_.size() - position_;
        size_t result = std::min(size, static_cast<std::streamsize>(amount));

        // TODO: use ios eof symbol (template-based).
        if (result <= 0)
            return -1;

        const auto value = static_cast<typename Container::size_type>(result);
        DEBUG_ONLY(const auto maximum =
            std::numeric_limits<typename Container::size_type>::max());
        BITCOIN_ASSERT(result < maximum);
        BITCOIN_ASSERT(position_ + value < maximum);
        const auto upperbound = position_ + value;
        std::copy(container_.begin() + position_,
            container_.begin() + upperbound, buffer);
        position_ = upperbound;
        return result;
    }

private:
    const Container& container_;
    typename Container::size_type position_;
};

template<typename Container>
using byte_source = container_source<Container, uint8_t, char>;

using data_source = boost::iostreams::stream<byte_source<data_chunk>>;

} // namespace libbitcoin

#endif

<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// 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
//
//     https://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 "distbench_threadpool.h"

namespace distbench {

DistbenchThreadpool::DistbenchThreadpool(int nb_threads) {

  for (int i = 0; i < nb_threads; i++) {
    auto task_runner = [&, i]() {
      do {
        std::function<void()> task;
        {
          absl::MutexLock m(&mutex_);
          if (work_queue_.empty()) {
            // All threads except thread-0 relinquish CPU
            // if there is no work.
            if ( i != 0 ) sched_yield();
            if (shutdown_.HasBeenNotified()) return;
            continue;
          }
          task = work_queue_.front();
          work_queue_.pop();
        }
        task();
      } while (true);
    };
    threads_.push_back(RunRegisteredThread("ThreadPool", task_runner));
  }
}

DistbenchThreadpool::~DistbenchThreadpool() {
  shutdown_.Notify();
  for (auto& thread : threads_) {
    thread.join();
  }
}

void DistbenchThreadpool::AddWork(std::function<void()> function) {
  absl::MutexLock m(&mutex_);
  work_queue_.push(function);
}

}  // namespace distbench
<commit_msg>Format fixes<commit_after>// Copyright 2022 Google LLC
//
// 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
//
//     https://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 "distbench_threadpool.h"

namespace distbench {

DistbenchThreadpool::DistbenchThreadpool(int nb_threads) {
  for (int i = 0; i < nb_threads; i++) {
    auto task_runner = [&, i]() {
      do {
        std::function<void()> task;
        {
          absl::MutexLock m(&mutex_);
          if (work_queue_.empty()) {
            // All threads except thread-0 relinquish CPU
            // if there is no work.
            if (i != 0) sched_yield();
            if (shutdown_.HasBeenNotified()) return;
            continue;
          }
          task = work_queue_.front();
          work_queue_.pop();
        }
        task();
      } while (true);
    };
    threads_.push_back(RunRegisteredThread("ThreadPool", task_runner));
  }
}

DistbenchThreadpool::~DistbenchThreadpool() {
  shutdown_.Notify();
  for (auto& thread : threads_) {
    thread.join();
  }
}

void DistbenchThreadpool::AddWork(std::function<void()> function) {
  absl::MutexLock m(&mutex_);
  work_queue_.push(function);
}

}  // namespace distbench
<|endoftext|>