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

#include <cstddef>
#include <functional>
#include <memory>
#include <metaverse/network.hpp>

namespace libbitcoin {
namespace node {

#define NAME "transaction"
#define CLASS protocol_transaction_out

using namespace bc::blockchain;
using namespace bc::message;
using namespace bc::network;
using namespace std::placeholders;

protocol_transaction_out::protocol_transaction_out(p2p& network,
    channel::ptr channel, block_chain& blockchain, transaction_pool& pool)
  : protocol_events(network, channel, NAME),
    blockchain_(blockchain),
    pool_(pool),

    // TODO: move fee filter to a derived class protocol_transaction_out_70013.
    minimum_fee_(0),

    // TODO: move relay to a derived class protocol_transaction_out_70001.
    relay_to_peer_(peer_version().relay),
    CONSTRUCT_TRACK(protocol_transaction_out)
{
}

protocol_transaction_out::ptr protocol_transaction_out::do_subscribe()
{
    SUBSCRIBE2(memory_pool, handle_receive_memory_pool, _1, _2);
    SUBSCRIBE2(fee_filter, handle_receive_fee_filter, _1, _2);
    SUBSCRIBE2(get_data, handle_receive_get_data, _1, _2);
    return std::dynamic_pointer_cast<protocol_transaction_out>(protocol::shared_from_this());
}

// TODO: move not_found to derived class protocol_transaction_out_70001.

// Start.
//-----------------------------------------------------------------------------

void protocol_transaction_out::start()
{
    protocol_events::start(BIND1(handle_stop, _1));
    // TODO: move relay to a derived class protocol_transaction_out_70001.
    // Prior to this level transaction relay is not configurable.
    if (relay_to_peer_)
    {
        // Subscribe to transaction pool notifications and relay txs.
        pool_.subscribe_transaction(BIND3(handle_floated, _1, _2, _3));
    }

    // TODO: move fee filter to a derived class protocol_transaction_out_70013.
    // Filter announcements by fee if set.

}

// Receive send_headers.
//-----------------------------------------------------------------------------

// TODO: move fee_filters to a derived class protocol_transaction_out_70013.
bool protocol_transaction_out::handle_receive_fee_filter(const code& ec,
    fee_filter_ptr message)
{
    if (stopped())
        return false;

    if (ec)
    {
        log::trace(LOG_NODE)
            << "Failure getting " << message->command << " from ["
            << authority() << "] " << ec.message();
        stop(ec);
        return false;
    }

    // TODO: move fee filter to a derived class protocol_transaction_out_70013.
    // Transaction annoucements will be filtered by fee amount.
    minimum_fee_.store(message->minimum_fee);

    // The fee filter may be adjusted.
    return true;
}

// Receive mempool sequence.
//-----------------------------------------------------------------------------

bool protocol_transaction_out::handle_receive_memory_pool(const code& ec,
    memory_pool_ptr)
{
    if (stopped()) {
        return false;
    }

    if (ec) {
        return false;
    }

    log::debug(LOG_NODE) << "protocol_transaction_out::handle_receive_memory_pool";
    pool_.fetch([this](const code& ec, const std::vector<transaction_ptr>& txs){
        if (stopped() || ec) {
            log::debug(LOG_NODE) << "pool fetch transaction failed," << ec.message();
            return;
        }

        if (txs.empty()) {
            return;
        }
        std::vector<hash_digest> hashes;
        hashes.reserve(txs.size());
        for(auto& t:txs) {
            hashes.push_back(t->hash());
        }
        log::debug(LOG_NODE) << "memory pool size," << txs.size();
        send<protocol_transaction_out>(inventory{hashes, inventory::type_id::transaction}, &protocol_transaction_out::handle_send, _1, inventory::command);
    });
    return false;
}

// Receive get_data sequence.
//-----------------------------------------------------------------------------

bool protocol_transaction_out::handle_receive_get_data(const code& ec,
    get_data_ptr message)
{
    if (stopped())
        return false;

    if (ec)
    {
        log::trace(LOG_NODE)
            << "Failure getting inventory from [" << authority() << "] "
            << ec.message();
        stop(ec);
        return false;
    }

//    if (message->inventories.size() > 50000)
//    {
//        return ! misbehaving(20);
//    }

    // TODO: these must return message objects or be copied!
    // Ignore non-transaction inventory requests in this protocol.
    for (const auto& inv: message->inventories)
        if (inv.type == inventory::type_id::transaction)
        {
            auto pThis = shared_from_this();
            pool_.fetch(inv.hash, [this, &inv, pThis](const code& ec, transaction_ptr tx){
                auto t = tx ? *tx : chain::transaction{};
                send_transaction(ec, t, inv.hash);
                if(ec)
                {
                    blockchain_.fetch_transaction(inv.hash,
                    BIND3(send_transaction, _1, _2, inv.hash));
                }
            });
        }

    return true;
}

void protocol_transaction_out::send_transaction(const code& ec,
    const chain::transaction& transaction, const hash_digest& hash)
{
    if (stopped() || ec == (code)error::service_stopped)
        return;

    if (ec == (code)error::not_found)
    {
        log::trace(LOG_NODE)
            << "Transaction requested by [" << authority() << "] not found.";

        const not_found reply{ { inventory::type_id::transaction, hash } };
        SEND2(reply, handle_send, _1, reply.command);
        return;
    }

    if (ec)
    {
        log::error(LOG_NODE)
            << "Internal failure locating trnsaction requested by ["
            << authority() << "] " << ec.message();
        stop(ec);
        return;
    }

    log::trace(LOG_NODE) << "send transaction " << encode_hash(transaction.hash()) << ", to " << authority();

    // TODO: eliminate copy.
    SEND2(transaction_message(transaction), handle_send, _1,
        transaction_message::command);
}

// Subscription.
//-----------------------------------------------------------------------------

bool protocol_transaction_out::handle_floated(const code& ec,
    const index_list& unconfirmed, transaction_ptr message)
{
    if (stopped() || ec == (code)error::service_stopped)
        return false;

    if (ec == (code)error::mock)
    {
        return true;
    }

    if (ec)
    {
        log::error(LOG_NODE)
            << "Failure handling transaction float: " << ec.message();
        stop(ec);
        return false;
    }

    // TODO: move fee filter to a derived class protocol_transaction_out_70013.
    // TODO: implement fee computation.
    const uint64_t fee = 0;

    // Transactions are discovered and announced individually.
    if (message->originator() != nonce() && fee >= minimum_fee_.load())
    {
        static const auto id = inventory::type_id::transaction;
        const inventory announcement{ { id, message->hash() } };
        log::trace(LOG_NODE) << "handle floated send transaction hash," << encode_hash(message->hash()) ;
        SEND2(announcement, handle_send, _1, announcement.command);
    }

    return true;
}

void protocol_transaction_out::handle_stop(const code&)
{
    log::trace(LOG_NETWORK)
        << "Stopped transaction_out protocol";
    pool_.fired();
}

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

#include <cstddef>
#include <functional>
#include <memory>
#include <metaverse/network.hpp>

namespace libbitcoin {
namespace node {

#define NAME "transaction"
#define CLASS protocol_transaction_out

using namespace bc::blockchain;
using namespace bc::message;
using namespace bc::network;
using namespace std::placeholders;

protocol_transaction_out::protocol_transaction_out(p2p& network,
    channel::ptr channel, block_chain& blockchain, transaction_pool& pool)
  : protocol_events(network, channel, NAME),
    blockchain_(blockchain),
    pool_(pool),

    // TODO: move fee filter to a derived class protocol_transaction_out_70013.
    minimum_fee_(0),

    // TODO: move relay to a derived class protocol_transaction_out_70001.
    relay_to_peer_(peer_version().relay),
    CONSTRUCT_TRACK(protocol_transaction_out)
{
}

protocol_transaction_out::ptr protocol_transaction_out::do_subscribe()
{
    SUBSCRIBE2(memory_pool, handle_receive_memory_pool, _1, _2);
    SUBSCRIBE2(fee_filter, handle_receive_fee_filter, _1, _2);
    SUBSCRIBE2(get_data, handle_receive_get_data, _1, _2);
    return std::dynamic_pointer_cast<protocol_transaction_out>(protocol::shared_from_this());
}

// TODO: move not_found to derived class protocol_transaction_out_70001.

// Start.
//-----------------------------------------------------------------------------

void protocol_transaction_out::start()
{
    protocol_events::start(BIND1(handle_stop, _1));
    // TODO: move relay to a derived class protocol_transaction_out_70001.
    // Prior to this level transaction relay is not configurable.
    if (relay_to_peer_)
    {
        // Subscribe to transaction pool notifications and relay txs.
        pool_.subscribe_transaction(BIND3(handle_floated, _1, _2, _3));
    }

    // TODO: move fee filter to a derived class protocol_transaction_out_70013.
    // Filter announcements by fee if set.

}

// Receive send_headers.
//-----------------------------------------------------------------------------

// TODO: move fee_filters to a derived class protocol_transaction_out_70013.
bool protocol_transaction_out::handle_receive_fee_filter(const code& ec,
    fee_filter_ptr message)
{
    if (stopped())
        return false;

    if (ec)
    {
        log::trace(LOG_NODE)
            << "Failure getting " << message->command << " from ["
            << authority() << "] " << ec.message();
        stop(ec);
        return false;
    }

    // TODO: move fee filter to a derived class protocol_transaction_out_70013.
    // Transaction annoucements will be filtered by fee amount.
    minimum_fee_.store(message->minimum_fee);

    // The fee filter may be adjusted.
    return true;
}

// Receive mempool sequence.
//-----------------------------------------------------------------------------

bool protocol_transaction_out::handle_receive_memory_pool(const code& ec,
    memory_pool_ptr)
{
    if (stopped()) {
        return false;
    }

    if (ec) {
        return false;
    }

    log::debug(LOG_NODE) << "protocol_transaction_out::handle_receive_memory_pool";
    auto self = shared_from_this();
    pool_.fetch([this, self](const code& ec, const std::vector<transaction_ptr>& txs){
        if (stopped() || ec) {
            log::debug(LOG_NODE) << "pool fetch transaction failed," << ec.message();
            return;
        }

        if (txs.empty()) {
            return;
        }
        std::vector<hash_digest> hashes;
        hashes.reserve(txs.size());
        for(auto& t:txs) {
            hashes.push_back(t->hash());
        }
        log::debug(LOG_NODE) << "memory pool size," << txs.size();
        send<protocol_transaction_out>(inventory{hashes, inventory::type_id::transaction}, &protocol_transaction_out::handle_send, _1, inventory::command);
    });
    return false;
}

// Receive get_data sequence.
//-----------------------------------------------------------------------------

bool protocol_transaction_out::handle_receive_get_data(const code& ec,
    get_data_ptr message)
{
    if (stopped())
        return false;

    if (ec)
    {
        log::trace(LOG_NODE)
            << "Failure getting inventory from [" << authority() << "] "
            << ec.message();
        stop(ec);
        return false;
    }

//    if (message->inventories.size() > 50000)
//    {
//        return ! misbehaving(20);
//    }

    // TODO: these must return message objects or be copied!
    // Ignore non-transaction inventory requests in this protocol.
    for (const auto& inv: message->inventories)
        if (inv.type == inventory::type_id::transaction)
        {
            auto pThis = shared_from_this();
            pool_.fetch(inv.hash, [this, &inv, pThis](const code& ec, transaction_ptr tx){
                auto t = tx ? *tx : chain::transaction{};
                send_transaction(ec, t, inv.hash);
                if(ec)
                {
                    blockchain_.fetch_transaction(inv.hash,
                    BIND3(send_transaction, _1, _2, inv.hash));
                }
            });
        }

    return true;
}

void protocol_transaction_out::send_transaction(const code& ec,
    const chain::transaction& transaction, const hash_digest& hash)
{
    if (stopped() || ec == (code)error::service_stopped)
        return;

    if (ec == (code)error::not_found)
    {
        log::trace(LOG_NODE)
            << "Transaction requested by [" << authority() << "] not found.";

        const not_found reply{ { inventory::type_id::transaction, hash } };
        SEND2(reply, handle_send, _1, reply.command);
        return;
    }

    if (ec)
    {
        log::error(LOG_NODE)
            << "Internal failure locating trnsaction requested by ["
            << authority() << "] " << ec.message();
        stop(ec);
        return;
    }

    log::trace(LOG_NODE) << "send transaction " << encode_hash(transaction.hash()) << ", to " << authority();

    // TODO: eliminate copy.
    SEND2(transaction_message(transaction), handle_send, _1,
        transaction_message::command);
}

// Subscription.
//-----------------------------------------------------------------------------

bool protocol_transaction_out::handle_floated(const code& ec,
    const index_list& unconfirmed, transaction_ptr message)
{
    if (stopped() || ec == (code)error::service_stopped)
        return false;

    if (ec == (code)error::mock)
    {
        return true;
    }

    if (ec)
    {
        log::error(LOG_NODE)
            << "Failure handling transaction float: " << ec.message();
        stop(ec);
        return false;
    }

    // TODO: move fee filter to a derived class protocol_transaction_out_70013.
    // TODO: implement fee computation.
    const uint64_t fee = 0;

    // Transactions are discovered and announced individually.
    if (message->originator() != nonce() && fee >= minimum_fee_.load())
    {
        static const auto id = inventory::type_id::transaction;
        const inventory announcement{ { id, message->hash() } };
        log::trace(LOG_NODE) << "handle floated send transaction hash," << encode_hash(message->hash()) ;
        SEND2(announcement, handle_send, _1, announcement.command);
    }

    return true;
}

void protocol_transaction_out::handle_stop(const code&)
{
    log::trace(LOG_NETWORK)
        << "Stopped transaction_out protocol";
    pool_.fired();
}

} // namespace node
} // namespace libbitcoin
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <string>
#include <regex>
#include <vector>
#include <list>
#include <stdexcept>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>

using namespace std;

// trim from start (in place)
static inline void ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(),
            std::not1(std::ptr_fun<int, int>(std::isspace))));
}

