<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include "json_document.h"

#include <cassert>
#include <cstdlib>
#include <cstring>

#include "logging.h"
#include "util/exception.h"
#include "util/pointer.h"
#include "util/string.h"

using namespace std;  // NOLINT

bool ToJsonString(const JsonStringInput &input, std::string *output) {
  if (!output) {
    return false;
  }

  output->clear();
  *output = "{";
  for (size_t i = 0u; i < input.entries.size(); ++i) {
    *output += string("\"") + input.entries[i].key + "\":";
    if (input.entries[i].quoted) {  // check for nested object
      *output += string("\"") + input.entries[i].val + "\"";
    } else {
      *output += input.entries[i].val;
    }
    if (i < input.entries.size() - 1) {
      *output += ',';
    }
  }
  *output += string("}");

  return true;
}

JsonDocument *JsonDocument::Create(const string &text) {
  UniquePtr<JsonDocument> json(new JsonDocument());
  bool retval = json->Parse(text);
  if (!retval) return NULL;
  return json.Release();
}

string JsonDocument::EscapeString(const string &input) {
  string escaped;
  escaped.reserve(input.length());

  for (unsigned i = 0, s = input.length(); i < s; ++i) {
    if (input[i] == '\\') {
      escaped.push_back('\\');
      escaped.push_back('\\');
    } else if (input[i] == '"') {
      escaped.push_back('\\');
      escaped.push_back('"');
    } else {
      escaped.push_back(input[i]);
    }
  }
  return escaped;
}

JsonDocument::JsonDocument()
    : allocator_(kDefaultBlockSize), root_(NULL), raw_text_(NULL) {}

JsonDocument::~JsonDocument() {
  if (raw_text_) free(raw_text_);
}

/**
 * Parses a JSON string in text.
 *
 * @return        true if parsing was successful
 */
bool JsonDocument::Parse(const string &text) {
  assert(root_ == NULL);

  // The used JSON library 'vjson' is a destructive parser and therefore
  // alters the content of the provided buffer.  The buffer must persist as
  // name and string values from JSON nodes just point into it.
  raw_text_ = strdup(text.c_str());

  char *error_pos = 0;
  char *error_desc = 0;
  int error_line = 0;
  JSON *root =
      json_parse(raw_text_, &error_pos, &error_desc, &error_line, &allocator_);

  // check if the json string was parsed successfully
  if (!root) {
    LogCvmfs(kLogUtility, kLogDebug,
             "Failed to parse json string. Error at line %d: %s (%s)",
             error_line, error_desc, error_pos);
    return false;
  }

  root_ = root;
  return true;
}

string JsonDocument::PrintArray(JSON *first_child, PrintOptions print_options) {
  string result = "[";
  if (print_options.with_whitespace) {
    result += "\n";
    print_options.num_indent += 2;
  }
  JSON *value = first_child;
  if (value != NULL) {
    result += PrintValue(value, print_options);
    value = value->next_sibling;
  }
  while (value != NULL) {
    result += print_options.with_whitespace ? ",\n" : ",";
    result += PrintValue(value, print_options);
    value = value->next_sibling;
  }
  if (print_options.with_whitespace) {
    result += "\n";
    for (unsigned i = 2; i < print_options.num_indent; ++i)
      result.push_back(' ');
  }
  return result + "]";
}

/**
 * JSON string in a canonical format:
 *   - No whitespaces
 *   - Variable names and strings in quotes
 *
 * Can be used as a canonical representation to sign or encrypt a JSON text.
 */
string JsonDocument::PrintCanonical() {
  if (!root_) return "";
  PrintOptions print_options;
  return PrintObject(root_->first_child, print_options);
}

string JsonDocument::PrintObject(JSON *first_child,
                                 PrintOptions print_options) {
  string result = "{";
  if (print_options.with_whitespace) {
    result += "\n";
    print_options.num_indent += 2;
  }
  JSON *value = first_child;
  if (value != NULL) {
    result += PrintValue(value, print_options);
    value = value->next_sibling;
  }
  while (value != NULL) {
    result += print_options.with_whitespace ? ",\n" : ",";
    result += PrintValue(value, print_options);
    value = value->next_sibling;
  }
  if (print_options.with_whitespace) {
    result += "\n";
    for (unsigned i = 2; i < print_options.num_indent; ++i)
      result.push_back(' ');
  }
  return result + "}";
}

/**
 * JSON string for humans.
 */
string JsonDocument::PrintPretty() {
  if (!root_) return "";
  PrintOptions print_options;
  print_options.with_whitespace = true;
  return PrintObject(root_->first_child, print_options);
}

std::string JsonDocument::PrintValue(JSON *value, PrintOptions print_options) {
  assert(value);

  string result;
  for (unsigned i = 0; i < print_options.num_indent; ++i) result.push_back(' ');
  if (value->name) {
    result += "\"" + EscapeString(value->name) + "\":";
    if (print_options.with_whitespace) result += " ";
  }
  switch (value->type) {
    case JSON_NULL:
      result += "null";
      break;
    case JSON_OBJECT:
      result += PrintObject(value->first_child, print_options);
      break;
    case JSON_ARRAY:
      result += PrintArray(value->first_child, print_options);
      break;
    case JSON_STRING:
      result += "\"" + EscapeString(value->string_value) + "\"";
      break;
    case JSON_INT:
      result += StringifyInt(value->int_value);
      break;
    case JSON_FLOAT:
      result += StringifyDouble(value->float_value);
      break;
    case JSON_BOOL:
      result += value->int_value ? "true" : "false";
      break;
    default:
      PANIC(NULL);
  }
  return result;
}

JSON *JsonDocument::SearchInObject(const JSON *json_object, const string &name,
                                   const json_type type) {
  if (!json_object || (json_object->type != JSON_OBJECT)) return NULL;

  JSON *walker = json_object->first_child;
  while (walker != NULL) {
    if (string(walker->name) == name) {
      return (walker->type == type) ? walker : NULL;
    }
    walker = walker->next_sibling;
  }
  return NULL;
}

template <>
bool GetFromJSON<std::string>(const JSON *object, const std::string &name,
                              std::string *value) {
  const JSON *o = JsonDocument::SearchInObject(object, name, JSON_STRING);

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

  if (value) {
    *value = o->string_value;
  }

  return true;
}

template <>
bool GetFromJSON<int>(const JSON *object, const std::string &name, int *value) {
  const JSON *o = JsonDocument::SearchInObject(object, name, JSON_INT);

  if (o == NULL || value == NULL) {
    return false;
  }

  *value = o->int_value;

  return true;
}

template <>
bool GetFromJSON<float>(const JSON *object, const std::string &name,
                        float *value) {
  const JSON *o = JsonDocument::SearchInObject(object, name, JSON_FLOAT);

  if (o == NULL || value == NULL) {
    return false;
  }

  *value = o->float_value;

  return true;
}
<commit_msg>fixup! JSON: make ToJsonString more flexible<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include "json_document.h"

#include <cassert>
#include <cstdlib>
#include <cstring>

#include "logging.h"
#include "util/exception.h"
#include "util/pointer.h"
#include "util/string.h"

using namespace std;  // NOLINT

bool ToJsonString(const JsonStringInput &input, std::string *output) {
  if (!output) {
    return false;
  }

  output->clear();
  *output = "{";
  for (size_t i = 0u; i < input.entries.size(); ++i) {
    *output += string("\"") + input.entries[i].key + "\":";
    if (input.entries[i].quoted) {
      *output += string("\"") + input.entries[i].val + "\"";
    } else {
      *output += input.entries[i].val;
    }
    if (i < input.entries.size() - 1) {
      *output += ',';
    }
  }
  *output += string("}");

  return true;
}

JsonDocument *JsonDocument::Create(const string &text) {
  UniquePtr<JsonDocument> json(new JsonDocument());
  bool retval = json->Parse(text);
  if (!retval) return NULL;
  return json.Release();
}

string JsonDocument::EscapeString(const string &input) {
  string escaped;
  escaped.reserve(input.length());

  for (unsigned i = 0, s = input.length(); i < s; ++i) {
    if (input[i] == '\\') {
      escaped.push_back('\\');
      escaped.push_back('\\');
    } else if (input[i] == '"') {
      escaped.push_back('\\');
      escaped.push_back('"');
    } else {
      escaped.push_back(input[i]);
    }
  }
  return escaped;
}

JsonDocument::JsonDocument()
    : allocator_(kDefaultBlockSize), root_(NULL), raw_text_(NULL) {}

JsonDocument::~JsonDocument() {
  if (raw_text_) free(raw_text_);
}

/**
 * Parses a JSON string in text.
 *
 * @return        true if parsing was successful
 */
bool JsonDocument::Parse(const string &text) {
  assert(root_ == NULL);

  // The used JSON library 'vjson' is a destructive parser and therefore
  // alters the content of the provided buffer.  The buffer must persist as
  // name and string values from JSON nodes just point into it.
  raw_text_ = strdup(text.c_str());

  char *error_pos = 0;
  char *error_desc = 0;
  int error_line = 0;
  JSON *root =
      json_parse(raw_text_, &error_pos, &error_desc, &error_line, &allocator_);

  // check if the json string was parsed successfully
  if (!root) {
    LogCvmfs(kLogUtility, kLogDebug,
             "Failed to parse json string. Error at line %d: %s (%s)",
             error_line, error_desc, error_pos);
    return false;
  }

  root_ = root;
  return true;
}

string JsonDocument::PrintArray(JSON *first_child, PrintOptions print_options) {
  string result = "[";
  if (print_options.with_whitespace) {
    result += "\n";
    print_options.num_indent += 2;
  }
  JSON *value = first_child;
  if (value != NULL) {
    result += PrintValue(value, print_options);
    value = value->next_sibling;
  }
  while (value != NULL) {
    result += print_options.with_whitespace ? ",\n" : ",";
    result += PrintValue(value, print_options);
    value = value->next_sibling;
  }
  if (print_options.with_whitespace) {
    result += "\n";
    for (unsigned i = 2; i < print_options.num_indent; ++i)
      result.push_back(' ');
  }
  return result + "]";
}

/**
 * JSON string in a canonical format:
 *   - No whitespaces
 *   - Variable names and strings in quotes
 *
 * Can be used as a canonical representation to sign or encrypt a JSON text.
 */
string JsonDocument::PrintCanonical() {
  if (!root_) return "";
  PrintOptions print_options;
  return PrintObject(root_->first_child, print_options);
}

string JsonDocument::PrintObject(JSON *first_child,
                                 PrintOptions print_options) {
  string result = "{";
  if (print_options.with_whitespace) {
    result += "\n";
    print_options.num_indent += 2;
  }
  JSON *value = first_child;
  if (value != NULL) {
    result += PrintValue(value, print_options);
    value = value->next_sibling;
  }
  while (value != NULL) {
    result += print_options.with_whitespace ? ",\n" : ",";
    result += PrintValue(value, print_options);
    value = value->next_sibling;
  }
  if (print_options.with_whitespace) {
    result += "\n";
    for (unsigned i = 2; i < print_options.num_indent; ++i)
      result.push_back(' ');
  }
  return result + "}";
}

/**
 * JSON string for humans.
 */
string JsonDocument::PrintPretty() {
  if (!root_) return "";
  PrintOptions print_options;
  print_options.with_whitespace = true;
  return PrintObject(root_->first_child, print_options);
}

std::string JsonDocument::PrintValue(JSON *value, PrintOptions print_options) {
  assert(value);

  string result;
  for (unsigned i = 0; i < print_options.num_indent; ++i) result.push_back(' ');
  if (value->name) {
    result += "\"" + EscapeString(value->name) + "\":";
    if (print_options.with_whitespace) result += " ";
  }
  switch (value->type) {
    case JSON_NULL:
      result += "null";
      break;
    case JSON_OBJECT:
      result += PrintObject(value->first_child, print_options);
      break;
    case JSON_ARRAY:
      result += PrintArray(value->first_child, print_options);
      break;
    case JSON_STRING:
      result += "\"" + EscapeString(value->string_value) + "\"";
      break;
    case JSON_INT:
      result += StringifyInt(value->int_value);
      break;
    case JSON_FLOAT:
      result += StringifyDouble(value->float_value);
      break;
    case JSON_BOOL:
      result += value->int_value ? "true" : "false";
      break;
    default:
      PANIC(NULL);
  }
  return result;
}

