<commit_before>/* Copyright (C) 2018 INRA
 *
 * 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 <array>

#include "private.hpp"
#include "utils.hpp"

#ifdef BARYONYX_HAVE_NLOPT
#include <nlopt.hpp>
#include <utility>
#endif

struct manual_course
{
    std::array<double, 5> theta = { { 0.0, 0.3, 0.5, 0.7, 1.0 } };
    std::array<double, 5> delta = { { -1, 1e-2, 0.05, 0.001, 0.0003 } };
    std::array<double, 5> kappa_min = { { 0, 1e-2, 0.05, 0.1, 0.3 } };
    std::array<double, 5> kappa_step = { { 1e-7, 1e-5, 1e-3, 1e-2, 1e-1 } };
    std::array<double, 5> init_random = { { 0.0, 0.3, 0.5, 0.7, 1.0 } };
    std::array<int, 5> it = { { 0, 0, 0, 0, 0 } };

    void reset()
    {
        std::fill(it.begin(), it.end(), 0);
    }

    bool next()
    {
        auto size = static_cast<int>(it.size() - 1);

        for (int i = size; i >= 0; --i) {
            if (it[i] + 1 > 4) {
                it[i] = 0;
            } else {
                ++it[i];
                return true;
            }
        }

        return false;
    }
};

static baryonyx::result
manual_optimize(const baryonyx::context_ptr& ctx, baryonyx::problem& pb)
{
    ctx->parameters.auto_tune =
      baryonyx::solver_parameters::auto_tune_parameters::disabled;

    manual_course array;

    std::array<int, 5> best_params;
    double best = +HUGE_VAL;

    do {
        ctx->parameters.theta = array.theta[array.it[0]];
        ctx->parameters.delta = array.delta[array.it[1]];
        ctx->parameters.kappa_min = array.kappa_min[array.it[2]];
        ctx->parameters.kappa_step = array.kappa_step[array.it[3]];
        ctx->parameters.init_random = array.init_random[array.it[4]];

        auto copy_pb = pb;
        auto ret = baryonyx::optimize(ctx, copy_pb);
        if (ret) {
            if (best > ret.solutions.back().value) {
                best = ret.solutions.back().value;
                best_params = array.it;
            }
        }
    } while (array.next());

    baryonyx::notice(
      ctx,
      "  - manual optimization found solution {}: with theta:{} "
      "delta:{} kappa-min:{} kappa-step:{} init-random:{}\n",
      best,
      array.theta[array.it[0]],
      array.delta[array.it[1]],
      array.kappa_min[array.it[2]],
      array.kappa_step[array.it[3]],
      array.init_random[array.it[4]]);

    return baryonyx::optimize(ctx, pb);
}

#ifdef BARYONYX_HAVE_NLOPT
enum param
{
    param_theta = 0,
    // param_delta,
    param_kappa_min,
    param_kappa_step,
    param_init_random
};

struct nlopt_data
{
    nlopt_data(const baryonyx::context_ptr& ctx_, baryonyx::problem  pb_)
      : ctx(ctx_)
      , pb(std::move(pb_))
    {}

    const baryonyx::context_ptr& ctx;
    const baryonyx::problem pb;
};

static double
nlopt_optimize_fun(const std::vector<double>& x,
                   std::vector<double>& /*grad*/,
                   void* data_orig)
{
    try {
        auto* data = reinterpret_cast<nlopt_data*>(data_orig);

        data->ctx->parameters.theta = x[static_cast<int>(param_theta)];
        // data->ctx->parameters.delta = x[static_cast<int>(param_delta)];
        data->ctx->parameters.kappa_min = x[static_cast<int>(param_kappa_min)];
        data->ctx->parameters.kappa_step =
          x[static_cast<int>(param_kappa_step)];
        data->ctx->parameters.init_random =
          x[static_cast<int>(param_init_random)];

        auto copy_pb(data->pb);
        auto ret = baryonyx::optimize(data->ctx, copy_pb);
        if (not(ret))
            return HUGE_VAL;

        // baryonyx::notice(data->ctx,
        //                  "theta: {} delta: {} kappa_min: {} kappa_step: {} "
        //                  "init_random: {}: {}\n",
        //                  data->ctx->parameters.theta,
        //                  data->ctx->parameters.delta,
        //                  data->ctx->parameters.kappa_min,
        //                  data->ctx->parameters.kappa_step,
        //                  data->ctx->parameters.init_random,
        //                  ret.solutions.back().value);

        baryonyx::notice(data->ctx,
                         "theta: {} kappa_min: {} kappa_step: {} "
                         "init_random: {}: {}\n",
                         data->ctx->parameters.theta,
                         data->ctx->parameters.kappa_min,
                         data->ctx->parameters.kappa_step,
                         data->ctx->parameters.init_random,
                         ret.solutions.back().value);

        return ret.solutions.back().value;
    } catch (const std::exception& e) {
        fmt::print("Exception in nlopt_optimize_fun: {}\n", e.what());
    }
    return HUGE_VAL;
}

static baryonyx::result
nlopt_optimize(const baryonyx::context_ptr& ctx, baryonyx::problem& pb)
{
    auto old_log_priority = ctx->log_priority;
    ctx->log_priority = baryonyx::context::message_type::notice;

    ctx->parameters.auto_tune =
      baryonyx::solver_parameters::auto_tune_parameters::disabled;
    nlopt_data data(ctx, pb);

    const std::vector<double> low{ 0, 0.0, 1e-7, 0 };
    const std::vector<double> up{ 1, 0.5, 0.01, 1 };
    std::vector<double> x{ 0.5, 0, 0.001, 0.5 };

    nlopt::opt opt(nlopt::LN_NELDERMEAD, 4);
    opt.set_maxtime(3600);
    opt.set_vector_storage(100);
    opt.set_lower_bounds(low);
    opt.set_upper_bounds(up);
    opt.set_min_objective(nlopt_optimize_fun, reinterpret_cast<void*>(&data));

    //
    // Seems interesting to loop over:
    // - more time-limit
    // - more loop-limit
    // - more optimization algorithms.
    //

    double value;
    auto result = opt.optimize(x, value);

    ctx->log_priority = old_log_priority;

    if (result >= 1 or result == -4) {
        baryonyx::notice(
          ctx,
          "  - nlopt optimization found solution {}: with theta:xxx "
          "delta:{} kappa-min:{} kappa-step:{} init-random:{}\n",
          value,
          x[param_theta],
          // x[param_delta],
          x[param_kappa_min],
          x[param_kappa_step],
          x[param_init_random]);

        ctx->parameters.theta = x[param_theta];
        // ctx->parameters.delta = x[param_delta];
        ctx->parameters.kappa_min = x[param_kappa_min];
        ctx->parameters.kappa_step = x[param_kappa_step];
        ctx->parameters.init_random = x[param_init_random];

        return baryonyx::optimize(ctx, pb);
    } else {
        baryonyx::notice(ctx,
                         "  - nlopt optimization fail. Toggle to manual "
                         "parameters optimization.\n");

        return manual_optimize(ctx, pb);
    }
}
#endif

namespace baryonyx {
namespace itm {

baryonyx::result
automatic_optimizer(const baryonyx::context_ptr& ctx,
                    baryonyx::problem& pb,
                    int thread)
{
    baryonyx::notice(ctx, "- Automatic optimization starts\n");

    assert(ctx->parameters.auto_tune !=
           baryonyx::solver_parameters::auto_tune_parameters::disabled);

    (void)thread;

#ifdef BARYONYX_HAVE_NLOPT
    if (ctx->parameters.auto_tune ==
        baryonyx::solver_parameters::auto_tune_parameters::manual)
        return ::manual_optimize(ctx, pb);
    else
        return ::nlopt_optimize(ctx, pb);
#else
    if (ctx->auto_tune == context::auto_tune_parameters::nlop)
        baryonyx::error(ctx,
                        "Baryonyx does not have nlopt. "
                        "Toggle to manual parameters optimization.\n");

    return ::manual_optimize(ctx, pb);
#endif
}
} // namespace itm
} // namespace baryonyx
<commit_msg>auto: fix code if nlopt is not available<commit_after>/* Copyright (C) 2018 INRA
 *
 * 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 <array>

#include "private.hpp"
#include "utils.hpp"

#ifdef BARYONYX_HAVE_NLOPT
#include <nlopt.hpp>
#include <utility>
#endif

struct manual_course
{
    std::array<double, 5> theta = { { 0.0, 0.3, 0.5, 0.7, 1.0 } };
    std::array<double, 5> delta = { { -1, 1e-2, 0.05, 0.001, 0.0003 } };
    std::array<double, 5> kappa_min = { { 0, 1e-2, 0.05, 0.1, 0.3 } };
    std::array<double, 5> kappa_step = { { 1e-7, 1e-5, 1e-3, 1e-2, 1e-1 } };
    std::array<double, 5> init_random = { { 0.0, 0.3, 0.5, 0.7, 1.0 } };
    std::array<int, 5> it = { { 0, 0, 0, 0, 0 } };

    void reset()
    {
        std::fill(it.begin(), it.end(), 0);
    }

    bool next()
    {
        auto size = static_cast<int>(it.size() - 1);

        for (int i = size; i >= 0; --i) {
            if (it[i] + 1 > 4) {
                it[i] = 0;
            } else {
                ++it[i];
                return true;
            }
        }

        return false;
    }
};

static baryonyx::result
manual_optimize(const baryonyx::context_ptr& ctx, baryonyx::problem& pb)
{
    ctx->parameters.auto_tune =
      baryonyx::solver_parameters::auto_tune_parameters::disabled;

    manual_course array;

    std::array<int, 5> best_params;
    double best = +HUGE_VAL;

    do {
        ctx->parameters.theta = array.theta[array.it[0]];
        ctx->parameters.delta = array.delta[array.it[1]];
        ctx->parameters.kappa_min = array.kappa_min[array.it[2]];
        ctx->parameters.kappa_step = array.kappa_step[array.it[3]];
        ctx->parameters.init_random = array.init_random[array.it[4]];

        auto copy_pb = pb;
        auto ret = baryonyx::optimize(ctx, copy_pb);
        if (ret) {
            if (best > ret.solutions.back().value) {
                best = ret.solutions.back().value;
                best_params = array.it;
            }
        }
    } while (array.next());

    baryonyx::notice(
      ctx,
      "  - manual optimization found solution {}: with theta:{} "
      "delta:{} kappa-min:{} kappa-step:{} init-random:{}\n",
      best,
      array.theta[array.it[0]],
      array.delta[array.it[1]],
      array.kappa_min[array.it[2]],
      array.kappa_step[array.it[3]],
      array.init_random[array.it[4]]);

    return baryonyx::optimize(ctx, pb);
}

#ifdef BARYONYX_HAVE_NLOPT
enum param
{
    param_theta = 0,
    // param_delta,
    param_kappa_min,
    param_kappa_step,
    param_init_random
};

struct nlopt_data
{
    nlopt_data(const baryonyx::context_ptr& ctx_, baryonyx::problem pb_)
      : ctx(ctx_)
      , pb(std::move(pb_))
    {}

    const baryonyx::context_ptr& ctx;
    const baryonyx::problem pb;
};

static double
nlopt_optimize_fun(const std::vector<double>& x,
                   std::vector<double>& /*grad*/,
                   void* data_orig)
{
    try {
        auto* data = reinterpret_cast<nlopt_data*>(data_orig);

        data->ctx->parameters.theta = x[static_cast<int>(param_theta)];
        // data->ctx->parameters.delta = x[static_cast<int>(param_delta)];
        data->ctx->parameters.kappa_min = x[static_cast<int>(param_kappa_min)];
        data->ctx->parameters.kappa_step =
          x[static_cast<int>(param_kappa_step)];
        data->ctx->parameters.init_random =
          x[static_cast<int>(param_init_random)];

        auto copy_pb(data->pb);
        auto ret = baryonyx::optimize(data->ctx, copy_pb);
        if (not(ret))
            return HUGE_VAL;

        // baryonyx::notice(data->ctx,
        //                  "theta: {} delta: {} kappa_min: {} kappa_step: {} "
        //                  "init_random: {}: {}\n",
        //                  data->ctx->parameters.theta,
        //                  data->ctx->parameters.delta,
        //                  data->ctx->parameters.kappa_min,
        //                  data->ctx->parameters.kappa_step,
        //                  data->ctx->parameters.init_random,
        //                  ret.solutions.back().value);

        baryonyx::notice(data->ctx,
                         "theta: {} kappa_min: {} kappa_step: {} "
                         "init_random: {}: {}\n",
                         data->ctx->parameters.theta,
                         data->ctx->parameters.kappa_min,
                         data->ctx->parameters.kappa_step,
                         data->ctx->parameters.init_random,
                         ret.solutions.back().value);

        return ret.solutions.back().value;
    } catch (const std::exception& e) {
        fmt::print("Exception in nlopt_optimize_fun: {}\n", e.what());
    }
    return HUGE_VAL;
}