// trim from end (in place)
static inline void rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(),
            std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
}

// trim from both ends (in place)
static inline void trim(std::string &s) {
    ltrim(s);
    rtrim(s);
}

// trim from start (copying)
static inline std::string ltrimmed(std::string s) {
    ltrim(s);
    return s;
}

// trim from end (copying)
static inline std::string rtrimmed(std::string s) {
    rtrim(s);
    return s;
}

// trim from both ends (copying)
static inline std::string trimmed(std::string s) {
    trim(s);
    return s;
}

std::list<std::string> readFile(std::string fileName) {

  /* Function which takes a file name as a parameter and
   * read all its content line per line
   *
   * INPUT - filename , std::std::string
   * OUTPUT - list of filecontent, std::list<std::std::string>
   * throws File not found exception error when file is not present
   */

  std::list<std::string> myFileContent;
  std::ifstream myFile (fileName);

  if(!myFile) {
    cout<<"File hi nahi hai beta";
    throw "File does not exist!";
  }
  //myFile.exceptions (ifstream::failbit | ifstream::badbit );
  try {
    for(std::string line; std::getline( myFile, line ); ) {
      myFileContent.push_back(line);
      cout<<line<<endl;
    }
  }
  catch(std::exception const& e) {
    cout << "There was an error: " << e.what() << endl;
  }

  myFile.close();

  return myFileContent;

}

void writeFile(std::string filename, std::list<std::string> myFileContent) {

  std::ofstream myFile (filename);
  if(!myFile) {
    cout<<"File hi nahi hai beta";
    throw "File not found";
  }
  for( auto iterator = myFileContent.begin() ; iterator != myFileContent.end() ; ++iterator ) {
    myFile << *iterator << '\n' ;
  }
  std::cout<< "Hey, it's done'";
  myFile.close();

}

bool StringMatcher(std::string stringOne, std::string stringTwo) {

  cout<<stringOne<<endl;
  cout<<trimmed(stringOne);
  std::string regexString = "(\\s*)("+ trimmed(stringOne) + ")(\\s*)";
  std::regex e (regexString);
  std::cout<<"this - "<<regexString<<endl;
  //std::regex e (stringOne);
  if (regex_match(stringTwo, e)) {
    cout << " matches" << endl;
    return true;
  }

  else {
    cout << " doesn’t match" << endl;
    return false;
 }

}

std::list<std::string> deleteMatching(std::list<std::string> myList, std::list<std::string> myNewList) {

  std::list<std::string>::iterator it1,it2;
  for(it1=myList.begin(); it1!=myList.end(); ++it1) {
    for(it2=myNewList.begin(); it2!=myNewList.end(); ++it2) {
      if(StringMatcher(*it1, *it2)==true) {
        cout<<"Yeh gaya - " <<*it2<<endl;
        it2 = myNewList.erase(it2);
      }
    }
  }
  for(it1=myNewList.begin(); it1!=myNewList.end(); ++it1) {
    cout<<*it1<<endl;
  }
  cout<< "\nKhatam";
  return myNewList;
}

int main() {

  std::list<std::string> referenceList, targetList;
  std::string targetFileName = "files/patchinfo", referenceFileName = "files/reference";

  try {
    referenceList = readFile(referenceFileName);
    targetList = readFile(targetFileName);
    targetList = deleteMatching(referenceList, targetList);
    writeFile(targetFileName, targetList);
    cout<< StringMatcher("hi", "hi     ");
  }
  catch (std::exception const& errr) {
    std::cerr << errr.what()<<endl;

  }
  catch(const char *e) {
    std::cerr << e;

  }

}

<commit_msg>added comments and removed output statements<commit_after>#include <iostream>
#include <fstream>
#include <string>
#include <regex>
#include <vector>
#include <list>
#include <stdexcept>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>

using namespace std;

// trim from start (in place)
static inline void ltrim(std::string &s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(),
            std::not1(std::ptr_fun<int, int>(std::isspace))));
}