JSON *JsonDocument::SearchInObject(const JSON *json_object, const string &name,
                                   const json_type type) {
  if (!json_object || (json_object->type != JSON_OBJECT)) return NULL;

  JSON *walker = json_object->first_child;
  while (walker != NULL) {
    if (string(walker->name) == name) {
      return (walker->type == type) ? walker : NULL;
    }
    walker = walker->next_sibling;
  }
  return NULL;
}

template <>
bool GetFromJSON<std::string>(const JSON *object, const std::string &name,
                              std::string *value) {
  const JSON *o = JsonDocument::SearchInObject(object, name, JSON_STRING);

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

  if (value) {
    *value = o->string_value;
  }

  return true;
}

template <>
bool GetFromJSON<int>(const JSON *object, const std::string &name, int *value) {
  const JSON *o = JsonDocument::SearchInObject(object, name, JSON_INT);

  if (o == NULL || value == NULL) {
    return false;
  }

  *value = o->int_value;

  return true;
}

template <>
bool GetFromJSON<float>(const JSON *object, const std::string &name,
                        float *value) {
  const JSON *o = JsonDocument::SearchInObject(object, name, JSON_FLOAT);

  if (o == NULL || value == NULL) {
    return false;
  }

  *value = o->float_value;

  return true;
}
<|endoftext|>


<commit_before>#include "explorer-impl.hpp"
#include "include-opencv.hpp"

namespace fmo {
    namespace {
        inline cv::Point toCv(Pos p) { return {p.x, p.y}; }
    }

    void Explorer::Impl::visualize() {
        mVisualized.resize(Format::GRAY, mCfg.dims);
        cv::Mat mat = mVisualized.wrap();

        if (mIgnoredLevels.empty()) {
            mat.setTo(0);
        } else {
            // cover the visualization image with the highest-resolution difference image
            cv::resize(mIgnoredLevels[0].image.wrap(), mat,
                       cv::Size{mCfg.dims.width, mCfg.dims.height}, 0, 0, cv::INTER_NEAREST);
        }

        // draw strips
        auto kpIt = begin(mStrips);
        {
            auto& level = mLevel;
            int halfWidth = level.step / 2;
            for (int i = 0; i < level.numStrips; i++, kpIt++) {
                auto kp = *kpIt;
                cv::Point p1{kp.x - halfWidth, kp.y - kp.halfHeight};
                cv::Point p2{kp.x + halfWidth, kp.y + kp.halfHeight};
                cv::rectangle(mat, p1, p2, 0xFF);
            }
        }

        // draw trajectories
        for (auto& traj : mTrajectories) {
            Component* comp = &mComponents[traj.first];

            // connect components in the trajectory with lines
            while (comp->next != Component::NO_COMPONENT) {
                Component* next = &mComponents[comp->next];
                Strip& s1 = mStrips[comp->last];
                Strip& s2 = mStrips[next->first];
                cv::Point p1{s1.x, s1.y};
                cv::Point p2{s2.x, s2.y};
                cv::line(mat, p1, p2, 0xFF);
                comp = next;
            }
        }

        // draw rejected objects
        for (auto* traj : mRejected) {
            auto bounds = findBounds(*traj);
            cv::rectangle(mat, toCv(bounds.min), toCv(bounds.max), 0x00);
        }

        // draw accepted objects
        for (auto* traj : mObjects) {
            auto bounds = findBounds(*traj);
            cv::rectangle(mat, toCv(bounds.min), toCv(bounds.max), 0xFF);
        }
    }
}
<commit_msg>Display image from processed level for very low resolutions<commit_after>#include "explorer-impl.hpp"
#include "include-opencv.hpp"

namespace fmo {
    namespace {
        inline cv::Point toCv(Pos p) { return {p.x, p.y}; }
    }

    void Explorer::Impl::visualize() {
        mVisualized.resize(Format::GRAY, mCfg.dims);
        cv::Mat mat = mVisualized.wrap();

        if (!mIgnoredLevels.empty()) {
            // cover the visualization image with the highest-resolution difference image
            cv::resize(mIgnoredLevels[0].image.wrap(), mat,
                       cv::Size{mCfg.dims.width, mCfg.dims.height}, 0, 0, cv::INTER_NEAREST);
        }
        else {
            cv::resize(mLevel.image1.wrap(), mat, cv::Size{ mCfg.dims.width, mCfg.dims.height },
                       0, 0, cv::INTER_NEAREST);
        }

        // draw strips
        auto kpIt = begin(mStrips);
        {
            auto& level = mLevel;
            int halfWidth = level.step / 2;
            for (int i = 0; i < level.numStrips; i++, kpIt++) {
                auto kp = *kpIt;
                cv::Point p1{kp.x - halfWidth, kp.y - kp.halfHeight};
                cv::Point p2{kp.x + halfWidth, kp.y + kp.halfHeight};
                cv::rectangle(mat, p1, p2, 0xFF);
            }
        }

        // draw trajectories
        for (auto& traj : mTrajectories) {
            Component* comp = &mComponents[traj.first];

            // connect components in the trajectory with lines
            while (comp->next != Component::NO_COMPONENT) {
                Component* next = &mComponents[comp->next];
                Strip& s1 = mStrips[comp->last];
                Strip& s2 = mStrips[next->first];
                cv::Point p1{s1.x, s1.y};
                cv::Point p2{s2.x, s2.y};
                cv::line(mat, p1, p2, 0xFF);
                comp = next;
            }
        }

        // draw rejected objects
        for (auto* traj : mRejected) {
            auto bounds = findBounds(*traj);
            cv::rectangle(mat, toCv(bounds.min), toCv(bounds.max), 0x00);
        }

        // draw accepted objects
        for (auto* traj : mObjects) {
            auto bounds = findBounds(*traj);
            cv::rectangle(mat, toCv(bounds.min), toCv(bounds.max), 0xFF);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2019 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <validation.h>
#include <services/asset.h>
#include <consensus/validation.h>

std::string stringFromSyscoinTx(const int &nVersion) {
    switch (nVersion) {
    case SYSCOIN_TX_VERSION_ASSET_ACTIVATE:
		return "assetactivate";
    case SYSCOIN_TX_VERSION_ASSET_UPDATE:
		return "assetupdate";
	case SYSCOIN_TX_VERSION_ASSET_SEND:
		return "assetsend";
	case SYSCOIN_TX_VERSION_ALLOCATION_SEND:
		return "assetallocationsend";
	case SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_ETHEREUM:
		return "assetallocationburntoethereum";
	case SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_SYSCOIN:
		return "assetallocationburntosyscoin";
	case SYSCOIN_TX_VERSION_SYSCOIN_BURN_TO_ALLOCATION:
		return "syscoinburntoassetallocation";
    case SYSCOIN_TX_VERSION_ALLOCATION_MINT:
        return "assetallocationmint";
    default:
        return "<unknown assetallocation op>";
    }
}

std::vector<unsigned char> vchFromString(const std::string &str) {
	unsigned char *strbeg = (unsigned char*)str.c_str();
	return std::vector<unsigned char>(strbeg, strbeg + str.size());
}
std::string stringFromVch(const std::vector<unsigned char> &vch) {
	std::string res;
	std::vector<unsigned char>::const_iterator vi = vch.begin();
	while (vi != vch.end()) {
		res += (char)(*vi);
		vi++;
	}
	return res;
}

bool CAsset::UnserializeFromData(const std::vector<unsigned char> &vchData) {
    try {
		CDataStream dsAsset(vchData, SER_NETWORK, PROTOCOL_VERSION);
		Unserialize(dsAsset);
    } catch (std::exception &e) {
		SetNull();
        return false;
    }
	return true;
}

bool CAsset::UnserializeFromTx(const CTransaction &tx) {
	std::vector<unsigned char> vchData;
	int nOut;
	if (!GetSyscoinData(tx, vchData, nOut))
	{
		SetNull();
		return false;
	}
	if(!UnserializeFromData(vchData))
	{
		SetNull();
		return false;
	}
    return true;
}

int32_t GenerateSyscoinGuid(const COutPoint& outPoint) {
    const arith_uint256 &txidArith = UintToArith256(outPoint.hash);
    int32_t low32 = (int32_t)txidArith.GetLow64();
    low32 += outPoint.n;
    if(low32 < 0){
        low32 *= -1;
    }
    if(low32 <= SYSCOIN_TX_VERSION_ALLOCATION_SEND*10){
        low32 = SYSCOIN_TX_VERSION_ALLOCATION_SEND*10;
    }
    return low32;
}

void CAsset::SerializeData( std::vector<unsigned char> &vchData) {
    CDataStream dsAsset(SER_NETWORK, PROTOCOL_VERSION);
    Serialize(dsAsset);
	vchData = std::vector<unsigned char>(dsAsset.begin(), dsAsset.end());
}

bool GetAsset(const int32_t &nAsset,
        CAsset& txPos) {
    if (passetdb == nullptr || !passetdb->ReadAsset(nAsset, txPos))
        return false;
    return true;
}

bool ReserializeAssetCommitment(CMutableTransaction& mtx) {
    // load tx.voutAssets from tx.vout.assetInfo info
    // when change is added this function should be called and preceding this the vout.assetInfo
    // should all be in sync with the asset commitment in OP_RETURN. This will resync that commitment
    // because when change is added the vout.assetInfo is filled and we should capture that in LoadAssetsFromVout as it
    // re-orders tx->voutAssets if change address was somewhere before the last asset output
    mtx.LoadAssetsFromVout();
    // store tx.voutAssets into OP_RETURN data overwriting previous commitment
    const CTransactionRef& tx = MakeTransactionRef(mtx);
    std::vector<unsigned char> data;
    if(IsSyscoinMintTx(tx->nVersion)) {
        CMintSyscoin mintSyscoin(*tx);
        mintSyscoin.assetAllocation.voutAssets = tx->voutAssets;
        mintSyscoin.SerializeData(data);
    } else if(tx->nVersion == SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_SYSCOIN) {
        CBurnSyscoin burnSyscoin(*tx);
        burnSyscoin.assetAllocation.voutAssets = tx->voutAssets;
        burnSyscoin.SerializeData(data);
    } else if(IsAssetTx(tx->nVersion)) {
        CAsset asset(*tx);
        asset.assetAllocation.voutAssets = tx->voutAssets;
        asset.SerializeData(data);
    } else if(IsAssetAllocationTx(tx->nVersion)) {
        CAssetAllocation allocation(*tx);
        allocation.voutAssets = tx->voutAssets;
        allocation.SerializeData(data);
    }
    // find previous commitment (OP_RETURN) and replace script
    CScript scriptData;
    scriptData << OP_RETURN << data;
    bool bFoundData = false;
    for(auto& vout: mtx.vout) {
        if(vout.scriptPubKey.IsUnspendable()) {
            vout.scriptPubKey = scriptData;
            bFoundData = true;
            break;
        }
    }
    if(!bFoundData) {
        return false;
    }
    return true;
}
<commit_msg>include consensus<commit_after>// Copyright (c) 2013-2019 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <validation.h>
#include <services/asset.h>
#include <services/assetconsensus.h>
#include <consensus/validation.h>

std::string stringFromSyscoinTx(const int &nVersion) {
    switch (nVersion) {
    case SYSCOIN_TX_VERSION_ASSET_ACTIVATE:
		return "assetactivate";
    case SYSCOIN_TX_VERSION_ASSET_UPDATE:
		return "assetupdate";
	case SYSCOIN_TX_VERSION_ASSET_SEND:
		return "assetsend";
	case SYSCOIN_TX_VERSION_ALLOCATION_SEND:
		return "assetallocationsend";
	case SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_ETHEREUM:
		return "assetallocationburntoethereum";
	case SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_SYSCOIN:
		return "assetallocationburntosyscoin";
	case SYSCOIN_TX_VERSION_SYSCOIN_BURN_TO_ALLOCATION:
		return "syscoinburntoassetallocation";
    case SYSCOIN_TX_VERSION_ALLOCATION_MINT:
        return "assetallocationmint";
    default:
        return "<unknown assetallocation op>";
    }
}

std::vector<unsigned char> vchFromString(const std::string &str) {
	unsigned char *strbeg = (unsigned char*)str.c_str();
	return std::vector<unsigned char>(strbeg, strbeg + str.size());
}
std::string stringFromVch(const std::vector<unsigned char> &vch) {
	std::string res;
	std::vector<unsigned char>::const_iterator vi = vch.begin();
	while (vi != vch.end()) {
		res += (char)(*vi);
		vi++;
	}
	return res;
}

bool CAsset::UnserializeFromData(const std::vector<unsigned char> &vchData) {
    try {
		CDataStream dsAsset(vchData, SER_NETWORK, PROTOCOL_VERSION);
		Unserialize(dsAsset);
    } catch (std::exception &e) {
		SetNull();
        return false;
    }
	return true;
}

bool CAsset::UnserializeFromTx(const CTransaction &tx) {
	std::vector<unsigned char> vchData;
	int nOut;
	if (!GetSyscoinData(tx, vchData, nOut))
	{
		SetNull();
		return false;
	}
	if(!UnserializeFromData(vchData))
	{
		SetNull();
		return false;
	}
    return true;
}

int32_t GenerateSyscoinGuid(const COutPoint& outPoint) {
    const arith_uint256 &txidArith = UintToArith256(outPoint.hash);
    int32_t low32 = (int32_t)txidArith.GetLow64();
    low32 += outPoint.n;
    if(low32 < 0){
        low32 *= -1;
    }
    if(low32 <= SYSCOIN_TX_VERSION_ALLOCATION_SEND*10){
        low32 = SYSCOIN_TX_VERSION_ALLOCATION_SEND*10;
    }
    return low32;
}

void CAsset::SerializeData( std::vector<unsigned char> &vchData) {
    CDataStream dsAsset(SER_NETWORK, PROTOCOL_VERSION);
    Serialize(dsAsset);
	vchData = std::vector<unsigned char>(dsAsset.begin(), dsAsset.end());
}

bool GetAsset(const int32_t &nAsset,
        CAsset& txPos) {
    if (passetdb == nullptr || !passetdb->ReadAsset(nAsset, txPos))
        return false;
    return true;
}

bool ReserializeAssetCommitment(CMutableTransaction& mtx) {
    // load tx.voutAssets from tx.vout.assetInfo info
    // when change is added this function should be called and preceding this the vout.assetInfo
    // should all be in sync with the asset commitment in OP_RETURN. This will resync that commitment
    // because when change is added the vout.assetInfo is filled and we should capture that in LoadAssetsFromVout as it
    // re-orders tx->voutAssets if change address was somewhere before the last asset output
    mtx.LoadAssetsFromVout();
    // store tx.voutAssets into OP_RETURN data overwriting previous commitment
    const CTransactionRef& tx = MakeTransactionRef(mtx);
    std::vector<unsigned char> data;
    if(IsSyscoinMintTx(tx->nVersion)) {
        CMintSyscoin mintSyscoin(*tx);
        mintSyscoin.assetAllocation.voutAssets = tx->voutAssets;
        mintSyscoin.SerializeData(data);
    } else if(tx->nVersion == SYSCOIN_TX_VERSION_ALLOCATION_BURN_TO_SYSCOIN) {
        CBurnSyscoin burnSyscoin(*tx);
        burnSyscoin.assetAllocation.voutAssets = tx->voutAssets;
        burnSyscoin.SerializeData(data);
    } else if(IsAssetTx(tx->nVersion)) {
        CAsset asset(*tx);
        asset.assetAllocation.voutAssets = tx->voutAssets;
        asset.SerializeData(data);
    } else if(IsAssetAllocationTx(tx->nVersion)) {
        CAssetAllocation allocation(*tx);
        allocation.voutAssets = tx->voutAssets;
        allocation.SerializeData(data);
    }
    // find previous commitment (OP_RETURN) and replace script
    CScript scriptData;
    scriptData << OP_RETURN << data;
    bool bFoundData = false;
    for(auto& vout: mtx.vout) {
        if(vout.scriptPubKey.IsUnspendable()) {
            vout.scriptPubKey = scriptData;
            bFoundData = true;
            break;
        }
    }
    if(!bFoundData) {
        return false;
    }
    return true;
}
<|endoftext|>


<commit_before>//===- FunctionTest.cpp - Function unit tests -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/IR/Function.h"
#include "gtest/gtest.h"
using namespace llvm;

namespace {

TEST(FunctionTest, hasLazyArguments) {
  LLVMContext C;

  Type *ArgTypes[] = {Type::getInt8Ty(C), Type::getInt32Ty(C)};
  FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), ArgTypes, false);

  // Functions start out with lazy arguments.
  std::unique_ptr<Function> F(
      Function::Create(FTy, GlobalValue::ExternalLinkage, "F"));
  EXPECT_TRUE(F->hasLazyArguments());

  // Checking for empty or size shouldn't force arguments to be instantiated.
  EXPECT_FALSE(F->arg_empty());
  EXPECT_TRUE(F->hasLazyArguments());
  EXPECT_EQ(2u, F->arg_size());
  EXPECT_TRUE(F->hasLazyArguments());

  // The argument list should be populated at first access.
  (void)F->arg_begin();
  EXPECT_FALSE(F->hasLazyArguments());
}

TEST(FunctionTest, stealArgumentListFrom) {
  LLVMContext C;

  Type *ArgTypes[] = {Type::getInt8Ty(C), Type::getInt32Ty(C)};
  FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), ArgTypes, false);
  std::unique_ptr<Function> F1(
      Function::Create(FTy, GlobalValue::ExternalLinkage, "F1"));
  std::unique_ptr<Function> F2(
      Function::Create(FTy, GlobalValue::ExternalLinkage, "F1"));
  EXPECT_TRUE(F1->hasLazyArguments());
  EXPECT_TRUE(F2->hasLazyArguments());