static baryonyx::result
nlopt_optimize(const baryonyx::context_ptr& ctx, baryonyx::problem& pb)
{
    auto old_log_priority = ctx->log_priority;
    ctx->log_priority = baryonyx::context::message_type::notice;

    ctx->parameters.auto_tune =
      baryonyx::solver_parameters::auto_tune_parameters::disabled;
    nlopt_data data(ctx, pb);

    const std::vector<double> low{ 0, 0.0, 1e-7, 0 };
    const std::vector<double> up{ 1, 0.5, 0.01, 1 };
    std::vector<double> x{ 0.5, 0, 0.001, 0.5 };

    nlopt::opt opt(nlopt::LN_NELDERMEAD, 4);
    opt.set_maxtime(3600);
    opt.set_vector_storage(100);
    opt.set_lower_bounds(low);
    opt.set_upper_bounds(up);
    opt.set_min_objective(nlopt_optimize_fun, reinterpret_cast<void*>(&data));

    //
    // Seems interesting to loop over:
    // - more time-limit
    // - more loop-limit
    // - more optimization algorithms.
    //

    double value;
    auto result = opt.optimize(x, value);

    ctx->log_priority = old_log_priority;

    if (result >= 1 or result == -4) {
        baryonyx::notice(
          ctx,
          "  - nlopt optimization found solution {}: with theta:xxx "
          "delta:{} kappa-min:{} kappa-step:{} init-random:{}\n",
          value,
          x[param_theta],
          // x[param_delta],
          x[param_kappa_min],
          x[param_kappa_step],
          x[param_init_random]);

        ctx->parameters.theta = x[param_theta];
        // ctx->parameters.delta = x[param_delta];
        ctx->parameters.kappa_min = x[param_kappa_min];
        ctx->parameters.kappa_step = x[param_kappa_step];
        ctx->parameters.init_random = x[param_init_random];

        return baryonyx::optimize(ctx, pb);
    } else {
        baryonyx::notice(ctx,
                         "  - nlopt optimization fail. Toggle to manual "
                         "parameters optimization.\n");

        return manual_optimize(ctx, pb);
    }
}
#endif

namespace baryonyx {
namespace itm {

baryonyx::result
automatic_optimizer(const baryonyx::context_ptr& ctx,
                    baryonyx::problem& pb,
                    int thread)
{
    baryonyx::notice(ctx, "- Automatic optimization starts\n");

    assert(ctx->parameters.auto_tune !=
           baryonyx::solver_parameters::auto_tune_parameters::disabled);

    (void)thread;

#ifdef BARYONYX_HAVE_NLOPT
    if (ctx->parameters.auto_tune ==
        baryonyx::solver_parameters::auto_tune_parameters::manual)
        return ::manual_optimize(ctx, pb);
    else
        return ::nlopt_optimize(ctx, pb);
#else
    if (ctx->parameters.auto_tune == context::auto_tune_parameters::nlop)
        baryonyx::error(ctx,
                        "Baryonyx does not have nlopt. "
                        "Toggle to manual parameters optimization.\n");

    return ::manual_optimize(ctx, pb);
#endif
}
} // namespace itm
} // namespace baryonyx
<|endoftext|>


<commit_before>#include <pxp-agent/util/daemonize.hpp>
#include <pxp-agent/configuration.hpp>

#define LEATHERMAN_LOGGING_NAMESPACE "puppetlabs.pxp_agent.util.daemonize"
#include <leatherman/logging/logging.hpp>

#include <sys/types.h>
#include <stdlib.h>         // exit()
#include <unistd.h>         // _exit(), getpid(), fork(), setsid(), chdir()
#include <sys/wait.h>       // waitpid()
#include <sys/stat.h>       // umask()
#include <signal.h>
#include <stdio.h>

#include <memory>
#include <vector>

namespace PXPAgent {
namespace Util {

const mode_t UMASK_FLAGS { 002 };
const std::string DEFAULT_DAEMON_WORKING_DIR = "/";

static void sigHandler(int sig) {
    // NOTE(ale): if issued by the init process, between SIGTERM and
    // the successive SIGKILL there are only 5 s - must be fast
    auto pidfile = Configuration::Instance().get<std::string>("pidfile");
    LOG_INFO("Caught signal {1} - removing PID file '{2}'",
             std::to_string(sig), pidfile);
    PIDFile pidf { pidfile };
    pidf.cleanup();
    exit(EXIT_SUCCESS);
}

static void dumbSigHandler(int sig) {}

std::unique_ptr<PIDFile> daemonize() {
    // Check if we're already a daemon
    if (getppid() == 1) {
        // Parent is init process (PID 1)
        LOG_INFO("Already a daemon with PID={1}", std::to_string(getpid()));
        return nullptr;
    }

    // Set umask; child processes will inherit
    umask(UMASK_FLAGS);

    // Check PID file; get read lock; ensure we can obtain write lock

    auto pidfile = Configuration::Instance().get<std::string>("pidfile");
    std::unique_ptr<PIDFile> pidf_ptr { new PIDFile(pidfile) };

    auto removeLockAndExit = [&pidf_ptr] () {
                                 pidf_ptr->cleanupWhenDone();
                                 exit(EXIT_FAILURE);
                             };

    if (pidf_ptr->isExecuting()) {
        auto pid = pidf_ptr->read();
        LOG_ERROR("Already running with PID={1}", pid);
        removeLockAndExit();
    }

    try {
        pidf_ptr->lockRead();
        LOG_DEBUG("Obtained a read lock for the PID file; no other pxp-agent "
                  "daemon should be executing");
    } catch (const PIDFile::Error& e) {
        LOG_ERROR("Failed get a read lock for the PID file: {1}", e.what());
        removeLockAndExit();
    }

    try {
        if (pidf_ptr->canLockWrite()) {
            LOG_DEBUG("It is possible to get a write lock for the PID file; no "
                      "other pxp-agent daemonization should be in progress");
        } else {
            LOG_ERROR("Cannot acquire the write lock for the PID file; please "
                      "ensure that there is no other pxp-agent instance executing");
            removeLockAndExit();
        }
    } catch (const PIDFile::Error& e) {
        LOG_ERROR("Failed to check if we can lock the PID file: {1}", e.what());
        removeLockAndExit();
    }

    // First fork - run in background

    auto first_child_pid = fork();

    switch (first_child_pid) {
        case -1:
            LOG_ERROR("Failed to perform the first fork; {1} ({2})",
                      strerror(errno), errno);
            removeLockAndExit();
        case 0:
            // CHILD - will fork and exit soon
            LOG_DEBUG("First child spawned, with PID={1}",
                      std::to_string(getpid()));
            break;
        default:
            // PARENT - wait for the child, to avoid a zombie process
            // and don't unlock the PID file
            waitpid(first_child_pid, nullptr, 0);

            // Exit with _exit(); note that after a fork(), only one
            // of parent and child should terminate with exit()
            _exit(EXIT_SUCCESS);
    }

    // Get the read lock

    try {
        pidf_ptr->lockRead();
        LOG_DEBUG("Obtained the read lock after first fork");
    } catch (const PIDFile::Error& e) {
        LOG_ERROR("Failed get a read lock after first fork: {1}", e.what());
        removeLockAndExit();
    }

    // Create a new group session and become leader in order to
    // disassociate from a possible controlling terminal later

    if (setsid() == -1) {
        LOG_ERROR("Failed to create new session for first child process; "
                  "{1} ({2})", strerror(errno), errno);
        removeLockAndExit();
    }

    // Prepare signal mask for the second fork in order to catch the
    // child signal: block the child signal for now in order to avoid
    // races and change signal disposition for SIGUSR1

    sigset_t block_mask, orig_mask, empty_mask;
    struct sigaction sa;

    sigemptyset(&block_mask);
    sigaddset(&block_mask, SIGUSR1);

    if (sigprocmask(SIG_BLOCK, &block_mask, &orig_mask) == -1) {
        LOG_ERROR("Failed to set the signal mask after first fork");
        removeLockAndExit();
    }

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = dumbSigHandler;

    if (sigaction(SIGUSR1, &sa, NULL) == -1) {
        LOG_ERROR("Failed to set SIGUSR1 disposition after first fork");
        removeLockAndExit();
    }

    // Second fork - the child won't be a session leader and won't be
    // associated with any controlling terminal

    auto second_child_pid = fork();

    switch (second_child_pid) {
        case -1:
            LOG_ERROR("Failed to perform the second fork; {1} ({2})",
                      strerror(errno), errno);
            removeLockAndExit();
        case 0:
            // CHILD - will be the pxp-agent!
            break;
        default:
            // PARENT - wait for the child signal to avoid unlocking
            // the PID file
            sigemptyset(&empty_mask);

            if (sigsuspend(&empty_mask) == -1 && errno != EINTR) {
                LOG_ERROR("Unexpected error while waiting for pending signals "
                          "after second fork; {1} ({2})", strerror(errno), errno);
            }

            _exit(EXIT_SUCCESS);
    }

    // Get read lock, signal the parent, and restore signal mask

    try {
        pidf_ptr->lockRead();
        LOG_DEBUG("Obtained the read lock after second fork");
    } catch (const PIDFile::Error& e) {
        LOG_ERROR("Failed get a read lock after second fork: {1}", e.what());
        kill(getppid(), SIGUSR1);
        removeLockAndExit();
    }

    kill(getppid(), SIGUSR1);

    if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) == -1) {
        LOG_ERROR("Failed to reset signal mask after second fork; "
                  "{1} ({2})", strerror(errno), errno);
        removeLockAndExit();
    }

    auto agent_pid = getpid();
    LOG_DEBUG("Second child spawned, with PID={1}", agent_pid);

    // Convert the read lock to a write lock and write PID to file

    LOG_DEBUG("Converting the read lock to write lock after second fork");

    try {
        pidf_ptr->lockWrite(true);  // blocking call
        LOG_DEBUG("Successfully converted read lock to write lock");
    } catch (const PIDFile::Error& e) {
        LOG_ERROR("Failed to convert to write lock after second fork: {1}",
                  e.what());
        removeLockAndExit();
    }