// trim from end (in place)
static inline void rtrim(std::string &s) {
    s.erase(std::find_if(s.rbegin(), s.rend(),
            std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
}

// trim from both ends (in place)
static inline void trim(std::string &s) {
    ltrim(s);
    rtrim(s);
}

// trim from start (copying)
static inline std::string ltrimmed(std::string s) {
    ltrim(s);
    return s;
}

// trim from end (copying)
static inline std::string rtrimmed(std::string s) {
    rtrim(s);
    return s;
}

// trim from both ends (copying)
static inline std::string trimmed(std::string s) {
    trim(s);
    return s;
}

std::list<std::string> readFile(std::string fileName) {

  /* Function which takes a file name as a parameter and
   * read all its content line per line
   *
   * INPUT - filename , std::std::string
   * OUTPUT - list of filecontent, std::list<std::std::string>
   * throws File not found exception error when file is not present
   */

  std::list<std::string> myFileContent;
  std::ifstream myFile (fileName);

  if(!myFile) {
    throw "File does not exist!";
  }
  //myFile.exceptions (ifstream::failbit | ifstream::badbit );
  try {
    for(std::string line; std::getline( myFile, line ); ) {
      myFileContent.push_back(line);
    }
  }
  catch(std::exception const& e) {
    cout << "There was an error: " << e.what() << endl;
  }

  myFile.close();

  return myFileContent;

}

void writeFile(std::string filename, std::list<std::string> myFileContent) {

    /* Function which takes a file name and FileContent as string list a parameter and
   * writes all its content element per element
   *
   * INPUT - filename , std::std::string
   * OUTPUT - list of filecontent, std::list<std::std::string>
   * throws File not found exception error when file is not present
   */

  std::ofstream myFile (filename);
  if(!myFile) {
    throw "File not found";
  }
  for( auto iterator = myFileContent.begin() ; iterator != myFileContent.end() ; ++iterator ) {
    myFile << *iterator << '\n' ;
  }
  myFile.close();

}

bool StringMatcher(std::string stringOne, std::string stringTwo) {

    /* Matches two strings by trimming the forward and trailing spaces
     * and returns true if matched else returns false
     */

  std::string regexString = "(\\s*)("+ trimmed(stringOne) + ")(\\s*)";
  std::regex e (regexString);
  //std::regex e (stringOne);
  if (regex_match(stringTwo, e)) {
    return true;
  else
    return false;

}

std::list<std::string> deleteMatching(std::list<std::string> myList, std::list<std::string> myNewList) {

  std::list<std::string>::iterator it1,it2;
  for(it1=myList.begin(); it1!=myList.end(); ++it1) {
    for(it2=myNewList.begin(); it2!=myNewList.end(); ++it2) {
      if(StringMatcher(*it1, *it2)==true) {
        cout<<"Yeh gaya - " <<*it2<<endl;
        it2 = myNewList.erase(it2);
      }
    }
  }
  return myNewList;
}

int main() {

  std::list<std::string> referenceList, targetList;
  std::string targetFileName = "files/patchinfo", referenceFileName = "files/reference";

  try {
    referenceList = readFile(referenceFileName);
    targetList = readFile(targetFileName);
    targetList = deleteMatching(referenceList, targetList);
    writeFile(targetFileName, targetList);
  }
  catch (std::exception const& errr) {
    std::cerr << errr.what()<<endl;

  }
  catch(const char *e) {
    std::cerr << e;

  }

}

<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/fluid/framework/executor.h"

#include <set>

#include "gflags/gflags.h"
#include "paddle/fluid/framework/feed_fetch_method.h"
#include "paddle/fluid/framework/feed_fetch_type.h"
#include "paddle/fluid/framework/lod_rank_table.h"
#include "paddle/fluid/framework/lod_tensor_array.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/reader.h"
#include "paddle/fluid/platform/place.h"
#include "paddle/fluid/platform/profiler.h"

DECLARE_bool(benchmark);
DEFINE_bool(check_nan_inf, false,
            "Checking whether operator produce NAN/INF or not. It will be "
            "extremely slow so please use this flag wisely.");

namespace paddle {
namespace framework {

Executor::Executor(const platform::Place& place) : place_(place) {}

static void CreateTensor(Variable* var, proto::VarDesc::VarType var_type) {
  if (var_type == proto::VarDesc::LOD_TENSOR) {
    var->GetMutable<LoDTensor>();
  } else if (var_type == proto::VarDesc::SELECTED_ROWS) {
    var->GetMutable<SelectedRows>();
  } else if (var_type == proto::VarDesc::FEED_MINIBATCH) {
    var->GetMutable<FeedFetchList>();
  } else if (var_type == proto::VarDesc::FETCH_LIST) {
    var->GetMutable<FeedFetchList>();
  } else if (var_type == proto::VarDesc::STEP_SCOPES) {
    var->GetMutable<std::vector<framework::Scope>>();
  } else if (var_type == proto::VarDesc::LOD_RANK_TABLE) {
    var->GetMutable<LoDRankTable>();
  } else if (var_type == proto::VarDesc::LOD_TENSOR_ARRAY) {
    var->GetMutable<LoDTensorArray>();
  } else if (var_type == proto::VarDesc::PLACE_LIST) {
    var->GetMutable<platform::PlaceList>();
  } else if (var_type == proto::VarDesc::READER) {
    var->GetMutable<ReaderHolder>();
  } else if (var_type == proto::VarDesc::NCCL_COM) {
    // GetMutable will be called in ncclInit
  } else {
    PADDLE_THROW(
        "Variable type %d is not in "
        "[LOD_TENSOR, SELECTED_ROWS, FEED_MINIBATCH, FETCH_LIST, "
        "LOD_RANK_TABLE, PLACE_LIST, READER, NCCL_COM]",
        var_type);
  }
}

static void CheckTensorNANOrInf(const std::string& name,
                                const framework::Tensor& tensor) {
  if (tensor.memory_size() == 0) {
    return;
  }
  if (tensor.type().hash_code() != typeid(float).hash_code() &&
      tensor.type().hash_code() != typeid(double).hash_code()) {
    return;
  }
  PADDLE_ENFORCE(!framework::HasInf(tensor), "Tensor %s has Inf", name);
  PADDLE_ENFORCE(!framework::HasNAN(tensor), "Tensor %s has NAN", name);
}

void Executor::Run(const ProgramDesc& pdesc, Scope* scope, int block_id,
                   bool create_local_scope, bool create_vars) {
  // TODO(tonyyang-svail):
  //    - only runs on the first device (i.e. no interdevice communication)
  //    - will change to use multiple blocks for RNN op and Cond Op
  PADDLE_ENFORCE_LT(static_cast<size_t>(block_id), pdesc.Size());
  auto& block = pdesc.Block(block_id);

  Scope* local_scope = scope;
  if (create_vars) {
    if (create_local_scope) {
      local_scope = &scope->NewScope();
      for (auto& var : block.AllVars()) {
        if (var->Name() == framework::kEmptyVarName) {
          continue;
        }

        if (var->Persistable()) {
          auto* ptr = scope->Var(var->Name());
          CreateTensor(ptr, var->GetType());
          VLOG(3) << "Create Variable " << var->Name()
                  << " global, which pointer is " << ptr;
        } else {
          auto* ptr = local_scope->Var(var->Name());
          CreateTensor(ptr, var->GetType());
          VLOG(3) << "Create Variable " << var->Name()
                  << " locally, which pointer is " << ptr;
        }
      }
    } else {
      for (auto& var : block.AllVars()) {
        auto* ptr = local_scope->Var(var->Name());
        CreateTensor(ptr, var->GetType());
        VLOG(3) << "Create variable " << var->Name() << ", which pointer is "
                << ptr;
      }
    }  // if (create_local_scope)
  }    // if (create_vars)

  for (auto& op_desc : block.AllOps()) {
    auto op = paddle::framework::OpRegistry::CreateOp(*op_desc);
    VLOG(3) << op->DebugStringEx(local_scope);

    platform::DeviceContextPool& pool = platform::DeviceContextPool::Instance();
    platform::RecordEvent record_event(op->Type(), pool.Get(place_));

    op->Run(*local_scope, place_);
    if (FLAGS_benchmark) {
      VLOG(2) << "Memory used after operator " + op->Type() + " running: "
              << memory::memory_usage(place_);
    }
    if (FLAGS_check_nan_inf) {
      for (auto& vname : op->OutputVars(true)) {
        auto* var = local_scope->FindVar(vname);
        if (var == nullptr) continue;
        if (var->IsType<framework::LoDTensor>()) {
          CheckTensorNANOrInf(vname, var->Get<framework::LoDTensor>());
        }
      }
    }
  }
  if (create_vars && create_local_scope) {
    scope->DeleteScope(local_scope);
  }
  if (FLAGS_benchmark) {
    VLOG(2) << "-------------------------------------------------------";
    VLOG(2) << "Memory used after deleting local scope: "
            << memory::memory_usage(place_);
    VLOG(2) << "-------------------------------------------------------";
  }
}

// Check whether the block already has feed operators and feed_holder.
// Return false if the block does not have any feed operators.
// If some feed operators have been prepended to the block, check that
// the info contained in these feed operators matches the feed_targets
// and feed_holder_name. Raise exception when any mismatch is found.
// Return true if the block has feed operators and holder of matching info.
static bool has_feed_operators(
    BlockDesc* block, std::map<std::string, const LoDTensor*>& feed_targets,
    const std::string& feed_holder_name) {
  size_t feed_count = 0;
  for (auto* op : block->AllOps()) {
    if (op->Type() == kFeedOpType) {
      feed_count++;
      PADDLE_ENFORCE_EQ(op->Input("X")[0], feed_holder_name,
                        "Input to feed op should be '%s'", feed_holder_name);
      std::string feed_target_name = op->Output("Out")[0];
      PADDLE_ENFORCE(
          feed_targets.find(feed_target_name) != feed_targets.end(),
          "Feed operator output name '%s' cannot be found in 'feed_targets'",
          feed_target_name);
    }
  }

  if (feed_count > 0) {
    PADDLE_ENFORCE_EQ(
        feed_count, feed_targets.size(),
        "The number of feed operators should match 'feed_targets'");

    // When feed operator are present, so should be feed_holder
    auto var = block->FindVar(feed_holder_name);
    PADDLE_ENFORCE_NOT_NULL(var, "Block should already have a '%s' variable",
                            feed_holder_name);
    PADDLE_ENFORCE_EQ(var->GetType(), proto::VarDesc::FEED_MINIBATCH,
                      "'%s' variable should be 'FEED_MINIBATCH' type",
                      feed_holder_name);
  }

  return feed_count > 0;
}

// Check whether the block already has fetch operators and fetch_holder.
// Return false if the block does not have any fetch operators.
// If some fetch operators have been appended to the block, check that
// the info contained in these fetch operators matches the fetch_targets
// and fetch_holder_name. Raise exception when any mismatch is found.
// Return true if the block has fetch operators and holder of matching info.
static bool has_fetch_operators(
    BlockDesc* block, std::map<std::string, LoDTensor*>& fetch_targets,
    const std::string& fetch_holder_name) {
  size_t fetch_count = 0;
  for (auto* op : block->AllOps()) {
    if (op->Type() == kFetchOpType) {
      fetch_count++;
      PADDLE_ENFORCE_EQ(op->Output("Out")[0], fetch_holder_name,
                        "Output of fetch op should be '%s'", fetch_holder_name);
      std::string fetch_target_name = op->Input("X")[0];
      PADDLE_ENFORCE(
          fetch_targets.find(fetch_target_name) != fetch_targets.end(),
          "Fetch operator input name '%s' cannot be found in 'fetch_targets'",
          fetch_target_name);
    }
  }

  if (fetch_count > 0) {
    PADDLE_ENFORCE_EQ(
        fetch_count, fetch_targets.size(),
        "The number of fetch operators should match 'fetch_targets'");

    // When fetch operator are present, so should be fetch_holder
    auto var = block->FindVar(fetch_holder_name);
    PADDLE_ENFORCE_NOT_NULL(var, "Block should already have a '%s' variable",
                            fetch_holder_name);
    PADDLE_ENFORCE_EQ(var->GetType(), proto::VarDesc::FETCH_LIST,
                      "'%s' variable should be 'FETCH_LIST' type",
                      fetch_holder_name);
  }

  return fetch_count > 0;
}

void Executor::Run(const ProgramDesc& program, Scope* scope,
                   std::map<std::string, const LoDTensor*>& feed_targets,
                   std::map<std::string, LoDTensor*>& fetch_targets,
                   const std::string& feed_holder_name,
                   const std::string& fetch_holder_name) {
  auto* copy_program = new ProgramDesc(program);
  auto* global_block = copy_program->MutableBlock(0);

  if (!has_feed_operators(global_block, feed_targets, feed_holder_name)) {
    // create feed_holder variable
    auto* feed_holder = global_block->Var(feed_holder_name);
    feed_holder->SetType(proto::VarDesc::FEED_MINIBATCH);
    feed_holder->SetPersistable(true);

    int i = 0;
    for (auto& feed_target : feed_targets) {
      std::string var_name = feed_target.first;
      VLOG(3) << "feed target's name: " << var_name;

      // prepend feed op
      auto* op = global_block->PrependOp();
      op->SetType(kFeedOpType);
      op->SetInput("X", {feed_holder_name});
      op->SetOutput("Out", {var_name});
      op->SetAttr("col", {static_cast<int>(i)});
      op->CheckAttrs();

      i++;
    }
  }

  // map the data of feed_targets to feed_holder
  for (auto* op : global_block->AllOps()) {
    if (op->Type() == kFeedOpType) {
      std::string feed_target_name = op->Output("Out")[0];
      int idx = boost::get<int>(op->GetAttr("col"));
      SetFeedVariable(scope, *feed_targets[feed_target_name], feed_holder_name,
                      idx);
    }
  }

  if (!has_fetch_operators(global_block, fetch_targets, fetch_holder_name)) {
    // create fetch_holder variable
    auto* fetch_holder = global_block->Var(fetch_holder_name);
    fetch_holder->SetType(proto::VarDesc::FETCH_LIST);
    fetch_holder->SetPersistable(true);

    int i = 0;
    for (auto& fetch_target : fetch_targets) {
      std::string var_name = fetch_target.first;
      VLOG(3) << "fetch target's name: " << var_name;

      // append fetch op
      auto* op = global_block->AppendOp();
      op->SetType(kFetchOpType);
      op->SetInput("X", {var_name});
      op->SetOutput("Out", {fetch_holder_name});
      op->SetAttr("col", {static_cast<int>(i)});
      op->CheckAttrs();

      i++;
    }
  }

  Run(*copy_program, scope, 0, true, true);

  // obtain the data of fetch_targets from fetch_holder
  for (auto* op : global_block->AllOps()) {
    if (op->Type() == kFetchOpType) {
      std::string fetch_target_name = op->Input("X")[0];
      int idx = boost::get<int>(op->GetAttr("col"));
      *fetch_targets[fetch_target_name] =
          GetFetchVariable(*scope, fetch_holder_name, idx);
    }
  }

  delete copy_program;
}

}  // namespace framework
}  // namespace paddle
<commit_msg>diable debug string due to vector bug<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/fluid/framework/executor.h"

#include <set>

#include "gflags/gflags.h"
#include "paddle/fluid/framework/feed_fetch_method.h"
#include "paddle/fluid/framework/feed_fetch_type.h"
#include "paddle/fluid/framework/lod_rank_table.h"
#include "paddle/fluid/framework/lod_tensor_array.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/reader.h"
#include "paddle/fluid/platform/place.h"
#include "paddle/fluid/platform/profiler.h"

DECLARE_bool(benchmark);
DEFINE_bool(check_nan_inf, false,
            "Checking whether operator produce NAN/INF or not. It will be "
            "extremely slow so please use this flag wisely.");

namespace paddle {
namespace framework {

Executor::Executor(const platform::Place& place) : place_(place) {}

static void CreateTensor(Variable* var, proto::VarDesc::VarType var_type) {
  if (var_type == proto::VarDesc::LOD_TENSOR) {
    var->GetMutable<LoDTensor>();
  } else if (var_type == proto::VarDesc::SELECTED_ROWS) {
    var->GetMutable<SelectedRows>();
  } else if (var_type == proto::VarDesc::FEED_MINIBATCH) {
    var->GetMutable<FeedFetchList>();
  } else if (var_type == proto::VarDesc::FETCH_LIST) {
    var->GetMutable<FeedFetchList>();
  } else if (var_type == proto::VarDesc::STEP_SCOPES) {
    var->GetMutable<std::vector<framework::Scope>>();
  } else if (var_type == proto::VarDesc::LOD_RANK_TABLE) {
    var->GetMutable<LoDRankTable>();
  } else if (var_type == proto::VarDesc::LOD_TENSOR_ARRAY) {
    var->GetMutable<LoDTensorArray>();
  } else if (var_type == proto::VarDesc::PLACE_LIST) {
    var->GetMutable<platform::PlaceList>();
  } else if (var_type == proto::VarDesc::READER) {
    var->GetMutable<ReaderHolder>();
  } else if (var_type == proto::VarDesc::NCCL_COM) {
    // GetMutable will be called in ncclInit
  } else {
    PADDLE_THROW(
        "Variable type %d is not in "
        "[LOD_TENSOR, SELECTED_ROWS, FEED_MINIBATCH, FETCH_LIST, "
        "LOD_RANK_TABLE, PLACE_LIST, READER, NCCL_COM]",
        var_type);
  }
}

static void CheckTensorNANOrInf(const std::string& name,
                                const framework::Tensor& tensor) {
  if (tensor.memory_size() == 0) {
    return;
  }
  if (tensor.type().hash_code() != typeid(float).hash_code() &&
      tensor.type().hash_code() != typeid(double).hash_code()) {
    return;
  }
  PADDLE_ENFORCE(!framework::HasInf(tensor), "Tensor %s has Inf", name);
  PADDLE_ENFORCE(!framework::HasNAN(tensor), "Tensor %s has NAN", name);
}

void Executor::Run(const ProgramDesc& pdesc, Scope* scope, int block_id,
                   bool create_local_scope, bool create_vars) {
  // TODO(tonyyang-svail):
  //    - only runs on the first device (i.e. no interdevice communication)
  //    - will change to use multiple blocks for RNN op and Cond Op
  PADDLE_ENFORCE_LT(static_cast<size_t>(block_id), pdesc.Size());
  auto& block = pdesc.Block(block_id);

  Scope* local_scope = scope;
  if (create_vars) {
    if (create_local_scope) {
      local_scope = &scope->NewScope();
      for (auto& var : block.AllVars()) {
        if (var->Name() == framework::kEmptyVarName) {
          continue;
        }

        if (var->Persistable()) {
          auto* ptr = scope->Var(var->Name());
          CreateTensor(ptr, var->GetType());
          VLOG(3) << "Create Variable " << var->Name()
                  << " global, which pointer is " << ptr;
        } else {
          auto* ptr = local_scope->Var(var->Name());
          CreateTensor(ptr, var->GetType());
          VLOG(3) << "Create Variable " << var->Name()
                  << " locally, which pointer is " << ptr;
        }
      }
    } else {
      for (auto& var : block.AllVars()) {
        auto* ptr = local_scope->Var(var->Name());
        CreateTensor(ptr, var->GetType());
        VLOG(3) << "Create variable " << var->Name() << ", which pointer is "
                << ptr;
      }
    }  // if (create_local_scope)
  }    // if (create_vars)

  for (auto& op_desc : block.AllOps()) {
    auto op = paddle::framework::OpRegistry::CreateOp(*op_desc);
    //    VLOG(3) << op->DebugStringEx(local_scope);

    platform::DeviceContextPool& pool = platform::DeviceContextPool::Instance();
    platform::RecordEvent record_event(op->Type(), pool.Get(place_));

    VLOG(3) << op->Type();
    op->Run(*local_scope, place_);
    if (FLAGS_benchmark) {
      VLOG(2) << "Memory used after operator " + op->Type() + " running: "
              << memory::memory_usage(place_);
    }
    if (FLAGS_check_nan_inf) {
      for (auto& vname : op->OutputVars(true)) {
        auto* var = local_scope->FindVar(vname);
        if (var == nullptr) continue;
        if (var->IsType<framework::LoDTensor>()) {
          CheckTensorNANOrInf(vname, var->Get<framework::LoDTensor>());
        }
      }
    }
  }
  if (create_vars && create_local_scope) {
    scope->DeleteScope(local_scope);
  }
  if (FLAGS_benchmark) {
    VLOG(2) << "-------------------------------------------------------";
    VLOG(2) << "Memory used after deleting local scope: "
            << memory::memory_usage(place_);
    VLOG(2) << "-------------------------------------------------------";
  }
}

// Check whether the block already has feed operators and feed_holder.
// Return false if the block does not have any feed operators.
// If some feed operators have been prepended to the block, check that
// the info contained in these feed operators matches the feed_targets
// and feed_holder_name. Raise exception when any mismatch is found.
// Return true if the block has feed operators and holder of matching info.
static bool has_feed_operators(
    BlockDesc* block, std::map<std::string, const LoDTensor*>& feed_targets,
    const std::string& feed_holder_name) {
  size_t feed_count = 0;
  for (auto* op : block->AllOps()) {
    if (op->Type() == kFeedOpType) {
      feed_count++;
      PADDLE_ENFORCE_EQ(op->Input("X")[0], feed_holder_name,
                        "Input to feed op should be '%s'", feed_holder_name);
      std::string feed_target_name = op->Output("Out")[0];
      PADDLE_ENFORCE(
          feed_targets.find(feed_target_name) != feed_targets.end(),
          "Feed operator output name '%s' cannot be found in 'feed_targets'",
          feed_target_name);
    }
  }

  if (feed_count > 0) {
    PADDLE_ENFORCE_EQ(
        feed_count, feed_targets.size(),
        "The number of feed operators should match 'feed_targets'");

    // When feed operator are present, so should be feed_holder
    auto var = block->FindVar(feed_holder_name);
    PADDLE_ENFORCE_NOT_NULL(var, "Block should already have a '%s' variable",
                            feed_holder_name);
    PADDLE_ENFORCE_EQ(var->GetType(), proto::VarDesc::FEED_MINIBATCH,
                      "'%s' variable should be 'FEED_MINIBATCH' type",
                      feed_holder_name);
  }

  return feed_count > 0;
}

// Check whether the block already has fetch operators and fetch_holder.
// Return false if the block does not have any fetch operators.
// If some fetch operators have been appended to the block, check that
// the info contained in these fetch operators matches the fetch_targets
// and fetch_holder_name. Raise exception when any mismatch is found.
// Return true if the block has fetch operators and holder of matching info.
static bool has_fetch_operators(
    BlockDesc* block, std::map<std::string, LoDTensor*>& fetch_targets,
    const std::string& fetch_holder_name) {
  size_t fetch_count = 0;
  for (auto* op : block->AllOps()) {
    if (op->Type() == kFetchOpType) {
      fetch_count++;
      PADDLE_ENFORCE_EQ(op->Output("Out")[0], fetch_holder_name,
                        "Output of fetch op should be '%s'", fetch_holder_name);
      std::string fetch_target_name = op->Input("X")[0];
      PADDLE_ENFORCE(
          fetch_targets.find(fetch_target_name) != fetch_targets.end(),
          "Fetch operator input name '%s' cannot be found in 'fetch_targets'",
          fetch_target_name);
    }
  }

  if (fetch_count > 0) {
    PADDLE_ENFORCE_EQ(
        fetch_count, fetch_targets.size(),
        "The number of fetch operators should match 'fetch_targets'");

    // When fetch operator are present, so should be fetch_holder
    auto var = block->FindVar(fetch_holder_name);
    PADDLE_ENFORCE_NOT_NULL(var, "Block should already have a '%s' variable",
                            fetch_holder_name);
    PADDLE_ENFORCE_EQ(var->GetType(), proto::VarDesc::FETCH_LIST,
                      "'%s' variable should be 'FETCH_LIST' type",
                      fetch_holder_name);
  }

  return fetch_count > 0;
}

void Executor::Run(const ProgramDesc& program, Scope* scope,
                   std::map<std::string, const LoDTensor*>& feed_targets,
                   std::map<std::string, LoDTensor*>& fetch_targets,
                   const std::string& feed_holder_name,
                   const std::string& fetch_holder_name) {
  auto* copy_program = new ProgramDesc(program);
  auto* global_block = copy_program->MutableBlock(0);

  if (!has_feed_operators(global_block, feed_targets, feed_holder_name)) {
    // create feed_holder variable
    auto* feed_holder = global_block->Var(feed_holder_name);
    feed_holder->SetType(proto::VarDesc::FEED_MINIBATCH);
    feed_holder->SetPersistable(true);

    int i = 0;
    for (auto& feed_target : feed_targets) {
      std::string var_name = feed_target.first;
      VLOG(3) << "feed target's name: " << var_name;

      // prepend feed op
      auto* op = global_block->PrependOp();
      op->SetType(kFeedOpType);
      op->SetInput("X", {feed_holder_name});
      op->SetOutput("Out", {var_name});
      op->SetAttr("col", {static_cast<int>(i)});
      op->CheckAttrs();

      i++;
    }
  }

  // map the data of feed_targets to feed_holder
  for (auto* op : global_block->AllOps()) {
    if (op->Type() == kFeedOpType) {
      std::string feed_target_name = op->Output("Out")[0];
      int idx = boost::get<int>(op->GetAttr("col"));
      SetFeedVariable(scope, *feed_targets[feed_target_name], feed_holder_name,
                      idx);
    }
  }

  if (!has_fetch_operators(global_block, fetch_targets, fetch_holder_name)) {
    // create fetch_holder variable
    auto* fetch_holder = global_block->Var(fetch_holder_name);
    fetch_holder->SetType(proto::VarDesc::FETCH_LIST);
    fetch_holder->SetPersistable(true);

    int i = 0;
    for (auto& fetch_target : fetch_targets) {
      std::string var_name = fetch_target.first;
      VLOG(3) << "fetch target's name: " << var_name;

      // append fetch op
      auto* op = global_block->AppendOp();
      op->SetType(kFetchOpType);
      op->SetInput("X", {var_name});
      op->SetOutput("Out", {fetch_holder_name});
      op->SetAttr("col", {static_cast<int>(i)});
      op->CheckAttrs();

      i++;
    }
  }

  Run(*copy_program, scope, 0, true, true);

  // obtain the data of fetch_targets from fetch_holder
  for (auto* op : global_block->AllOps()) {
    if (op->Type() == kFetchOpType) {
      std::string fetch_target_name = op->Input("X")[0];
      int idx = boost::get<int>(op->GetAttr("col"));
      *fetch_targets[fetch_target_name] =
          GetFetchVariable(*scope, fetch_holder_name, idx);
    }
  }

  delete copy_program;
}

}  // namespace framework
}  // namespace paddle
<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "test.hpp"
#include "setup_transfer.hpp"
#include "dht_server.hpp"
#include "peer_server.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/alert_types.hpp"

#include <fstream>

using namespace libtorrent;

char const* proxy_name[] = {
	"none",
	"socks4",
	"socks5",
	"socks5_pw",
	"http",
	"http_pw",
	"i2p_proxy"
};

std::vector<std::string> rejected_trackers;

bool alert_predicate(libtorrent::alert* a)
{
	anonymous_mode_alert* am = alert_cast<anonymous_mode_alert>(a);
	if (am == NULL) return false;

	if (am->kind == anonymous_mode_alert::tracker_not_anonymous)
		rejected_trackers.push_back(am->str);

	return false;
}

enum flags_t
{
	anonymous_mode = 1,
	expect_http_connection = 2,
	expect_udp_connection = 4,
	expect_http_reject = 8,
	expect_udp_reject = 16,
	expect_dht_msg = 32,
	expect_peer_connection = 64,
};

void test_proxy(proxy_settings::proxy_type proxy_type, int flags)
{
#ifdef TORRENT_DISABLE_DHT
	// if DHT is disabled, we won't get any requests to it
	flags &= ~expect_dht_msg;
#endif
	fprintf(stderr, "\n=== TEST == proxy: %s anonymous-mode: %s\n\n", proxy_name[proxy_type], (flags & anonymous_mode) ? "yes" : "no");
	int http_port = start_web_server();
	int udp_port = start_tracker();
	int dht_port = start_dht();
	int peer_port = start_peer();

	int prev_udp_announces = g_udp_tracker_requests;
	int prev_http_announces = g_http_tracker_requests;

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	session* s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	sett.stop_tracker_timeout = 1;
	sett.tracker_completion_timeout = 1;
	sett.tracker_receive_timeout = 1;
	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	sett.anonymous_mode = flags & anonymous_mode;
	sett.force_proxy = flags & anonymous_mode;

	// if we don't do this, the peer connection test
	// will be delayed by several seconds, by first
	// trying uTP
	sett.enable_outgoing_utp = false;
	s->set_settings(sett);

	proxy_settings ps;
	ps.hostname = "non-existing.com";
	ps.port = 4444;
	ps.type = proxy_type;
	s->set_proxy(ps);

	s->start_dht();

	error_code ec;
	create_directory("tmp1_privacy", ec);
	std::ofstream file(combine_path("tmp1_privacy", "temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char http_tracker_url[200];
	snprintf(http_tracker_url, sizeof(http_tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(http_tracker_url, 0);

	char udp_tracker_url[200];
	snprintf(udp_tracker_url, sizeof(udp_tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(udp_tracker_url, 1);

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;
	addp.ti = t;
	addp.save_path = "tmp1_privacy";
	addp.dht_nodes.push_back(std::pair<std::string, int>("127.0.0.1", dht_port));
	torrent_handle h = s->add_torrent(addp);

	printf("connect_peer: 127.0.0.1:%d\n", peer_port);
	h.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), peer_port));

	rejected_trackers.clear();
	for (int i = 0; i < 15; ++i)
	{
		print_alerts(*s, "s", false, false, false, &alert_predicate);
		test_sleep(100);

		if (g_udp_tracker_requests >= prev_udp_announces + 1
			&& g_http_tracker_requests >= prev_http_announces + 1
			&& num_peer_hits() > 0)
			break;
	}

	// we should have announced to the tracker by now
	TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + bool(flags & expect_udp_connection));
	TEST_EQUAL(g_http_tracker_requests, prev_http_announces + bool(flags & expect_http_connection));
	if (flags & expect_dht_msg)
	{
		TEST_CHECK(num_dht_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_dht_hits(), 0);
	}

	if (flags & expect_peer_connection)
	{
		TEST_CHECK(num_peer_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_peer_hits(), 0);
	}

	if (flags & expect_udp_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), udp_tracker_url) != rejected_trackers.end());

	if (flags & expect_http_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), http_tracker_url) != rejected_trackers.end());

	fprintf(stderr, "%s: ~session\n", time_now_string());
	delete s;
	fprintf(stderr, "%s: ~session done\n", time_now_string());

	stop_peer();
	stop_dht();
	stop_tracker();
	stop_web_server();
}

int test_main()
{
	// not using anonymous mode
	// UDP fails open if we can't connect to the proxy
	// or if the proxy doesn't support UDP
	test_proxy(proxy_settings::none, expect_udp_connection | expect_http_connection | expect_dht_msg | expect_peer_connection);
	test_proxy(proxy_settings::socks4, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::socks5, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::socks5_pw, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::http, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::http_pw, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::i2p_proxy, expect_udp_connection | expect_dht_msg);

	// using anonymous mode

	// anonymous mode doesn't require a proxy when one isn't configured. It could be
	// used with a VPN for instance. This will all changed in 1.0, where anonymous
	// mode is separated from force_proxy
	test_proxy(proxy_settings::none, anonymous_mode | expect_peer_connection);
	test_proxy(proxy_settings::socks4, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::socks5, anonymous_mode);
	test_proxy(proxy_settings::socks5_pw, anonymous_mode);
	test_proxy(proxy_settings::http, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::http_pw, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::i2p_proxy, anonymous_mode);
	return 0;
}

<commit_msg>increase tracker timeouts for test_privacy<commit_after>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "test.hpp"
#include "setup_transfer.hpp"
#include "dht_server.hpp"
#include "peer_server.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/alert_types.hpp"

#include <fstream>

using namespace libtorrent;

char const* proxy_name[] = {
	"none",
	"socks4",
	"socks5",
	"socks5_pw",
	"http",
	"http_pw",
	"i2p_proxy"
};

std::vector<std::string> rejected_trackers;

bool alert_predicate(libtorrent::alert* a)
{
	anonymous_mode_alert* am = alert_cast<anonymous_mode_alert>(a);
	if (am == NULL) return false;

	if (am->kind == anonymous_mode_alert::tracker_not_anonymous)
		rejected_trackers.push_back(am->str);

	return false;
}

enum flags_t
{
	anonymous_mode = 1,
	expect_http_connection = 2,
	expect_udp_connection = 4,
	expect_http_reject = 8,
	expect_udp_reject = 16,
	expect_dht_msg = 32,
	expect_peer_connection = 64,
};

void test_proxy(proxy_settings::proxy_type proxy_type, int flags)
{
#ifdef TORRENT_DISABLE_DHT
	// if DHT is disabled, we won't get any requests to it
	flags &= ~expect_dht_msg;
#endif
	fprintf(stderr, "\n=== TEST == proxy: %s anonymous-mode: %s\n\n", proxy_name[proxy_type], (flags & anonymous_mode) ? "yes" : "no");
	int http_port = start_web_server();
	int udp_port = start_tracker();
	int dht_port = start_dht();
	int peer_port = start_peer();

	int prev_udp_announces = g_udp_tracker_requests;
	int prev_http_announces = g_http_tracker_requests;

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	session* s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	sett.stop_tracker_timeout = 2;
	sett.tracker_completion_timeout = 2;
	sett.tracker_receive_timeout = 2;
	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	sett.anonymous_mode = flags & anonymous_mode;
	sett.force_proxy = flags & anonymous_mode;

	// if we don't do this, the peer connection test
	// will be delayed by several seconds, by first
	// trying uTP
	sett.enable_outgoing_utp = false;
	s->set_settings(sett);

	proxy_settings ps;
	ps.hostname = "non-existing.com";
	ps.port = 4444;
	ps.type = proxy_type;
	s->set_proxy(ps);

	s->start_dht();

	error_code ec;
	create_directory("tmp1_privacy", ec);
	std::ofstream file(combine_path("tmp1_privacy", "temporary").c_str());
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char http_tracker_url[200];
	snprintf(http_tracker_url, sizeof(http_tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(http_tracker_url, 0);

	char udp_tracker_url[200];
	snprintf(udp_tracker_url, sizeof(udp_tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(udp_tracker_url, 1);

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;
	addp.ti = t;
	addp.save_path = "tmp1_privacy";
	addp.dht_nodes.push_back(std::pair<std::string, int>("127.0.0.1", dht_port));
	torrent_handle h = s->add_torrent(addp);

	printf("connect_peer: 127.0.0.1:%d\n", peer_port);
	h.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), peer_port));

	rejected_trackers.clear();
	for (int i = 0; i < 15; ++i)
	{
		print_alerts(*s, "s", false, false, false, &alert_predicate);
		test_sleep(100);

		if (g_udp_tracker_requests >= prev_udp_announces + 1
			&& g_http_tracker_requests >= prev_http_announces + 1
			&& num_peer_hits() > 0)
			break;
	}

	// we should have announced to the tracker by now
	TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + bool(flags & expect_udp_connection));
	TEST_EQUAL(g_http_tracker_requests, prev_http_announces + bool(flags & expect_http_connection));
	if (flags & expect_dht_msg)
	{
		TEST_CHECK(num_dht_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_dht_hits(), 0);
	}

	if (flags & expect_peer_connection)
	{
		TEST_CHECK(num_peer_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_peer_hits(), 0);
	}

	if (flags & expect_udp_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), udp_tracker_url) != rejected_trackers.end());

	if (flags & expect_http_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), http_tracker_url) != rejected_trackers.end());

	fprintf(stderr, "%s: ~session\n", time_now_string());
	delete s;
	fprintf(stderr, "%s: ~session done\n", time_now_string());

	stop_peer();
	stop_dht();
	stop_tracker();
	stop_web_server();
}