  // Steal arguments before they've been accessed.  Nothing should change; both
  // functions should still have lazy arguments.
  //
  //   steal(empty); drop (empty)
  F1->stealArgumentListFrom(*F2);
  EXPECT_TRUE(F1->hasLazyArguments());
  EXPECT_TRUE(F2->hasLazyArguments());

  // Save arguments from F1 for later assertions.  F1 won't have lazy arguments
  // anymore.
  SmallVector<Argument *, 4> Args;
  for (Argument &A : F1->args())
    Args.push_back(&A);
  EXPECT_EQ(2u, Args.size());
  EXPECT_FALSE(F1->hasLazyArguments());

  // Steal arguments from F1 to F2.  F1's arguments should be lazy again.
  //
  //   steal(real); drop (empty)
  F2->stealArgumentListFrom(*F1);
  EXPECT_TRUE(F1->hasLazyArguments());
  EXPECT_FALSE(F2->hasLazyArguments());
  unsigned I = 0;
  for (Argument &A : F2->args())
    EXPECT_EQ(Args[I++], &A);
  EXPECT_EQ(2u, I);

  // Check that arguments in F1 don't have pointer equality with the saved ones.
  // This also instantiates F1's arguments.
  I = 0;
  for (Argument &A : F1->args())
    EXPECT_NE(Args[I++], &A);
  EXPECT_EQ(2u, I);
  EXPECT_FALSE(F1->hasLazyArguments());
  EXPECT_FALSE(F2->hasLazyArguments());

  // Steal back from F2.  F2's arguments should be lazy again.
  //
  //   steal(real); drop (real)
  F1->stealArgumentListFrom(*F2);
  EXPECT_FALSE(F1->hasLazyArguments());
  EXPECT_TRUE(F2->hasLazyArguments());
  I = 0;
  for (Argument &A : F1->args())
    EXPECT_EQ(Args[I++], &A);
  EXPECT_EQ(2u, I);

  // Steal from F2 a second time.  Now both functions should have lazy
  // arguments.
  //
  //   steal(empty); drop (real)
  F1->stealArgumentListFrom(*F2);
  EXPECT_TRUE(F1->hasLazyArguments());
  EXPECT_TRUE(F2->hasLazyArguments());
}

} // end namespace
<commit_msg>Fix warnings in FunctionTest.cpp.<commit_after>//===- FunctionTest.cpp - Function unit tests -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/IR/Function.h"
#include "gtest/gtest.h"
using namespace llvm;

namespace {

TEST(FunctionTest, hasLazyArguments) {
  LLVMContext C;

  Type *ArgTypes[] = {Type::getInt8Ty(C), Type::getInt32Ty(C)};
  FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), ArgTypes, false);

  // Functions start out with lazy arguments.
  std::unique_ptr<Function> F(
      Function::Create(FTy, GlobalValue::ExternalLinkage, "F"));
  EXPECT_TRUE(F->hasLazyArguments());

  // Checking for empty or size shouldn't force arguments to be instantiated.
  EXPECT_FALSE(F->arg_empty());
  EXPECT_TRUE(F->hasLazyArguments());
  EXPECT_EQ(2u, F->arg_size());
  EXPECT_TRUE(F->hasLazyArguments());

  // The argument list should be populated at first access.
  (void)F->arg_begin();
  EXPECT_FALSE(F->hasLazyArguments());
}

TEST(FunctionTest, stealArgumentListFrom) {
  LLVMContext C;

  Type *ArgTypes[] = {Type::getInt8Ty(C), Type::getInt32Ty(C)};
  FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), ArgTypes, false);
  std::unique_ptr<Function> F1(
      Function::Create(FTy, GlobalValue::ExternalLinkage, "F1"));
  std::unique_ptr<Function> F2(
      Function::Create(FTy, GlobalValue::ExternalLinkage, "F1"));
  EXPECT_TRUE(F1->hasLazyArguments());
  EXPECT_TRUE(F2->hasLazyArguments());

  // Steal arguments before they've been accessed.  Nothing should change; both
  // functions should still have lazy arguments.
  //
  //   steal(empty); drop (empty)
  F1->stealArgumentListFrom(*F2);
  EXPECT_TRUE(F1->hasLazyArguments());
  EXPECT_TRUE(F2->hasLazyArguments());

  // Save arguments from F1 for later assertions.  F1 won't have lazy arguments
  // anymore.
  SmallVector<Argument *, 4> Args;
  for (Argument &A : F1->args())
    Args.push_back(&A);
  EXPECT_EQ(2u, Args.size());
  EXPECT_FALSE(F1->hasLazyArguments());

  // Steal arguments from F1 to F2.  F1's arguments should be lazy again.
  //
  //   steal(real); drop (empty)
  F2->stealArgumentListFrom(*F1);
  EXPECT_TRUE(F1->hasLazyArguments());
  EXPECT_FALSE(F2->hasLazyArguments());
  unsigned I = 0;
  for (Argument &A : F2->args()) {
    EXPECT_EQ(Args[I], &A);
    I++;
  }
  EXPECT_EQ(2u, I);

  // Check that arguments in F1 don't have pointer equality with the saved ones.
  // This also instantiates F1's arguments.
  I = 0;
  for (Argument &A : F1->args()) {
    EXPECT_NE(Args[I], &A);
    I++;
  }
  EXPECT_EQ(2u, I);
  EXPECT_FALSE(F1->hasLazyArguments());
  EXPECT_FALSE(F2->hasLazyArguments());

  // Steal back from F2.  F2's arguments should be lazy again.
  //
  //   steal(real); drop (real)
  F1->stealArgumentListFrom(*F2);
  EXPECT_FALSE(F1->hasLazyArguments());
  EXPECT_TRUE(F2->hasLazyArguments());
  I = 0;
  for (Argument &A : F1->args()) {
    EXPECT_EQ(Args[I], &A);
    I++;
  }
  EXPECT_EQ(2u, I);

  // Steal from F2 a second time.  Now both functions should have lazy
  // arguments.
  //
  //   steal(empty); drop (real)
  F1->stealArgumentListFrom(*F2);
  EXPECT_TRUE(F1->hasLazyArguments());
  EXPECT_TRUE(F2->hasLazyArguments());
}

} // end namespace
<|endoftext|>


<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0

#include "test.hpp"

#define private public
#define protected public
#include "iceoryx_posh/internal/roudi/service_registry.hpp"
#include "iceoryx_utils/cxx/string.hpp"
#undef protected
#undef private

using namespace ::testing;
using ::testing::Return;

class ServiceRegistry_test : public Test
{
  public:
    using ServiceDescription = iox::capro::ServiceDescription;
    virtual void SetUp()
    {
        internal::CaptureStdout();
    }

    virtual void TearDown()
    {
        std::string output = internal::GetCapturedStdout();
        if (Test::HasFailure())
        {
            std::cout << output << std::endl;
        }
    }
    iox::roudi::ServiceRegistry registry;
    iox::roudi::ServiceRegistry::InstanceSet_t searchResults;

    iox::cxx::string<100> AnyInstanceString{iox::capro::AnyInstanceString};
};

TEST_F(ServiceRegistry_test, SingleAdd)
{
    registry.add("a", "b");
    registry.find(searchResults, "a", AnyInstanceString);

    EXPECT_THAT(searchResults.size(), Eq(1));
    EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("b")));
}

