<commit_before>#include <set>
#include <map>
#include <iostream>
#include <cassert>
#include <memory>

#include <exception>
#include <stdexcept>

#include "structures/affectation.h"
#include "structures/deductions.h"
#include "structures/CL_proof.h"
#include "structures/formula.h"
#include "structures/clause.h"
#include "solvers/dpll.h"
#include "config.h"

#define CONFLICT_GRAPH_FILE_NAME "/tmp/conflict_graph.dot"
#define CL_PROOF_FILE_NAME "/tmp/CL_proof.tex"

using namespace satsolver;

#define AS_AFF(a, l) (a.is_true(l) ? l : -l)

void make_conflict_graph(const Deductions &deductions, const Affectation &aff, int root, int literal) {
    FILE *graph_file = NULL;

    graph_file = fopen(CONFLICT_GRAPH_FILE_NAME, "w");
    fprintf(graph_file, "digraph G {\n");

    // Arêtes
    deductions.print_edges(graph_file,aff) ;

    // Noeuds
    deductions.print_UIP(graph_file,aff,root,literal) ;
    fprintf(graph_file, "\t%d [color = \"red\"];\n", literal);
    fprintf(graph_file, "}\n");
    fclose(graph_file);
}

unsigned int cl_interact(const Deductions &deductions, const Affectation &aff, int last_bet, int literal, bool *with_proof) {
    char mode;
    unsigned int steps;
    assert(deductions.has_variable(abs(literal)));
    std::cout << "Conflict on literal " << literal << ". Action? [g/r/c/s/t] ";
    assert(with_proof);
    *with_proof = false;
    while (true) {
        std::cin >> mode;
        switch (mode) {
            case 'g':
                make_conflict_graph(deductions, aff, last_bet, literal);
                return 1;
            case 'r':
                if (!WITH_CL) {
                    std::cout << "Clause learning is not enabled. Use -CL. [g/r/c/s/t]. " << std::endl;
                    continue;
                }
                *with_proof = true;
                return 1;
            case 'c':
                return 1;
            case 's':
                std::cin >> steps;
                return steps;
            case 't':
                CL_INTERACT = false;
                return 0;
            default:
                std::cout << "Invalid character [g/r/c/s/t]. ";
                continue;
        }
    }
}

std::shared_ptr<Clause> learn_clause(const Deductions &deductions, const std::vector<std::pair<int, bool>> &mem, const Affectation &aff, int nb_variables, int literal, CLProof *proof) {
    (void) aff;
    long unsigned int mem_top = mem.size()-1; // The index in the memory “stack” of the literal we are making the resolution on.
    std::unordered_set<int> clause(deductions.get_deduced_from(literal)), clause2;
    assert(clause.find(literal) != clause.end());
    mem_top--;
    while (mem.at(mem_top).second) {
        literal = mem.at(mem_top).first;
        assert(mem.at(mem_top).first == literal);
        clause2 = deductions.get_deduced_from(literal); // This is the clause we will make the resolution with
        if (!clause2.size())
            break;

        if (clause.find(-literal) == clause.end())
            break;
        assert(clause2.find(literal) != clause.end());
        // Resolution
        // TODO: Replace 0 with the clause id.
        proof->insert_top(literal, std::make_pair(0, Clause(nb_variables, clause)), std::make_pair(0, Clause(nb_variables, clause2)));
        clause.erase(clause.find(-literal));
        clause2.erase(clause2.find(literal));
        clause.insert(clause2.begin(), clause2.end());

        mem_top--;
    }
    return std::shared_ptr<Clause>(new Clause(nb_variables, clause));
}

Affectation* satsolver::solve(Formula *formula) {
    int literal;
    bool with_proof;
    CLProof *proof;
    unsigned int clause_id;
    bool contains_false_clause;
    unsigned int skip_conflicts = 1; // Number of conflicts we will skip before showing another prompt
    int last_bet = 0; // Used for generating the graph.
    while(formula->get_aff()->get_nb_unknown() != 0 && !formula->only_true_clauses(NULL)) {
        formula->get_ded()->print() ;
        if(!WITH_WL && (literal = formula->monome(&clause_id))) {
            // We set the clause identified by “claused_id” as the one which
            // made us deduce the value of the literal.
            formula->deduce_true(literal, clause_id); // Return value ignored, WITH_WL is false
            contains_false_clause = formula->contains_false_clause(&clause_id);
        }
        else if((literal = formula->isolated_literal(&clause_id))) {
	        formula->deduce_true(literal,-1) ;
        }
        else {
            literal = formula->choose_literal(HEURISTIC) ;
            if (WITH_WL)
                contains_false_clause = !formula->bet_true(literal);
            else {
                formula->bet_true(literal);
                contains_false_clause = formula->contains_false_clause(&clause_id);
            }
            last_bet = literal;
        }
        while(contains_false_clause) {
            if (CL_INTERACT && --skip_conflicts == 0) {
                assert(last_bet);
                skip_conflicts = cl_interact(*formula->get_ded(), formula->get_aff(), last_bet, literal, &with_proof);
            }
            if (WITH_CL) {
                proof = new CLProof(formula->to_clauses_vector()[clause_id]);
                learn_clause(*formula->get_ded(), formula->get_mem(), formula->get_aff(), formula->get_nb_variables(), literal, proof);
                if (with_proof)
                    proof->to_latex_file(CL_PROOF_FILE_NAME);
                delete proof;
            }
            literal = formula->back() ;
            last_bet = -last_bet;
            if(literal == 0)
                throw Conflict() ;
            if (WITH_WL)
                contains_false_clause = !formula->deduce_false(literal,-1);
            else {
                formula->deduce_false(literal, -1);
                contains_false_clause = formula->contains_false_clause(&clause_id);
            }
        }
    }
    return formula->get_aff() ;
}
<commit_msg>Revert "Fix handling of 'r' in command-line interaction."<commit_after>#include <set>
#include <map>
#include <iostream>
#include <cassert>
#include <memory>

#include <exception>
#include <stdexcept>

#include "structures/affectation.h"
#include "structures/deductions.h"
#include "structures/CL_proof.h"
#include "structures/formula.h"
#include "structures/clause.h"
#include "solvers/dpll.h"
#include "config.h"

#define CONFLICT_GRAPH_FILE_NAME "/tmp/conflict_graph.dot"
#define CL_PROOF_FILE_NAME "/tmp/CL_proof.tex"

using namespace satsolver;

#define AS_AFF(a, l) (a.is_true(l) ? l : -l)

void make_conflict_graph(const Deductions &deductions, const Affectation &aff, int root, int literal) {
    FILE *graph_file = NULL;

    graph_file = fopen(CONFLICT_GRAPH_FILE_NAME, "w");
    fprintf(graph_file, "digraph G {\n");

    // Arêtes
    deductions.print_edges(graph_file,aff) ;

    // Noeuds
    deductions.print_UIP(graph_file,aff,root,literal) ;
    fprintf(graph_file, "\t%d [color = \"red\"];\n", literal);
    fprintf(graph_file, "}\n");
    fclose(graph_file);
}

unsigned int cl_interact(const Deductions &deductions, const Affectation &aff, int last_bet, int literal, bool *with_proof) {
    char mode;
    unsigned int steps;
    assert(deductions.has_variable(abs(literal)));
    std::cout << "Conflict on literal " << literal << ". Action? [g/r/c/s/t] ";
    assert(with_proof);
    *with_proof = false;
    while (true) {
        std::cin >> mode;
        switch (mode) {
            case 'g':
                make_conflict_graph(deductions, aff, last_bet, literal);
                return 1;
            case 'r':
                if (!WITH_CL) {
                    std::cout << "Clause learning is not enabled. Use -CL. [g/r/c/s/t]. " << std::endl;
                    continue;
                }
                *with_proof = true;
                return 0;
            case 'c':
                return 1;
            case 's':
                std::cin >> steps;
                return steps;
            case 't':
                CL_INTERACT = false;
                return 0;
            default:
                std::cout << "Invalid character [g/r/c/s/t]. ";
                continue;
        }
    }
}

std::shared_ptr<Clause> learn_clause(const Deductions &deductions, const std::vector<std::pair<int, bool>> &mem, const Affectation &aff, int nb_variables, int literal, CLProof *proof) {
    (void) aff;
    long unsigned int mem_top = mem.size()-1; // The index in the memory “stack” of the literal we are making the resolution on.
    std::unordered_set<int> clause(deductions.get_deduced_from(literal)), clause2;
    assert(clause.find(literal) != clause.end());
    mem_top--;
    while (mem.at(mem_top).second) {
        literal = mem.at(mem_top).first;
        assert(mem.at(mem_top).first == literal);
        clause2 = deductions.get_deduced_from(literal); // This is the clause we will make the resolution with
        if (!clause2.size())
            break;

        if (clause.find(-literal) == clause.end())
            break;
        assert(clause2.find(literal) != clause.end());
        // Resolution
        // TODO: Replace 0 with the clause id.
        proof->insert_top(literal, std::make_pair(0, Clause(nb_variables, clause)), std::make_pair(0, Clause(nb_variables, clause2)));
        clause.erase(clause.find(-literal));
        clause2.erase(clause2.find(literal));
        clause.insert(clause2.begin(), clause2.end());

        mem_top--;
    }
    return std::shared_ptr<Clause>(new Clause(nb_variables, clause));
}

Affectation* satsolver::solve(Formula *formula) {
    int literal;
    bool with_proof;
    CLProof *proof;
    unsigned int clause_id;
    bool contains_false_clause;
    unsigned int skip_conflicts = 1; // Number of conflicts we will skip before showing another prompt
    int last_bet = 0; // Used for generating the graph.
    while(formula->get_aff()->get_nb_unknown() != 0 && !formula->only_true_clauses(NULL)) {
        formula->get_ded()->print() ;
        if(!WITH_WL && (literal = formula->monome(&clause_id))) {
            // We set the clause identified by “claused_id” as the one which
            // made us deduce the value of the literal.
            formula->deduce_true(literal, clause_id); // Return value ignored, WITH_WL is false
            contains_false_clause = formula->contains_false_clause(&clause_id);
        }
        else if((literal = formula->isolated_literal(&clause_id))) {
	        formula->deduce_true(literal,-1) ;
        }
        else {
            literal = formula->choose_literal(HEURISTIC) ;
            if (WITH_WL)
                contains_false_clause = !formula->bet_true(literal);
            else {
                formula->bet_true(literal);
                contains_false_clause = formula->contains_false_clause(&clause_id);
            }
            last_bet = literal;
        }
        while(contains_false_clause) {
            if (CL_INTERACT && --skip_conflicts == 0) {
                assert(last_bet);
                skip_conflicts = cl_interact(*formula->get_ded(), formula->get_aff(), last_bet, literal, &with_proof);
            }
            if (WITH_CL) {
                proof = new CLProof(formula->to_clauses_vector()[clause_id]);
                learn_clause(*formula->get_ded(), formula->get_mem(), formula->get_aff(), formula->get_nb_variables(), literal, proof);
                if (with_proof)
                    proof->to_latex_file(CL_PROOF_FILE_NAME);
                delete proof;
            }
            literal = formula->back() ;
            last_bet = -last_bet;
            if(literal == 0)
                throw Conflict() ;
            if (WITH_WL)
                contains_false_clause = !formula->deduce_false(literal,-1);
            else {
                formula->deduce_false(literal, -1);
                contains_false_clause = formula->contains_false_clause(&clause_id);
            }
        }
    }
    return formula->get_aff() ;
}
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "Copyright (c) 2007 Tokutek Inc.  All rights reserved."
#ident "$Id: perf_nop.cc 45903 2012-07-19 13:06:39Z leifwalsh $"
#include "test.h"