    pidf_ptr->write(agent_pid);

    // Change work directory

    if (chdir(DEFAULT_DAEMON_WORKING_DIR.data())) {
        LOG_ERROR("Failed to change work directory to '{1}'; {2} ({3})",
                  DEFAULT_DAEMON_WORKING_DIR, strerror(errno), errno);
        removeLockAndExit();
    } else {
        LOG_DEBUG("Changed working directory to '{1}'", DEFAULT_DAEMON_WORKING_DIR);
    }

    // Change signal dispositions
    // HERE(ale): don't touch SIGUSR2; it's used to reopen the logfile

    for (auto s : std::vector<int> { SIGINT, SIGTERM, SIGQUIT }) {
        if (signal(s, sigHandler) == SIG_ERR) {
            LOG_ERROR("Failed to set signal handler for sig {1}", s);
            removeLockAndExit();
        }
    }

    signal(SIGCHLD, SIG_DFL);
    signal(SIGTSTP, SIG_IGN);
    signal(SIGTTOU, SIG_IGN);
    signal(SIGTTIN, SIG_IGN);
    signal(SIGHUP, SIG_IGN);

    // Redirect standard files; we always use boost::log anyway

    auto tmpin = freopen("/dev/null", "r", stdin);
    if (tmpin == nullptr) {
        LOG_WARNING("Failed to redirect stdin to /dev/null; {1} ({2})",
                    strerror(errno), errno);
    }
    auto tmpout = freopen("/dev/null", "w", stdout);
    if (tmpout == nullptr) {
        LOG_WARNING("Failed to redirect stdout to /dev/null; {1} ({2})",
                    strerror(errno), errno);
    }
    auto tmperr = freopen("/dev/null", "w", stderr);
    if (tmperr == nullptr) {
        LOG_WARNING("Failed to redirect stderr to /dev/null; {1} ({2})",
                    strerror(errno), errno);
    }

    LOG_INFO("Daemonization completed; pxp-agent PID={1}, PID lock file in '{2}'",
             agent_pid, pidfile);

    // Set PIDFile dtor to clean itself up and return pointer for RAII
    pidf_ptr->cleanupWhenDone();

    return pidf_ptr;
}

}  // namespace Util
}  // namespace PXPAgent
<commit_msg>(PCP-736) Remove umask settings<commit_after>#include <pxp-agent/util/daemonize.hpp>
#include <pxp-agent/configuration.hpp>

#define LEATHERMAN_LOGGING_NAMESPACE "puppetlabs.pxp_agent.util.daemonize"
#include <leatherman/logging/logging.hpp>

#include <sys/types.h>
#include <stdlib.h>         // exit()
#include <unistd.h>         // _exit(), getpid(), fork(), setsid(), chdir()
#include <sys/wait.h>       // waitpid()
#include <signal.h>
#include <stdio.h>

#include <memory>
#include <vector>

namespace PXPAgent {
namespace Util {

const std::string DEFAULT_DAEMON_WORKING_DIR = "/";

static void sigHandler(int sig) {
    // NOTE(ale): if issued by the init process, between SIGTERM and
    // the successive SIGKILL there are only 5 s - must be fast
    auto pidfile = Configuration::Instance().get<std::string>("pidfile");
    LOG_INFO("Caught signal {1} - removing PID file '{2}'",
             std::to_string(sig), pidfile);
    PIDFile pidf { pidfile };
    pidf.cleanup();
    exit(EXIT_SUCCESS);
}

static void dumbSigHandler(int sig) {}

std::unique_ptr<PIDFile> daemonize() {
    // Check if we're already a daemon
    if (getppid() == 1) {
        // Parent is init process (PID 1)
        LOG_INFO("Already a daemon with PID={1}", std::to_string(getpid()));
        return nullptr;
    }

    // Check PID file; get read lock; ensure we can obtain write lock

    auto pidfile = Configuration::Instance().get<std::string>("pidfile");
    std::unique_ptr<PIDFile> pidf_ptr { new PIDFile(pidfile) };

    auto removeLockAndExit = [&pidf_ptr] () {
                                 pidf_ptr->cleanupWhenDone();
                                 exit(EXIT_FAILURE);
                             };

    if (pidf_ptr->isExecuting()) {
        auto pid = pidf_ptr->read();
        LOG_ERROR("Already running with PID={1}", pid);
        removeLockAndExit();
    }

    try {
        pidf_ptr->lockRead();
        LOG_DEBUG("Obtained a read lock for the PID file; no other pxp-agent "
                  "daemon should be executing");
    } catch (const PIDFile::Error& e) {
        LOG_ERROR("Failed get a read lock for the PID file: {1}", e.what());
        removeLockAndExit();
    }

    try {
        if (pidf_ptr->canLockWrite()) {
            LOG_DEBUG("It is possible to get a write lock for the PID file; no "
                      "other pxp-agent daemonization should be in progress");
        } else {
            LOG_ERROR("Cannot acquire the write lock for the PID file; please "
                      "ensure that there is no other pxp-agent instance executing");
            removeLockAndExit();
        }
    } catch (const PIDFile::Error& e) {
        LOG_ERROR("Failed to check if we can lock the PID file: {1}", e.what());
        removeLockAndExit();
    }

    // First fork - run in background

    auto first_child_pid = fork();

    switch (first_child_pid) {
        case -1:
            LOG_ERROR("Failed to perform the first fork; {1} ({2})",
                      strerror(errno), errno);
            removeLockAndExit();
        case 0:
            // CHILD - will fork and exit soon
            LOG_DEBUG("First child spawned, with PID={1}",
                      std::to_string(getpid()));
            break;
        default:
            // PARENT - wait for the child, to avoid a zombie process
            // and don't unlock the PID file
            waitpid(first_child_pid, nullptr, 0);

            // Exit with _exit(); note that after a fork(), only one
            // of parent and child should terminate with exit()
            _exit(EXIT_SUCCESS);
    }

    // Get the read lock

    try {
        pidf_ptr->lockRead();
        LOG_DEBUG("Obtained the read lock after first fork");
    } catch (const PIDFile::Error& e) {
        LOG_ERROR("Failed get a read lock after first fork: {1}", e.what());
        removeLockAndExit();
    }

    // Create a new group session and become leader in order to
    // disassociate from a possible controlling terminal later

    if (setsid() == -1) {
        LOG_ERROR("Failed to create new session for first child process; "
                  "{1} ({2})", strerror(errno), errno);
        removeLockAndExit();
    }

    // Prepare signal mask for the second fork in order to catch the
    // child signal: block the child signal for now in order to avoid
    // races and change signal disposition for SIGUSR1

    sigset_t block_mask, orig_mask, empty_mask;
    struct sigaction sa;

    sigemptyset(&block_mask);
    sigaddset(&block_mask, SIGUSR1);

    if (sigprocmask(SIG_BLOCK, &block_mask, &orig_mask) == -1) {
        LOG_ERROR("Failed to set the signal mask after first fork");
        removeLockAndExit();
    }

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = dumbSigHandler;

    if (sigaction(SIGUSR1, &sa, NULL) == -1) {
        LOG_ERROR("Failed to set SIGUSR1 disposition after first fork");
        removeLockAndExit();
    }

    // Second fork - the child won't be a session leader and won't be
    // associated with any controlling terminal

    auto second_child_pid = fork();

    switch (second_child_pid) {
        case -1:
            LOG_ERROR("Failed to perform the second fork; {1} ({2})",
                      strerror(errno), errno);
            removeLockAndExit();
        case 0:
            // CHILD - will be the pxp-agent!
            break;
        default:
            // PARENT - wait for the child signal to avoid unlocking
            // the PID file
            sigemptyset(&empty_mask);

            if (sigsuspend(&empty_mask) == -1 && errno != EINTR) {
                LOG_ERROR("Unexpected error while waiting for pending signals "
                          "after second fork; {1} ({2})", strerror(errno), errno);
            }

            _exit(EXIT_SUCCESS);
    }

    // Get read lock, signal the parent, and restore signal mask

    try {
        pidf_ptr->lockRead();
        LOG_DEBUG("Obtained the read lock after second fork");
    } catch (const PIDFile::Error& e) {
        LOG_ERROR("Failed get a read lock after second fork: {1}", e.what());
        kill(getppid(), SIGUSR1);
        removeLockAndExit();
    }

    kill(getppid(), SIGUSR1);

    if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) == -1) {
        LOG_ERROR("Failed to reset signal mask after second fork; "
                  "{1} ({2})", strerror(errno), errno);
        removeLockAndExit();
    }

    auto agent_pid = getpid();
    LOG_DEBUG("Second child spawned, with PID={1}", agent_pid);

    // Convert the read lock to a write lock and write PID to file

    LOG_DEBUG("Converting the read lock to write lock after second fork");

    try {
        pidf_ptr->lockWrite(true);  // blocking call
        LOG_DEBUG("Successfully converted read lock to write lock");
    } catch (const PIDFile::Error& e) {
        LOG_ERROR("Failed to convert to write lock after second fork: {1}",
                  e.what());
        removeLockAndExit();
    }

    pidf_ptr->write(agent_pid);

    // Change work directory

    if (chdir(DEFAULT_DAEMON_WORKING_DIR.data())) {
        LOG_ERROR("Failed to change work directory to '{1}'; {2} ({3})",
                  DEFAULT_DAEMON_WORKING_DIR, strerror(errno), errno);
        removeLockAndExit();
    } else {
        LOG_DEBUG("Changed working directory to '{1}'", DEFAULT_DAEMON_WORKING_DIR);
    }

    // Change signal dispositions
    // HERE(ale): don't touch SIGUSR2; it's used to reopen the logfile

    for (auto s : std::vector<int> { SIGINT, SIGTERM, SIGQUIT }) {
        if (signal(s, sigHandler) == SIG_ERR) {
            LOG_ERROR("Failed to set signal handler for sig {1}", s);
            removeLockAndExit();
        }
    }

    signal(SIGCHLD, SIG_DFL);
    signal(SIGTSTP, SIG_IGN);
    signal(SIGTTOU, SIG_IGN);
    signal(SIGTTIN, SIG_IGN);
    signal(SIGHUP, SIG_IGN);

    // Redirect standard files; we always use boost::log anyway

    auto tmpin = freopen("/dev/null", "r", stdin);
    if (tmpin == nullptr) {
        LOG_WARNING("Failed to redirect stdin to /dev/null; {1} ({2})",
                    strerror(errno), errno);
    }
    auto tmpout = freopen("/dev/null", "w", stdout);
    if (tmpout == nullptr) {
        LOG_WARNING("Failed to redirect stdout to /dev/null; {1} ({2})",
                    strerror(errno), errno);
    }
    auto tmperr = freopen("/dev/null", "w", stderr);
    if (tmperr == nullptr) {
        LOG_WARNING("Failed to redirect stderr to /dev/null; {1} ({2})",
                    strerror(errno), errno);
    }

    LOG_INFO("Daemonization completed; pxp-agent PID={1}, PID lock file in '{2}'",
             agent_pid, pidfile);

    // Set PIDFile dtor to clean itself up and return pointer for RAII
    pidf_ptr->cleanupWhenDone();

    return pidf_ptr;
}

}  // namespace Util
}  // namespace PXPAgent
<|endoftext|>


<commit_before>// RUN: %clangxx %s -o %t && %run %t
// UNSUPPORTED: ios

#include <assert.h>
#include <grp.h>
#include <memory>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>

std::string any_group;
const int N = 123456;