int test_main()
{
	// not using anonymous mode
	// UDP fails open if we can't connect to the proxy
	// or if the proxy doesn't support UDP
	test_proxy(proxy_settings::none, expect_udp_connection | expect_http_connection | expect_dht_msg | expect_peer_connection);
	test_proxy(proxy_settings::socks4, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::socks5, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::socks5_pw, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::http, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::http_pw, expect_udp_connection | expect_dht_msg);
	test_proxy(proxy_settings::i2p_proxy, expect_udp_connection | expect_dht_msg);

	// using anonymous mode

	// anonymous mode doesn't require a proxy when one isn't configured. It could be
	// used with a VPN for instance. This will all changed in 1.0, where anonymous
	// mode is separated from force_proxy
	test_proxy(proxy_settings::none, anonymous_mode | expect_peer_connection);
	test_proxy(proxy_settings::socks4, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::socks5, anonymous_mode);
	test_proxy(proxy_settings::socks5_pw, anonymous_mode);
	test_proxy(proxy_settings::http, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::http_pw, anonymous_mode | expect_udp_reject);
	test_proxy(proxy_settings::i2p_proxy, anonymous_mode);
	return 0;
}

<|endoftext|>


<commit_before>#include <sstream>

#include "Module/Decoder/BCH/Standard/Decoder_BCH_std.hpp"
#include "Module/Decoder/BCH/Genius/Decoder_BCH_genius.hpp"