#include <stdio.h>
#include <stdlib.h>

#include <toku_pthread.h>
#include <unistd.h>
#include <memory.h>
#include <sys/stat.h>
#include <db.h>

#include "threaded_stress_test_helpers.h"

// The intent of this test is to measure the throughput of the test infrastructure executing a nop
// on multiple threads.

DB_TXN** txns;
int num_txns;

static int commit_and_create_txn(
    DB_TXN* UU(txn),
    ARG arg,
    void* UU(operation_extra),
    void* UU(stats_extra)
    )
{
    int rand_txn_id = random() % num_txns;
    int r = txns[rand_txn_id]->commit(txns[rand_txn_id], 0);
    CKERR(r);
    r = arg->env->txn_begin(arg->env, 0, &txns[rand_txn_id], arg->txn_type);
    CKERR(r);
    return 0;
}

static void
stress_table(DB_ENV* env, DB** dbp, struct cli_args *cli_args) {
    if (verbose) printf("starting running of stress\n");

    num_txns = cli_args->txn_size;
    XCALLOC_N(num_txns, txns);
    for (int i = 0; i < num_txns; i++) {
        int r = env->txn_begin(env, 0, &txns[i], DB_TXN_SNAPSHOT);
        CKERR(r);
    }

    struct arg myarg;
    arg_init(&myarg, dbp, env, cli_args);
    myarg.operation = commit_and_create_txn;

    run_workers(&myarg, 1, cli_args->time_of_test, false, cli_args);

    for (int i = 0; i < num_txns; i++) {
        int chk_r = txns[i]->commit(txns[i], 0);
        CKERR(chk_r);
    }
    toku_free(txns);
    num_txns = 0;
}

int
test_main(int argc, char *const argv[]) {
    num_txns = 0;
    txns = NULL;
    struct cli_args args = get_default_args_for_perf();
    parse_stress_test_args(argc, argv, &args);
    args.single_txn = true;
    // this test is all about transactions, make the DB small
    args.num_elements = 1;
    args.num_DBs= 1;
    stress_test_main(&args);
    return 0;
}
<commit_msg>refs #5404, add a comment explaining what the test does<commit_after>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "Copyright (c) 2007 Tokutek Inc.  All rights reserved."
#ident "$Id: perf_nop.cc 45903 2012-07-19 13:06:39Z leifwalsh $"
#include "test.h"

#include <stdio.h>
#include <stdlib.h>

#include <toku_pthread.h>
#include <unistd.h>
#include <memory.h>
#include <sys/stat.h>
#include <db.h>

#include "threaded_stress_test_helpers.h"

// The intent of this test is to measure how fast a single thread can
// commit and create transactions when there exist N transactions.

DB_TXN** txns;
int num_txns;

static int commit_and_create_txn(
    DB_TXN* UU(txn),
    ARG arg,
    void* UU(operation_extra),
    void* UU(stats_extra)
    )
{
    int rand_txn_id = random() % num_txns;
    int r = txns[rand_txn_id]->commit(txns[rand_txn_id], 0);
    CKERR(r);
    r = arg->env->txn_begin(arg->env, 0, &txns[rand_txn_id], arg->txn_type);
    CKERR(r);
    return 0;
}

static void
stress_table(DB_ENV* env, DB** dbp, struct cli_args *cli_args) {
    if (verbose) printf("starting running of stress\n");

    num_txns = cli_args->txn_size;
    XCALLOC_N(num_txns, txns);
    for (int i = 0; i < num_txns; i++) {
        int r = env->txn_begin(env, 0, &txns[i], DB_TXN_SNAPSHOT);
        CKERR(r);
    }

    struct arg myarg;
    arg_init(&myarg, dbp, env, cli_args);
    myarg.operation = commit_and_create_txn;

    run_workers(&myarg, 1, cli_args->time_of_test, false, cli_args);

    for (int i = 0; i < num_txns; i++) {
        int chk_r = txns[i]->commit(txns[i], 0);
        CKERR(chk_r);
    }
    toku_free(txns);
    num_txns = 0;
}

int
test_main(int argc, char *const argv[]) {
    num_txns = 0;
    txns = NULL;
    struct cli_args args = get_default_args_for_perf();
    parse_stress_test_args(argc, argv, &args);
    args.single_txn = true;
    // this test is all about transactions, make the DB small
    args.num_elements = 1;
    args.num_DBs= 1;
    stress_test_main(&args);
    return 0;
}
<|endoftext|>


<commit_before>#include "sotarviclient.h"

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
#include <stdexcept>

#include "logger.h"
#include "types.h"

char service_names[6][12] = {"notify", "start",       "chunk",
                             "finish", "getpackages", "abort"};

void callbackWrapper(int fd, void *service_data, const char *parameters) {
  (void)fd;
  SotaRVIClient *client = (SotaRVIClient *)((void **)service_data)[0];
  std::string service((char *)((void **)service_data)[1]);
  Json::Reader reader;
  Json::Value json;
  reader.parse(parameters, json);

  if (service == "notify") {
    client->sendEvent(
        boost::make_shared<event::UpdateAvailable>(event::UpdateAvailable(
            data::UpdateAvailable::fromJson(json[0]["update_available"]))));
  } else if (service == "start") {
    client->invokeAck(json[0]["update_id"].asString());
  } else if (service == "chunk") {
    client->saveChunk(json[0]);
  } else if (service == "finish") {
    client->downloadComplete(json[0]);
  } else if (service == "getpackages") {
    LOGGER_LOG(LVL_error, "service " << service << "not implemented yet");
  }
}

SotaRVIClient::SotaRVIClient(const Config &config_in,
                             event::Channel *events_channel_in)
    : config(config_in), events_channel(events_channel_in) {
  std::string client_config("./config/" + config.rvi.client_config);
  rvi = rviInit(const_cast<char *>(client_config.c_str()));
  if (!rvi) {
    throw std::runtime_error("cannot initialize rvi with config file " +
                             client_config);
  }
  connection = rviConnect(rvi, config.rvi.node_host.c_str(),
                          config.rvi.node_port.c_str());

  if (connection <= 0) {
    LOGGER_LOG(LVL_error, "cannot connect to rvi node");
  }
  unsigned int services_count =
      sizeof(service_names) / sizeof(service_names[0]);
  void *pointers[2];
  pointers[0] = (void *)(this);
  for (unsigned int i = 0; i < services_count; ++i) {
    pointers[1] = (void *)service_names[i];
    int stat = rviRegisterService(
        rvi, (std::string("sota/") + service_names[i]).c_str(), callbackWrapper,
        pointers, sizeof(pointers));
    if (stat) {
      LOGGER_LOG(LVL_error, "unable to register " << service_names[i]);
    }
    services[service_names[i]] =
        std::string("genivi.org/" + config.device.uuid + "/") +
        service_names[i];
  }
  LOGGER_LOG(LVL_info, "rvi services registered!!");
  boost::thread(boost::bind(&SotaRVIClient::run, this));
}

void SotaRVIClient::sendEvent(
    const boost::shared_ptr<event::BaseEvent> &event) {
  *events_channel << event;
}

void SotaRVIClient::run() {
  while (true) {
    int result = rviProcessInput(rvi, &connection, 1);
    if (result != 0) {
      LOGGER_LOG(LVL_error, "rviProcessInput error: " << result);
    }
  }
}

void SotaRVIClient::startDownload(const data::UpdateRequestId &update_id) {
  Json::Value value;
  value["device"] = config.device.uuid;
  value["update_id"] = update_id;
  value["services"] = services;
  Json::Value params(Json::arrayValue);
  params.append(value);
  int stat = rviInvokeService(rvi, "genivi.org/backend/sota/start",
                              Json::FastWriter().write(params).c_str());
  LOGGER_LOG(LVL_info, "invoked genivi.org/backend/sota/start, return code is "
                           << stat);
}

void SotaRVIClient::invokeAck(const std::string &update_id) {
  std::vector<int> chunks = chunks_map[update_id];

  Json::Value value;
  value["device"] = config.device.uuid;
  value["update_id"] = update_id;
  value["chunks"] = Json::arrayValue;

  for (std::vector<int>::iterator it = chunks.begin(); it != chunks.end();
       ++it) {
    value["chunks"].append(*it);
  }
  Json::Value params(Json::arrayValue);
  params.append(value);
  int stat = rviInvokeService(rvi, "genivi.org/backend/sota/ack",
                              Json::FastWriter().write(params).c_str());
  LOGGER_LOG(LVL_info, "invoked genivi.org/backend/sota/ack, return code is "
                           << stat);
}

void SotaRVIClient::saveChunk(const Json::Value &chunk_json) {
  std::string b64_text = chunk_json["bytes"].asString();

  unsigned long long paddChars =
      std::count(b64_text.begin(), b64_text.end(), '=');
  std::replace(b64_text.begin(), b64_text.end(), '=', 'A');
  std::string output(base64_to_bin(b64_text.begin()),
                     base64_to_bin(b64_text.end()));
  output.erase(output.end() - paddChars, output.end());

  std::ofstream update_file(
      config.device.packages_dir + chunk_json["update_id"].asString(),
      std::ios::out | std::ios::app | std::ios::binary);
  update_file << output;
  update_file.close();

  chunks_map[chunk_json["update_id"].asString()].push_back(
      chunk_json["index"].asInt());
  invokeAck(chunk_json["update_id"].asString());
}

void SotaRVIClient::downloadComplete(const Json::Value &parameters) {
  data::DownloadComplete download_complete;
  download_complete.update_id = parameters["update_id"].asString();
  download_complete.signature = parameters["signature"].asString();
  download_complete.update_image =
      config.device.packages_dir + download_complete.update_id;
  sendEvent(boost::make_shared<event::DownloadComplete>(download_complete));
}