void Check(const char *str) {
  if (!str)
    return;
  assert(strlen(str) != N);
}

void Check(const passwd *result) {
  Check(result->pw_name);
  Check(result->pw_passwd);
  assert(result->pw_uid != N);
  assert(result->pw_gid != N);
#if !defined(__ANDROID__)
  Check(result->pw_gecos);
#endif
  Check(result->pw_dir);

#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
  assert(result->pw_change != N);
  Check(result->pw_class);
  assert(result->pw_expire != N);
#endif

#if defined(__FreeBSD__)
  assert(result->pw_fields != N);
#endif

  // SunOS also has pw_age and pw_comment which are documented as unused.
}

void Check(const group *result) {
  Check(result->gr_name);
  Check(result->gr_passwd);
  assert(result->gr_gid != N);
  for (char **mem = result->gr_mem; *mem; ++mem)
    Check(*mem);
  if (any_group.empty())
    any_group = result->gr_name;
}

template <class T, class Fn, class... Args>
void test(Fn f, Args... args) {
  T *result = f(args...);
  Check(result);
}

template <class T, class Fn, class... Args>
void test_r(Fn f, Args... args) {
  T gr;
  T *result;
  char buff[10000];
  assert(!f(args..., &gr, buff, sizeof(buff), &result));
  Check(&gr);
  Check(result);
}

int main(int argc, const char *argv[]) {
  test<passwd>(&getpwuid, 0);
  test<passwd>(&getpwnam, "root");
  test<group>(&getgrgid, 0);
  // Disable this test for now since it seems to hit a bug in EGLIBC 2.19
  //test<group>(&getgrnam, any_group.c_str());

#if !defined(__ANDROID__)
  setpwent();
  test<passwd>(&getpwent);
  setgrent();
  test<group>(&getgrent);

#if !defined(__APPLE__)
  setpwent();
  test_r<passwd>(&getpwent_r);
  setgrent();
  test_r<group>(&getgrent_r);
#endif

  test_r<passwd>(&getpwuid_r, 0);
  test_r<passwd>(&getpwnam_r, "root");

  test_r<group>(&getgrgid_r, 0);
  // Disable this test for now since it seems to hit a bug in EGLIBC 2.19
  //test_r<group>(&getgrnam_r, any_group.c_str());

#if defined(__linux__)
  auto pwd_file = [] {
    return std::unique_ptr<FILE, decltype(&fclose)>(fopen("/etc/passwd", "r"),
                                                    &fclose);
  };
  auto gr_file = [] {
    return std::unique_ptr<FILE, decltype(&fclose)>(fopen("/etc/group", "r"),
                                                    &fclose);
  };
  test<passwd>(&fgetpwent, pwd_file().get());
  test<group>(&fgetgrent, gr_file().get());
  test_r<passwd>(&fgetpwent_r, pwd_file().get());
  test_r<group>(&fgetgrent_r, gr_file().get());
#endif

#endif // __ANDROID__

  return 0;
}
<commit_msg>Revert "Temporarily disable calls to getgrnam/getgrnam_r in test due to it hitting unrelated issues in EGLIBC 2.19."<commit_after>// RUN: %clangxx %s -o %t && %run %t
// UNSUPPORTED: ios

#include <assert.h>
#include <grp.h>
#include <memory>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>

std::string any_group;
const int N = 123456;

void Check(const char *str) {
  if (!str)
    return;
  assert(strlen(str) != N);
}

void Check(const passwd *result) {
  Check(result->pw_name);
  Check(result->pw_passwd);
  assert(result->pw_uid != N);
  assert(result->pw_gid != N);
#if !defined(__ANDROID__)
  Check(result->pw_gecos);
#endif
  Check(result->pw_dir);

#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
  assert(result->pw_change != N);
  Check(result->pw_class);
  assert(result->pw_expire != N);
#endif

#if defined(__FreeBSD__)
  assert(result->pw_fields != N);
#endif

  // SunOS also has pw_age and pw_comment which are documented as unused.
}

void Check(const group *result) {
  Check(result->gr_name);
  Check(result->gr_passwd);
  assert(result->gr_gid != N);
  for (char **mem = result->gr_mem; *mem; ++mem)
    Check(*mem);
  if (any_group.empty())
    any_group = result->gr_name;
}

template <class T, class Fn, class... Args>
void test(Fn f, Args... args) {
  T *result = f(args...);
  Check(result);
}

template <class T, class Fn, class... Args>
void test_r(Fn f, Args... args) {
  T gr;
  T *result;
  char buff[10000];
  assert(!f(args..., &gr, buff, sizeof(buff), &result));
  Check(&gr);
  Check(result);
}

int main(int argc, const char *argv[]) {
  test<passwd>(&getpwuid, 0);
  test<passwd>(&getpwnam, "root");
  test<group>(&getgrgid, 0);
  test<group>(&getgrnam, any_group.c_str());

#if !defined(__ANDROID__)
  setpwent();
  test<passwd>(&getpwent);
  setgrent();
  test<group>(&getgrent);

#if !defined(__APPLE__)
  setpwent();
  test_r<passwd>(&getpwent_r);
  setgrent();
  test_r<group>(&getgrent_r);
#endif

  test_r<passwd>(&getpwuid_r, 0);
  test_r<passwd>(&getpwnam_r, "root");

  test_r<group>(&getgrgid_r, 0);
  test_r<group>(&getgrnam_r, any_group.c_str());

#if defined(__linux__)
  auto pwd_file = [] {
    return std::unique_ptr<FILE, decltype(&fclose)>(fopen("/etc/passwd", "r"),
                                                    &fclose);
  };
  auto gr_file = [] {
    return std::unique_ptr<FILE, decltype(&fclose)>(fopen("/etc/group", "r"),
                                                    &fclose);
  };
  test<passwd>(&fgetpwent, pwd_file().get());
  test<group>(&fgetgrent, gr_file().get());
  test_r<passwd>(&fgetpwent_r, pwd_file().get());
  test_r<group>(&fgetgrent_r, gr_file().get());
#endif

#endif // __ANDROID__

  return 0;
}
<|endoftext|>


<commit_before>// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t
// RUN: %run %t 2>&1 | FileCheck %s
// Verify that we can disable symbolization if needed:
// RUN: %env_ubsan_opts=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM

#include <stdint.h>

void f() {}

void g(int x) {}

void make_valid_call() {
  // CHECK-NOT: runtime error: call to function g
  reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(g))(42);
}

void make_invalid_call() {
  // CHECK: function.cpp:[[@LINE+4]]:3: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)'
  // CHECK-NEXT: function.cpp:[[@LINE-11]]: note: f() defined here
  // NOSYM: function.cpp:[[@LINE+2]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)'
  // NOSYM-NEXT: ({{.*}}+0x{{.*}}): note: (unknown) defined here
  reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42);
}

int main(void) {
  make_valid_call();
  make_invalid_call();
  // Check that no more errors will be printed.
  // CHECK-NOT: runtime error: call to function
  // NOSYM-NOT: runtime error: call to function
  make_invalid_call();
}
<commit_msg>XFAIL ubsan/TestCases/TypeCheck/Function/function.cpp on Windows<commit_after>// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t
// RUN: %run %t 2>&1 | FileCheck %s
// Verify that we can disable symbolization if needed:
// RUN: %env_ubsan_opts=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM
// XFAIL: win32,win64

#include <stdint.h>

void f() {}

void g(int x) {}

void make_valid_call() {
  // CHECK-NOT: runtime error: call to function g
  reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(g))(42);
}

void make_invalid_call() {
  // CHECK: function.cpp:[[@LINE+4]]:3: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)'
  // CHECK-NEXT: function.cpp:[[@LINE-11]]: note: f() defined here
  // NOSYM: function.cpp:[[@LINE+2]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)'
  // NOSYM-NEXT: ({{.*}}+0x{{.*}}): note: (unknown) defined here
  reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42);
}

int main(void) {
  make_valid_call();
  make_invalid_call();
  // Check that no more errors will be printed.
  // CHECK-NOT: runtime error: call to function
  // NOSYM-NOT: runtime error: call to function
  make_invalid_call();
}
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   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.
*/

/**
  \file    MathTools.cpp
  \author    Jens Krueger
        SCI Institute
        University of Utah
  \version  1.11
  \date    October 2008
*/

#include "MathTools.h"
#include <algorithm>

UINT32 MathTools::Log(UINT32 value, UINT32 base) {
  return UINT32(log(float(value)) / log(float(base)));
}

float MathTools::Log(float value, float base) {
  return log(value) / log(base);
}

UINT32 MathTools::Pow(UINT32 base, UINT32 exponent) {
  return UINT32(0.5f+pow(float(base), float(exponent)));
}

UINT64 MathTools::Pow(UINT64 base, UINT64 exponent) {
  return UINT64(0.5+pow(double(base), double(exponent)));
}

UINT32 MathTools::Log2(UINT32 n) {
  int iLog=0;
  while( n>>=1 ) iLog++;
  return iLog;
}

UINT32 MathTools::Pow2(UINT32 e) {
  return 1<<e;
}

UINT64 MathTools::Log2(UINT64 n) {
  int iLog=0;
  while( n>>=1 ) iLog++;
  return iLog;
}

UINT64 MathTools::Pow2(UINT64 e) {
  return static_cast<UINT64>(1) << e;
}

UINT32 MathTools::GaussianSum(UINT32 n) {
  return n*(n+1)/2;
}

bool MathTools::IsPow2(UINT32 n) {
    return ((n&(n-1))==0);
};

UINT32 MathTools::NextPow2(UINT32 n, bool bReturn_ID_on_Pow2) {
    if (bReturn_ID_on_Pow2 && IsPow2(n)) return n;
    return Pow2(Log2(n)+1);
}

bool MathTools::NaN(float f)
{
#ifdef USABLE_TR1
  return std::tr1::isnan(f);
#elif defined(_MSC_VER)
  return _finite(f) != 0;
#else
  // Hack, relies on 'f' being IEEE-754!
  return f != f;
#endif
}

float MathTools::Clamp(float val, float a, float b) {
  return std::max(a, std::min(b, val));
}

UINT32 MathTools::Clamp(UINT32 val, UINT32 a, UINT32 b) {
  return std::max(a, std::min(b, val));
}

UINT64 MathTools::Clamp(UINT64 val, UINT64 a, UINT64 b) {
  return std::max(a, std::min(b, val));
}

int MathTools::Clamp(int val, int a, int b) {
  return std::max(a, std::min(b, val));
}
<commit_msg>I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code. I shall not break Tom's code.....<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   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.
*/

/**
  \file    MathTools.cpp
  \author    Jens Krueger
        SCI Institute
        University of Utah
  \version  1.11
  \date    October 2008
*/

#include "MathTools.h"
#include <algorithm>

UINT32 MathTools::Log(UINT32 value, UINT32 base) {
  return UINT32(log(float(value)) / log(float(base)));
}

float MathTools::Log(float value, float base) {
  return log(value) / log(base);
}

UINT32 MathTools::Pow(UINT32 base, UINT32 exponent) {
  return UINT32(0.5f+pow(float(base), float(exponent)));
}

UINT64 MathTools::Pow(UINT64 base, UINT64 exponent) {
  return UINT64(0.5+pow(double(base), double(exponent)));
}

UINT32 MathTools::Log2(UINT32 n) {
  int iLog=0;
  while( n>>=1 ) iLog++;
  return iLog;
}

UINT32 MathTools::Pow2(UINT32 e) {
  return 1<<e;
}