TEST_F(ServiceRegistry_test, SingleMultiAdd)
{
    registry.add("a", "b");
    registry.add("a", "c");
    registry.add("a", "d");
    registry.find(searchResults, "a", AnyInstanceString);

    EXPECT_THAT(searchResults.size(), Eq(3));

    bool hasFoundB = false;
    bool hasFoundC = false;
    bool hasFoundD = false;

    for (auto& e : searchResults)
    {
        if (e == iox::cxx::string<100>("b"))
            hasFoundB = true;
        if (e == iox::cxx::string<100>("c"))
            hasFoundC = true;
        if (e == iox::cxx::string<100>("d"))
            hasFoundD = true;
    }

    EXPECT_THAT(hasFoundB && hasFoundC && hasFoundD, Eq(true));
}

TEST_F(ServiceRegistry_test, SingleAddMultiService)
{
    registry.add("a", "b");
    registry.add("c", "d");
    registry.find(searchResults, "a", AnyInstanceString);

    EXPECT_THAT(searchResults.size(), Eq(1));
    EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("b")));
    searchResults.clear();

    registry.find(searchResults, "c", AnyInstanceString);
    EXPECT_THAT(searchResults.size(), Eq(1));
    EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("d")));
}

TEST_F(ServiceRegistry_test, FindSpecificInstance)
{
    registry.add("a", "b");
    registry.add("a", "c");
    registry.add("a", "d");
    registry.find(searchResults, "a", "c");

    EXPECT_THAT(searchResults.size(), Eq(1));
    EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("c")));
}

TEST_F(ServiceRegistry_test, FindSpecificNonExistingInstance)
{
    registry.add("a", "b");
    registry.add("a", "c");
    registry.add("a", "d");
    registry.find(searchResults, "a", "g");

    EXPECT_THAT(searchResults.size(), Eq(0));
}

TEST_F(ServiceRegistry_test, RemoveSingle)
{
    registry.add("a", "b");
    registry.add("a", "c");
    registry.add("a", "d");

    registry.remove("a", "c");

    registry.find(searchResults, "a", "c");
    EXPECT_THAT(searchResults.size(), Eq(0));
}

TEST_F(ServiceRegistry_test, RemoveSingleFromMultipleServices)
{
    registry.add("a", "b");
    registry.add("b", "c");
    registry.add("c", "d");

    registry.remove("b", "c");

    registry.find(searchResults, "b", "c");
    EXPECT_THAT(searchResults.size(), Eq(0));
}

TEST_F(ServiceRegistry_test, RemoveAll)
{
    registry.add("a", "b");
    registry.add("a", "c");
    registry.add("a", "d");

    registry.remove("a", "b");
    registry.remove("a", "c");
    registry.remove("a", "d");

    registry.find(searchResults, "a", AnyInstanceString);
    EXPECT_THAT(searchResults.size(), Eq(0));
}

TEST_F(ServiceRegistry_test, GetServiceMap)
{
    iox::roudi::ServiceRegistry::serviceMap_t serviceMap;

    registry.add("a", "b");
    // add same service a, instance c to check if in registry only one entry is created
    registry.add("a", "c");
    registry.add("a", "c");
    registry.add("a", "d");
    registry.add("e", "f");

    serviceMap = registry.getServiceMap();

    bool mapA = false;
    bool mapE = false;

    for (auto const& x : serviceMap)
    {
        if (x.first == iox::cxx::string<100>("a"))
        {
            ASSERT_THAT(x.second.instanceSet.size(), Eq(3));
            mapA = true;
            EXPECT_THAT(x.second.instanceSet[0], Eq(iox::cxx::string<100>("b")));
            EXPECT_THAT(x.second.instanceSet[1], Eq(iox::cxx::string<100>("c")));
            EXPECT_THAT(x.second.instanceSet[2], Eq(iox::cxx::string<100>("d")));
        }

        if (x.first == iox::cxx::string<100>("e"))
            mapE = true;
    }

    EXPECT_THAT(mapA && mapE, Eq(true));
}
<commit_msg>iox-##529 remove 'define private public' from test_roudi_service_registry.cpp<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0

#include "test.hpp"

#include "iceoryx_posh/internal/roudi/service_registry.hpp"
#include "iceoryx_utils/cxx/string.hpp"

using namespace ::testing;
using ::testing::Return;

class ServiceRegistry_test : public Test
{
  public:
    using ServiceDescription = iox::capro::ServiceDescription;
    virtual void SetUp()
    {
        internal::CaptureStdout();
    }

    virtual void TearDown()
    {
        std::string output = internal::GetCapturedStdout();
        if (Test::HasFailure())
        {
            std::cout << output << std::endl;
        }
    }
    iox::roudi::ServiceRegistry registry;
    iox::roudi::ServiceRegistry::InstanceSet_t searchResults;

    iox::cxx::string<100> AnyInstanceString{iox::capro::AnyInstanceString};
};

TEST_F(ServiceRegistry_test, SingleAdd)
{
    registry.add("a", "b");
    registry.find(searchResults, "a", AnyInstanceString);

    EXPECT_THAT(searchResults.size(), Eq(1));
    EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("b")));
}

TEST_F(ServiceRegistry_test, SingleMultiAdd)
{
    registry.add("a", "b");
    registry.add("a", "c");
    registry.add("a", "d");
    registry.find(searchResults, "a", AnyInstanceString);

    EXPECT_THAT(searchResults.size(), Eq(3));

    bool hasFoundB = false;
    bool hasFoundC = false;
    bool hasFoundD = false;

    for (auto& e : searchResults)
    {
        if (e == iox::cxx::string<100>("b"))
            hasFoundB = true;
        if (e == iox::cxx::string<100>("c"))
            hasFoundC = true;
        if (e == iox::cxx::string<100>("d"))
            hasFoundD = true;
    }

    EXPECT_THAT(hasFoundB && hasFoundC && hasFoundD, Eq(true));
}

TEST_F(ServiceRegistry_test, SingleAddMultiService)
{
    registry.add("a", "b");
    registry.add("c", "d");
    registry.find(searchResults, "a", AnyInstanceString);

    EXPECT_THAT(searchResults.size(), Eq(1));
    EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("b")));
    searchResults.clear();

    registry.find(searchResults, "c", AnyInstanceString);
    EXPECT_THAT(searchResults.size(), Eq(1));
    EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("d")));
}

TEST_F(ServiceRegistry_test, FindSpecificInstance)
{
    registry.add("a", "b");
    registry.add("a", "c");
    registry.add("a", "d");
    registry.find(searchResults, "a", "c");

    EXPECT_THAT(searchResults.size(), Eq(1));
    EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("c")));
}

TEST_F(ServiceRegistry_test, FindSpecificNonExistingInstance)
{
    registry.add("a", "b");
    registry.add("a", "c");
    registry.add("a", "d");
    registry.find(searchResults, "a", "g");

    EXPECT_THAT(searchResults.size(), Eq(0));
}

TEST_F(ServiceRegistry_test, RemoveSingle)
{
    registry.add("a", "b");
    registry.add("a", "c");
    registry.add("a", "d");

    registry.remove("a", "c");

    registry.find(searchResults, "a", "c");
    EXPECT_THAT(searchResults.size(), Eq(0));
}

TEST_F(ServiceRegistry_test, RemoveSingleFromMultipleServices)
{
    registry.add("a", "b");
    registry.add("b", "c");
    registry.add("c", "d");

    registry.remove("b", "c");

    registry.find(searchResults, "b", "c");
    EXPECT_THAT(searchResults.size(), Eq(0));
}

TEST_F(ServiceRegistry_test, RemoveAll)
{
    registry.add("a", "b");
    registry.add("a", "c");
    registry.add("a", "d");

    registry.remove("a", "b");
    registry.remove("a", "c");
    registry.remove("a", "d");

    registry.find(searchResults, "a", AnyInstanceString);
    EXPECT_THAT(searchResults.size(), Eq(0));
}