void SotaRVIClient::sendUpdateReport(data::UpdateReport update_report) {
  Json::Value params(Json::arrayValue);
  params.append(update_report.toJson());

  int stat = rviInvokeService(rvi, "genivi.org/backend/sota/report",
                              Json::FastWriter().write(params).c_str());
  LOGGER_LOG(LVL_info, "invoked genivi.org/backend/sota/report, return code is "
                           << stat);
  chunks_map.erase(update_report.update_id);
}
<commit_msg>wait 5 seconds on RviProcessInput error<commit_after>#include "sotarviclient.h"

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
#include <stdexcept>

#include "logger.h"
#include "types.h"

char service_names[6][12] = {"notify", "start",       "chunk",
                             "finish", "getpackages", "abort"};

void callbackWrapper(int fd, void *service_data, const char *parameters) {
  (void)fd;
  SotaRVIClient *client = (SotaRVIClient *)((void **)service_data)[0];
  std::string service((char *)((void **)service_data)[1]);
  Json::Reader reader;
  Json::Value json;
  reader.parse(parameters, json);

  if (service == "notify") {
    client->sendEvent(
        boost::make_shared<event::UpdateAvailable>(event::UpdateAvailable(
            data::UpdateAvailable::fromJson(json[0]["update_available"]))));
  } else if (service == "start") {
    client->invokeAck(json[0]["update_id"].asString());
  } else if (service == "chunk") {
    client->saveChunk(json[0]);
  } else if (service == "finish") {
    client->downloadComplete(json[0]);
  } else if (service == "getpackages") {
    LOGGER_LOG(LVL_error, "service " << service << "not implemented yet");
  }
}

SotaRVIClient::SotaRVIClient(const Config &config_in,
                             event::Channel *events_channel_in)
    : config(config_in), events_channel(events_channel_in) {
  std::string client_config("./config/" + config.rvi.client_config);
  rvi = rviInit(const_cast<char *>(client_config.c_str()));
  if (!rvi) {
    throw std::runtime_error("cannot initialize rvi with config file " +
                             client_config);
  }
  connection = rviConnect(rvi, config.rvi.node_host.c_str(),
                          config.rvi.node_port.c_str());

  if (connection <= 0) {
    LOGGER_LOG(LVL_error, "cannot connect to rvi node");
  }
  unsigned int services_count =
      sizeof(service_names) / sizeof(service_names[0]);
  void *pointers[2];
  pointers[0] = (void *)(this);
  for (unsigned int i = 0; i < services_count; ++i) {
    pointers[1] = (void *)service_names[i];
    int stat = rviRegisterService(
        rvi, (std::string("sota/") + service_names[i]).c_str(), callbackWrapper,
        pointers, sizeof(pointers));
    if (stat) {
      LOGGER_LOG(LVL_error, "unable to register " << service_names[i]);
    }
    services[service_names[i]] =
        std::string("genivi.org/" + config.device.uuid + "/") +
        service_names[i];
  }
  LOGGER_LOG(LVL_info, "rvi services registered!!");
  boost::thread(boost::bind(&SotaRVIClient::run, this));
}

void SotaRVIClient::sendEvent(
    const boost::shared_ptr<event::BaseEvent> &event) {
  *events_channel << event;
}

void SotaRVIClient::run() {
  while (true) {
    int result = rviProcessInput(rvi, &connection, 1);
    if (result != 0) {
      LOGGER_LOG(LVL_error, "rviProcessInput error: " << result);
      sleep(5);
    }
  }
}

void SotaRVIClient::startDownload(const data::UpdateRequestId &update_id) {
  Json::Value value;
  value["device"] = config.device.uuid;
  value["update_id"] = update_id;
  value["services"] = services;
  Json::Value params(Json::arrayValue);
  params.append(value);
  int stat = rviInvokeService(rvi, "genivi.org/backend/sota/start",
                              Json::FastWriter().write(params).c_str());
  LOGGER_LOG(LVL_info, "invoked genivi.org/backend/sota/start, return code is "
                           << stat);
}

void SotaRVIClient::invokeAck(const std::string &update_id) {
  std::vector<int> chunks = chunks_map[update_id];

  Json::Value value;
  value["device"] = config.device.uuid;
  value["update_id"] = update_id;
  value["chunks"] = Json::arrayValue;

  for (std::vector<int>::iterator it = chunks.begin(); it != chunks.end();
       ++it) {
    value["chunks"].append(*it);
  }
  Json::Value params(Json::arrayValue);
  params.append(value);
  int stat = rviInvokeService(rvi, "genivi.org/backend/sota/ack",
                              Json::FastWriter().write(params).c_str());
  LOGGER_LOG(LVL_info, "invoked genivi.org/backend/sota/ack, return code is "
                           << stat);
}

void SotaRVIClient::saveChunk(const Json::Value &chunk_json) {
  std::string b64_text = chunk_json["bytes"].asString();

  unsigned long long paddChars =
      std::count(b64_text.begin(), b64_text.end(), '=');
  std::replace(b64_text.begin(), b64_text.end(), '=', 'A');
  std::string output(base64_to_bin(b64_text.begin()),
                     base64_to_bin(b64_text.end()));
  output.erase(output.end() - paddChars, output.end());

  std::ofstream update_file(
      config.device.packages_dir + chunk_json["update_id"].asString(),
      std::ios::out | std::ios::app | std::ios::binary);
  update_file << output;
  update_file.close();

  chunks_map[chunk_json["update_id"].asString()].push_back(
      chunk_json["index"].asInt());
  invokeAck(chunk_json["update_id"].asString());
}

void SotaRVIClient::downloadComplete(const Json::Value &parameters) {
  data::DownloadComplete download_complete;
  download_complete.update_id = parameters["update_id"].asString();
  download_complete.signature = parameters["signature"].asString();
  download_complete.update_image =
      config.device.packages_dir + download_complete.update_id;
  sendEvent(boost::make_shared<event::DownloadComplete>(download_complete));
}

void SotaRVIClient::sendUpdateReport(data::UpdateReport update_report) {
  Json::Value params(Json::arrayValue);
  params.append(update_report.toJson());

  int stat = rviInvokeService(rvi, "genivi.org/backend/sota/report",
                              Json::FastWriter().write(params).c_str());
  LOGGER_LOG(LVL_info, "invoked genivi.org/backend/sota/report, return code is "
                           << stat);
  chunks_map.erase(update_report.update_id);
}
<|endoftext|>


<commit_before>/**
 * @file Frame.cpp
 *
 * Handling signal frames.
 *
 * This file is part of the Aquila DSP library.
 * Aquila is free software, licensed under the MIT/X11 License. A copy of
 * the license is provided with the library in the LICENSE file.
 *
 * @package Aquila
 * @version 3.0.0-dev
 * @author Zbigniew Siciarz
 * @date 2007-2010
 * @license http://www.opensource.org/licenses/mit-license.php MIT
 * @since 0.2.2
 */

#include "Frame.h"

namespace Aquila
{
    /**
     * Creates the frame object - sets signal source and frame boundaries.
     *
     * Frame should not change original data, so the source is a const
     * reference.
     *
     * @param source const reference to signal source
     * @param indexBegin position of first sample of this frame in the source
     * @param indexEnd position of last sample of this frame in the source
     */
    Frame::Frame(const SignalSource& source, unsigned int indexBegin,
            unsigned int indexEnd):
        m_source(&source), m_begin(indexBegin), m_end(indexEnd)
    {
    }

    /**
     * Copy constructor.
     *
     * @param other reference to another frame
     */
    Frame::Frame(const Frame &other):
        m_source(other.m_source), m_begin(other.m_begin), m_end(other.m_end)
    {
    }

    /**
     * Assignes another frame to this one using copy-and-swap idiom.
     *
     * @param other reference to another frame
     * @return reference to the current object
     */
    Frame& Frame::operator=(const Frame& other)
    {
        Frame temp(other);
        swap(temp);

        return *this;
    }
}
<commit_msg>Added frame size clipping when the frame end points beyond last source sample.<commit_after>/**
 * @file Frame.cpp
 *
 * Handling signal frames.
 *
 * This file is part of the Aquila DSP library.
 * Aquila is free software, licensed under the MIT/X11 License. A copy of
 * the license is provided with the library in the LICENSE file.
 *
 * @package Aquila
 * @version 3.0.0-dev
 * @author Zbigniew Siciarz
 * @date 2007-2010
 * @license http://www.opensource.org/licenses/mit-license.php MIT
 * @since 0.2.2
 */

#include "Frame.h"

namespace Aquila
{
    /**
     * Creates the frame object - sets signal source and frame boundaries.
     *
     * Frame should not change original data, so the source is a const
     * reference.
     *
     * @param source const reference to signal source
     * @param indexBegin position of first sample of this frame in the source
     * @param indexEnd position of last sample of this frame in the source
     */
    Frame::Frame(const SignalSource& source, unsigned int indexBegin,
            unsigned int indexEnd):
        m_source(&source), m_begin(indexBegin),
        m_end((indexEnd > source.getSamplesCount()) ? source.getSamplesCount() : indexEnd)
    {
    }

    /**
     * Copy constructor.
     *
     * @param other reference to another frame
     */
    Frame::Frame(const Frame &other):
        m_source(other.m_source), m_begin(other.m_begin), m_end(other.m_end)
    {
    }

    /**
     * Assignes another frame to this one using copy-and-swap idiom.
     *
     * @param other reference to another frame
     * @return reference to the current object
     */
    Frame& Frame::operator=(const Frame& other)
    {
        Frame temp(other);
        swap(temp);

        return *this;
    }
}
<|endoftext|>


<commit_before>#pragma once
/*
*  Author(s):
*  - Chris  Kilner <ckilner@aldebaran-robotics.com>
*  - Cedric Gestes <gestes@aldebaran-robotics.com>
*
*  Copyright (C) 2010 Aldebaran Robotics
*/

#ifndef _QIMESSAGING_SIGNATURE_DETAIL_TYPE_SIGNATURE_HPP_
#define _QIMESSAGING_SIGNATURE_DETAIL_TYPE_SIGNATURE_HPP_

# include <string>
# include <vector>
# include <map>
# include <boost/utility.hpp>
# include <boost/function_types/is_function_pointer.hpp>
# include <boost/function_types/is_function.hpp>
# include <qimessaging/value.hpp>
//# include <qimessaging/message.hpp>