UINT64 MathTools::Log2(UINT64 n) {
  int iLog=0;
  while( n>>=1 ) iLog++;
  return iLog;
}

UINT64 MathTools::Pow2(UINT64 e) {
  return static_cast<UINT64>(1) << e;
}

UINT32 MathTools::GaussianSum(UINT32 n) {
  return n*(n+1)/2;
}

bool MathTools::IsPow2(UINT32 n) {
    return ((n&(n-1))==0);
};

UINT32 MathTools::NextPow2(UINT32 n, bool bReturn_ID_on_Pow2) {
    if (bReturn_ID_on_Pow2 && IsPow2(n)) return n;
    return Pow2(Log2(n)+1);
}

bool MathTools::NaN(float f)
{
#ifdef USABLE_TR1
  return std::tr1::isnan(f);
#elif defined(_MSC_VER)
  return _finite(f) == 0;
#else
  // Hack, relies on 'f' being IEEE-754!
  return f != f;
#endif
}

float MathTools::Clamp(float val, float a, float b) {
  return std::max(a, std::min(b, val));
}

UINT32 MathTools::Clamp(UINT32 val, UINT32 a, UINT32 b) {
  return std::max(a, std::min(b, val));
}

UINT64 MathTools::Clamp(UINT64 val, UINT64 a, UINT64 b) {
  return std::max(a, std::min(b, val));
}

int MathTools::Clamp(int val, int a, int b) {
  return std::max(a, std::min(b, val));
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file MixClient.cpp
 * @author Arkadiy Paronyan arkadiy@ethdev.com
 * @date 2015
 * Ethereum IDE client.
 */

#include "MixClient.h"
#include <vector>
#include <utility>
#include <libdevcore/Exceptions.h>
#include <libethcore/Params.h>
#include <libethcore/BasicAuthority.h>
#include <libethereum/CanonBlockChain.h>
#include <libethereum/Transaction.h>
#include <libethereum/Executive.h>
#include <libethereum/ExtVM.h>
#include <libethereum/BlockChain.h>
#include <libevm/VM.h>
#include "Exceptions.h"
using namespace std;
using namespace dev;
using namespace dev::eth;

namespace dev
{
namespace mix
{

u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix somehow

namespace
{
}

MixBlockChain::MixBlockChain(std::string const& _path, h256 _stateRoot):
	FullBlockChain<NoProof>(createGenesisBlock(_stateRoot), std::unordered_map<Address, Account>(), _path, WithExisting::Kill)
{
}

bytes MixBlockChain::createGenesisBlock(h256 _stateRoot)
{
	RLPStream block(3);
	block.appendList(13)
			<< h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie
			<< LogBloom() << c_mixGenesisDifficulty << 0 << 3141592 << 0 << (unsigned)0
			<< std::string();
	block.appendRaw(RLPEmptyList);
	block.appendRaw(RLPEmptyList);
	return block.out();
}

MixClient::MixClient(std::string const& _dbPath):
	m_dbPath(_dbPath)
{
	resetState(std::unordered_map<Address, Account>());
}

MixClient::~MixClient()
{
}

void MixClient::resetState(std::unordered_map<Address, Account> const& _accounts,  Secret const& _miner)
{
	WriteGuard l(x_state);
	Guard fl(x_filtersWatches);

	m_filters.clear();
	for (auto& i: m_specialFilters)
		i.second.clear();
	m_watches.clear();

	m_stateDB = OverlayDB();
	SecureTrieDB<Address, MemoryDB> accountState(&m_stateDB);
	accountState.init();

	dev::eth::commit(_accounts, accountState);
	h256 stateRoot = accountState.root();
	m_bc.reset();
	m_bc.reset(new MixBlockChain(m_dbPath, stateRoot));
	Block b(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address());
	b.sync(bc());
	m_preMine = b;
	m_postMine = b;
	WriteGuard lx(x_executions);
	m_executions.clear();
}

Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secret const& _secret)
{
	Transaction ret;
	if (_secret)
	{
		if (_t.isCreation())
			ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce(), _secret);
		else
			ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce(), _secret);
	}
	else
	{
		if (_t.isCreation())
			ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce());
		else
			ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce());
		ret.forceSender(_t.safeSender());
	}
	return ret;
}

// TODO: prototype changed - will need rejigging.
ExecutionResult MixClient::debugTransaction(Transaction const& _t, State const& _state, EnvInfo const& _envInfo, bool _call)
{
	State execState = _state;
	execState.addBalance(_t.sender(), _t.gas() * _t.gasPrice()); //give it enough balance for gas estimation
	eth::ExecutionResult er;
	Executive execution(execState, _envInfo);
	execution.setResultRecipient(er);

	ExecutionResult d;
	d.address = _t.receiveAddress();
	d.sender = _t.sender();
	d.value = _t.value();
	d.inputParameters = _t.data();
	d.executonIndex = m_executions.size();
	if (!_call)
		d.transactionIndex = m_postMine.pending().size();

	try
	{
		execution.initialize(_t);
		execution.execute();
	}
	catch (Exception const& _e)
	{
		d.excepted = toTransactionException(_e);
		d.transactionData.push_back(_t.data());
		return d;
	}

	std::vector<MachineState> machineStates;
	std::vector<unsigned> levels;
	std::vector<MachineCode> codes;
	std::map<bytes const*, unsigned> codeIndexes;
	std::vector<bytes> data;
	std::map<bytesConstRef const*, unsigned> dataIndexes;
	bytes const* lastCode = nullptr;
	bytesConstRef const* lastData = nullptr;
	unsigned codeIndex = 0;
	unsigned dataIndex = 0;
	auto onOp = [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, void* voidVM, void const* voidExt)
	{
		VM& vm = *static_cast<VM*>(voidVM);
		ExtVM const& ext = *static_cast<ExtVM const*>(voidExt);
		if (lastCode == nullptr || lastCode != &ext.code)
		{
			auto const& iter = codeIndexes.find(&ext.code);
			if (iter != codeIndexes.end())
				codeIndex = iter->second;
			else
			{
				codeIndex = codes.size();
				codes.push_back(MachineCode({ext.myAddress, ext.code}));
				codeIndexes[&ext.code] = codeIndex;
			}
			lastCode = &ext.code;
		}

		if (lastData == nullptr || lastData != &ext.data)
		{
			auto const& iter = dataIndexes.find(&ext.data);
			if (iter != dataIndexes.end())
				dataIndex = iter->second;
			else
			{
				dataIndex = data.size();
				data.push_back(ext.data.toBytes());
				dataIndexes[&ext.data] = dataIndex;
			}
			lastData = &ext.data;
		}

		if (levels.size() < ext.depth)
			levels.push_back(machineStates.size() - 1);
		else
			levels.resize(ext.depth);

		machineStates.push_back(MachineState{
									steps,
									vm.curPC(),
									inst,
									newMemSize,
									static_cast<u256>(gas),
									vm.stack(),
									vm.memory(),
									gasCost,
									ext.state().storage(ext.myAddress),
									std::move(levels),
									codeIndex,
									dataIndex
								});
	};

	execution.go(onOp);
	execution.finalize();

	d.excepted = er.excepted;
	d.result = er;
	d.machineStates = machineStates;
	d.executionCode = std::move(codes);
	d.transactionData = std::move(data);
	d.gasUsed = er.gasUsed + er.gasRefunded + c_callStipend;
	if (_t.isCreation())
		d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce())));
	return d;
}

void MixClient::executeTransaction(Transaction const& _t, Block& _block, bool _call, bool _gasAuto, Secret const& _secret)
{
	Transaction t = _gasAuto ? replaceGas(_t, m_postMine.gasLimitRemaining()) : _t;

	// do debugging run first
	EnvInfo envInfo(bc().info(), bc().lastHashes());
	ExecutionResult d = debugTransaction(t, _block.state(), envInfo, _call);

	// execute on a state
	if (!_call && d.excepted == TransactionException::None)
	{
		u256 useGas = min(d.gasUsed, _block.gasLimitRemaining());
		t = _gasAuto ? replaceGas(_t, useGas, _secret) : _t;
		eth::ExecutionResult const& er = _block.execute(envInfo.lastHashes(), t);
		if (t.isCreation() && _block.state().code(d.contractAddress).empty())
			BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment"));
		d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend;
		LocalisedLogEntries logs;
		TransactionReceipt const& tr = _block.receipt(_block.pending().size() - 1);

		LogEntries le = tr.log();
		if (le.size())
			for (unsigned j = 0; j < le.size(); ++j)
				logs.insert(logs.begin(), LocalisedLogEntry(le[j]));
		d.logs =  logs;
	}
	WriteGuard l(x_executions);
	m_executions.emplace_back(std::move(d));
}

void MixClient::mine()
{
	WriteGuard l(x_state);
	m_postMine.commitToSeal(bc());

	NoProof::BlockHeader h(m_postMine.info());
	RLPStream header;
	h.streamRLP(header);
	m_postMine.sealBlock(header.out());
	bc().import(m_postMine.blockData(), m_stateDB, (ImportRequirements::Everything & ~ImportRequirements::ValidSeal) != 0);
	m_postMine.sync(bc());
	m_preMine = m_postMine;
}

ExecutionResult MixClient::lastExecution() const
{
	ReadGuard l(x_executions);
	return m_executions.empty() ? ExecutionResult() : m_executions.back();
}

ExecutionResult MixClient::execution(unsigned _index) const
{
	ReadGuard l(x_executions);
	return m_executions.at(_index);
}

Block MixClient::asOf(h256 const& _block) const
{
	ReadGuard l(x_state);
	Block ret(m_stateDB);
	ret.populateFromChain(bc(), _block);
	return ret;
}

pair<h256, Address> MixClient::submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret, bool _gasAuto)
{
	WriteGuard l(x_state);
	TransactionSkeleton ts = _ts;
	ts.from = toAddress(_secret);
	ts.nonce = m_postMine.transactionsFrom(ts.from);
	eth::Transaction t(ts, _secret);
	executeTransaction(t, m_postMine, false, _gasAuto, _secret);
	return make_pair(t.sha3(), toAddress(ts.from, ts.nonce));
}

dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto, FudgeFactor _ff)
{
	(void)_blockNumber;
	Block block = asOf(eth::PendingBlock);
	u256 n = block.transactionsFrom(_from);
	Transaction t(_value, _gasPrice, _gas, _dest, _data, n);
	t.forceSender(_from);
	if (_ff == FudgeFactor::Lenient)
		block.mutableState().addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
	WriteGuard lw(x_state); //TODO: lock is required only for last execution state
	executeTransaction(t, block, true, _gasAuto);
	return lastExecution().result;
}

dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff)
{
	return call(_from, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff);
}

dev::eth::ExecutionResult MixClient::create(Address const& _from, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff)
{
	(void)_blockNumber;
	u256 n;
	Block temp;
	{
		ReadGuard lr(x_state);
		temp = asOf(eth::PendingBlock);
		n = temp.transactionsFrom(_from);
	}
	Transaction t(_value, _gasPrice, _gas, _data, n);
	t.forceSender(_from);
	if (_ff == FudgeFactor::Lenient)
		temp.mutableState().addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
	WriteGuard lw(x_state); //TODO: lock is required only for last execution state
	executeTransaction(t, temp, true, false);
	return lastExecution().result;
}

eth::BlockInfo MixClient::blockInfo() const
{
	ReadGuard l(x_state);
	return BlockInfo(bc().block());
}

void MixClient::setBeneficiary(Address _us)
{
	WriteGuard l(x_state);
	m_postMine.setBeneficiary(_us);
}