#include "Tools/Exception/exception.hpp"

#include "Decoder_BCH.hpp"

using namespace aff3ct;
using namespace aff3ct::factory;

const std::string aff3ct::factory::Decoder_BCH_name   = "Decoder BCH";
const std::string aff3ct::factory::Decoder_BCH_prefix = "dec";

Decoder_BCH::parameters
::parameters(const std::string &prefix)
: Decoder::parameters(Decoder_BCH_name, prefix)
{
	this->type   = "ALGEBRAIC";
	this->implem = "STD";
}

Decoder_BCH::parameters
::~parameters()
{
}

Decoder_BCH::parameters* Decoder_BCH::parameters
::clone() const
{
	return new Decoder_BCH::parameters(*this);
}

void Decoder_BCH::parameters
::get_description(tools::Argument_map_info &args) const
{
	Decoder::parameters::get_description(args);

	auto p = this->get_prefix();

	args.add(
		{p+"-corr-pow", "T"},
		tools::Integer(tools::Positive(), tools::Non_zero()),
		"correction power of the BCH code.");

	args.add_link({p+"-corr-pow", "T"}, {p+"-info-bits", "K"});

	tools::add_options(args.at({p+"-type", "D"}), 0, "ALGEBRAIC");
	tools::add_options(args.at({p+"-implem"   }), 0, "GENIUS");
}