namespace qi {
  namespace detail {

#define _QI_SIMPLE_SIGNATURE(THETYPE, THENAME)                  \
  template <>                                                   \
  struct signature<THETYPE>  {                                  \
    static std::string &value(std::string &val) {               \
      val += THENAME;                                           \
      return val;                                               \
    }                                                           \
  };

#define _QI_LIST_SIGNATURE(TYPE)                       \
  template <typename U>                                \
  struct signature< TYPE<U> > {                        \
    static std::string &value(std::string &val) {      \
      val += "[";                                      \
      qi::detail::signature<U>::value(val);            \
      val += "]";                                      \
      return val;                                      \
    }                                                  \
  };

#define _QI_MAP_SIGNATURE(TYPE)                        \
  template <typename T1, typename T2>                  \
  struct signature< TYPE<T1, T2> > {                   \
    static std::string &value(std::string &val) {      \
      val += "{";                                      \
      qi::detail::signature<T1>::value(val);           \
      qi::detail::signature<T2>::value(val);           \
      val += "}";                                      \
      return val;                                      \
    }                                                  \
  };

    template <typename T, class Enable = void>
    struct signature {
      static std::string &value(std::string &val) {
        val += "UNKNOWN";
        return val;
      }
    };

    _QI_SIMPLE_SIGNATURE(void       , "v");
    _QI_SIMPLE_SIGNATURE(bool       , "b");
    _QI_SIMPLE_SIGNATURE(char       , "c");
    _QI_SIMPLE_SIGNATURE(int        , "i");
    _QI_SIMPLE_SIGNATURE(float      , "f");
    _QI_SIMPLE_SIGNATURE(double     , "d");
    _QI_SIMPLE_SIGNATURE(qi::Value  , "m");

    //pointer
    template <typename T>
    struct signature<T*, typename boost::disable_if< boost::function_types::is_function<T> >::type> {
      static std::string &value(std::string &val) {
        qi::detail::signature<T>::value(val);
        val += "*"; return val;
      }
    };

    //& and const are not used for function signature, it's only a compiler detail
    template <typename T>
    struct signature<T&> {
      static std::string &value(std::string &val) {
        return qi::detail::signature<T>::value(val);
      }
    };

    template <typename T>
    struct signature<const T> {
      static std::string &value(std::string &val) {
        return qi::detail::signature<T>::value(val);
      }
    };

  }
}

#endif  // _QIMESSAGING_SIGNATURE_DETAIL_TYPE_SIGNATURE_HPP_
<commit_msg>signature: X instead of UNKNOWN on error<commit_after>#pragma once
/*
*  Author(s):
*  - Chris  Kilner <ckilner@aldebaran-robotics.com>
*  - Cedric Gestes <gestes@aldebaran-robotics.com>
*
*  Copyright (C) 2010 Aldebaran Robotics
*/

#ifndef _QIMESSAGING_SIGNATURE_DETAIL_TYPE_SIGNATURE_HPP_
#define _QIMESSAGING_SIGNATURE_DETAIL_TYPE_SIGNATURE_HPP_

# include <string>
# include <vector>
# include <map>
# include <boost/utility.hpp>
# include <boost/function_types/is_function_pointer.hpp>
# include <boost/function_types/is_function.hpp>
# include <qimessaging/value.hpp>
//# include <qimessaging/message.hpp>

namespace qi {
  namespace detail {

#define _QI_SIMPLE_SIGNATURE(THETYPE, THENAME)                  \
  template <>                                                   \
  struct signature<THETYPE>  {                                  \
    static std::string &value(std::string &val) {               \
      val += THENAME;                                           \
      return val;                                               \
    }                                                           \
  };

#define _QI_LIST_SIGNATURE(TYPE)                       \
  template <typename U>                                \
  struct signature< TYPE<U> > {                        \
    static std::string &value(std::string &val) {      \
      val += "[";                                      \
      qi::detail::signature<U>::value(val);            \
      val += "]";                                      \
      return val;                                      \
    }                                                  \
  };

#define _QI_MAP_SIGNATURE(TYPE)                        \
  template <typename T1, typename T2>                  \
  struct signature< TYPE<T1, T2> > {                   \
    static std::string &value(std::string &val) {      \
      val += "{";                                      \
      qi::detail::signature<T1>::value(val);           \
      qi::detail::signature<T2>::value(val);           \
      val += "}";                                      \
      return val;                                      \
    }                                                  \
  };

    template <typename T, class Enable = void>
    struct signature {
      static std::string &value(std::string &val) {
        val += "X";
        return val;
      }
    };

    _QI_SIMPLE_SIGNATURE(void       , "v");
    _QI_SIMPLE_SIGNATURE(bool       , "b");
    _QI_SIMPLE_SIGNATURE(char       , "c");
    _QI_SIMPLE_SIGNATURE(int        , "i");
    _QI_SIMPLE_SIGNATURE(float      , "f");
    _QI_SIMPLE_SIGNATURE(double     , "d");
    _QI_SIMPLE_SIGNATURE(qi::Value  , "m");

    //pointer
    template <typename T>
    struct signature<T*, typename boost::disable_if< boost::function_types::is_function<T> >::type> {
      static std::string &value(std::string &val) {
        qi::detail::signature<T>::value(val);
        val += "*"; return val;
      }
    };

    //& and const are not used for function signature, it's only a compiler detail
    template <typename T>
    struct signature<T&> {
      static std::string &value(std::string &val) {
        return qi::detail::signature<T>::value(val);
      }
    };

    template <typename T>
    struct signature<const T> {
      static std::string &value(std::string &val) {
        return qi::detail::signature<T>::value(val);
      }
    };

  }
}

#endif  // _QIMESSAGING_SIGNATURE_DETAIL_TYPE_SIGNATURE_HPP_
<|endoftext|>


<commit_before>#pragma once
#include <cstdint>
#include <limits>
#include "type.hpp"

namespace spn {
	//! 表現に何ビット使うか計算
	/*! +1すればMSBの取得にもつかえる */
	template <unsigned int N>
	struct NBits {
		enum { result=1+NBits<((N)>>1)>::result };
	};
	template <>
	struct NBits<0> {
		enum { result=1 };
	};
	template <>
	struct NBits<1> {
		enum { result=1 };
	};

	//! NをLで何回割れるか(と、その余り)
	template <int N, int L, int N2=N>
	struct NDivide {
		typedef NDivide<N/L,L,N> Lower;
		enum { result=Lower::result + ((N>=L) ? 1 : 0),
				sum=N + Lower::sum,
				odd=Lower::odd };
	};
	template <int L, int N2>
	struct NDivide<0, L, N2> {
		enum { result=0,
				sum=0,
				odd=N2 };
	};

	//! コンパイル時累乗
	template <int N, int P>
	struct NPow {
		enum { result=NPow<N,P-1>::result * N };
	};
	template <int N>
	struct NPow<N,0> {
		enum { result=1 };
	};

	//! 引数のペアを全てXORしたものをORする
	inline int X_OrArgs() { return 0; }
	template <class T, class... Args>
	inline T X_OrArgs(const T& t0, const T& t1, Args... args) {
		return (t0^t1) | X_OrArgs(args...);
	}

	//! 定数Nの使用ビット
	template <int N>
	struct BitLength {
		enum { length = BitLength<(N>>1)>::length + 1 };
	};
	template <>
	struct BitLength<0> {
		enum { length = 0 };
	};

	//! ビットフィールド定義用
	template <int OFS, int LEN>
	struct BitF {
		enum { offset=OFS,
		length=LEN };
	};
	//! 特定のビットを対象として値を取得 & 代入
	/*! \param T 値を保持する型 (unsigned)
	 * 	\param OFS ビットオフセット
	 * 	\param LEN ビット長 */
	template <class T, int OFS, int LEN>
	class BitOp {
		enum { offset=OFS,
		length=LEN };
		T&	_value;
		constexpr static T MASKLOW = ((1 << LEN) - 1),
		MASK =  MASKLOW << OFS;
		// Tが非数値型だったりsignedな型ならコンパイルエラーを起こす
		using Limits = std::numeric_limits<T>;
		constexpr static int Dummy[Limits::is_specialized && Limits::is_integer && !Limits::is_signed ? 0 : -1] = {};

	public:
		template <class P>
		BitOp(P* ptr): _value(*(T*)ptr) {}
		BitOp(T* ptr): _value(*ptr) {}
		BitOp(T& ref): _value(ref) {}

		template <class V>
		BitOp& operator = (const V v) {
			// ビットクリア
			_value &= ~MASK;
			_value |= (T(v)<<OFS & MASK);
			return *this;
		}

		operator T () const {
			return (_value >> OFS) & MASKLOW;
		}
	};
	//! ワードに対するビット操作
	/*! \param WORD 値を保持する型
	 * 	\param OFS 下位ビット位置
	 * 	\param LEN 処理対象ビット幅 */
	template <class WORD, int OFS, int LEN>
	class BitSub {
		const static WORD MASKLOW = ((1 << LEN) - 1),
		MASK =  MASKLOW << OFS;
		using Word = WORD;
		Word&	_word;

	public:
		BitSub(Word& w): _word(w) {}

		template <class V>
		BitSub& operator = (const V v) {
			// ビットクリア
			_word &= ~MASK;
			_word |= (Word(v)<<OFS & MASK);
			return *this;
		}
		operator Word() const {
			return get(_word);
		}
		static Word get(const Word& w) {
			return (w >> OFS) & MASKLOW;
		}
		//! 違う基本型やビット位置でも交換可能だが、サイズ違いは駄目
		template <class T_WORD, int T_OFS>
		void swap(BitSub<T_WORD, T_OFS, LEN>& bs) noexcept {
			Word val0(*this);
			(*this) = Word(bs);
			bs = val0;
		}
	};
	//! テンプレートにてビットフィールドを定義
	/*! \param T 値を保持する型
	 \*param Args ビットフィールドを定義するBitOpクラス */
	template <class T, class... Ts>
	struct BitDef : CType<Ts...> {
		// Tが非数値型だったりsignedな型ならコンパイルエラーを起こす
		using Limits = std::numeric_limits<T>;
		constexpr static int UnsignedCheck[Limits::is_specialized && Limits::is_integer && !Limits::is_signed ? 0 : -1] = {};

		using Word = T;
	};
	//! ビットフィールドテンプレートクラス
	/*! \example
		struct MyDef : BitDef<uint32_t, BitF<0,14>, BitF<14,6>, BitF<20,12>> {

				enum { VAL0, VAL1, VAL2 }; };

		using Value = BitField<MyDef>;

		Value value;

		value.at<Value::VAL0>() = 128;

		int toGet = value.at<Value::VAL0>();

		\param BF BitDefクラス */
	template <class BF>
	struct BitField : BF {
		// BF(CTypes)から総サイズとオフセット計算
		constexpr static int maxbit = BF::template Size<>::maxbit,
							buffsize = ((maxbit-1)/8)+1;
		using Word = typename BF::Word;
		constexpr static int WordCheck[buffsize > sizeof(Word) ? -1 : 0] = {};

		Word _word;

		BitField() = default;
		BitField(const BitField& bf): _word(bf.value()) {}
		BitField(const Word& w): _word(w) {}
		Word& value() { return _word; }
		const Word& value() const { return _word; }