void MixClient::startMining()
{
	//no-op
}

void MixClient::stopMining()
{
	//no-op
}

bool MixClient::isMining() const
{
	return false;
}

uint64_t MixClient::hashrate() const
{
	return 0;
}

eth::WorkingProgress MixClient::miningProgress() const
{
	return eth::WorkingProgress();
}

}
}
<commit_msg>fixed block mining<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file MixClient.cpp
 * @author Arkadiy Paronyan arkadiy@ethdev.com
 * @date 2015
 * Ethereum IDE client.
 */

#include "MixClient.h"
#include <vector>
#include <utility>
#include <libdevcore/Exceptions.h>
#include <libethcore/Params.h>
#include <libethcore/BasicAuthority.h>
#include <libethereum/CanonBlockChain.h>
#include <libethereum/Transaction.h>
#include <libethereum/Executive.h>
#include <libethereum/ExtVM.h>
#include <libethereum/BlockChain.h>
#include <libevm/VM.h>
#include "Exceptions.h"
using namespace std;
using namespace dev;
using namespace dev::eth;

namespace dev
{
namespace mix
{

u256 const c_mixGenesisDifficulty = 131072; //TODO: make it lower for Mix somehow

namespace
{
}

MixBlockChain::MixBlockChain(std::string const& _path, h256 _stateRoot):
	FullBlockChain<NoProof>(createGenesisBlock(_stateRoot), std::unordered_map<Address, Account>(), _path, WithExisting::Kill)
{
}

bytes MixBlockChain::createGenesisBlock(h256 _stateRoot)
{
	RLPStream block(3);
	block.appendList(13)
			<< h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie
			<< LogBloom() << c_mixGenesisDifficulty << 0 << 3141592 << 0 << (unsigned)0
			<< std::string();
	block.appendRaw(RLPEmptyList);
	block.appendRaw(RLPEmptyList);
	return block.out();
}

MixClient::MixClient(std::string const& _dbPath):
	m_dbPath(_dbPath)
{
	resetState(std::unordered_map<Address, Account>());
}

MixClient::~MixClient()
{
}

void MixClient::resetState(std::unordered_map<Address, Account> const& _accounts,  Secret const& _miner)
{
	WriteGuard l(x_state);
	Guard fl(x_filtersWatches);

	m_filters.clear();
	for (auto& i: m_specialFilters)
		i.second.clear();
	m_watches.clear();

	m_stateDB = OverlayDB();
	SecureTrieDB<Address, MemoryDB> accountState(&m_stateDB);
	accountState.init();

	dev::eth::commit(_accounts, accountState);
	h256 stateRoot = accountState.root();
	m_bc.reset();
	m_bc.reset(new MixBlockChain(m_dbPath, stateRoot));
	Block b(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address());
	b.sync(bc());
	m_preMine = b;
	m_postMine = b;
	WriteGuard lx(x_executions);
	m_executions.clear();
}

Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secret const& _secret)
{
	Transaction ret;
	if (_secret)
	{
		if (_t.isCreation())
			ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce(), _secret);
		else
			ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce(), _secret);
	}
	else
	{
		if (_t.isCreation())
			ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce());
		else
			ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce());
		ret.forceSender(_t.safeSender());
	}
	return ret;
}

// TODO: prototype changed - will need rejigging.
ExecutionResult MixClient::debugTransaction(Transaction const& _t, State const& _state, EnvInfo const& _envInfo, bool _call)
{
	State execState = _state;
	execState.addBalance(_t.sender(), _t.gas() * _t.gasPrice()); //give it enough balance for gas estimation
	eth::ExecutionResult er;
	Executive execution(execState, _envInfo);
	execution.setResultRecipient(er);

	ExecutionResult d;
	d.address = _t.receiveAddress();
	d.sender = _t.sender();
	d.value = _t.value();
	d.inputParameters = _t.data();
	d.executonIndex = m_executions.size();
	if (!_call)
		d.transactionIndex = m_postMine.pending().size();

	try
	{
		execution.initialize(_t);
		execution.execute();
	}
	catch (Exception const& _e)
	{
		d.excepted = toTransactionException(_e);
		d.transactionData.push_back(_t.data());
		return d;
	}

	std::vector<MachineState> machineStates;
	std::vector<unsigned> levels;
	std::vector<MachineCode> codes;
	std::map<bytes const*, unsigned> codeIndexes;
	std::vector<bytes> data;
	std::map<bytesConstRef const*, unsigned> dataIndexes;
	bytes const* lastCode = nullptr;
	bytesConstRef const* lastData = nullptr;
	unsigned codeIndex = 0;
	unsigned dataIndex = 0;
	auto onOp = [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, void* voidVM, void const* voidExt)
	{
		VM& vm = *static_cast<VM*>(voidVM);
		ExtVM const& ext = *static_cast<ExtVM const*>(voidExt);
		if (lastCode == nullptr || lastCode != &ext.code)
		{
			auto const& iter = codeIndexes.find(&ext.code);
			if (iter != codeIndexes.end())
				codeIndex = iter->second;
			else
			{
				codeIndex = codes.size();
				codes.push_back(MachineCode({ext.myAddress, ext.code}));
				codeIndexes[&ext.code] = codeIndex;
			}
			lastCode = &ext.code;
		}

		if (lastData == nullptr || lastData != &ext.data)
		{
			auto const& iter = dataIndexes.find(&ext.data);
			if (iter != dataIndexes.end())
				dataIndex = iter->second;
			else
			{
				dataIndex = data.size();
				data.push_back(ext.data.toBytes());
				dataIndexes[&ext.data] = dataIndex;
			}
			lastData = &ext.data;
		}

		if (levels.size() < ext.depth)
			levels.push_back(machineStates.size() - 1);
		else
			levels.resize(ext.depth);

		machineStates.push_back(MachineState{
									steps,
									vm.curPC(),
									inst,
									newMemSize,
									static_cast<u256>(gas),
									vm.stack(),
									vm.memory(),
									gasCost,
									ext.state().storage(ext.myAddress),
									std::move(levels),
									codeIndex,
									dataIndex
								});
	};

	execution.go(onOp);
	execution.finalize();

	d.excepted = er.excepted;
	d.result = er;
	d.machineStates = machineStates;
	d.executionCode = std::move(codes);
	d.transactionData = std::move(data);
	d.gasUsed = er.gasUsed + er.gasRefunded + c_callStipend;
	if (_t.isCreation())
		d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce())));
	return d;
}

void MixClient::executeTransaction(Transaction const& _t, Block& _block, bool _call, bool _gasAuto, Secret const& _secret)
{
	Transaction t = _gasAuto ? replaceGas(_t, m_postMine.gasLimitRemaining()) : _t;

	// do debugging run first
	EnvInfo envInfo(bc().info(), bc().lastHashes());
	ExecutionResult d = debugTransaction(t, _block.state(), envInfo, _call);

	// execute on a state
	if (!_call && d.excepted == TransactionException::None)
	{
		u256 useGas = min(d.gasUsed, _block.gasLimitRemaining());
		t = _gasAuto ? replaceGas(_t, useGas, _secret) : _t;
		eth::ExecutionResult const& er = _block.execute(envInfo.lastHashes(), t);
		if (t.isCreation() && _block.state().code(d.contractAddress).empty())
			BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment"));
		d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend;
		LocalisedLogEntries logs;
		TransactionReceipt const& tr = _block.receipt(_block.pending().size() - 1);

		LogEntries le = tr.log();
		if (le.size())
			for (unsigned j = 0; j < le.size(); ++j)
				logs.insert(logs.begin(), LocalisedLogEntry(le[j]));
		d.logs =  logs;
	}
	WriteGuard l(x_executions);
	m_executions.emplace_back(std::move(d));
}

void MixClient::mine()
{
	WriteGuard l(x_state);
	m_postMine.commitToSeal(bc());

	NoProof::BlockHeader h(m_postMine.info());
	RLPStream header;
	h.streamRLP(header);
	m_postMine.sealBlock(header.out());
	bc().import(m_postMine.blockData(), m_postMine.state().db(), (ImportRequirements::Everything & ~ImportRequirements::ValidSeal) != 0);
	m_postMine.sync(bc());
	m_preMine = m_postMine;
}

ExecutionResult MixClient::lastExecution() const
{
	ReadGuard l(x_executions);
	return m_executions.empty() ? ExecutionResult() : m_executions.back();
}

ExecutionResult MixClient::execution(unsigned _index) const
{
	ReadGuard l(x_executions);
	return m_executions.at(_index);
}

Block MixClient::asOf(h256 const& _block) const
{
	ReadGuard l(x_state);
	Block ret(m_stateDB);
	ret.populateFromChain(bc(), _block);
	return ret;
}

pair<h256, Address> MixClient::submitTransaction(eth::TransactionSkeleton const& _ts, Secret const& _secret, bool _gasAuto)
{
	WriteGuard l(x_state);
	TransactionSkeleton ts = _ts;
	ts.from = toAddress(_secret);
	ts.nonce = m_postMine.transactionsFrom(ts.from);
	eth::Transaction t(ts, _secret);
	executeTransaction(t, m_postMine, false, _gasAuto, _secret);
	return make_pair(t.sha3(), toAddress(ts.from, ts.nonce));
}

dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto, FudgeFactor _ff)
{
	(void)_blockNumber;
	Block block = asOf(eth::PendingBlock);
	u256 n = block.transactionsFrom(_from);
	Transaction t(_value, _gasPrice, _gas, _dest, _data, n);
	t.forceSender(_from);
	if (_ff == FudgeFactor::Lenient)
		block.mutableState().addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
	WriteGuard lw(x_state); //TODO: lock is required only for last execution state
	executeTransaction(t, block, true, _gasAuto);
	return lastExecution().result;
}

dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff)
{
	return call(_from, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff);
}

dev::eth::ExecutionResult MixClient::create(Address const& _from, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff)
{
	(void)_blockNumber;
	u256 n;
	Block temp;
	{
		ReadGuard lr(x_state);
		temp = asOf(eth::PendingBlock);
		n = temp.transactionsFrom(_from);
	}
	Transaction t(_value, _gasPrice, _gas, _data, n);
	t.forceSender(_from);
	if (_ff == FudgeFactor::Lenient)
		temp.mutableState().addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value()));
	WriteGuard lw(x_state); //TODO: lock is required only for last execution state
	executeTransaction(t, temp, true, false);
	return lastExecution().result;
}

eth::BlockInfo MixClient::blockInfo() const
{
	ReadGuard l(x_state);
	return BlockInfo(bc().block());
}

void MixClient::setBeneficiary(Address _us)
{
	WriteGuard l(x_state);
	m_postMine.setBeneficiary(_us);
}

void MixClient::startMining()
{
	//no-op
}

void MixClient::stopMining()
{
	//no-op
}

bool MixClient::isMining() const
{
	return false;
}

uint64_t MixClient::hashrate() const
{
	return 0;
}

eth::WorkingProgress MixClient::miningProgress() const
{
	return eth::WorkingProgress();
}

}
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2011-2012 Stéphane Raimbault <stephane.raimbault@gmail.com>
 *
 * License ISC, see LICENSE for more details.
 *
 * This library implements the Modbus protocol.
 * http://libmodbus.org/
 *
 */

#include <inttypes.h>

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#include <pins_arduino.h>
#endif
#include "Modbusino.h"

#define _MODBUS_RTU_SLAVE 0
#define _MODBUS_RTU_FUNCTION 1
#define _MODBUS_RTU_PRESET_REQ_LENGTH 6
#define _MODBUS_RTU_PRESET_RSP_LENGTH 2