void Decoder_BCH::parameters
::store(const tools::Argument_map_value &vals)
{
	Decoder::parameters::store(vals);

	auto p = this->get_prefix();

	this->m = (int)std::ceil(std::log2(this->N_cw));
	if (this->m == 0)
	{
		std::stringstream message;
		message << "The Gallois Field order is null (because N_cw = " << this->N_cw << ").";
		throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
	}

	if (vals.exist({p+"-corr-pow", "T"}))
	{
		this->t = vals.to_int({p + "-corr-pow", "T"});
		if (K == 0)
		{
			this->K = this->N_cw - tools::BCH_polynomial_generator(this->N_cw, this->t).get_n_rdncy();
			this->R = (float) this->K / (float) this->N_cw;
		}
	}
	else
		this->t = (this->N_cw - this->K) / this->m;
}

void Decoder_BCH::parameters
::get_headers(std::map<std::string,header_list>& headers, const bool full) const
{
	Decoder::parameters::get_headers(headers, full);

	if (this->type != "ML" && this->type != "CHASE")
	{
		auto p = this->get_prefix();

		headers[p].push_back(std::make_pair("Galois field order (m)", std::to_string(this->m)));
		headers[p].push_back(std::make_pair("Correction power (T)",   std::to_string(this->t)));
	}
}

template <typename B, typename Q>
module::Decoder_SIHO<B,Q>* Decoder_BCH::parameters
::build(const tools::BCH_polynomial_generator &GF, module::Encoder<B> *encoder) const
{
	try
	{
		return Decoder::parameters::build<B,Q>(encoder);
	}
	catch (tools::cannot_allocate const&)
	{
		return build_hiho<B,Q>(GF, encoder);
	}
}

template <typename B, typename Q>
module::Decoder_SIHO<B,Q>* Decoder_BCH
::build(const parameters &params, const tools::BCH_polynomial_generator &GF, module::Encoder<B> *encoder)
{
	return params.template build<B,Q>(GF, encoder);
}

template <typename B, typename Q>
module::Decoder_SIHO_HIHO<B,Q>* Decoder_BCH::parameters
::build_hiho(const tools::BCH_polynomial_generator &GF, module::Encoder<B> *encoder) const
{
	if (this->type == "ALGEBRAIC")
	{
		if (this->implem == "STD") return new module::Decoder_BCH_std<B,Q>(this->K, this->N_cw, GF, this->n_frames);

		if (encoder)
		{
			if (this->implem == "GENIUS") return new module::Decoder_BCH_genius<B,Q>(this->K, this->N_cw, this->t, *encoder, this->n_frames);
		}
	}

	throw tools::cannot_allocate(__FILE__, __LINE__, __func__);
}

template <typename B, typename Q>
module::Decoder_SIHO_HIHO<B,Q>* Decoder_BCH
::build_hiho(const parameters &params, const tools::BCH_polynomial_generator &GF, module::Encoder<B> *encoder)
{
	return params.template build_hiho<B,Q>(GF, encoder);
}

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template aff3ct::module::Decoder_SIHO<B_8 ,Q_8 >* aff3ct::factory::Decoder_BCH::parameters::build<B_8 ,Q_8 >(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_8 >*) const;
template aff3ct::module::Decoder_SIHO<B_16,Q_16>* aff3ct::factory::Decoder_BCH::parameters::build<B_16,Q_16>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_16>*) const;
template aff3ct::module::Decoder_SIHO<B_32,Q_32>* aff3ct::factory::Decoder_BCH::parameters::build<B_32,Q_32>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_32>*) const;
template aff3ct::module::Decoder_SIHO<B_64,Q_64>* aff3ct::factory::Decoder_BCH::parameters::build<B_64,Q_64>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_64>*) const;
template aff3ct::module::Decoder_SIHO<B_8 ,Q_8 >* aff3ct::factory::Decoder_BCH::build<B_8 ,Q_8 >(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_8 >*);
template aff3ct::module::Decoder_SIHO<B_16,Q_16>* aff3ct::factory::Decoder_BCH::build<B_16,Q_16>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_16>*);
template aff3ct::module::Decoder_SIHO<B_32,Q_32>* aff3ct::factory::Decoder_BCH::build<B_32,Q_32>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_32>*);
template aff3ct::module::Decoder_SIHO<B_64,Q_64>* aff3ct::factory::Decoder_BCH::build<B_64,Q_64>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_64>*);
#else
template aff3ct::module::Decoder_SIHO<B,Q>* aff3ct::factory::Decoder_BCH::parameters::build<B,Q>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B>*) const;
template aff3ct::module::Decoder_SIHO<B,Q>* aff3ct::factory::Decoder_BCH::build<B,Q>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B>*);
#endif
// ==================================================================================== explicit template instantiation

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template aff3ct::module::Decoder_SIHO_HIHO<B_8 ,Q_8 >* aff3ct::factory::Decoder_BCH::parameters::build_hiho<B_8 ,Q_8 >(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_8 >*) const;
template aff3ct::module::Decoder_SIHO_HIHO<B_16,Q_16>* aff3ct::factory::Decoder_BCH::parameters::build_hiho<B_16,Q_16>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_16>*) const;
template aff3ct::module::Decoder_SIHO_HIHO<B_32,Q_32>* aff3ct::factory::Decoder_BCH::parameters::build_hiho<B_32,Q_32>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_32>*) const;
template aff3ct::module::Decoder_SIHO_HIHO<B_64,Q_64>* aff3ct::factory::Decoder_BCH::parameters::build_hiho<B_64,Q_64>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_64>*) const;
template aff3ct::module::Decoder_SIHO_HIHO<B_8 ,Q_8 >* aff3ct::factory::Decoder_BCH::build_hiho<B_8 ,Q_8 >(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_8 >*);
template aff3ct::module::Decoder_SIHO_HIHO<B_16,Q_16>* aff3ct::factory::Decoder_BCH::build_hiho<B_16,Q_16>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_16>*);
template aff3ct::module::Decoder_SIHO_HIHO<B_32,Q_32>* aff3ct::factory::Decoder_BCH::build_hiho<B_32,Q_32>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_32>*);
template aff3ct::module::Decoder_SIHO_HIHO<B_64,Q_64>* aff3ct::factory::Decoder_BCH::build_hiho<B_64,Q_64>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_64>*);
#else
template aff3ct::module::Decoder_SIHO_HIHO<B,Q>* aff3ct::factory::Decoder_BCH::parameters::build_hiho<B>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B>*) const;
template aff3ct::module::Decoder_SIHO_HIHO<B,Q>* aff3ct::factory::Decoder_BCH::build_hiho<B>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B>*);
#endif
// ==================================================================================== explicit template instantiation

<commit_msg> Spelling correction<commit_after>#include <sstream>

#include "Module/Decoder/BCH/Standard/Decoder_BCH_std.hpp"
#include "Module/Decoder/BCH/Genius/Decoder_BCH_genius.hpp"

#include "Tools/Exception/exception.hpp"

#include "Decoder_BCH.hpp"

using namespace aff3ct;
using namespace aff3ct::factory;

const std::string aff3ct::factory::Decoder_BCH_name   = "Decoder BCH";
const std::string aff3ct::factory::Decoder_BCH_prefix = "dec";

Decoder_BCH::parameters
::parameters(const std::string &prefix)
: Decoder::parameters(Decoder_BCH_name, prefix)
{
	this->type   = "ALGEBRAIC";
	this->implem = "STD";
}

Decoder_BCH::parameters
::~parameters()
{
}

Decoder_BCH::parameters* Decoder_BCH::parameters
::clone() const
{
	return new Decoder_BCH::parameters(*this);
}

void Decoder_BCH::parameters
::get_description(tools::Argument_map_info &args) const
{
	Decoder::parameters::get_description(args);

	auto p = this->get_prefix();

	args.add(
		{p+"-corr-pow", "T"},
		tools::Integer(tools::Positive(), tools::Non_zero()),
		"correction power of the BCH code.");

	args.add_link({p+"-corr-pow", "T"}, {p+"-info-bits", "K"});

	tools::add_options(args.at({p+"-type", "D"}), 0, "ALGEBRAIC");
	tools::add_options(args.at({p+"-implem"   }), 0, "GENIUS");
}

void Decoder_BCH::parameters
::store(const tools::Argument_map_value &vals)
{
	Decoder::parameters::store(vals);

	auto p = this->get_prefix();

	this->m = (int)std::ceil(std::log2(this->N_cw));
	if (this->m == 0)
	{
		std::stringstream message;
		message << "The Galois Field order is null (because N_cw = " << this->N_cw << ").";
		throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
	}

	if (vals.exist({p+"-corr-pow", "T"}))
	{
		this->t = vals.to_int({p + "-corr-pow", "T"});
		if (K == 0)
		{
			this->K = this->N_cw - tools::BCH_polynomial_generator(this->N_cw, this->t).get_n_rdncy();
			this->R = (float) this->K / (float) this->N_cw;
		}
	}
	else
		this->t = (this->N_cw - this->K) / this->m;
}

void Decoder_BCH::parameters
::get_headers(std::map<std::string,header_list>& headers, const bool full) const
{
	Decoder::parameters::get_headers(headers, full);

	if (this->type != "ML" && this->type != "CHASE")
	{
		auto p = this->get_prefix();

		headers[p].push_back(std::make_pair("Galois field order (m)", std::to_string(this->m)));
		headers[p].push_back(std::make_pair("Correction power (T)",   std::to_string(this->t)));
	}
}

template <typename B, typename Q>
module::Decoder_SIHO<B,Q>* Decoder_BCH::parameters
::build(const tools::BCH_polynomial_generator &GF, module::Encoder<B> *encoder) const
{
	try
	{
		return Decoder::parameters::build<B,Q>(encoder);
	}
	catch (tools::cannot_allocate const&)
	{
		return build_hiho<B,Q>(GF, encoder);
	}
}

template <typename B, typename Q>
module::Decoder_SIHO<B,Q>* Decoder_BCH
::build(const parameters &params, const tools::BCH_polynomial_generator &GF, module::Encoder<B> *encoder)
{
	return params.template build<B,Q>(GF, encoder);
}

template <typename B, typename Q>
module::Decoder_SIHO_HIHO<B,Q>* Decoder_BCH::parameters
::build_hiho(const tools::BCH_polynomial_generator &GF, module::Encoder<B> *encoder) const
{
	if (this->type == "ALGEBRAIC")
	{
		if (this->implem == "STD") return new module::Decoder_BCH_std<B,Q>(this->K, this->N_cw, GF, this->n_frames);

		if (encoder)
		{
			if (this->implem == "GENIUS") return new module::Decoder_BCH_genius<B,Q>(this->K, this->N_cw, this->t, *encoder, this->n_frames);
		}
	}

	throw tools::cannot_allocate(__FILE__, __LINE__, __func__);
}