		template <int N>
		using BFAt = typename BF::template At<N>::type;
		template <int N>
		using BitSubT = BitSub<Word, BFAt<N>::offset, BFAt<N>::length>;

		//! ビット領域参照
		template <int N>
		BitSubT<N> at() {
			return BitSubT<N>(_word);
		}
		//! ビットフィールド値取得
		template <int N>
		Word at() const {
			return BitSubT<N>::get(_word);
		}
		//! ビット幅マスク取得
		template <int N>
		static Word length_mask() {
			return (Word(1) << BFAt<N>::length) - 1;
		}
		//! ビットマスク取得
		template <int N>
		static Word mask() {
			auto ret = length_mask<N>();
			return ret << BFAt<N>::offset;
		}

		//! ビットフィールドで使う場所以外をゼロクリアした値を取得
		Word cleanedValue() const {
			constexpr Word msk = (1 << maxbit)-1;
			return value() & msk;
		}
		bool operator == (const BitField& bf) const { return cleanedValue() == bf.cleanedValue(); }
		bool operator != (const BitField& bf) const { return !(this->operator == (bf)); }
		bool operator < (const BitField& bf) const {
			return cleanedValue() < bf.cleanedValue();
		}
	};

	//! コンパイル時計算
	namespace CTBit {
		template <unsigned int N>
		struct MSB_N { constexpr static int result = 1 + MSB_N<(N >> 1)>::result; };
		template <>
		struct MSB_N<1> { constexpr static int result = 0; };
		template <>
		struct MSB_N<0> { constexpr static int result = 0; };
		template <unsigned int N>
		struct LowClear { constexpr static unsigned int result = 1 << MSB_N<N>::result; };
	};
	struct Bit {
		static bool Check(uint32_t val, uint32_t flag) {
			return val & flag;
		}
		static void Clear(uint32_t& val, uint32_t flag) {
			val &= ~flag;
		}
		static void Set(uint32_t& val, uint32_t flag) {
			val |= flag;
		}
		//! ビットチェックした結果を返し、ビットは消去する
		static bool ChClear(uint32_t& val, uint32_t flag) {
			bool bRet = Check(val, flag);
			Clear(val, flag);
			return bRet;
		}
		//! 入力値の一番左のビットだけを残す
		template <class T, class=typename std::enable_if<std::is_unsigned<T>::value>::type*>
		static T LowClear(T x) {
			x = x | (x >> 1);
			x = x | (x >> 2);
			x = x | (x >> 4);
			x = x | (x >> 8);
			x = x | (x >>16);
			return x & ~(x>>1);
		}
		//! ビットが幾つ立っているか数える
		static int Count(uint32_t v) {
			uint32_t tmp = v & 0xaaaaaaaa;
			v &= 0x55555555;
			v = v + (tmp >> 1);
			tmp = v & 0xcccccccc;
			v &= 0x33333333;
			v = v + (tmp >> 2);
			tmp = v & 0xf0f0f0f0;
			v &= 0x0f0f0f0f;
			v = v + (tmp >> 4);
			tmp = v & 0xff00ff00;
			v &= 0x00ff00ff;
			v = v + (tmp >> 8);
			tmp = v & 0xffff0000;
			v &= 0x0000ffff;
			v = v + (tmp >> 16);
			return v;
		}
		//! 入力値が0なら0, それ以外は~0を返す
		static int32_t ZeroOrFull(int32_t v) {
			return (v | -v) >> 31;
		}

		// ビットの位置を計算
		#ifdef USEASM_BITSEARCH
			static uint32_t MSB_N(uint32_t x) {
				uint32_t ret;
				asm("movl %1, %%eax;"
					"orl $0x01, %%eax;"
					"bsrl %%eax, %0;"
					:"=r" (ret)
					:"r" (x)
					:"%eax"
				);
				return ret;
			}
			static uint32_t LSB_N(uint32_t x) {
				uint32_t ret;
				asm("movl %1, %%eax;"
					"orl $0x80000000, %%eax;"
					"bsfl %%eax, %0;"
					:"=r" (ret)
					:"r" (x)
					:"%eax"
				);
				return ret;
			}
		#else
			const static char NLRZ_TABLE[33];
			//! most significant bit を取得
			/*! もし入力値が0の場合は0を返す */
			static uint32_t MSB_N(uint32_t x) {
				x |= 0x01;
				return NLRZ_TABLE[0x0aec7cd2U * LowClear(x) >> 27];
			}
			//! least significant bit を取得
			/*! もし入力値が0の場合は31を返す */
			static uint32_t LSB_N(uint32_t x) {
				x |= 0x80000000;
				return NLRZ_TABLE[0x0aec7cd2U * (x & -x) >> 27];
			}
		#endif

		//! 32bit値のエンディアン変換 [little -> bit]
		static uint32_t LtoB32(uint32_t v) {
			uint32_t a = v<<24,
				b = (v&0xff00)<<8,
				c = (v>>8)&0xff00,
				d = v>>24;
			return a|b|c|d;
		}
		//! 16bit値のエンディアン変換 [little -> bit]
		static uint32_t LtoB16(uint32_t v) {
			uint32_t a = (v>>8)&0xff,
				b = (v&0xff)<<8;
			return a|b;
		}
	};
}
namespace std {
	template <class W0, int OFS0, class W1, int OFS1, int LEN>
	inline void swap(spn::BitSub<W0,OFS0,LEN>&& b0, spn::BitSub<W1,OFS1,LEN>&& b1) { b0.swap(b1); }
	template <class W0, int OFS0, class W1, int OFS1, int LEN>
	inline void swap(spn::BitSub<W0,OFS0,LEN>&& b0, spn::BitSub<W1,OFS1,LEN>& b1) { b0.swap(b1); }
	template <class W0, int OFS0, class W1, int OFS1, int LEN>
	inline void swap(spn::BitSub<W0,OFS0,LEN>& b0, spn::BitSub<W1,OFS1,LEN>&& b1) { b0.swap(b1); }
}
<commit_msg>BitField: ビットマスクの生成箇所を修正<commit_after>#pragma once
#include <cstdint>
#include <limits>
#include "type.hpp"

namespace spn {
	//! 表現に何ビット使うか計算
	/*! +1すればMSBの取得にもつかえる */
	template <unsigned int N>
	struct NBits {
		enum { result=1+NBits<((N)>>1)>::result };
	};
	template <>
	struct NBits<0> {
		enum { result=1 };
	};
	template <>
	struct NBits<1> {
		enum { result=1 };
	};

	//! NをLで何回割れるか(と、その余り)
	template <int N, int L, int N2=N>
	struct NDivide {
		typedef NDivide<N/L,L,N> Lower;
		enum { result=Lower::result + ((N>=L) ? 1 : 0),
				sum=N + Lower::sum,
				odd=Lower::odd };
	};
	template <int L, int N2>
	struct NDivide<0, L, N2> {
		enum { result=0,
				sum=0,
				odd=N2 };
	};

	//! コンパイル時累乗
	template <int N, int P>
	struct NPow {
		enum { result=NPow<N,P-1>::result * N };
	};
	template <int N>
	struct NPow<N,0> {
		enum { result=1 };
	};

	//! 引数のペアを全てXORしたものをORする
	inline int X_OrArgs() { return 0; }
	template <class T, class... Args>
	inline T X_OrArgs(const T& t0, const T& t1, Args... args) {
		return (t0^t1) | X_OrArgs(args...);
	}

	//! 定数Nの使用ビット
	template <int N>
	struct BitLength {
		enum { length = BitLength<(N>>1)>::length + 1 };
	};
	template <>
	struct BitLength<0> {
		enum { length = 0 };
	};

	//! ビットフィールド定義用
	template <int OFS, int LEN>
	struct BitF {
		enum { offset=OFS,
		length=LEN };
	};
	//! 特定のビットを対象として値を取得 & 代入
	/*! \param T 値を保持する型 (unsigned)
	 * 	\param OFS ビットオフセット
	 * 	\param LEN ビット長 */
	template <class T, int OFS, int LEN>
	class BitOp {
		enum { offset=OFS,
		length=LEN };
		T&	_value;
		constexpr static T MASKLOW = ((1 << LEN) - 1),
		MASK =  MASKLOW << OFS;
		// Tが非数値型だったりsignedな型ならコンパイルエラーを起こす
		using Limits = std::numeric_limits<T>;
		constexpr static int Dummy[Limits::is_specialized && Limits::is_integer && !Limits::is_signed ? 0 : -1] = {};

	public:
		template <class P>
		BitOp(P* ptr): _value(*(T*)ptr) {}
		BitOp(T* ptr): _value(*ptr) {}
		BitOp(T& ref): _value(ref) {}

		template <class V>
		BitOp& operator = (const V v) {
			// ビットクリア
			_value &= ~MASK;
			_value |= (T(v)<<OFS & MASK);
			return *this;
		}

		operator T () const {
			return (_value >> OFS) & MASKLOW;
		}
	};
	//! ワードに対するビット操作
	/*! \param WORD 値を保持する型
	 * 	\param OFS 下位ビット位置
	 * 	\param LEN 処理対象ビット幅 */
	template <class WORD, int OFS, int LEN>
	class BitSub {
		const static WORD MASKLOW = ((1 << LEN) - 1),
		MASK =  MASKLOW << OFS;
		using Word = WORD;
		Word&	_word;

	public:
		BitSub(Word& w): _word(w) {}

		template <class V>
		BitSub& operator = (const V v) {
			// ビットクリア
			_word &= ~MASK;
			_word |= (Word(v)<<OFS & MASK);
			return *this;
		}
		operator Word() const {
			return get(_word);
		}
		static Word get(const Word& w) {
			return (w >> OFS) & MASKLOW;
		}
		//! 違う基本型やビット位置でも交換可能だが、サイズ違いは駄目
		template <class T_WORD, int T_OFS>
		void swap(BitSub<T_WORD, T_OFS, LEN>& bs) noexcept {
			Word val0(*this);
			(*this) = Word(bs);
			bs = val0;
		}
	};
	//! テンプレートにてビットフィールドを定義
	/*! \param T 値を保持する型
	 \*param Args ビットフィールドを定義するBitOpクラス */
	template <class T, class... Ts>
	struct BitDef : CType<Ts...> {
		// Tが非数値型だったりsignedな型ならコンパイルエラーを起こす
		using Limits = std::numeric_limits<T>;
		constexpr static int UnsignedCheck[Limits::is_specialized && Limits::is_integer && !Limits::is_signed ? 0 : -1] = {};