TEST_F(ServiceRegistry_test, GetServiceMap)
{
    iox::roudi::ServiceRegistry::serviceMap_t serviceMap;

    registry.add("a", "b");
    // add same service a, instance c to check if in registry only one entry is created
    registry.add("a", "c");
    registry.add("a", "c");
    registry.add("a", "d");
    registry.add("e", "f");

    serviceMap = registry.getServiceMap();

    bool mapA = false;
    bool mapE = false;

    for (auto const& x : serviceMap)
    {
        if (x.first == iox::cxx::string<100>("a"))
        {
            ASSERT_THAT(x.second.instanceSet.size(), Eq(3));
            mapA = true;
            EXPECT_THAT(x.second.instanceSet[0], Eq(iox::cxx::string<100>("b")));
            EXPECT_THAT(x.second.instanceSet[1], Eq(iox::cxx::string<100>("c")));
            EXPECT_THAT(x.second.instanceSet[2], Eq(iox::cxx::string<100>("d")));
        }

        if (x.first == iox::cxx::string<100>("e"))
            mapE = true;
    }

    EXPECT_THAT(mapA && mapE, Eq(true));
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// 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.

namespace iox
{
namespace cxx
{
template <typename T>
inline optional<T>::optional(const nullopt_t&) noexcept
{
}

template <typename T>
inline optional<T>::optional() noexcept
    : optional(nullopt_t())
{
}

template <typename T>
inline optional<T>::optional(T&& value) noexcept
{
    construct_value(std::forward<T>(value));
}

template <typename T>
inline optional<T>::optional(const optional& rhs) noexcept
{
    if (rhs.m_hasValue)
    {
        construct_value(rhs.value());
    }
}

template <typename T>
inline optional<T>::optional(optional&& rhs) noexcept
{
    if (rhs.m_hasValue)
    {
        construct_value(std::move(rhs.value()));
        rhs.destruct_value();
    }
}

template <typename T>
inline optional<T>& optional<T>::operator=(const optional& rhs) noexcept
{
    if (this != &rhs)
    {
        if (!rhs.m_hasValue && m_hasValue)
        {
            destruct_value();
        }
        else if (rhs.m_hasValue && m_hasValue)
        {
            value() = rhs.value();
        }
        else if (rhs.m_hasValue && !m_hasValue)
        {
            construct_value(rhs.value());
        }
    }
    return *this;
}

template <typename T>
inline optional<T>& optional<T>::operator=(optional&& rhs) noexcept
{
    if (this != &rhs)
    {
        if (!rhs.m_hasValue && m_hasValue)
        {
            destruct_value();
        }
        else if (rhs.m_hasValue && m_hasValue)
        {
            value() = std::move(rhs.value());
        }
        else if (rhs.m_hasValue && !m_hasValue)
        {
            construct_value(std::move(rhs.value()));
        }
        if (rhs.m_hasValue)
        {
            rhs.destruct_value();
        }
    }
    return *this;
}

template <typename T>
inline optional<T>::~optional() noexcept
{
    if (m_hasValue)
    {
        destruct_value();
    }
}

template <typename T>
template <typename U>
inline typename ::std::enable_if<!::std::is_same<U, optional<T>&>::value, optional<T>>::type& optional<T>::
operator=(U&& newValue) noexcept
{
    if (m_hasValue)
    {
/// @todo broken msvc compiler, see:
///  https://developercommunity.visualstudio.com/content/problem/858688/stdforward-none-of-these-2-overloads-could-convert.html
/// remove this as soon as it is fixed;
#ifdef _WIN32
        value() = newValue;
#else
        value() = std::forward<T>(newValue);
#endif
    }
    else
    {
/// @todo again broken msvc compiler
#ifdef _WIN32
        construct_value(newValue);
#else
        construct_value(std::forward<T>(newValue));
#endif
    }
    return *this;
}

template <typename T>
constexpr inline bool optional<T>::operator==(const optional<T>& rhs) const noexcept
{
    return (!m_hasValue && !rhs.m_hasValue) || ((m_hasValue && rhs.m_hasValue) && (value() == rhs.value()));
}

template <typename T>
constexpr inline bool optional<T>::operator==(const nullopt_t&) const noexcept
{
    return !m_hasValue;
}

template <typename T>
constexpr inline bool optional<T>::operator!=(const optional<T>& rhs) const noexcept
{
    return !(*this == rhs);
}

template <typename T>
constexpr inline bool optional<T>::operator!=(const nullopt_t& rhs) const noexcept
{
    return !(*this == rhs);
}

template <typename T>
inline const T* optional<T>::operator->() const noexcept
{
    return &value();
}

template <typename T>
inline const T& optional<T>::operator*() const noexcept
{
    return value();
}

template <typename T>
inline T* optional<T>::operator->() noexcept
{
    return const_cast<T*>(const_cast<const optional*>(this)->operator->());
}

template <typename T>
inline T& optional<T>::operator*() noexcept
{
    return const_cast<T&>(const_cast<const optional*>(this)->operator*());
}

template <typename T>
inline constexpr optional<T>::operator bool() const noexcept
{
    return m_hasValue;
}

template <typename T>
template <typename... Targs>
inline T& optional<T>::emplace(Targs&&... args) noexcept
{
    if (m_hasValue)
    {
        destruct_value();
    }

    construct_value(std::forward<Targs>(args)...);
    return value();
}

template <typename T>
inline constexpr bool optional<T>::has_value() const noexcept
{
    return m_hasValue;
}

template <typename T>
inline void optional<T>::reset() noexcept
{
    if (m_hasValue)
    {
        destruct_value();
    }
}

template <typename T>
    inline T& optional<T>::value() & noexcept
{
    auto data = static_cast<T*>(static_cast<void*>(m_data));
    return *data;
}

template <typename T>
inline const T& optional<T>::value() const& noexcept
{
    auto data = static_cast<const T*>(static_cast<const void*>(m_data));
    return *data;
}

template <typename T>
    inline T&& optional<T>::value() && noexcept
{
    auto data = static_cast<T*>(static_cast<void*>(m_data));
    return std::move(*data);
}

template <typename T>
inline const T&& optional<T>::value() const&& noexcept
{
    auto data = static_cast<const T*>(static_cast<const void*>(m_data));
    return std::move(*data);
}

template <typename T>
template <typename U>
inline constexpr T optional<T>::value_or(U&& default_value) const noexcept
{
    return (m_hasValue) ? value() : std::forward<U>(default_value);
}

template <typename T>
template <typename... Targs>
inline void optional<T>::construct_value(Targs&&... args) noexcept
{
    new (&value()) T(std::forward<Targs>(args)...);
    m_hasValue = true;
}

template <typename T>
inline void optional<T>::destruct_value() noexcept
{
    value().~T();
    m_hasValue = false;
}

template <typename OptionalBaseType, typename... Targs>
inline optional<OptionalBaseType> make_optional(Targs&&... args) noexcept
{
    optional<OptionalBaseType> returnValue = nullopt_t();
    returnValue.emplace(std::forward<Targs>(args)...);
    return returnValue;
}
} // namespace cxx
} // namespace iox
<commit_msg>iox-#33 removed undefined behavior from optional - if you dereference a nullopt you essentially dereference a nullptr now<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// 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.

namespace iox
{
namespace cxx
{
template <typename T>
inline optional<T>::optional(const nullopt_t&) noexcept
{
}

template <typename T>
inline optional<T>::optional() noexcept
    : optional(nullopt_t())
{
}

template <typename T>
inline optional<T>::optional(T&& value) noexcept
{
    construct_value(std::forward<T>(value));
}

template <typename T>
inline optional<T>::optional(const optional& rhs) noexcept
{
    if (rhs.m_hasValue)
    {
        construct_value(rhs.value());
    }
}

template <typename T>
inline optional<T>::optional(optional&& rhs) noexcept
{
    if (rhs.m_hasValue)
    {
        construct_value(std::move(rhs.value()));
        rhs.destruct_value();
    }
}

template <typename T>
inline optional<T>& optional<T>::operator=(const optional& rhs) noexcept
{
    if (this != &rhs)
    {
        if (!rhs.m_hasValue && m_hasValue)
        {
            destruct_value();
        }
        else if (rhs.m_hasValue && m_hasValue)
        {
            value() = rhs.value();
        }
        else if (rhs.m_hasValue && !m_hasValue)
        {
            construct_value(rhs.value());
        }
    }
    return *this;
}

template <typename T>
inline optional<T>& optional<T>::operator=(optional&& rhs) noexcept
{
    if (this != &rhs)
    {
        if (!rhs.m_hasValue && m_hasValue)
        {
            destruct_value();
        }
        else if (rhs.m_hasValue && m_hasValue)
        {
            value() = std::move(rhs.value());
        }
        else if (rhs.m_hasValue && !m_hasValue)
        {
            construct_value(std::move(rhs.value()));
        }
        if (rhs.m_hasValue)
        {
            rhs.destruct_value();
        }
    }
    return *this;
}

template <typename T>
inline optional<T>::~optional() noexcept
{
    if (m_hasValue)
    {
        destruct_value();
    }
}

template <typename T>
template <typename U>
inline typename ::std::enable_if<!::std::is_same<U, optional<T>&>::value, optional<T>>::type& optional<T>::
operator=(U&& newValue) noexcept
{
    if (m_hasValue)
    {
/// @todo broken msvc compiler, see:
///  https://developercommunity.visualstudio.com/content/problem/858688/stdforward-none-of-these-2-overloads-could-convert.html
/// remove this as soon as it is fixed;
#ifdef _WIN32
        value() = newValue;
#else
        value() = std::forward<T>(newValue);
#endif
    }
    else
    {
/// @todo again broken msvc compiler
#ifdef _WIN32
        construct_value(newValue);
#else
        construct_value(std::forward<T>(newValue));
#endif
    }
    return *this;
}

template <typename T>
constexpr inline bool optional<T>::operator==(const optional<T>& rhs) const noexcept
{
    return (!m_hasValue && !rhs.m_hasValue) || ((m_hasValue && rhs.m_hasValue) && (value() == rhs.value()));
}

template <typename T>
constexpr inline bool optional<T>::operator==(const nullopt_t&) const noexcept
{
    return !m_hasValue;
}

template <typename T>
constexpr inline bool optional<T>::operator!=(const optional<T>& rhs) const noexcept
{
    return !(*this == rhs);
}

template <typename T>
constexpr inline bool optional<T>::operator!=(const nullopt_t& rhs) const noexcept
{
    return !(*this == rhs);
}

template <typename T>
inline const T* optional<T>::operator->() const noexcept
{
    return &value();
}

template <typename T>
inline const T& optional<T>::operator*() const noexcept
{
    return value();
}

template <typename T>
inline T* optional<T>::operator->() noexcept
{
    return const_cast<T*>(const_cast<const optional*>(this)->operator->());
}

template <typename T>
inline T& optional<T>::operator*() noexcept
{
    return const_cast<T&>(const_cast<const optional*>(this)->operator*());
}

template <typename T>
inline constexpr optional<T>::operator bool() const noexcept
{
    return m_hasValue;
}

template <typename T>
template <typename... Targs>
inline T& optional<T>::emplace(Targs&&... args) noexcept
{
    if (m_hasValue)
    {
        destruct_value();
    }

    construct_value(std::forward<Targs>(args)...);
    return value();
}

template <typename T>
inline constexpr bool optional<T>::has_value() const noexcept
{
    return m_hasValue;
}

template <typename T>
inline void optional<T>::reset() noexcept
{
    if (m_hasValue)
    {
        destruct_value();
    }
}

template <typename T>
    inline T& optional<T>::value() & noexcept
{
    auto data = (has_value()) ? static_cast<T*>(static_cast<void*>(m_data)) : nullptr;
    return *data;
}

template <typename T>
inline const T& optional<T>::value() const& noexcept
{
    return const_cast<optional<T>*>(this)->value();
}

template <typename T>
    inline T&& optional<T>::value() && noexcept
{
    auto data = (has_value()) ? static_cast<T*>(static_cast<void*>(m_data)) : nullptr;
    return std::move(*data);
}

template <typename T>
inline const T&& optional<T>::value() const&& noexcept
{
    return std::move(*const_cast<optional<T>*>(this)->value());
}

template <typename T>
template <typename U>
inline constexpr T optional<T>::value_or(U&& default_value) const noexcept
{
    return (m_hasValue) ? value() : std::forward<U>(default_value);
}

template <typename T>
template <typename... Targs>
inline void optional<T>::construct_value(Targs&&... args) noexcept
{
    new (static_cast<T*>(static_cast<void*>(m_data))) T(std::forward<Targs>(args)...);
    m_hasValue = true;
}

template <typename T>
inline void optional<T>::destruct_value() noexcept
{
    value().~T();
    m_hasValue = false;
}

template <typename OptionalBaseType, typename... Targs>
inline optional<OptionalBaseType> make_optional(Targs&&... args) noexcept
{
    optional<OptionalBaseType> returnValue = nullopt_t();
    returnValue.emplace(std::forward<Targs>(args)...);
    return returnValue;
}
} // namespace cxx
} // namespace iox
<|endoftext|>


<commit_before>/*
 * File:   STUNClient.cpp
 * Author: daniel
 *
 * Created on January 1, 2016, 12:50 PM
 */

#include "sip/STUNClient.h"
#include "network/UDPWrapper.h"

#include <chrono>

using namespace ohmcomm::sip;

const std::vector<std::string> STUNClient::STUN_SERVERS = {
    "stun.stunprotocol.org",
    "stun.sipgate.net",
    //"stun.l.google.com:19302",
    "stun01.sipphone.com",
    "stunserver.org"
};

const std::string STUNClient::DEFAULT_SOURCE_IP{"0.0.0.0"};

STUNClient::STUNClient()
{
}

STUNClient::~STUNClient()
{
}

const std::tuple<bool, std::string, unsigned short> STUNClient::retrieveSIPInfo()
{
    std::tuple<bool, std::string, unsigned short> result = std::make_tuple(false, "", 0);
    unsigned short index = 0;
    while(index < STUN_SERVERS.size() && std::get<0>(result) == false)
    {
        const std::string serverIP = Utility::getAddressForHostName(STUN_SERVERS[index]);
        if(!serverIP.empty())
        {
            result = testSTUNServer(serverIP);
        }
        ++index;
    }
    std::cout << "STUN: Found result: " << std::get<1>(result) << ':' << std::get<2>(result) << std::endl;
    return result;
}

const std::tuple<bool, std::string, unsigned short> STUNClient::testSTUNServer(const std::string& stunServer, unsigned short serverPort)
{
    ohmcomm::network::UDPWrapper network(LOCAL_PORT, stunServer, serverPort);

    std::cout << "STUN: Testing ... " << stunServer << ':' << serverPort << std::endl;
    const unsigned int sendSize = createRequestMessage(STUN_BINDING_REQUEST);
    int receivedSize = INVALID_SOCKET;
    uint8_t numRetries = MAX_RETRIES;
    do
    {
        //we re-send until we receive something (or run out of retries)
        network.sendData(buffer, sendSize);
        receivedSize = network.receiveData(buffer, BUFFER_SIZE).status;
        --numRetries;
    }
    while(numRetries > 0 && receivedSize == ohmcomm::network::UDPWrapper::RECEIVE_TIMEOUT);
    if (receivedSize != INVALID_SOCKET && receivedSize != ohmcomm::network::UDPWrapper::RECEIVE_TIMEOUT && receivedSize >= STUN_HEADER_SIZE)
    {
        //handle response
        //1. check response-type
        const uint16_t responseType = ntohs(*(reinterpret_cast<uint16_t*>(buffer)));
        if(responseType == STUN_BINDING_RESPONSE || responseType == STUN_BINDING_ERROR_RESPONSE)
        {
            //1.1 read body-length
            const uint16_t bodySize = ntohs(*(reinterpret_cast<uint16_t*>(buffer + 2)));
            //1.2 check magic cookie and transaction-ID
            const uint32_t magicCookie = ntohl(*(reinterpret_cast<uint32_t*>(buffer + 4)));
            const char* transID = (const char*)(buffer + 8);
            if(magicCookie != MAGIC_COOKIE)
            {
                std::cout << "STUN: Magic Cookie does not match!" << std::endl;
            }
            else if(transactionID.compare(transID) != 0)
            {
                std::cout << "STUN: Transaction-IDs do not match!" << std::endl;
            }
            else //2. check attributes
            {
                //2.0 read attributes
                unsigned int position = STUN_HEADER_SIZE;
                std::vector<STUNClient::STUNAttribute> attributes;
                auto attribute = readAttribute(bodySize, position);
                int mappedAddressIndex = -1, xorMappedAddressIndex = -1, alternateServerIndex = -1, errorCodeIndex = -1;
                while(attribute.type != STUN_INVALID_ATTRIBUTE)
                {
                    attributes.push_back(attribute);
                    position += 4 + attribute.valueLength;

                    //attributes may occur more than once, but only the first needs to be processed
                    if(attribute.type == STUN_MAPPED_ADDRESS && mappedAddressIndex == -1)
                        mappedAddressIndex = attributes.size()-1;
                    if(attribute.type == STUN_XOR_MAPPED_ADDRESS && xorMappedAddressIndex == -1)
                        xorMappedAddressIndex = attributes.size()-1;
                    if(attribute.type == STUN_ALTERNATE_SERVER && alternateServerIndex == -1)
                        alternateServerIndex = attributes.size()-1;
                    if(attribute.type == STUN_ERROR_CODE && errorCodeIndex == -1)
                        errorCodeIndex = attributes.size()-1;

                    attribute = readAttribute(bodySize, position);
                }
                //2.1. check MAPPED-ADDRESS
                if(mappedAddressIndex != -1 && attributes[mappedAddressIndex].valueLength > 0)
                {
                    std::tuple<std::string, unsigned short> address = readMappedAddress(attributes[mappedAddressIndex], magicCookie);
                    return std::make_tuple(true, std::get<0>(address), std::get<1>(address));
                }
                //2.2 check XOR-MAPPED-ADDRESS
                if(xorMappedAddressIndex != -1 && attributes[xorMappedAddressIndex].valueLength > 0)
                {
                    std::tuple<std::string, unsigned short> address = readMappedAddress(attributes[mappedAddressIndex], magicCookie);
                    return std::make_tuple(true, std::get<0>(address), std::get<1>(address));
                }
                //2.3 check ALTERNATE-SERVER
                if(alternateServerIndex != -1 && attributes[alternateServerIndex].valueLength > 0)
                {
                    //try to contact alternate server
                    const std::tuple<std::string, unsigned short> serverAddress = readMappedAddress(attributes[mappedAddressIndex], magicCookie);
                    return testSTUNServer(std::get<0>(serverAddress), std::get<1>(serverAddress));
                }
                //2.4 print info from ERROR-CODE
                if(errorCodeIndex != -1 && attributes[errorCodeIndex].valueLength > 0)
                {
                    const STUNAttribute& attribute = attributes[errorCodeIndex];
                    //the class (the hundreds from the error-code) are the least 3 bits of the third byte
                    uint8_t errorClass = *((uint8_t*)(attribute.valuePointer + 2)) & 0x7;
                    uint8_t errorNumber = *((uint8_t*)(attribute.valuePointer + 3));
                    uint16_t errorCode = errorClass * 100 + errorNumber;
                    std::string reason(attribute.valuePointer + 4, attribute.valueLength - 4);
                    std::cout << "STUN: Error " << errorCode << " received: " << reason << std::endl;
                }
            }
        }
        else
        {
            std::cout << "STUN: Invalid response type: " << responseType << std::endl;
        }
    }
    return std::make_tuple(false, "", 0);
}

unsigned int STUNClient::createRequestMessage(STUNMessageType type, const std::string& messageBody)
{
    uint16_t requestType = htons(type);
    memcpy((void*)buffer, &requestType, 2);
    uint16_t bodySize = htons((uint16_t)messageBody.size());
    memcpy((buffer + 2), &bodySize, 2);
    uint32_t magicCookie = htonl(MAGIC_COOKIE);
    memcpy((buffer + 4), &magicCookie, 4);
    createTransactionID((char*)(buffer + 8));
    transactionID = std::string(buffer + 8, 12);
    if(messageBody.size() > 0)
    {
        memcpy((buffer + 20), messageBody.data(), messageBody.size());
    }
    return messageBody.size() + STUN_HEADER_SIZE;
}

void STUNClient::createTransactionID(char* position)
{
    std::srand(::time(nullptr));
    uint32_t rnd = std::rand();
    memcpy(position, &rnd, 4);
    rnd = std::rand();
    memcpy(position + 4, &rnd, 4);
    rnd = std::rand();
    memcpy(position + 8, &rnd, 4);
}

const STUNClient::STUNAttribute STUNClient::readAttribute(unsigned int maxSize, unsigned int position) const
{
    if(maxSize < position + 2)
    {
        return {STUN_INVALID_ATTRIBUTE, nullptr, 0};
    }
    const uint16_t attributeType = ntohs(*(reinterpret_cast<const uint16_t*>(buffer + position)));
    const uint16_t attributeContentLength = ntohs(*(reinterpret_cast<const uint16_t*>(buffer + position + 2)));
    return {attributeType, (const char*)(buffer + position + 4), attributeContentLength};
}

const std::tuple<std::string, unsigned short> STUNClient::readMappedAddress(const STUNAttribute& attribute, const uint32_t magicCookie)
{
    const uint16_t addressFamily = ntohs(*((uint16_t*)attribute.valuePointer));
    uint16_t port = ntohs(*((uint16_t*)(attribute.valuePointer + 2)));
    //RFC 5389 section 15.2:
    //"X-Port is computed by taking the mapped port in host byte order,
    //XOR'ing it with the most significant 16 bits of the magic cookie"
    if(attribute.type == STUN_XOR_MAPPED_ADDRESS)
    {
        port = port xor (magicCookie >> 16);
    }
    if(addressFamily == MAPPED_ADDRESS_IPv4)
    {
        unsigned char* addressPtr = (unsigned char*)attribute.valuePointer + 4;
        const uint32_t xoredAddress = *((uint32_t*)addressPtr) xor magicCookie;
        std::string address("");
        if(attribute.type == STUN_XOR_MAPPED_ADDRESS)
        {
            //RFC 5389 section 15.2:
            //"If the IP address family is IPv4, X-Address is computed by taking the mapped IP address in host byte order,
            //XOR'ing it with the magic cookie."
            addressPtr = reinterpret_cast<unsigned char*>(xoredAddress);
        }
        address.append(std::to_string(*addressPtr)).append(".");
        address.append(std::to_string(*(addressPtr+1))).append(".");
        address.append(std::to_string(*(addressPtr+2))).append(".");
        address.append(std::to_string(*(addressPtr+3)));
        return std::make_tuple(address, port);
    }
    else if(addressFamily == MAPPED_ADDRESS_IPv6)
    {
        const unsigned char* addressPtr = (unsigned char*)attribute.valuePointer + 4;
        std::string address("");
        //TODO RFC 5389 section 15.2:
        //"If the IP address family is IPv6, X-Address is computed by taking the mapped IP address
        //in host byte order, XOR'ing it with the concatenation of the magic cookie and the 96-bit transaction ID"
        //read hexadecimal values from ptr and join with ':'
        uint8_t part = *addressPtr;
        address.append(Utility::toHexString(part));
        for(unsigned int i = 1; i < 16; i++)
        {
            address.append(":");
            part = *(addressPtr + 1);
            address.append(Utility::toHexString(part));
        }
        return std::make_tuple(address, port);
    }
    return std::make_tuple("", 0);
}<commit_msg>Fixed compiler error in VC++ not recognizing xor operator Signed-off-by:doe300 <stadeldani@web.de><commit_after>/*
 * File:   STUNClient.cpp
 * Author: daniel
 *
 * Created on January 1, 2016, 12:50 PM
 */

#include "sip/STUNClient.h"
#include "network/UDPWrapper.h"

#include <chrono>

using namespace ohmcomm::sip;

const std::vector<std::string> STUNClient::STUN_SERVERS = {
    "stun.stunprotocol.org",
    "stun.sipgate.net",
    //"stun.l.google.com:19302",
    "stun01.sipphone.com",
    "stunserver.org"
};

const std::string STUNClient::DEFAULT_SOURCE_IP{"0.0.0.0"};

STUNClient::STUNClient()
{
}

STUNClient::~STUNClient()
{
}

const std::tuple<bool, std::string, unsigned short> STUNClient::retrieveSIPInfo()
{
    std::tuple<bool, std::string, unsigned short> result = std::make_tuple(false, "", 0);
    unsigned short index = 0;
    while(index < STUN_SERVERS.size() && std::get<0>(result) == false)
    {
        const std::string serverIP = Utility::getAddressForHostName(STUN_SERVERS[index]);
        if(!serverIP.empty())
        {
            result = testSTUNServer(serverIP);
        }
        ++index;
    }
    std::cout << "STUN: Found result: " << std::get<1>(result) << ':' << std::get<2>(result) << std::endl;
    return result;
}

const std::tuple<bool, std::string, unsigned short> STUNClient::testSTUNServer(const std::string& stunServer, unsigned short serverPort)
{
    ohmcomm::network::UDPWrapper network(LOCAL_PORT, stunServer, serverPort);

    std::cout << "STUN: Testing ... " << stunServer << ':' << serverPort << std::endl;
    const unsigned int sendSize = createRequestMessage(STUN_BINDING_REQUEST);
    int receivedSize = INVALID_SOCKET;
    uint8_t numRetries = MAX_RETRIES;
    do
    {
        //we re-send until we receive something (or run out of retries)
        network.sendData(buffer, sendSize);
        receivedSize = network.receiveData(buffer, BUFFER_SIZE).status;
        --numRetries;
    }
    while(numRetries > 0 && receivedSize == ohmcomm::network::UDPWrapper::RECEIVE_TIMEOUT);
    if (receivedSize != INVALID_SOCKET && receivedSize != ohmcomm::network::UDPWrapper::RECEIVE_TIMEOUT && receivedSize >= STUN_HEADER_SIZE)
    {
        //handle response
        //1. check response-type
        const uint16_t responseType = ntohs(*(reinterpret_cast<uint16_t*>(buffer)));
        if(responseType == STUN_BINDING_RESPONSE || responseType == STUN_BINDING_ERROR_RESPONSE)
        {
            //1.1 read body-length
            const uint16_t bodySize = ntohs(*(reinterpret_cast<uint16_t*>(buffer + 2)));
            //1.2 check magic cookie and transaction-ID
            const uint32_t magicCookie = ntohl(*(reinterpret_cast<uint32_t*>(buffer + 4)));
            const char* transID = (const char*)(buffer + 8);
            if(magicCookie != MAGIC_COOKIE)
            {
                std::cout << "STUN: Magic Cookie does not match!" << std::endl;
            }
            else if(transactionID.compare(transID) != 0)
            {
                std::cout << "STUN: Transaction-IDs do not match!" << std::endl;
            }
            else //2. check attributes
            {
                //2.0 read attributes
                unsigned int position = STUN_HEADER_SIZE;
                std::vector<STUNClient::STUNAttribute> attributes;
                auto attribute = readAttribute(bodySize, position);
                int mappedAddressIndex = -1, xorMappedAddressIndex = -1, alternateServerIndex = -1, errorCodeIndex = -1;
                while(attribute.type != STUN_INVALID_ATTRIBUTE)
                {
                    attributes.push_back(attribute);
                    position += 4 + attribute.valueLength;

                    //attributes may occur more than once, but only the first needs to be processed
                    if(attribute.type == STUN_MAPPED_ADDRESS && mappedAddressIndex == -1)
                        mappedAddressIndex = attributes.size()-1;
                    if(attribute.type == STUN_XOR_MAPPED_ADDRESS && xorMappedAddressIndex == -1)
                        xorMappedAddressIndex = attributes.size()-1;
                    if(attribute.type == STUN_ALTERNATE_SERVER && alternateServerIndex == -1)
                        alternateServerIndex = attributes.size()-1;
                    if(attribute.type == STUN_ERROR_CODE && errorCodeIndex == -1)
                        errorCodeIndex = attributes.size()-1;

                    attribute = readAttribute(bodySize, position);
                }
                //2.1. check MAPPED-ADDRESS
                if(mappedAddressIndex != -1 && attributes[mappedAddressIndex].valueLength > 0)
                {
                    std::tuple<std::string, unsigned short> address = readMappedAddress(attributes[mappedAddressIndex], magicCookie);
                    return std::make_tuple(true, std::get<0>(address), std::get<1>(address));
                }
                //2.2 check XOR-MAPPED-ADDRESS
                if(xorMappedAddressIndex != -1 && attributes[xorMappedAddressIndex].valueLength > 0)
                {
                    std::tuple<std::string, unsigned short> address = readMappedAddress(attributes[mappedAddressIndex], magicCookie);
                    return std::make_tuple(true, std::get<0>(address), std::get<1>(address));
                }
                //2.3 check ALTERNATE-SERVER
                if(alternateServerIndex != -1 && attributes[alternateServerIndex].valueLength > 0)
                {
                    //try to contact alternate server
                    const std::tuple<std::string, unsigned short> serverAddress = readMappedAddress(attributes[mappedAddressIndex], magicCookie);
                    return testSTUNServer(std::get<0>(serverAddress), std::get<1>(serverAddress));
                }
                //2.4 print info from ERROR-CODE
                if(errorCodeIndex != -1 && attributes[errorCodeIndex].valueLength > 0)
                {
                    const STUNAttribute& attribute = attributes[errorCodeIndex];
                    //the class (the hundreds from the error-code) are the least 3 bits of the third byte
                    uint8_t errorClass = *((uint8_t*)(attribute.valuePointer + 2)) & 0x7;
                    uint8_t errorNumber = *((uint8_t*)(attribute.valuePointer + 3));
                    uint16_t errorCode = errorClass * 100 + errorNumber;
                    std::string reason(attribute.valuePointer + 4, attribute.valueLength - 4);
                    std::cout << "STUN: Error " << errorCode << " received: " << reason << std::endl;
                }
            }
        }
        else
        {
            std::cout << "STUN: Invalid response type: " << responseType << std::endl;
        }
    }
    return std::make_tuple(false, "", 0);
}

unsigned int STUNClient::createRequestMessage(STUNMessageType type, const std::string& messageBody)
{
    uint16_t requestType = htons(type);
    memcpy((void*)buffer, &requestType, 2);
    uint16_t bodySize = htons((uint16_t)messageBody.size());
    memcpy((buffer + 2), &bodySize, 2);
    uint32_t magicCookie = htonl(MAGIC_COOKIE);
    memcpy((buffer + 4), &magicCookie, 4);
    createTransactionID((char*)(buffer + 8));
    transactionID = std::string(buffer + 8, 12);
    if(messageBody.size() > 0)
    {
        memcpy((buffer + 20), messageBody.data(), messageBody.size());
    }
    return messageBody.size() + STUN_HEADER_SIZE;
}

void STUNClient::createTransactionID(char* position)
{
    std::srand(::time(nullptr));
    uint32_t rnd = std::rand();
    memcpy(position, &rnd, 4);
    rnd = std::rand();
    memcpy(position + 4, &rnd, 4);
    rnd = std::rand();
    memcpy(position + 8, &rnd, 4);
}

const STUNClient::STUNAttribute STUNClient::readAttribute(unsigned int maxSize, unsigned int position) const
{
    if(maxSize < position + 2)
    {
        return {STUN_INVALID_ATTRIBUTE, nullptr, 0};
    }
    const uint16_t attributeType = ntohs(*(reinterpret_cast<const uint16_t*>(buffer + position)));
    const uint16_t attributeContentLength = ntohs(*(reinterpret_cast<const uint16_t*>(buffer + position + 2)));
    return {attributeType, (const char*)(buffer + position + 4), attributeContentLength};
}

const std::tuple<std::string, unsigned short> STUNClient::readMappedAddress(const STUNAttribute& attribute, const uint32_t magicCookie)
{
    const uint16_t addressFamily = ntohs(*((uint16_t*)attribute.valuePointer));
    uint16_t port = ntohs(*((uint16_t*)(attribute.valuePointer + 2)));
    //RFC 5389 section 15.2:
    //"X-Port is computed by taking the mapped port in host byte order,
    //XOR'ing it with the most significant 16 bits of the magic cookie"
    if(attribute.type == STUN_XOR_MAPPED_ADDRESS)
    {
        port = port ^ (magicCookie >> 16);
    }
    if(addressFamily == MAPPED_ADDRESS_IPv4)
    {
        unsigned char* addressPtr = (unsigned char*)attribute.valuePointer + 4;
        const uint32_t xoredAddress = *((uint32_t*)addressPtr) xor magicCookie;
        std::string address("");
        if(attribute.type == STUN_XOR_MAPPED_ADDRESS)
        {
            //RFC 5389 section 15.2:
            //"If the IP address family is IPv4, X-Address is computed by taking the mapped IP address in host byte order,
            //XOR'ing it with the magic cookie."
            addressPtr = reinterpret_cast<unsigned char*>(xoredAddress);
        }
        address.append(std::to_string(*addressPtr)).append(".");
        address.append(std::to_string(*(addressPtr+1))).append(".");
        address.append(std::to_string(*(addressPtr+2))).append(".");
        address.append(std::to_string(*(addressPtr+3)));
        return std::make_tuple(address, port);
    }
    else if(addressFamily == MAPPED_ADDRESS_IPv6)
    {
        const unsigned char* addressPtr = (unsigned char*)attribute.valuePointer + 4;
        std::string address("");
        //TODO RFC 5389 section 15.2:
        //"If the IP address family is IPv6, X-Address is computed by taking the mapped IP address
        //in host byte order, XOR'ing it with the concatenation of the magic cookie and the 96-bit transaction ID"
        //read hexadecimal values from ptr and join with ':'
        uint8_t part = *addressPtr;
        address.append(Utility::toHexString(part));
        for(unsigned int i = 1; i < 16; i++)
        {
            address.append(":");
            part = *(addressPtr + 1);
            address.append(Utility::toHexString(part));
        }
        return std::make_tuple(address, port);
    }
    return std::make_tuple("", 0);
}<|endoftext|>


<commit_before>/***************************************************************
*
* Copyright (C) 1990-2008, Condor Team, Computer Sciences Department,
* University of Wisconsin-Madison, WI.
*
* 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 "condor_common.h"
#include "condor_uid.h"
#include "internet.h"
#include "network_adapter.linux.h"

#if HAVE_NET_IF_H
#  include <net/if.h>
#endif
#if HAVE_LINUX_SOCKIOS_H
#  include <linux/sockios.h>
#endif
#if HAVE_LINUX_TYPES_H
#  include <linux/types.h>
#endif
#if HAVE_OS_TYPES_H
#  include <os_types.h>
#endif
#if HAVE_LINUX_ETHTOOL_H
#  include <linux/ethtool.h>
#endif

// For now, the only wake-on-lan type we use is UDP magic
#if defined(HAVE_LINUX_ETHTOOL_H)
# define WAKE_MASK	( 0 | (WAKE_MAGIC) )
#endif

// Possible values for the above (OR them together) :
//	WAKE_PHY
//	WAKE_UCAST
//	WAKE_MCAST
//	WAKE_BCAST
//	WAKE_ARP
//	WAKE_MAGIC
//	WAKE_MAGICSECURE

/***************************************************************
* LinuxNetworkAdapter class
***************************************************************/

/// Constructor
LinuxNetworkAdapter::LinuxNetworkAdapter ( const char */*ip_string*/,
										   unsigned int ip_addr ) throw ()
		: UnixNetworkAdapter( ip_addr )
{
	m_wol_support_mask = 0;
	m_wol_enable_mask = 0;
}

LinuxNetworkAdapter::LinuxNetworkAdapter ( const char *name ) throw()
		: UnixNetworkAdapter( name )
{
	m_wol_support_mask = 0;
	m_wol_enable_mask = 0;
}

/// Destructor
LinuxNetworkAdapter::~LinuxNetworkAdapter ( void ) throw()
{
}

bool
LinuxNetworkAdapter::findAdapter( unsigned int ip_addr )
{
	bool			found = false;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifconf	ifc;
	int				sock;
	int				num_req = 3;	// Should be enough for a machine
									// with lo, eth0, eth1

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Loop 'til we've read in all the interfaces, keep increasing
	// the number that we try to read each time
	struct sockaddr_in	in_addr;
	ifc.ifc_buf = NULL;
	while( !found ) {
		int size	= num_req * sizeof(struct ifreq);
		ifc.ifc_buf	= (char *) calloc( num_req, sizeof(struct ifreq) );
		ifc.ifc_len	= size;

		int status = ioctl( sock, SIOCGIFCONF, &ifc );
		if ( status < 0 ) {
			derror( "ioctl(SIOCGIFCONF)" );
			break;
		}

		// Did we find it in the ifc?
		int				 num = ifc.ifc_len / sizeof(struct ifreq);
		struct ifreq	*ifr = ifc.ifc_req;
		for ( int i = 0;  i < num;  i++, ifr++ ) {
			struct sockaddr_in *in = (struct sockaddr_in*)&(ifr->ifr_addr);
			MemCopy( &in_addr, in, sizeof(struct sockaddr_in) );

			if ( in->sin_addr.s_addr == ip_addr ) {
				setIpAddr( *ifr );
				setName( *ifr );
				found = true;
				break;
			}
		}

		// If the length returned by ioctl() is the same as the size
		// we started with, it probably overflowed.... try again
		if ( (!found) && (ifc.ifc_len == size) ) {
			num_req += 2;
			free( ifc.ifc_buf );
			ifc.ifc_buf = NULL;
		}
		else {
			break;
		}
	}

	// Make sure we free up the buffer memory
	if ( ifc.ifc_buf ) {
		free( ifc.ifc_buf );
	}

	if ( found ) {
		dprintf( D_FULLDEBUG,
				 "Found interface %s that matches %s\n",
				 interfaceName( ),
				 sin_to_string( &in_addr )
				 );
	}
	else
	{
		m_if_name = NULL;
		dprintf( D_FULLDEBUG,
				 "No interface for address %s\n",
				 sin_to_string( &in_addr )
				 );
	}

	// Don't forget to close the socket!
	close( sock );

#endif
	return found;

}

bool
LinuxNetworkAdapter::findAdapter( const char *name )
{
	bool			found = false;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifreq	ifr;
	int				sock;

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Loop 'til we've read in all the interfaces, keep increasing
	// the number that we try to read each time
	getName( ifr, name );
	int status = ioctl( sock, SIOCGIFADDR, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFADDR)" );
	}
	else {
		found = true;
		setIpAddr( ifr );
	}

	if ( found ) {
		dprintf( D_FULLDEBUG,
				 "Found interface %s with ip %s\n",
				 name,
				 inet_ntoa( m_in_addr )
				 );
	}
	else
	{
		m_if_name = NULL;
		dprintf( D_FULLDEBUG, "No interface for name %s\n", name );
	}

	// Don't forget to close the socket!
	close( sock );

#endif
	return found;

}