#define _MODBUS_RTU_CHECKSUM_LENGTH 2

#define _MODBUSINO_RTU_MAX_ADU_LENGTH 128

/* Supported function codes */
#define _FC_READ_HOLDING_REGISTERS 0x03
#define _FC_WRITE_MULTIPLE_REGISTERS 0x10

enum { _STEP_FUNCTION = 0x01, _STEP_META, _STEP_DATA };

static uint16_t crc16(uint8_t *req, uint8_t req_length)
{
    uint8_t j;
    uint16_t crc;

    crc = 0xFFFF;
    while (req_length--) {
        crc = crc ^ *req++;
        for (j = 0; j < 8; j++) {
            if (crc & 0x0001)
                crc = (crc >> 1) ^ 0xA001;
            else
                crc = crc >> 1;
        }
    }

    return (crc << 8 | crc >> 8);
}

ModbusinoSlave::ModbusinoSlave(uint8_t slave)
{
    if (slave >= 0 & slave <= 247) {
        _slave = slave;
    }
}

void ModbusinoSlave::setup(long baud)
{
    Serial.begin(baud);
}

static int check_integrity(uint8_t *msg, uint8_t msg_length)
{
    uint16_t crc_calculated;
    uint16_t crc_received;

    if (msg_length < 2)
        return -1;

    crc_calculated = crc16(msg, msg_length - 2);
    crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];

    /* Check CRC of msg */
    if (crc_calculated == crc_received) {
        return msg_length;
    } else {
        return -1;
    }
}

static int build_response_basis(uint8_t slave, uint8_t function, uint8_t *rsp)
{
    rsp[0] = slave;
    rsp[1] = function;

    return _MODBUS_RTU_PRESET_RSP_LENGTH;
}

static void send_msg(uint8_t *msg, uint8_t msg_length)
{
    uint16_t crc = crc16(msg, msg_length);

    msg[msg_length++] = crc >> 8;
    msg[msg_length++] = crc & 0x00FF;

    Serial.write(msg, msg_length);
}

static uint8_t response_exception(uint8_t slave, uint8_t function,
                                  uint8_t exception_code, uint8_t *rsp)
{
    uint8_t rsp_length;

    rsp_length = build_response_basis(slave, function + 0x80, rsp);

    /* Positive exception code */
    rsp[rsp_length++] = exception_code;

    return rsp_length;
}

static void flush(void)
{
    uint8_t i = 0;

    /* Wait a moment to receive the remaining garbage but avoid getting stuck
     * because the line is saturated */
    while (Serial.available() && i++ < 10) {
        Serial.flush();
        delay(3);
    }
}

static int receive(uint8_t *req, uint8_t _slave)
{
    uint8_t i;
    uint8_t length_to_read;
    uint8_t req_index;
    uint8_t step;
    uint8_t function;

    /* We need to analyse the message step by step.  At the first step, we want
     * to reach the function code because all packets contain this
     * information. */
    step = _STEP_FUNCTION;
    length_to_read = _MODBUS_RTU_FUNCTION + 1;

    req_index = 0;
    while (length_to_read != 0) {

        /* The timeout is defined to ~10 ms between each bytes.  Precision is
           not that important so I rather to avoid millis() to apply the KISS
           principle (millis overflows after 50 days, etc) */
        if (!Serial.available()) {
            i = 0;
            while (!Serial.available()) {
                if (++i == 10) {
                    /* Too late, bye */
                    return -1 - MODBUS_INFORMATIVE_RX_TIMEOUT;
                }
                delay(1);
            }
        }

        req[req_index] = Serial.read();

        /* Moves the pointer to receive other data */
        req_index++;

        /* Computes remaining bytes */
        length_to_read--;

        if (length_to_read == 0) {
            if (req[_MODBUS_RTU_SLAVE] != _slave
                && req[_MODBUS_RTU_SLAVE != MODBUS_BROADCAST_ADDRESS]) {
                flush();
                return -1 - MODBUS_INFORMATIVE_NOT_FOR_US;
            }

            switch (step) {
            case _STEP_FUNCTION:
                /* Function code position */
                function = req[_MODBUS_RTU_FUNCTION];
                if (function == _FC_READ_HOLDING_REGISTERS) {
                    length_to_read = 4;
                } else if (function == _FC_WRITE_MULTIPLE_REGISTERS) {
                    length_to_read = 5;
                } else {
                    /* Wait a moment to receive the remaining garbage */
                    flush();
                    if (req[_MODBUS_RTU_SLAVE] == _slave
                        || req[_MODBUS_RTU_SLAVE] == MODBUS_BROADCAST_ADDRESS) {
                        /* It's for me so send an exception (reuse req) */
                        uint8_t rsp_length = response_exception(
                            _slave, function, MODBUS_EXCEPTION_ILLEGAL_FUNCTION,
                            req);
                        send_msg(req, rsp_length);
                        return -1 - MODBUS_EXCEPTION_ILLEGAL_FUNCTION;
                    }

                    return -1;
                }
                step = _STEP_META;
                break;
            case _STEP_META:
                length_to_read = _MODBUS_RTU_CHECKSUM_LENGTH;

                if (function == _FC_WRITE_MULTIPLE_REGISTERS)
                    length_to_read += req[_MODBUS_RTU_FUNCTION + 5];

                if ((req_index + length_to_read)
                    > _MODBUSINO_RTU_MAX_ADU_LENGTH) {
                    flush();
                    if (req[_MODBUS_RTU_SLAVE] == _slave
                        || req[_MODBUS_RTU_SLAVE] == MODBUS_BROADCAST_ADDRESS) {
                        /* It's for me so send an exception (reuse req) */
                        uint8_t rsp_length = response_exception(
                            _slave, function,
                            MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, req);
                        send_msg(req, rsp_length);
                        return -1 - MODBUS_EXCEPTION_ILLEGAL_FUNCTION;
                    }
                    return -1;
                }
                step = _STEP_DATA;
                break;
            default:
                break;
            }
        }
    }
    return check_integrity(req, req_index);
}