		using Word = T;
	};
	//! ビットフィールドテンプレートクラス
	/*! \example
		struct MyDef : BitDef<uint32_t, BitF<0,14>, BitF<14,6>, BitF<20,12>> {

				enum { VAL0, VAL1, VAL2 }; };

		using Value = BitField<MyDef>;

		Value value;

		value.at<Value::VAL0>() = 128;

		int toGet = value.at<Value::VAL0>();

		\param BF BitDefクラス */
	template <class BF>
	struct BitField : BF {
		// BF(CTypes)から総サイズとオフセット計算
		constexpr static int maxbit = BF::template Size<>::maxbit,
							buffsize = ((maxbit-1)/8)+1;
		using Word = typename BF::Word;
		constexpr static int WordCheck[buffsize > sizeof(Word) ? -1 : 0] = {};

		Word _word;

		BitField() = default;
		BitField(const BitField& bf): _word(bf.value()) {}
		BitField(const Word& w): _word(w) {}
		Word& value() { return _word; }
		const Word& value() const { return _word; }

		template <int N>
		using BFAt = typename BF::template At<N>::type;
		template <int N>
		using BitSubT = BitSub<Word, BFAt<N>::offset, BFAt<N>::length>;

		//! ビット領域参照
		template <int N>
		BitSubT<N> at() {
			return BitSubT<N>(_word);
		}
		//! ビットフィールド値取得
		template <int N>
		Word at() const {
			return BitSubT<N>::get(_word);
		}
		//! ビット幅マスク取得
		template <int N>
		static Word length_mask() {
			return (Word(1) << BFAt<N>::length) - 1;
		}
		//! ビットマスク取得
		template <int N>
		static Word mask() {
			auto ret = length_mask<N>();
			return ret << BFAt<N>::offset;
		}

		//! ビットフィールドで使う場所以外をゼロクリアした値を取得
		Word cleanedValue() const {
			constexpr Word msk = (maxbit >= 64) ? ~0 : ((uint64_t(1) << maxbit)-1);
			return value() & msk;
		}
		bool operator == (const BitField& bf) const { return cleanedValue() == bf.cleanedValue(); }
		bool operator != (const BitField& bf) const { return !(this->operator == (bf)); }
		bool operator < (const BitField& bf) const {
			return cleanedValue() < bf.cleanedValue();
		}
	};

	//! コンパイル時計算
	namespace CTBit {
		template <unsigned int N>
		struct MSB_N { constexpr static int result = 1 + MSB_N<(N >> 1)>::result; };
		template <>
		struct MSB_N<1> { constexpr static int result = 0; };
		template <>
		struct MSB_N<0> { constexpr static int result = 0; };
		template <unsigned int N>
		struct LowClear { constexpr static unsigned int result = 1 << MSB_N<N>::result; };
	};
	struct Bit {
		static bool Check(uint32_t val, uint32_t flag) {
			return val & flag;
		}
		static void Clear(uint32_t& val, uint32_t flag) {
			val &= ~flag;
		}
		static void Set(uint32_t& val, uint32_t flag) {
			val |= flag;
		}
		//! ビットチェックした結果を返し、ビットは消去する
		static bool ChClear(uint32_t& val, uint32_t flag) {
			bool bRet = Check(val, flag);
			Clear(val, flag);
			return bRet;
		}
		//! 入力値の一番左のビットだけを残す
		template <class T, class=typename std::enable_if<std::is_unsigned<T>::value>::type*>
		static T LowClear(T x) {
			x = x | (x >> 1);
			x = x | (x >> 2);
			x = x | (x >> 4);
			x = x | (x >> 8);
			x = x | (x >>16);
			return x & ~(x>>1);
		}
		//! ビットが幾つ立っているか数える
		static int Count(uint32_t v) {
			uint32_t tmp = v & 0xaaaaaaaa;
			v &= 0x55555555;
			v = v + (tmp >> 1);
			tmp = v & 0xcccccccc;
			v &= 0x33333333;
			v = v + (tmp >> 2);
			tmp = v & 0xf0f0f0f0;
			v &= 0x0f0f0f0f;
			v = v + (tmp >> 4);
			tmp = v & 0xff00ff00;
			v &= 0x00ff00ff;
			v = v + (tmp >> 8);
			tmp = v & 0xffff0000;
			v &= 0x0000ffff;
			v = v + (tmp >> 16);
			return v;
		}
		//! 入力値が0なら0, それ以外は~0を返す
		static int32_t ZeroOrFull(int32_t v) {
			return (v | -v) >> 31;
		}

		// ビットの位置を計算
		#ifdef USEASM_BITSEARCH
			static uint32_t MSB_N(uint32_t x) {
				uint32_t ret;
				asm("movl %1, %%eax;"
					"orl $0x01, %%eax;"
					"bsrl %%eax, %0;"
					:"=r" (ret)
					:"r" (x)
					:"%eax"
				);
				return ret;
			}
			static uint32_t LSB_N(uint32_t x) {
				uint32_t ret;
				asm("movl %1, %%eax;"
					"orl $0x80000000, %%eax;"
					"bsfl %%eax, %0;"
					:"=r" (ret)
					:"r" (x)
					:"%eax"
				);
				return ret;
			}
		#else
			const static char NLRZ_TABLE[33];
			//! most significant bit を取得
			/*! もし入力値が0の場合は0を返す */
			static uint32_t MSB_N(uint32_t x) {
				x |= 0x01;
				return NLRZ_TABLE[0x0aec7cd2U * LowClear(x) >> 27];
			}
			//! least significant bit を取得
			/*! もし入力値が0の場合は31を返す */
			static uint32_t LSB_N(uint32_t x) {
				x |= 0x80000000;
				return NLRZ_TABLE[0x0aec7cd2U * (x & -x) >> 27];
			}
		#endif

		//! 32bit値のエンディアン変換 [little -> bit]
		static uint32_t LtoB32(uint32_t v) {
			uint32_t a = v<<24,
				b = (v&0xff00)<<8,
				c = (v>>8)&0xff00,
				d = v>>24;
			return a|b|c|d;
		}
		//! 16bit値のエンディアン変換 [little -> bit]
		static uint32_t LtoB16(uint32_t v) {
			uint32_t a = (v>>8)&0xff,
				b = (v&0xff)<<8;
			return a|b;
		}
	};
}
namespace std {
	template <class W0, int OFS0, class W1, int OFS1, int LEN>
	inline void swap(spn::BitSub<W0,OFS0,LEN>&& b0, spn::BitSub<W1,OFS1,LEN>&& b1) { b0.swap(b1); }
	template <class W0, int OFS0, class W1, int OFS1, int LEN>
	inline void swap(spn::BitSub<W0,OFS0,LEN>&& b0, spn::BitSub<W1,OFS1,LEN>& b1) { b0.swap(b1); }
	template <class W0, int OFS0, class W1, int OFS1, int LEN>
	inline void swap(spn::BitSub<W0,OFS0,LEN>& b0, spn::BitSub<W1,OFS1,LEN>&& b1) { b0.swap(b1); }
}
<|endoftext|>


<commit_before>#include <windows.h>
#include <string>
#include <sstream>
#include <memory>

#include "subscription.h"
#include "../../result.h"
#include "../../helper/windows/helper.h"

using std::wstring;
using std::ostringstream;
using std::wostringstream;

const DWORD DEFAULT_BUFFER_SIZE = 1024 * 1024;
const DWORD NETWORK_BUFFER_SIZE = 64 * 1024;

Subscription::Subscription(
  ChannelID channel,
  HANDLE root,
  const wstring &path,
  WindowsWorkerPlatform *platform
) :
  command{0},
  channel{channel},
  platform{platform},
  path{path},
  root{root},
  terminating{false},
  buffer_size{DEFAULT_BUFFER_SIZE},
  buffer{new BYTE[buffer_size]},
  written{new BYTE[buffer_size]}
{
  ZeroMemory(&overlapped, sizeof(OVERLAPPED));
  overlapped.hEvent = this;
}

Subscription::~Subscription()
{
  CloseHandle(root);
}

Result<> Subscription::schedule(LPOVERLAPPED_COMPLETION_ROUTINE fn)
{
  int success = ReadDirectoryChangesW(
    root, // root directory handle
    buffer.get(), // result buffer
    buffer_size, // result buffer size
    TRUE, // recursive
    FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES
      | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS
      | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, // change flags
    NULL, // bytes returned
    &overlapped, // overlapped
    fn // completion routine
  );
  if (!success) {
    return windows_error_result<>("Unable to subscribe to filesystem events");
  }

  return ok_result();
}

Result<> Subscription::use_network_size()
{
  if (buffer_size <= NETWORK_BUFFER_SIZE) {
    ostringstream out("Buffer size of ");
    out
      << buffer_size
      << " is already lower than the network buffer size "
      << NETWORK_BUFFER_SIZE;
    return error_result(out.str());
  }

  buffer_size = NETWORK_BUFFER_SIZE;
  buffer.reset(new BYTE[buffer_size]);
  written.reset(new BYTE[buffer_size]);

  return ok_result();
}

BYTE *Subscription::get_written(DWORD written_size)
{
  memcpy(written.get(), buffer.get(), written_size);
  return written.get();
}

wstring Subscription::make_absolute(const wstring &sub_path)
{
  wostringstream out;

  out << path;
  if (path.back() != L'\\' && sub_path.front() != L'\\') {
    out << L'\\';
  }
  out << sub_path;

  return out.str();
}

Result<> Subscription::stop(const CommandID cmd)
{
  if (terminating) return ok_result();

  bool success = CancelIo(root);
  if (!success) return windows_error_result<>("Unable to cancel pending I/O");

  terminating = true;
  command = cmd;

  return ok_result();
}
<commit_msg>Prevent calls to ReadDirectoryChangesW on terminating Subscriptions<commit_after>#include <windows.h>
#include <string>
#include <sstream>
#include <iostream>
#include <memory>

#include "subscription.h"
#include "../../log.h"
#include "../../result.h"
#include "../../helper/windows/helper.h"

using std::wstring;
using std::ostringstream;
using std::wostringstream;
using std::endl;

const DWORD DEFAULT_BUFFER_SIZE = 1024 * 1024;
const DWORD NETWORK_BUFFER_SIZE = 64 * 1024;

Subscription::Subscription(
  ChannelID channel,
  HANDLE root,
  const wstring &path,
  WindowsWorkerPlatform *platform
) :
  command{0},
  channel{channel},
  platform{platform},
  path{path},
  root{root},
  terminating{false},
  buffer_size{DEFAULT_BUFFER_SIZE},
  buffer{new BYTE[buffer_size]},
  written{new BYTE[buffer_size]}
{
  ZeroMemory(&overlapped, sizeof(OVERLAPPED));
  overlapped.hEvent = this;
}

Subscription::~Subscription()
{
  CloseHandle(root);
}