bool
LinuxNetworkAdapter::getAdapterInfo( void )
{
	bool			ok = true;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifreq	ifr;
	int				sock;
	int				status;

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Get the hardware address
	getName( ifr );
	status = ioctl( sock, SIOCGIFHWADDR, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFHWADDR)" );
	}
	else {
		setHwAddr( ifr );
	}

	// Get the net mask
	getName( ifr );
	ifr.ifr_addr.sa_family = AF_INET;
	status = ioctl( sock, SIOCGIFNETMASK, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFNETMASK)" );
	}
	else {
		setNetMask( ifr );
	}

	// And, we're done
# endif
	return ok;
}

bool
LinuxNetworkAdapter::detectWOL ( void )
{
	bool					ok = false;
#if (HAVE_DECL_SIOCETHTOOL) && (HAVE_STRUCT_IFREQ) && (HAVE_LINUX_ETHTOOL_H)
	int						err;
	struct ethtool_wolinfo	wolinfo;
	struct ifreq			ifr;

	// Open control socket.
	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		dprintf( D_ALWAYS, "Cannot get control socket for WOL detection\n" );
		return false;
	}

	// Fill in the WOL request and the ioctl request
	wolinfo.cmd = ETHTOOL_GWOL;
	getName( ifr );
	ifr.ifr_data = (caddr_t)(& wolinfo);

	priv_state saved_priv = set_priv( PRIV_ROOT );
	err = ioctl(sock, SIOCETHTOOL, &ifr);
	set_priv( saved_priv );

	if ( err < 0 ) {
		derror( "ioctl(SIOCETHTOOL/GWOL)" );
		m_wol_support_mask = 0;
		m_wol_enable_mask = 0;
	}
	else {
		m_wol_support_mask = wolinfo.supported;
		m_wol_enable_mask = wolinfo.wolopts;
		ok = true;
	}

	// For now, all we support is the "magic" packet
	setWolBits( NetworkAdapterBase::WOL_HW_SUPPORT, m_wol_support_mask );
	setWolBits( NetworkAdapterBase::WOL_HW_ENABLED, m_wol_enable_mask );
	dprintf( D_FULLDEBUG, "%s supports Wake-on: %s (raw: 0x%02x)\n",
			 m_if_name, isWakeSupported() ? "yes" : "no", m_wol_support_mask );
	dprintf( D_FULLDEBUG, "%s enabled Wake-on: %s (raw: 0x%02x)\n",
			 m_if_name, isWakeEnabled() ? "yes" : "no", m_wol_enable_mask );

	close( sock );