template <typename B, typename Q>
module::Decoder_SIHO_HIHO<B,Q>* Decoder_BCH
::build_hiho(const parameters &params, const tools::BCH_polynomial_generator &GF, module::Encoder<B> *encoder)
{
	return params.template build_hiho<B,Q>(GF, encoder);
}

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template aff3ct::module::Decoder_SIHO<B_8 ,Q_8 >* aff3ct::factory::Decoder_BCH::parameters::build<B_8 ,Q_8 >(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_8 >*) const;
template aff3ct::module::Decoder_SIHO<B_16,Q_16>* aff3ct::factory::Decoder_BCH::parameters::build<B_16,Q_16>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_16>*) const;
template aff3ct::module::Decoder_SIHO<B_32,Q_32>* aff3ct::factory::Decoder_BCH::parameters::build<B_32,Q_32>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_32>*) const;
template aff3ct::module::Decoder_SIHO<B_64,Q_64>* aff3ct::factory::Decoder_BCH::parameters::build<B_64,Q_64>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_64>*) const;
template aff3ct::module::Decoder_SIHO<B_8 ,Q_8 >* aff3ct::factory::Decoder_BCH::build<B_8 ,Q_8 >(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_8 >*);
template aff3ct::module::Decoder_SIHO<B_16,Q_16>* aff3ct::factory::Decoder_BCH::build<B_16,Q_16>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_16>*);
template aff3ct::module::Decoder_SIHO<B_32,Q_32>* aff3ct::factory::Decoder_BCH::build<B_32,Q_32>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_32>*);
template aff3ct::module::Decoder_SIHO<B_64,Q_64>* aff3ct::factory::Decoder_BCH::build<B_64,Q_64>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_64>*);
#else
template aff3ct::module::Decoder_SIHO<B,Q>* aff3ct::factory::Decoder_BCH::parameters::build<B,Q>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B>*) const;
template aff3ct::module::Decoder_SIHO<B,Q>* aff3ct::factory::Decoder_BCH::build<B,Q>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B>*);
#endif
// ==================================================================================== explicit template instantiation

// ==================================================================================== explicit template instantiation
#include "Tools/types.h"
#ifdef MULTI_PREC
template aff3ct::module::Decoder_SIHO_HIHO<B_8 ,Q_8 >* aff3ct::factory::Decoder_BCH::parameters::build_hiho<B_8 ,Q_8 >(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_8 >*) const;
template aff3ct::module::Decoder_SIHO_HIHO<B_16,Q_16>* aff3ct::factory::Decoder_BCH::parameters::build_hiho<B_16,Q_16>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_16>*) const;
template aff3ct::module::Decoder_SIHO_HIHO<B_32,Q_32>* aff3ct::factory::Decoder_BCH::parameters::build_hiho<B_32,Q_32>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_32>*) const;
template aff3ct::module::Decoder_SIHO_HIHO<B_64,Q_64>* aff3ct::factory::Decoder_BCH::parameters::build_hiho<B_64,Q_64>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_64>*) const;
template aff3ct::module::Decoder_SIHO_HIHO<B_8 ,Q_8 >* aff3ct::factory::Decoder_BCH::build_hiho<B_8 ,Q_8 >(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_8 >*);
template aff3ct::module::Decoder_SIHO_HIHO<B_16,Q_16>* aff3ct::factory::Decoder_BCH::build_hiho<B_16,Q_16>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_16>*);
template aff3ct::module::Decoder_SIHO_HIHO<B_32,Q_32>* aff3ct::factory::Decoder_BCH::build_hiho<B_32,Q_32>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_32>*);
template aff3ct::module::Decoder_SIHO_HIHO<B_64,Q_64>* aff3ct::factory::Decoder_BCH::build_hiho<B_64,Q_64>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B_64>*);
#else
template aff3ct::module::Decoder_SIHO_HIHO<B,Q>* aff3ct::factory::Decoder_BCH::parameters::build_hiho<B>(const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B>*) const;
template aff3ct::module::Decoder_SIHO_HIHO<B,Q>* aff3ct::factory::Decoder_BCH::build_hiho<B>(const aff3ct::factory::Decoder_BCH::parameters&, const aff3ct::tools::BCH_polynomial_generator&, module::Encoder<B>*);
#endif
// ==================================================================================== explicit template instantiation

<|endoftext|>


<commit_before>#include <errno.h>
#include <netdb.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <linux/errqueue.h>
#include <linux/icmp.h>
#include <sys/socket.h>
#include <sys/time.h>

#include "udpping.h"

namespace
{
    bool getAddress(const QString &address, sockaddr_any *addr)
    {
        struct addrinfo hints;
        struct addrinfo *rp = NULL, *result = NULL;

        memset(&hints, 0, sizeof(hints));
        hints.ai_family = PF_UNSPEC;

        if (getaddrinfo(address.toStdString().c_str(), NULL, &hints, &result))
        {
            return false;
        }

        for (rp = result; rp && rp->ai_family != AF_INET &&
             rp->ai_family != AF_INET6;
             rp = rp->ai_next)
        {
        }

        if (!rp)
        {
            rp = result;
        }

        memcpy(addr, rp->ai_addr, rp->ai_addrlen);

        freeaddrinfo(result);

        return true;
    }

    void randomizePayload(char *payload, const quint32 size)
    {
        char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

        for (quint32 i = 0; i < size; i++)
        {
            payload[i] = chars[qrand() % strlen(chars)];
        }

        if (size > 15)
        {
            // ignore terminating null character
            strncpy(&payload[size - 15], " measure-it.net", 15);
        }
    }
}

UdpPing::UdpPing(QObject *parent)
: Measurement(parent)
, currentStatus(Unknown)
, m_device(NULL)
, m_capture(NULL)
, m_destAddress()
, m_payload(NULL)
{
}

UdpPing::~UdpPing()
{
}

Measurement::Status UdpPing::status() const
{
    return currentStatus;
}

void UdpPing::setStatus(Status status)
{
    if (currentStatus != status)
    {
        currentStatus = status;
        emit statusChanged(status);
    }
}

bool UdpPing::prepare(NetworkManager *networkManager, const MeasurementDefinitionPtr &measurementDefinition)
{
    Q_UNUSED(networkManager);

    definition = measurementDefinition.dynamicCast<UdpPingDefinition>();

    if (definition->payload > 65536)
    {
        emit error("payload is too large (> 65536)");
        return false;
    }

    memset(&m_destAddress, 0, sizeof(m_destAddress));

    // resolve
    if (!getAddress(definition->url, &m_destAddress))
    {
        return false;
    }

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        m_destAddress.sin.sin_port = htons(definition->destinationPort ? definition->destinationPort : 33434);
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        m_destAddress.sin6.sin6_port = htons(definition->destinationPort ? definition->destinationPort : 33434);
    }
    else
    {
        // unreachable
        return false;
    }

    return true;
}

bool UdpPing::start()
{
    PingProbe probe;

    // include null-character
    m_payload = new char[definition->payload + 1];

    if (m_payload == NULL)
    {
        return false;
    }

    memset(m_payload, 0, definition->payload + 1);

    setStartDateTime(QDateTime::currentDateTime());

    setStatus(UdpPing::Running);

    memset(&probe, 0, sizeof(probe));
    probe.sock = initSocket();

    if (probe.sock < 0)
    {
        emit error("socket: " + QString(strerror(errno)));
        delete[] m_payload;
        return false;
    }

    for (quint32 i = 0; i < definition->count; i++)
    {
        ping(&probe);
        m_pingProbes.append(probe);
    }

    close(probe.sock);

    setStatus(UdpPing::Finished);
    delete[] m_payload;
    emit finished();

    return true;
}

bool UdpPing::stop()
{
    return true;
}

ResultPtr UdpPing::result() const
{
    QVariantList res;

    foreach (const PingProbe &probe, m_pingProbes)
    {
        if (probe.sendTime > 0 && probe.recvTime > 0)
        {
            res << probe.recvTime - probe.sendTime;
        }
    }

    return ResultPtr(new Result(startDateTime(), QDateTime::currentDateTime(), res, QVariant()));
}

int UdpPing::initSocket()
{
    int n = 0;
    int sock = 0;
    int ttl = definition->ttl ? definition->ttl : 64;
    sockaddr_any src_addr;

    memset(&src_addr, 0, sizeof(src_addr));

    sock = socket(m_destAddress.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);

    if (sock < 0)
    {
        emit error("socket: " + QString(strerror(errno)));
        return -1;
    }

    src_addr.sa.sa_family = m_destAddress.sa.sa_family;

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        src_addr.sin.sin_port = htons(definition->sourcePort);
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        src_addr.sin6.sin6_port = htons(definition->sourcePort);
    }
    else
    {
        // unreachable
        goto cleanup;
    }

    if (src_addr.sa.sa_family == AF_INET)
    {
        n = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr.sin));
    }
    else if (src_addr.sa.sa_family == AF_INET6)
    {
        n = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr.sin6));
    }

    if (n < 0)
    {
        emit error("bind: " + QString(strerror(errno)));
        goto cleanup;
    }

    n = 1;

    if (setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &n, sizeof(n)) < 0)
    {
        emit error("setsockopt SOL_TIMESTAMP: " + QString(strerror(errno)));
        goto cleanup;
    }

    // set TTL
    if (setsockopt(sock, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
    {
        emit error("setsockopt IP_TTL: " + QString(strerror(errno)));
        goto cleanup;
    }

    // use RECVRR
    n = 1;

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        if (setsockopt(sock, SOL_IP, IP_RECVERR, &n, sizeof(n)) < 0)
        {
            emit error("setsockopt IP_RECVERR: " + QString(strerror(errno)));
            goto cleanup;
        }
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVERR, &n, sizeof(n)) < 0)
        {
            emit error("setsockopt IPV6_RECVERR: " + QString(strerror(errno)));
            goto cleanup;
        }
    }
    else
    {
        // unreachable
        goto cleanup;
    }

    return sock;

cleanup:
    close(sock);
    return -1;
}

bool UdpPing::sendData(PingProbe *probe)
{
    int n = 0;
    struct timeval tv;

    memset(&tv, 0, sizeof(tv));
    gettimeofday(&tv, NULL);
    probe->sendTime = tv.tv_sec * 1e6 + tv.tv_usec;

    // randomize payload to prevent caching
    randomizePayload(m_payload, definition->payload);

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        n = sendto(probe->sock, m_payload, definition->payload, 0,
                   (sockaddr *)&m_destAddress, sizeof(m_destAddress.sin));
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        n = sendto(probe->sock, m_payload, definition->payload, 0,
                   (sockaddr *)&m_destAddress, sizeof(m_destAddress.sin6));
    }

    if (n < 0)
    {
        emit error("send: " + QString(strerror(errno)));
        return false;
    }

    return true;
}