Result<> Subscription::schedule(LPOVERLAPPED_COMPLETION_ROUTINE fn)
{
  if (terminating) {
    LOGGER << "Declining to schedule a new change callback for channel " << channel
      << " because the subscription is terminating." << endl;
    return ok_result();
  }
  LOGGER << "Scheduling the next change callback for channel " << channel << "." << endl;

  int success = ReadDirectoryChangesW(
    root, // root directory handle
    buffer.get(), // result buffer
    buffer_size, // result buffer size
    TRUE, // recursive
    FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES
      | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS
      | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, // change flags
    NULL, // bytes returned
    &overlapped, // overlapped
    fn // completion routine
  );
  if (!success) {
    return windows_error_result<>("Unable to subscribe to filesystem events");
  }

  return ok_result();
}

Result<> Subscription::use_network_size()
{
  if (buffer_size <= NETWORK_BUFFER_SIZE) {
    ostringstream out("Buffer size of ");
    out
      << buffer_size
      << " is already lower than the network buffer size "
      << NETWORK_BUFFER_SIZE;
    return error_result(out.str());
  }

  buffer_size = NETWORK_BUFFER_SIZE;
  buffer.reset(new BYTE[buffer_size]);
  written.reset(new BYTE[buffer_size]);

  return ok_result();
}

BYTE *Subscription::get_written(DWORD written_size)
{
  memcpy(written.get(), buffer.get(), written_size);
  return written.get();
}

wstring Subscription::make_absolute(const wstring &sub_path)
{
  wostringstream out;

  out << path;
  if (path.back() != L'\\' && sub_path.front() != L'\\') {
    out << L'\\';
  }
  out << sub_path;

  return out.str();
}

Result<> Subscription::stop(const CommandID cmd)
{
  if (terminating) return ok_result();

  bool success = CancelIo(root);
  if (!success) return windows_error_result<>("Unable to cancel pending I/O");

  terminating = true;
  command = cmd;

  return ok_result();
}
<|endoftext|>


<commit_before>#include "client_socket.h"

#include <sstream>

using boost::asio::ip::tcp;

Client_socket::Client_socket ( std::string address, std::string service ) :
    io_service ( std::make_shared < boost::asio::io_service > () ),
    socket ( new tcp::socket ( *io_service ) )
{
    tcp::resolver resolver ( *io_service );
    tcp::resolver::query query ( address, service );
    tcp::resolver::iterator endpoint_iterator = resolver.resolve ( query );

    boost::asio::connect ( *socket, endpoint_iterator );
}

Client_socket::Client_socket (
        std::unique_ptr < tcp::socket >&& socket,
        std::shared_ptr < boost::asio::io_service > io_service
        ) :
    io_service ( io_service ),
    socket ( std::move ( socket ) )
{}

std::string Client_socket::read_line ()
{
    while ( next_lines.empty () )
    {
        std::vector < char > buffer ( 1024 );

        size_t len = ( *socket ).read_some ( boost::asio::buffer ( buffer ) );

        std::string data_string = std::string ( buffer.begin (), buffer.begin () + len );

        std::string line;
        std::stringstream ss ( std::string ( buffer.begin (), buffer.begin () + len ) );
        while ( ( std::getline ( ss, line, '\n' ) ) )
        {
            line = line_rest + line;
            line_rest.clear ();
            while ( line.back () == '\n' || line.back () == '\r' )
            {
                line.pop_back ();
            }
            next_lines.push_back ( line );
        }

        if ( buffer.back () != '\n' )
        {
            line_rest = next_lines.back ();
            next_lines.pop_back ();
        }
    }

    std::string line = next_lines.front ();
    next_lines.pop_front ();
    return line;
}

void Client_socket::send ( std::string message )
{
    boost::asio::write ( *socket, boost::asio::buffer ( message ) );
}
<commit_msg>Fix Bug in Client_socket<commit_after>#include "client_socket.h"

#include <sstream>

using boost::asio::ip::tcp;

Client_socket::Client_socket ( std::string address, std::string service ) :
    io_service ( std::make_shared < boost::asio::io_service > () ),
    socket ( new tcp::socket ( *io_service ) )
{
    tcp::resolver resolver ( *io_service );
    tcp::resolver::query query ( address, service );
    tcp::resolver::iterator endpoint_iterator = resolver.resolve ( query );

    boost::asio::connect ( *socket, endpoint_iterator );
}

Client_socket::Client_socket (
        std::unique_ptr < tcp::socket >&& socket,
        std::shared_ptr < boost::asio::io_service > io_service
        ) :
    io_service ( io_service ),
    socket ( std::move ( socket ) )
{}

std::string Client_socket::read_line ()
{
    while ( next_lines.empty () )
    {
        std::vector < char > buffer ( 1024 );

        size_t len = ( *socket ).read_some ( boost::asio::buffer ( buffer ) );

        std::string data_string = std::string ( buffer.begin (), buffer.begin () + len );

        std::string line;
        std::string buffer_string = std::string ( buffer.begin (), buffer.begin () + len );
        std::stringstream ss ( buffer_string );
        while ( ( std::getline ( ss, line, '\n' ) ) )
        {
            line = line_rest + line;
            line_rest.clear ();
            while ( line.back () == '\n' || line.back () == '\r' )
            {
                line.pop_back ();
            }
            next_lines.push_back ( line );
        }

        if ( buffer_string.back () != '\n' )
        {
            line_rest = next_lines.back ();
            next_lines.pop_back ();
        }
    }

    std::string line = next_lines.front ();
    next_lines.pop_front ();
    return line;
}

void Client_socket::send ( std::string message )
{
    boost::asio::write ( *socket, boost::asio::buffer ( message ) );
}
<|endoftext|>


<commit_before>// This file is part of the "x0" project, http://github.com/christianparpart/x0>
//   (c) 2009-2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/http/client/HttpClient.h>
#include <xzero/http/client/HttpTransport.h>
#include <xzero/http/client/Http1Connection.h>
#include <xzero/http/HttpRequest.h>
#include <xzero/http/HttpStatus.h>
#include <xzero/net/TcpEndPoint.h>
#include <xzero/net/SslEndPoint.h>
#include <xzero/net/DnsClient.h>
#include <xzero/net/InetAddress.h>
#include <xzero/net/IPAddress.h>
#include <xzero/net/TcpUtil.h>
#include <xzero/io/FileView.h>
#include <xzero/RuntimeError.h>
#include <xzero/logging.h>

#if !defined(NDEBUG)
#define TRACE(msg...) logTrace("HttpClient", msg)
#else
#warning "No NDEBUG set"
#define TRACE(msg...) do {} while (0)
#endif

namespace xzero::http::client {

template<typename T> static bool isConnectionHeader(const T& name) { // {{{
  static const std::vector<T> connectionHeaderFields = {
    "Connection",
    "Content-Length",
    "Close",
    "Keep-Alive",
    "TE",
    "Trailer",
    "Transfer-Encoding",
    "Upgrade",
  };

  for (const auto& test: connectionHeaderFields)
    if (iequals(name, test))
      return true;

  return false;
} // }}}

HttpClient::HttpClient(Executor* executor,
                       const InetAddress& upstream)
    : HttpClient(executor,
                 upstream,
                 10_seconds,   // connectTimeout
                 5_minutes,    // readTimeout
                 10_seconds,   // writeTimeout
                 60_seconds) { // keepAlive
}

HttpClient::HttpClient(Executor* executor,
                       const InetAddress& upstream,
                       Duration connectTimeout,
                       Duration readTimeout,
                       Duration writeTimeout,
                       Duration keepAlive)
    : executor_(executor),
      createEndPoint_(std::bind(&HttpClient::createTcp, this,
            upstream,
            connectTimeout,
            readTimeout,
            writeTimeout)),
      keepAlive_(keepAlive),
      endpoint_(),
      request_(),
      listener_(),
      isListenerOwned_(false) {
}

HttpClient::HttpClient(Executor* executor,
                       RefPtr<TcpEndPoint> upstream,
                       Duration keepAlive)
    : executor_(executor),
      createEndPoint_(),
      keepAlive_(keepAlive),
      endpoint_(upstream),
      request_(),
      listener_(),
      isListenerOwned_(false) {
}

HttpClient::HttpClient(Executor* executor,
                       CreateEndPoint endpointCreator,
                       Duration keepAlive)
    : executor_(executor),
      createEndPoint_(endpointCreator),
      keepAlive_(keepAlive),
      endpoint_(),
      request_(),
      listener_(),
      isListenerOwned_(false) {
}

HttpClient::HttpClient(HttpClient&& other)
    : executor_(other.executor_),
      createEndPoint_(std::move(other.createEndPoint_)),
      keepAlive_(std::move(other.keepAlive_)),
      endpoint_(std::move(other.endpoint_)),
      request_(std::move(other.request_)),
      listener_(other.listener_),
      isListenerOwned_(other.isListenerOwned_) {
  other.isListenerOwned_ = false;
}

Future<RefPtr<TcpEndPoint>> HttpClient::createTcp(InetAddress address,
                                                  Duration connectTimeout,
                                                  Duration readTimeout,
                                                  Duration writeTimeout) {
  if (request_.scheme() == "https") {
    TRACE("createTcp: https");
    auto createApplicationConnection = [this](const std::string& protocolName,
                                              TcpEndPoint* endpoint) {
      endpoint->setConnection<Http1Connection>(listener_,
                                               endpoint,
                                               executor_);
    };
    Promise<RefPtr<TcpEndPoint>> promise;
    Future<RefPtr<SslEndPoint>> f = SslEndPoint::connect(address,
                                            connectTimeout,
                                            readTimeout,
                                            writeTimeout,
                                            executor_,
                                            request_.headers().get("Host"),
                                            {"http/1.1"},
                                            createApplicationConnection);
    f.onSuccess(promise);
    f.onFailure(promise);
    return promise.future();
  } else {
    TRACE("createTcp: http");
    return TcpEndPoint::connect(address,
                                connectTimeout,
                                readTimeout,
                                writeTimeout,
                                executor_);
  }
}

Future<HttpClient::Response> HttpClient::send(const std::string& method,
                                              const Uri& url,
                                              const HeaderFieldList& headers) {
  return send(Request{HttpVersion::VERSION_1_1,
                      method,
                      url.toString(),
                      headers,
                      false,
                      HugeBuffer()});
}

Future<HttpClient::Response> HttpClient::send(const Request& request) {
  Promise<Response> promise;

  request_ = request;
  listener_ = new ResponseBuilder(promise);
  isListenerOwned_ = true;

  execute();

  return promise.future();
}

void HttpClient::send(const Request& request,
                      HttpListener* responseListener) {
  request_ = request;
  listener_ = responseListener;
  isListenerOwned_ = false;

  execute();
}

void HttpClient::execute() {
  Future<RefPtr<TcpEndPoint>> f = createEndPoint_();

  f.onSuccess([this](RefPtr<TcpEndPoint> ep) {
    TRACE("endpoint created");
    endpoint_ = ep;

    if (!endpoint_->connection()) {
      TRACE("creating connection: http/1.1");
      endpoint_->setConnection<Http1Connection>(listener_, endpoint_.get(), executor_);
    }

    TRACE("getting channel");
    HttpTransport* channel = reinterpret_cast<HttpTransport*>(endpoint_->connection());
    channel->setListener(listener_);
    TRACE("sending request");
    channel->send(request_, nullptr);
    TRACE("sending request body");
    channel->send(request_.getContent().getBuffer(), nullptr);
    TRACE("mark completed!");
    channel->completed();
  });

  f.onFailure([this](std::error_code ec) {
    logError("HttpClient", "Failed to connect. $0", ec.message());
  });
}

// {{{ ResponseBuilder
HttpClient::ResponseBuilder::ResponseBuilder(Promise<Response> promise)
    : promise_(promise),
      response_() {
  TRACE("ResponseBuilder.ctor");
}

void HttpClient::ResponseBuilder::onMessageBegin(HttpVersion version,
                                                 HttpStatus code,
                                                 const BufferRef& text) {
  TRACE("ResponseBuilder.onMessageBegin($0, $1, $2)", version, (int)code, text);

  response_.setVersion(version);
  response_.setStatus(code);
  response_.setReason(text.str());
}

void HttpClient::ResponseBuilder::onMessageHeader(const BufferRef& name,
                                                  const BufferRef& value) {
  TRACE("ResponseBuilder.onMessageHeader($0, $1)", name, value);

  response_.headers().push_back(name.str(), value.str());
}

void HttpClient::ResponseBuilder::onMessageHeaderEnd() {
  TRACE("ResponseBuilder.onMessageHeaderEnd()");
}

void HttpClient::ResponseBuilder::onMessageContent(const BufferRef& chunk) {
  TRACE("ResponseBuilder.onMessageContent(BufferRef) $0 bytes", chunk.size());
  response_.content().write(chunk);
}

void HttpClient::ResponseBuilder::onMessageContent(FileView&& chunk) {
  TRACE("ResponseBuilder.onMessageContent(FileView) $0 bytes", chunk.size());
  response_.content().write(std::move(chunk));
}

void HttpClient::ResponseBuilder::onMessageEnd() {
  TRACE("ResponseBuilder.onMessageEnd()");
  response_.setContentLength(response_.content().size());
  promise_.success(response_);
  delete this;
}

void HttpClient::ResponseBuilder::onError(std::error_code ec) {
  logError("ResponseBuilder", "Error. $0; $1", ec.message());
  promise_.failure(ec);
  delete this;
}
// }}}

} // namespace xzero::http::client
<commit_msg>[xzero] HttpClient: fixed crash and dropped debug prints from prior WIP check-in<commit_after>// This file is part of the "x0" project, http://github.com/christianparpart/x0>
//   (c) 2009-2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/http/client/HttpClient.h>
#include <xzero/http/client/HttpTransport.h>
#include <xzero/http/client/Http1Connection.h>
#include <xzero/http/HttpRequest.h>
#include <xzero/http/HttpStatus.h>
#include <xzero/net/TcpEndPoint.h>
#include <xzero/net/SslEndPoint.h>
#include <xzero/net/DnsClient.h>
#include <xzero/net/InetAddress.h>
#include <xzero/net/IPAddress.h>
#include <xzero/net/TcpUtil.h>
#include <xzero/io/FileView.h>
#include <xzero/RuntimeError.h>
#include <xzero/logging.h>