#  endif
	return ok;
}

struct WolTable
{
	unsigned						bit_mask;
	NetworkAdapterBase::WOL_BITS	wol_bits;
};
static WolTable wol_table [] =
{
# if (HAVE_LINUX_ETHTOOL_H)
	{ WAKE_PHY,			NetworkAdapterBase::WOL_PHYSICAL },
	{ WAKE_UCAST,		NetworkAdapterBase::WOL_UCAST },
	{ WAKE_MCAST,		NetworkAdapterBase::WOL_MCAST },
	{ WAKE_BCAST,		NetworkAdapterBase::WOL_BCAST },
	{ WAKE_ARP,			NetworkAdapterBase::WOL_ARP },
	{ WAKE_MAGIC,		NetworkAdapterBase::WOL_MAGIC },
	{ WAKE_MAGICSECURE,	NetworkAdapterBase::WOL_MAGICSECURE },
# endif
	{ 0,				NetworkAdapterBase::WOL_NONE }
};

void
LinuxNetworkAdapter::setWolBits ( WOL_TYPE type, unsigned bits )
{
	if ( type == WOL_HW_SUPPORT ) {
		wolResetSupportBits( );
	}
	else {
		wolResetEnableBits( );
	}
	for( unsigned bit = 0;  wol_table[bit].bit_mask;  bit++ ) {
		if ( wol_table[bit].bit_mask & bits ) {
			wolSetBit( type, wol_table[bit].wol_bits );
		}
	}
}
<commit_msg>Added a simple message along with the error generated when the ioctl for detecting Wake-On-LAN fails -- that the error can be ignored unless you're using hibernation. (#231)<commit_after>/***************************************************************
*
* Copyright (C) 1990-2008, Condor Team, Computer Sciences Department,
* University of Wisconsin-Madison, WI.
*
* 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 "condor_common.h"
#include "condor_uid.h"
#include "internet.h"
#include "network_adapter.linux.h"