void UdpPing::receiveData(PingProbe *probe)
{
    struct msghdr msg;
    sockaddr_any from;
    struct iovec iov;
    char buf[1280];
    char control[1024];
    struct cmsghdr *cm;
    struct sock_extended_err *ee = NULL;

    memset(&msg, 0, sizeof(msg));
    msg.msg_name = &from;
    msg.msg_namelen = sizeof(from);
    msg.msg_control = control;
    msg.msg_controllen = sizeof(control);
    iov.iov_base = buf;
    iov.iov_len = sizeof(buf);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    // poll here
    struct pollfd pfd;
    memset(&pfd, 0, sizeof(pfd));
    pfd.fd = probe->sock;
    pfd.events = POLLIN | POLLERR;

    if (poll(&pfd, 1, definition->receiveTimeout) < 0)
    {
        emit error("poll: " + QString(strerror(errno)));
        goto cleanup;
    }

    if (!pfd.revents)
    {
        emit timeout(*probe);
        goto cleanup;
    }

    if (recvmsg(probe->sock, &msg, MSG_ERRQUEUE) < 0)
    {
        emit error("recvmsg: " + QString(strerror(errno)));
        goto cleanup;
    }

    for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm))
    {
        void *ptr = CMSG_DATA(cm);

        if (cm->cmsg_level == SOL_SOCKET)
        {

            if (cm->cmsg_type == SO_TIMESTAMP)
            {
                struct timeval *tv = (struct timeval *) ptr;
                probe->recvTime = tv->tv_sec * 1e6 + tv->tv_usec;
            }
        }
        else if (cm->cmsg_level == SOL_IP)
        {
            if (cm->cmsg_type == IP_RECVERR)
            {
                ee = (struct sock_extended_err *) ptr;

                if (ee->ee_origin != SO_EE_ORIGIN_ICMP)
                {
                    ee = NULL;
                    continue;
                }

                if (ee->ee_type == ICMP_SOURCE_QUENCH || ee->ee_type == ICMP_REDIRECT)
                {
                    goto cleanup;
                }
            }
        }
    }

    if (ee)
    {
        memcpy(&probe->source, SO_EE_OFFENDER(ee), sizeof(probe->source));

        if (ee->ee_type == ICMP_TIME_EXCEEDED && ee->ee_code == ICMP_EXC_TTL)
        {
            emit ttlExceeded(*probe);
        }
        else if (ee->ee_type == ICMP_DEST_UNREACH)
        {
            emit destinationUnreachable(*probe);
        }
    }

cleanup:
    return;
}

void UdpPing::ping(PingProbe *probe)
{
    // send
    if (sendData(probe))
    {
        receiveData(probe);
    }
}

// vim: set sts=4 sw=4 et:
<commit_msg>udpping: remove unreachable code<commit_after>#include <errno.h>
#include <netdb.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <linux/errqueue.h>
#include <linux/icmp.h>
#include <sys/socket.h>
#include <sys/time.h>

#include "udpping.h"

namespace
{
    bool getAddress(const QString &address, sockaddr_any *addr)
    {
        struct addrinfo hints;
        struct addrinfo *rp = NULL, *result = NULL;

        memset(&hints, 0, sizeof(hints));
        hints.ai_family = PF_UNSPEC;

        if (getaddrinfo(address.toStdString().c_str(), NULL, &hints, &result))
        {
            return false;
        }

        for (rp = result; rp && rp->ai_family != AF_INET &&
             rp->ai_family != AF_INET6;
             rp = rp->ai_next)
        {
        }

        if (!rp)
        {
            freeaddrinfo(result);
            return false;
        }

        memcpy(addr, rp->ai_addr, rp->ai_addrlen);

        freeaddrinfo(result);

        return true;
    }

    void randomizePayload(char *payload, const quint32 size)
    {
        char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

        for (quint32 i = 0; i < size; i++)
        {
            payload[i] = chars[qrand() % strlen(chars)];
        }

        if (size > 15)
        {
            // ignore terminating null character
            strncpy(&payload[size - 15], " measure-it.net", 15);
        }
    }
}

UdpPing::UdpPing(QObject *parent)
: Measurement(parent)
, currentStatus(Unknown)
, m_device(NULL)
, m_capture(NULL)
, m_destAddress()
, m_payload(NULL)
{
}

UdpPing::~UdpPing()
{
}

Measurement::Status UdpPing::status() const
{
    return currentStatus;
}

void UdpPing::setStatus(Status status)
{
    if (currentStatus != status)
    {
        currentStatus = status;
        emit statusChanged(status);
    }
}

bool UdpPing::prepare(NetworkManager *networkManager, const MeasurementDefinitionPtr &measurementDefinition)
{
    Q_UNUSED(networkManager);

    definition = measurementDefinition.dynamicCast<UdpPingDefinition>();

    if (definition->payload > 65536)
    {
        emit error("payload is too large (> 65536)");
        return false;
    }

    memset(&m_destAddress, 0, sizeof(m_destAddress));

    // resolve
    if (!getAddress(definition->url, &m_destAddress))
    {
        return false;
    }

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        m_destAddress.sin.sin_port = htons(definition->destinationPort ? definition->destinationPort : 33434);
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        m_destAddress.sin6.sin6_port = htons(definition->destinationPort ? definition->destinationPort : 33434);
    }

    return true;
}

bool UdpPing::start()
{
    PingProbe probe;

    // include null-character
    m_payload = new char[definition->payload + 1];

    if (m_payload == NULL)
    {
        return false;
    }

    memset(m_payload, 0, definition->payload + 1);

    setStartDateTime(QDateTime::currentDateTime());

    setStatus(UdpPing::Running);

    memset(&probe, 0, sizeof(probe));
    probe.sock = initSocket();

    if (probe.sock < 0)
    {
        emit error("socket: " + QString(strerror(errno)));
        delete[] m_payload;
        return false;
    }

    for (quint32 i = 0; i < definition->count; i++)
    {
        ping(&probe);
        m_pingProbes.append(probe);
    }

    close(probe.sock);

    setStatus(UdpPing::Finished);
    delete[] m_payload;
    emit finished();

    return true;
}

bool UdpPing::stop()
{
    return true;
}

ResultPtr UdpPing::result() const
{
    QVariantList res;

    foreach (const PingProbe &probe, m_pingProbes)
    {
        if (probe.sendTime > 0 && probe.recvTime > 0)
        {
            res << probe.recvTime - probe.sendTime;
        }
    }

    return ResultPtr(new Result(startDateTime(), QDateTime::currentDateTime(), res, QVariant()));
}

int UdpPing::initSocket()
{
    int n = 0;
    int sock = 0;
    int ttl = definition->ttl ? definition->ttl : 64;
    sockaddr_any src_addr;

    memset(&src_addr, 0, sizeof(src_addr));

    sock = socket(m_destAddress.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);

    if (sock < 0)
    {
        emit error("socket: " + QString(strerror(errno)));
        return -1;
    }

    src_addr.sa.sa_family = m_destAddress.sa.sa_family;

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        src_addr.sin.sin_port = htons(definition->sourcePort);
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        src_addr.sin6.sin6_port = htons(definition->sourcePort);
    }

    if (src_addr.sa.sa_family == AF_INET)
    {
        n = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr.sin));
    }
    else if (src_addr.sa.sa_family == AF_INET6)
    {
        n = bind(sock, (struct sockaddr *) &src_addr, sizeof(src_addr.sin6));
    }

    if (n < 0)
    {
        emit error("bind: " + QString(strerror(errno)));
        goto cleanup;
    }

    n = 1;

    if (setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &n, sizeof(n)) < 0)
    {
        emit error("setsockopt SOL_TIMESTAMP: " + QString(strerror(errno)));
        goto cleanup;
    }

    // set TTL
    if (setsockopt(sock, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0)
    {
        emit error("setsockopt IP_TTL: " + QString(strerror(errno)));
        goto cleanup;
    }

    // use RECVRR
    n = 1;

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        if (setsockopt(sock, SOL_IP, IP_RECVERR, &n, sizeof(n)) < 0)
        {
            emit error("setsockopt IP_RECVERR: " + QString(strerror(errno)));
            goto cleanup;
        }
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVERR, &n, sizeof(n)) < 0)
        {
            emit error("setsockopt IPV6_RECVERR: " + QString(strerror(errno)));
            goto cleanup;
        }
    }

    return sock;

cleanup:
    close(sock);
    return -1;
}

bool UdpPing::sendData(PingProbe *probe)
{
    int n = 0;
    struct timeval tv;

    memset(&tv, 0, sizeof(tv));
    gettimeofday(&tv, NULL);
    probe->sendTime = tv.tv_sec * 1e6 + tv.tv_usec;

    // randomize payload to prevent caching
    randomizePayload(m_payload, definition->payload);

    if (m_destAddress.sa.sa_family == AF_INET)
    {
        n = sendto(probe->sock, m_payload, definition->payload, 0,
                   (sockaddr *)&m_destAddress, sizeof(m_destAddress.sin));
    }
    else if (m_destAddress.sa.sa_family == AF_INET6)
    {
        n = sendto(probe->sock, m_payload, definition->payload, 0,
                   (sockaddr *)&m_destAddress, sizeof(m_destAddress.sin6));
    }

    if (n < 0)
    {
        emit error("send: " + QString(strerror(errno)));
        return false;
    }

    return true;
}

void UdpPing::receiveData(PingProbe *probe)
{
    struct msghdr msg;
    sockaddr_any from;
    struct iovec iov;
    char buf[1280];
    char control[1024];
    struct cmsghdr *cm;
    struct sock_extended_err *ee = NULL;

    memset(&msg, 0, sizeof(msg));
    msg.msg_name = &from;
    msg.msg_namelen = sizeof(from);
    msg.msg_control = control;
    msg.msg_controllen = sizeof(control);
    iov.iov_base = buf;
    iov.iov_len = sizeof(buf);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    // poll here
    struct pollfd pfd;
    memset(&pfd, 0, sizeof(pfd));
    pfd.fd = probe->sock;
    pfd.events = POLLIN | POLLERR;

    if (poll(&pfd, 1, definition->receiveTimeout) < 0)
    {
        emit error("poll: " + QString(strerror(errno)));
        goto cleanup;
    }

    if (!pfd.revents)
    {
        emit timeout(*probe);
        goto cleanup;
    }

    if (recvmsg(probe->sock, &msg, MSG_ERRQUEUE) < 0)
    {
        emit error("recvmsg: " + QString(strerror(errno)));
        goto cleanup;
    }

    for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm))
    {
        void *ptr = CMSG_DATA(cm);

        if (cm->cmsg_level == SOL_SOCKET)
        {

            if (cm->cmsg_type == SO_TIMESTAMP)
            {
                struct timeval *tv = (struct timeval *) ptr;
                probe->recvTime = tv->tv_sec * 1e6 + tv->tv_usec;
            }
        }
        else if (cm->cmsg_level == SOL_IP)
        {
            if (cm->cmsg_type == IP_RECVERR)
            {
                ee = (struct sock_extended_err *) ptr;

                if (ee->ee_origin != SO_EE_ORIGIN_ICMP)
                {
                    ee = NULL;
                    continue;
                }

                if (ee->ee_type == ICMP_SOURCE_QUENCH || ee->ee_type == ICMP_REDIRECT)
                {
                    goto cleanup;
                }
            }
        }
    }

    if (ee)
    {
        memcpy(&probe->source, SO_EE_OFFENDER(ee), sizeof(probe->source));

        if (ee->ee_type == ICMP_TIME_EXCEEDED && ee->ee_code == ICMP_EXC_TTL)
        {
            emit ttlExceeded(*probe);
        }
        else if (ee->ee_type == ICMP_DEST_UNREACH)
        {
            emit destinationUnreachable(*probe);
        }
    }

cleanup:
    return;
}

void UdpPing::ping(PingProbe *probe)
{
    // send
    if (sendData(probe))
    {
        receiveData(probe);
    }
}

// vim: set sts=4 sw=4 et:
<|endoftext|>