static void reply(uint16_t *tab_reg, uint16_t nb_reg, uint8_t *req,
                  uint8_t req_length, uint8_t _slave)
{
    uint8_t slave = req[_MODBUS_RTU_SLAVE];
    uint8_t function = req[_MODBUS_RTU_FUNCTION];
    uint16_t address =
        (req[_MODBUS_RTU_FUNCTION + 1] << 8) + req[_MODBUS_RTU_FUNCTION + 2];
    uint16_t nb =
        (req[_MODBUS_RTU_FUNCTION + 3] << 8) + req[_MODBUS_RTU_FUNCTION + 4];
    uint8_t rsp[_MODBUSINO_RTU_MAX_ADU_LENGTH];
    uint8_t rsp_length = 0;

    if (slave != _slave && slave != MODBUS_BROADCAST_ADDRESS) {
        return;
    }

    if (address + nb > nb_reg) {
        rsp_length = response_exception(
            slave, function, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
    } else {
        req_length -= _MODBUS_RTU_CHECKSUM_LENGTH;

        if (function == _FC_READ_HOLDING_REGISTERS) {
            uint16_t i;

            rsp_length = build_response_basis(slave, function, rsp);
            rsp[rsp_length++] = nb << 1;
            for (i = address; i < address + nb; i++) {
                rsp[rsp_length++] = tab_reg[i] >> 8;
                rsp[rsp_length++] = tab_reg[i] & 0xFF;
            }
        } else {
            uint16_t i, j;

            for (i = address, j = 6; i < address + nb; i++, j += 2) {
                /* 6 and 7 = first value */
                tab_reg[i] = (req[_MODBUS_RTU_FUNCTION + j] << 8)
                             + req[_MODBUS_RTU_FUNCTION + j + 1];
            }

            rsp_length = build_response_basis(slave, function, rsp);
            /* 4 to copy the address (2) and the no. of registers */
            memcpy(rsp + rsp_length, req + rsp_length, 4);
            rsp_length += 4;
        }
    }

    send_msg(rsp, rsp_length);
}

int ModbusinoSlave::loop(uint16_t *tab_reg, uint16_t nb_reg)
{
    int rc = 0;
    uint8_t req[_MODBUSINO_RTU_MAX_ADU_LENGTH];

    if (Serial.available()) {
        rc = receive(req, _slave);
        if (rc > 0) {
            reply(tab_reg, nb_reg, req, rc, _slave);
        }
    }

    /* Returns a positive value if successful,
       0 if a slave filtering has occured,
       -1 if an undefined error has occured,
       -2 for MODBUS_EXCEPTION_ILLEGAL_FUNCTION
       etc */
    return rc;
}
<commit_msg>Increase ADU size to 256 for conformance (closes #6)<commit_after>/*
 * Copyright © 2011-2012 Stéphane Raimbault <stephane.raimbault@gmail.com>
 *
 * License ISC, see LICENSE for more details.
 *
 * This library implements the Modbus protocol.
 * http://libmodbus.org/
 *
 */

#include <inttypes.h>

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#include <pins_arduino.h>
#endif
#include "Modbusino.h"

#define _MODBUS_RTU_SLAVE 0
#define _MODBUS_RTU_FUNCTION 1
#define _MODBUS_RTU_PRESET_REQ_LENGTH 6
#define _MODBUS_RTU_PRESET_RSP_LENGTH 2

#define _MODBUS_RTU_CHECKSUM_LENGTH 2

/* As reported in https://github.com/stephane/modbusino/issues/6, the code could
segfault for longer ADU */
#define _MODBUSINO_RTU_MAX_ADU_LENGTH 256

/* Supported function codes */
#define _FC_READ_HOLDING_REGISTERS 0x03
#define _FC_WRITE_MULTIPLE_REGISTERS 0x10

enum { _STEP_FUNCTION = 0x01, _STEP_META, _STEP_DATA };

static uint16_t crc16(uint8_t *req, uint8_t req_length)
{
    uint8_t j;
    uint16_t crc;

    crc = 0xFFFF;
    while (req_length--) {
        crc = crc ^ *req++;
        for (j = 0; j < 8; j++) {
            if (crc & 0x0001)
                crc = (crc >> 1) ^ 0xA001;
            else
                crc = crc >> 1;
        }
    }

    return (crc << 8 | crc >> 8);
}

ModbusinoSlave::ModbusinoSlave(uint8_t slave)
{
    if (slave >= 0 & slave <= 247) {
        _slave = slave;
    }
}

void ModbusinoSlave::setup(long baud)
{
    Serial.begin(baud);
}

static int check_integrity(uint8_t *msg, uint8_t msg_length)
{
    uint16_t crc_calculated;
    uint16_t crc_received;

    if (msg_length < 2)
        return -1;

    crc_calculated = crc16(msg, msg_length - 2);
    crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];

    /* Check CRC of msg */
    if (crc_calculated == crc_received) {
        return msg_length;
    } else {
        return -1;
    }
}

static int build_response_basis(uint8_t slave, uint8_t function, uint8_t *rsp)
{
    rsp[0] = slave;
    rsp[1] = function;

    return _MODBUS_RTU_PRESET_RSP_LENGTH;
}

static void send_msg(uint8_t *msg, uint8_t msg_length)
{
    uint16_t crc = crc16(msg, msg_length);

    msg[msg_length++] = crc >> 8;
    msg[msg_length++] = crc & 0x00FF;

    Serial.write(msg, msg_length);
}

static uint8_t response_exception(uint8_t slave, uint8_t function,
                                  uint8_t exception_code, uint8_t *rsp)
{
    uint8_t rsp_length;

    rsp_length = build_response_basis(slave, function + 0x80, rsp);

    /* Positive exception code */
    rsp[rsp_length++] = exception_code;

    return rsp_length;
}

static void flush(void)
{
    uint8_t i = 0;

    /* Wait a moment to receive the remaining garbage but avoid getting stuck
     * because the line is saturated */
    while (Serial.available() && i++ < 10) {
        Serial.flush();
        delay(3);
    }
}

static int receive(uint8_t *req, uint8_t _slave)
{
    uint8_t i;
    uint8_t length_to_read;
    uint8_t req_index;
    uint8_t step;
    uint8_t function;

    /* We need to analyse the message step by step.  At the first step, we want
     * to reach the function code because all packets contain this
     * information. */
    step = _STEP_FUNCTION;
    length_to_read = _MODBUS_RTU_FUNCTION + 1;

    req_index = 0;
    while (length_to_read != 0) {

        /* The timeout is defined to ~10 ms between each bytes.  Precision is
           not that important so I rather to avoid millis() to apply the KISS
           principle (millis overflows after 50 days, etc) */
        if (!Serial.available()) {
            i = 0;
            while (!Serial.available()) {
                if (++i == 10) {
                    /* Too late, bye */
                    return -1 - MODBUS_INFORMATIVE_RX_TIMEOUT;
                }
                delay(1);
            }
        }

        req[req_index] = Serial.read();

        /* Moves the pointer to receive other data */
        req_index++;

        /* Computes remaining bytes */
        length_to_read--;

        if (length_to_read == 0) {
            if (req[_MODBUS_RTU_SLAVE] != _slave
                && req[_MODBUS_RTU_SLAVE != MODBUS_BROADCAST_ADDRESS]) {
                flush();
                return -1 - MODBUS_INFORMATIVE_NOT_FOR_US;
            }

            switch (step) {
            case _STEP_FUNCTION:
                /* Function code position */
                function = req[_MODBUS_RTU_FUNCTION];
                if (function == _FC_READ_HOLDING_REGISTERS) {
                    length_to_read = 4;
                } else if (function == _FC_WRITE_MULTIPLE_REGISTERS) {
                    length_to_read = 5;
                } else {
                    /* Wait a moment to receive the remaining garbage */
                    flush();
                    if (req[_MODBUS_RTU_SLAVE] == _slave
                        || req[_MODBUS_RTU_SLAVE] == MODBUS_BROADCAST_ADDRESS) {
                        /* It's for me so send an exception (reuse req) */
                        uint8_t rsp_length = response_exception(
                            _slave, function, MODBUS_EXCEPTION_ILLEGAL_FUNCTION,
                            req);
                        send_msg(req, rsp_length);
                        return -1 - MODBUS_EXCEPTION_ILLEGAL_FUNCTION;
                    }

                    return -1;
                }
                step = _STEP_META;
                break;
            case _STEP_META:
                length_to_read = _MODBUS_RTU_CHECKSUM_LENGTH;

                if (function == _FC_WRITE_MULTIPLE_REGISTERS)
                    length_to_read += req[_MODBUS_RTU_FUNCTION + 5];

                if ((req_index + length_to_read)
                    > _MODBUSINO_RTU_MAX_ADU_LENGTH) {
                    flush();
                    if (req[_MODBUS_RTU_SLAVE] == _slave
                        || req[_MODBUS_RTU_SLAVE] == MODBUS_BROADCAST_ADDRESS) {
                        /* It's for me so send an exception (reuse req) */
                        uint8_t rsp_length = response_exception(
                            _slave, function,
                            MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, req);
                        send_msg(req, rsp_length);
                        return -1 - MODBUS_EXCEPTION_ILLEGAL_FUNCTION;
                    }
                    return -1;
                }
                step = _STEP_DATA;
                break;
            default:
                break;
            }
        }
    }
    return check_integrity(req, req_index);
}

static void reply(uint16_t *tab_reg, uint16_t nb_reg, uint8_t *req,
                  uint8_t req_length, uint8_t _slave)
{
    uint8_t slave = req[_MODBUS_RTU_SLAVE];
    uint8_t function = req[_MODBUS_RTU_FUNCTION];
    uint16_t address =
        (req[_MODBUS_RTU_FUNCTION + 1] << 8) + req[_MODBUS_RTU_FUNCTION + 2];
    uint16_t nb =
        (req[_MODBUS_RTU_FUNCTION + 3] << 8) + req[_MODBUS_RTU_FUNCTION + 4];
    uint8_t rsp[_MODBUSINO_RTU_MAX_ADU_LENGTH];
    uint8_t rsp_length = 0;

    if (slave != _slave && slave != MODBUS_BROADCAST_ADDRESS) {
        return;
    }

    if (address + nb > nb_reg) {
        rsp_length = response_exception(
            slave, function, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
    } else {
        req_length -= _MODBUS_RTU_CHECKSUM_LENGTH;

        if (function == _FC_READ_HOLDING_REGISTERS) {
            uint16_t i;

            rsp_length = build_response_basis(slave, function, rsp);
            rsp[rsp_length++] = nb << 1;
            for (i = address; i < address + nb; i++) {
                rsp[rsp_length++] = tab_reg[i] >> 8;
                rsp[rsp_length++] = tab_reg[i] & 0xFF;
            }
        } else {
            uint16_t i, j;

            for (i = address, j = 6; i < address + nb; i++, j += 2) {
                /* 6 and 7 = first value */
                tab_reg[i] = (req[_MODBUS_RTU_FUNCTION + j] << 8)
                             + req[_MODBUS_RTU_FUNCTION + j + 1];
            }

            rsp_length = build_response_basis(slave, function, rsp);
            /* 4 to copy the address (2) and the no. of registers */
            memcpy(rsp + rsp_length, req + rsp_length, 4);
            rsp_length += 4;
        }
    }

    send_msg(rsp, rsp_length);
}

int ModbusinoSlave::loop(uint16_t *tab_reg, uint16_t nb_reg)
{
    int rc = 0;
    uint8_t req[_MODBUSINO_RTU_MAX_ADU_LENGTH];

    if (Serial.available()) {
        rc = receive(req, _slave);
        if (rc > 0) {
            reply(tab_reg, nb_reg, req, rc, _slave);
        }
    }

    /* Returns a positive value if successful,
       0 if a slave filtering has occured,
       -1 if an undefined error has occured,
       -2 for MODBUS_EXCEPTION_ILLEGAL_FUNCTION
       etc */
    return rc;
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file JSLocalConsole.cpp
 * @author Marek Kotewicz <marek@ethdev.com>
 * @date 2015
 * Ethereum client.
 */

#include <iostream>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include "JSLocalConsole.h"
#include "JSV8Connector.h"

using namespace std;
using namespace dev;
using namespace dev::eth;

JSLocalConsole::JSLocalConsole()
{
	m_jsonrpcConnector.reset(new JSV8Connector(m_engine));
//	m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts, vector<KeyPair>()));
}
<commit_msg>removed unused commented line<commit_after>/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	cpp-ethereum 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 General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file JSLocalConsole.cpp
 * @author Marek Kotewicz <marek@ethdev.com>
 * @date 2015
 * Ethereum client.
 */

#include <iostream>
#include <libweb3jsonrpc/WebThreeStubServer.h>
#include "JSLocalConsole.h"
#include "JSV8Connector.h"

using namespace std;
using namespace dev;
using namespace dev::eth;

JSLocalConsole::JSLocalConsole()
{
	m_jsonrpcConnector.reset(new JSV8Connector(m_engine));
}
<|endoftext|>


<commit_before>/*
    ModbusIP.cpp - Source for Modbus IP Library
    Copyright (C) 2015 Andr Sarmento Barbosa
*/
#include "ModbusIP.h"

ModbusIP::ModbusIP():_server(MODBUSIP_PORT) {
}

bool ModbusIP::config(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) {
    Ethernet.begin(mac, ip);
    _server.begin();
    return true;
}

void ModbusIP::proc() {
    EthernetClient client = _server.available();

    if (client) {
        if (client.connected()) {
            int i = 0;
            while (client.available()){
                _MBAP[i] = client.read();
                i++;
                if (i==7) break;  //MBAP length has 7 bytes size
            }
			_len = _MBAP[4] << 8 | _MBAP[5];
			_len--;  // Do not count with last byte from MBAP

			if (_MBAP[2] !=0 | _MBAP[3] !=0) return;   //Not a MODBUSIP packet
			if (_len > MODBUSIP_MAXFRAME) return;      //Length is over MODBUSIP_MAXFRAME

			_frame = (byte*) malloc(_len);
			i = 0;
			while (client.available()){
			    _frame[i] = client.read();
                i++;
                if (i==_len) break;
			}

			if (this->receivePDU(_frame) && _reply != MB_REPLY_OFF)  {
                //MBAP
                _MBAP[4] = _len >> 8;
                _MBAP[5] = _len | 0x00FF;
				for (i = 0 ; i < 7 ; i++) {
					client.write(_MBAP[i]);
				}
                //PDU Frame
				for (i = 0 ; i < _len ; i++) {
					client.write(_frame[i]);
				}
			}

		    free(_frame);
	        _len = 0;
            client.stop();
        }
    }
}
<commit_msg>Overloaded config types. receivePDU to void.<commit_after>/*
    ModbusIP.cpp - Source for Modbus IP Library
    Copyright (C) 2015 Andr Sarmento Barbosa
*/
#include "ModbusIP.h"

ModbusIP::ModbusIP():_server(MODBUSIP_PORT) {
    _server.begin();
}

void ModbusIP::config(uint8_t *mac) {
    Ethernet.begin(mac);
}

void ModbusIP::config(uint8_t *mac, IPAddress ip) {
    Ethernet.begin(mac, ip);
}

void ModbusIP::config(uint8_t *mac, IPAddress ip, IPAddress dns) {
    Ethernet.begin(mac, ip, dns);
}

void ModbusIP::config(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway) {
    Ethernet.begin(mac, ip, dns, gateway);
}

void ModbusIP::config(uint8_t *mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) {
    Ethernet.begin(mac, ip, dns, gateway, subnet);
}

void ModbusIP::task() {
    EthernetClient client = _server.available();

    if (client) {
        if (client.connected()) {
            int i = 0;
            while (client.available()){
                _MBAP[i] = client.read();
                i++;
                if (i==7) break;  //MBAP length has 7 bytes size
            }
			_len = _MBAP[4] << 8 | _MBAP[5];
			_len--;  // Do not count with last byte from MBAP

			if (_MBAP[2] !=0 | _MBAP[3] !=0) return;   //Not a MODBUSIP packet
			if (_len > MODBUSIP_MAXFRAME) return;      //Length is over MODBUSIP_MAXFRAME

			_frame = (byte*) malloc(_len);
			i = 0;
			while (client.available()){
			    _frame[i] = client.read();
                i++;
                if (i==_len) break;
			}

            this->receivePDU(_frame);
			if (_reply != MB_REPLY_OFF) {
                //MBAP
                _MBAP[4] = _len >> 8;
                _MBAP[5] = _len | 0x00FF;
				for (i = 0 ; i < 7 ; i++) {
					client.write(_MBAP[i]);
				}
                //PDU Frame
				for (i = 0 ; i < _len ; i++) {
					client.write(_frame[i]);
				}
			}

		    free(_frame);
	        _len = 0;
            client.stop();
        }
    }
}
<|endoftext|>