#if !defined(NDEBUG)
#define TRACE(msg...) logTrace("HttpClient", msg)
#else
#warning "No NDEBUG set"
#define TRACE(msg...) do {} while (0)
#endif

namespace xzero::http::client {

template<typename T> static bool isConnectionHeader(const T& name) { // {{{
  static const std::vector<T> connectionHeaderFields = {
    "Connection",
    "Content-Length",
    "Close",
    "Keep-Alive",
    "TE",
    "Trailer",
    "Transfer-Encoding",
    "Upgrade",
  };

  for (const auto& test: connectionHeaderFields)
    if (iequals(name, test))
      return true;

  return false;
} // }}}

HttpClient::HttpClient(Executor* executor,
                       const InetAddress& upstream)
    : HttpClient(executor,
                 upstream,
                 10_seconds,   // connectTimeout
                 5_minutes,    // readTimeout
                 10_seconds,   // writeTimeout
                 60_seconds) { // keepAlive
}

HttpClient::HttpClient(Executor* executor,
                       const InetAddress& upstream,
                       Duration connectTimeout,
                       Duration readTimeout,
                       Duration writeTimeout,
                       Duration keepAlive)
    : executor_(executor),
      createEndPoint_(std::bind(&HttpClient::createTcp, this,
            upstream,
            connectTimeout,
            readTimeout,
            writeTimeout)),
      keepAlive_(keepAlive),
      endpoint_(),
      request_(),
      listener_(),
      isListenerOwned_(false) {
}

HttpClient::HttpClient(Executor* executor,
                       RefPtr<TcpEndPoint> upstream,
                       Duration keepAlive)
    : executor_(executor),
      createEndPoint_(),
      keepAlive_(keepAlive),
      endpoint_(upstream),
      request_(),
      listener_(),
      isListenerOwned_(false) {
}

HttpClient::HttpClient(Executor* executor,
                       CreateEndPoint endpointCreator,
                       Duration keepAlive)
    : executor_(executor),
      createEndPoint_(endpointCreator),
      keepAlive_(keepAlive),
      endpoint_(),
      request_(),
      listener_(),
      isListenerOwned_(false) {
}

HttpClient::HttpClient(HttpClient&& other)
    : executor_(other.executor_),
      createEndPoint_(std::move(other.createEndPoint_)),
      keepAlive_(std::move(other.keepAlive_)),
      endpoint_(std::move(other.endpoint_)),
      request_(std::move(other.request_)),
      listener_(other.listener_),
      isListenerOwned_(other.isListenerOwned_) {
  other.isListenerOwned_ = false;
}

Future<RefPtr<TcpEndPoint>> HttpClient::createTcp(InetAddress address,
                                                  Duration connectTimeout,
                                                  Duration readTimeout,
                                                  Duration writeTimeout) {
  if (request_.scheme() == "https") {
    TRACE("createTcp: https");
    auto createApplicationConnection = [this](const std::string& protocolName,
                                              TcpEndPoint* endpoint) {
      endpoint->setConnection<Http1Connection>(listener_,
                                               endpoint,
                                               executor_);
    };
    Promise<RefPtr<TcpEndPoint>> promise;
    Future<RefPtr<SslEndPoint>> f = SslEndPoint::connect(address,
                                            connectTimeout,
                                            readTimeout,
                                            writeTimeout,
                                            executor_,
                                            request_.headers().get("Host"),
                                            {"http/1.1"},
                                            createApplicationConnection);
    f.onSuccess(promise);
    f.onFailure(promise);
    return promise.future();
  } else {
    TRACE("createTcp: http");
    return TcpEndPoint::connect(address,
                                connectTimeout,
                                readTimeout,
                                writeTimeout,
                                executor_);
  }
}

Future<HttpClient::Response> HttpClient::send(const std::string& method,
                                              const Uri& url,
                                              const HeaderFieldList& headers) {
  return send(Request{HttpVersion::VERSION_1_1,
                      method,
                      url.toString(),
                      headers,
                      false,
                      HugeBuffer()});
}

Future<HttpClient::Response> HttpClient::send(const Request& request) {
  Promise<Response> promise;

  request_ = request;
  listener_ = new ResponseBuilder(promise);
  isListenerOwned_ = true;

  execute();

  return promise.future();
}

void HttpClient::send(const Request& request,
                      HttpListener* responseListener) {
  request_ = request;
  listener_ = responseListener;
  isListenerOwned_ = false;

  execute();
}

void HttpClient::execute() {
  Future<RefPtr<TcpEndPoint>> f = createEndPoint_();

  f.onSuccess([this](RefPtr<TcpEndPoint> ep) {
    TRACE("endpoint created");
    endpoint_ = ep;

    if (!endpoint_->connection()) {
      TRACE("creating connection: http/1.1");
      endpoint_->setConnection<Http1Connection>(listener_, endpoint_.get(), executor_);
    }

    // dynamic_cast, as we're having most-likely multiple inheritance here
    HttpTransport* channel = dynamic_cast<HttpTransport*>(endpoint_->connection());
    assert(channel != nullptr);

    channel->setListener(listener_);
    channel->send(request_, nullptr);
    channel->send(request_.getContent().getBuffer(), nullptr);
    channel->completed();
  });

  f.onFailure([this](std::error_code ec) {
    logError("HttpClient", "Failed to connect. $0", ec.message());
  });
}

// {{{ ResponseBuilder
HttpClient::ResponseBuilder::ResponseBuilder(Promise<Response> promise)
    : promise_(promise),
      response_() {
  TRACE("ResponseBuilder.ctor");
}

void HttpClient::ResponseBuilder::onMessageBegin(HttpVersion version,
                                                 HttpStatus code,
                                                 const BufferRef& text) {
  TRACE("ResponseBuilder.onMessageBegin($0, $1, $2)", version, (int)code, text);

  response_.setVersion(version);
  response_.setStatus(code);
  response_.setReason(text.str());
}

void HttpClient::ResponseBuilder::onMessageHeader(const BufferRef& name,
                                                  const BufferRef& value) {
  TRACE("ResponseBuilder.onMessageHeader($0, $1)", name, value);

  response_.headers().push_back(name.str(), value.str());
}

void HttpClient::ResponseBuilder::onMessageHeaderEnd() {
  TRACE("ResponseBuilder.onMessageHeaderEnd()");
}

void HttpClient::ResponseBuilder::onMessageContent(const BufferRef& chunk) {
  TRACE("ResponseBuilder.onMessageContent(BufferRef) $0 bytes", chunk.size());
  response_.content().write(chunk);
}

void HttpClient::ResponseBuilder::onMessageContent(FileView&& chunk) {
  TRACE("ResponseBuilder.onMessageContent(FileView) $0 bytes", chunk.size());
  response_.content().write(std::move(chunk));
}

void HttpClient::ResponseBuilder::onMessageEnd() {
  TRACE("ResponseBuilder.onMessageEnd()");
  response_.setContentLength(response_.content().size());
  promise_.success(response_);
  delete this;
}

void HttpClient::ResponseBuilder::onError(std::error_code ec) {
  logError("ResponseBuilder", "Error. $0; $1", ec.message());
  promise_.failure(ec);
  delete this;
}
// }}}

} // namespace xzero::http::client
<|endoftext|>