#if HAVE_NET_IF_H
#  include <net/if.h>
#endif
#if HAVE_LINUX_SOCKIOS_H
#  include <linux/sockios.h>
#endif
#if HAVE_LINUX_TYPES_H
#  include <linux/types.h>
#endif
#if HAVE_OS_TYPES_H
#  include <os_types.h>
#endif
#if HAVE_LINUX_ETHTOOL_H
#  include <linux/ethtool.h>
#endif

// For now, the only wake-on-lan type we use is UDP magic
#if defined(HAVE_LINUX_ETHTOOL_H)
# define WAKE_MASK	( 0 | (WAKE_MAGIC) )
#endif

// Possible values for the above (OR them together) :
//	WAKE_PHY
//	WAKE_UCAST
//	WAKE_MCAST
//	WAKE_BCAST
//	WAKE_ARP
//	WAKE_MAGIC
//	WAKE_MAGICSECURE

/***************************************************************
* LinuxNetworkAdapter class
***************************************************************/

/// Constructor
LinuxNetworkAdapter::LinuxNetworkAdapter ( const char */*ip_string*/,
										   unsigned int ip_addr ) throw ()
		: UnixNetworkAdapter( ip_addr )
{
	m_wol_support_mask = 0;
	m_wol_enable_mask = 0;
}

LinuxNetworkAdapter::LinuxNetworkAdapter ( const char *name ) throw()
		: UnixNetworkAdapter( name )
{
	m_wol_support_mask = 0;
	m_wol_enable_mask = 0;
}

/// Destructor
LinuxNetworkAdapter::~LinuxNetworkAdapter ( void ) throw()
{
}

bool
LinuxNetworkAdapter::findAdapter( unsigned int ip_addr )
{
	bool			found = false;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifconf	ifc;
	int				sock;
	int				num_req = 3;	// Should be enough for a machine
									// with lo, eth0, eth1

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Loop 'til we've read in all the interfaces, keep increasing
	// the number that we try to read each time
	struct sockaddr_in	in_addr;
	ifc.ifc_buf = NULL;
	while( !found ) {
		int size	= num_req * sizeof(struct ifreq);
		ifc.ifc_buf	= (char *) calloc( num_req, sizeof(struct ifreq) );
		ifc.ifc_len	= size;

		int status = ioctl( sock, SIOCGIFCONF, &ifc );
		if ( status < 0 ) {
			derror( "ioctl(SIOCGIFCONF)" );
			break;
		}

		// Did we find it in the ifc?
		int				 num = ifc.ifc_len / sizeof(struct ifreq);
		struct ifreq	*ifr = ifc.ifc_req;
		for ( int i = 0;  i < num;  i++, ifr++ ) {
			struct sockaddr_in *in = (struct sockaddr_in*)&(ifr->ifr_addr);
			MemCopy( &in_addr, in, sizeof(struct sockaddr_in) );

			if ( in->sin_addr.s_addr == ip_addr ) {
				setIpAddr( *ifr );
				setName( *ifr );
				found = true;
				break;
			}
		}

		// If the length returned by ioctl() is the same as the size
		// we started with, it probably overflowed.... try again
		if ( (!found) && (ifc.ifc_len == size) ) {
			num_req += 2;
			free( ifc.ifc_buf );
			ifc.ifc_buf = NULL;
		}
		else {
			break;
		}
	}

	// Make sure we free up the buffer memory
	if ( ifc.ifc_buf ) {
		free( ifc.ifc_buf );
	}

	if ( found ) {
		dprintf( D_FULLDEBUG,
				 "Found interface %s that matches %s\n",
				 interfaceName( ),
				 sin_to_string( &in_addr )
				 );
	}
	else
	{
		m_if_name = NULL;
		dprintf( D_FULLDEBUG,
				 "No interface for address %s\n",
				 sin_to_string( &in_addr )
				 );
	}

	// Don't forget to close the socket!
	close( sock );

#endif
	return found;

}

bool
LinuxNetworkAdapter::findAdapter( const char *name )
{
	bool			found = false;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifreq	ifr;
	int				sock;

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Loop 'til we've read in all the interfaces, keep increasing
	// the number that we try to read each time
	getName( ifr, name );
	int status = ioctl( sock, SIOCGIFADDR, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFADDR)" );
	}
	else {
		found = true;
		setIpAddr( ifr );
	}

	if ( found ) {
		dprintf( D_FULLDEBUG,
				 "Found interface %s with ip %s\n",
				 name,
				 inet_ntoa( m_in_addr )
				 );
	}
	else
	{
		m_if_name = NULL;
		dprintf( D_FULLDEBUG, "No interface for name %s\n", name );
	}

	// Don't forget to close the socket!
	close( sock );

#endif
	return found;

}

bool
LinuxNetworkAdapter::getAdapterInfo( void )
{
	bool			ok = true;
# if (HAVE_STRUCT_IFCONF) && (HAVE_STRUCT_IFREQ) && (HAVE_DECL_SIOCGIFCONF)
	struct ifreq	ifr;
	int				sock;
	int				status;

	// Get a 'control socket' for the operations
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		derror( "Cannot get control socket for WOL detection" );
		return false;
	}

	// Get the hardware address
	getName( ifr );
	status = ioctl( sock, SIOCGIFHWADDR, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFHWADDR)" );
	}
	else {
		setHwAddr( ifr );
	}

	// Get the net mask
	getName( ifr );
	ifr.ifr_addr.sa_family = AF_INET;
	status = ioctl( sock, SIOCGIFNETMASK, &ifr );
	if ( status < 0 ) {
		derror( "ioctl(SIOCGIFNETMASK)" );
	}
	else {
		setNetMask( ifr );
	}

	// And, we're done
# endif
	return ok;
}

bool
LinuxNetworkAdapter::detectWOL ( void )
{
	bool					ok = false;
#if (HAVE_DECL_SIOCETHTOOL) && (HAVE_STRUCT_IFREQ) && (HAVE_LINUX_ETHTOOL_H)
	int						err;
	struct ethtool_wolinfo	wolinfo;
	struct ifreq			ifr;

	// Open control socket.
	int sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		dprintf( D_ALWAYS, "Cannot get control socket for WOL detection\n" );
		return false;
	}

	// Fill in the WOL request and the ioctl request
	wolinfo.cmd = ETHTOOL_GWOL;
	getName( ifr );
	ifr.ifr_data = (caddr_t)(& wolinfo);

	priv_state saved_priv = set_priv( PRIV_ROOT );
	err = ioctl(sock, SIOCETHTOOL, &ifr);
	set_priv( saved_priv );

	if ( err < 0 ) {
		derror( "ioctl(SIOCETHTOOL/GWOL)" );
		dprintf( D_ALWAYS,
				 "You can safely ignore the above error if you're not"
				 " using hibernation\n" );
		m_wol_support_mask = 0;
		m_wol_enable_mask = 0;
	}
	else {
		m_wol_support_mask = wolinfo.supported;
		m_wol_enable_mask = wolinfo.wolopts;
		ok = true;
	}

	// For now, all we support is the "magic" packet
	setWolBits( NetworkAdapterBase::WOL_HW_SUPPORT, m_wol_support_mask );
	setWolBits( NetworkAdapterBase::WOL_HW_ENABLED, m_wol_enable_mask );
	dprintf( D_FULLDEBUG, "%s supports Wake-on: %s (raw: 0x%02x)\n",
			 m_if_name, isWakeSupported() ? "yes" : "no", m_wol_support_mask );
	dprintf( D_FULLDEBUG, "%s enabled Wake-on: %s (raw: 0x%02x)\n",
			 m_if_name, isWakeEnabled() ? "yes" : "no", m_wol_enable_mask );

	close( sock );
#  endif
	return ok;
}

struct WolTable
{
	unsigned						bit_mask;
	NetworkAdapterBase::WOL_BITS	wol_bits;
};
static WolTable wol_table [] =
{
# if (HAVE_LINUX_ETHTOOL_H)
	{ WAKE_PHY,			NetworkAdapterBase::WOL_PHYSICAL },
	{ WAKE_UCAST,		NetworkAdapterBase::WOL_UCAST },
	{ WAKE_MCAST,		NetworkAdapterBase::WOL_MCAST },
	{ WAKE_BCAST,		NetworkAdapterBase::WOL_BCAST },
	{ WAKE_ARP,			NetworkAdapterBase::WOL_ARP },
	{ WAKE_MAGIC,		NetworkAdapterBase::WOL_MAGIC },
	{ WAKE_MAGICSECURE,	NetworkAdapterBase::WOL_MAGICSECURE },
# endif
	{ 0,				NetworkAdapterBase::WOL_NONE }
};

void
LinuxNetworkAdapter::setWolBits ( WOL_TYPE type, unsigned bits )
{
	if ( type == WOL_HW_SUPPORT ) {
		wolResetSupportBits( );
	}
	else {
		wolResetEnableBits( );
	}
	for( unsigned bit = 0;  wol_table[bit].bit_mask;  bit++ ) {
		if ( wol_table[bit].bit_mask & bits ) {
			wolSetBit( type, wol_table[bit].wol_bits );
		}
	}
}
<|endoftext|>


<commit_before>//
//  Enemy.cpp
//  yobatronika
//
//  Created by Maxim Fedorenko on 07.04.15.
//
//

#include "Enemy.h"

using namespace Yoba;

Enemy::Enemy(const LoaderParams &params)
: SDLGameObject(params)
{
    m_velocity.setY(2);
    m_velocity.setX(0.001);
}

Enemy::~Enemy() {
    clean();
}

void Enemy::draw() {
    SDLGameObject::draw();
}

void Enemy::clean() {
    SDLGameObject::clean();
}

void Enemy::update()
{
    if(m_position.getY() < 0)
    {
        m_velocity.setY(2);
    }
    else if(m_position.getY() > 400)
    {
        m_velocity.setY(-2);
    }

    if(m_position.getX() < 0)
    {
        m_velocity.setX(0.001);
    }
    else if(m_position.getX() > 400)
    {
        m_velocity.setX(-0.001);
    }

    SDLGameObject::update();
}
<commit_msg>[Enemy] Fix rounding errors.<commit_after>//
//  Enemy.cpp
//  yobatronika
//
//  Created by Maxim Fedorenko on 07.04.15.
//
//

#include "Enemy.h"

using namespace Yoba;

Enemy::Enemy(const LoaderParams &params)
: SDLGameObject(params)
{
    m_velocity.setY(2);
    m_velocity.setX(0.001);
}

Enemy::~Enemy() {
    clean();
}

void Enemy::draw() {
    SDLGameObject::draw();
}

void Enemy::clean() {
    SDLGameObject::clean();
}

void Enemy::update()
{
    if(m_position.getY() <= 0)
    {
        m_position = Vector2D(m_position.getX(), 0);
        m_velocity.setY(2);
    }
    else if(m_position.getY() >= 400)
    {
        m_position = Vector2D(m_position.getX(), 400);
        m_velocity.setY(-2);
    }

    if(m_position.getX() <= 0)
    {
        m_velocity.setX(0.1);
    }
    else if(m_position.getX() >= 400)
    {
        m_velocity.setX(-0.1);
    }

    SDLGameObject::update();
}
<|endoftext|>