<commit_before>#include "p11engine.h"

#include <array>
#include <utility>
#include <vector>

#include <libp11.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <boost/algorithm/hex.hpp>
#include <boost/filesystem.hpp>
#include <boost/scoped_array.hpp>

#include "crypto/crypto.h"
#include "utilities/config_utils.h"
#include "utilities/utils.h"

P11Engine* P11EngineGuard::instance = nullptr;
int P11EngineGuard::ref_counter = 0;

P11ContextWrapper::P11ContextWrapper(const boost::filesystem::path& module) {
  if (module.empty()) {
    ctx = nullptr;
    return;
  }
  // never returns NULL
  ctx = PKCS11_CTX_new();
  if (PKCS11_CTX_load(ctx, module.c_str()) != 0) {
    PKCS11_CTX_free(ctx);
    LOG_ERROR << "Couldn't load PKCS11 module " << module.string() << ": "
              << ERR_error_string(ERR_get_error(), nullptr);
    throw std::runtime_error("PKCS11 error");
  }
}

P11ContextWrapper::~P11ContextWrapper() {
  if (ctx != nullptr) {
    PKCS11_CTX_unload(ctx);
    PKCS11_CTX_free(ctx);
  }
}

P11SlotsWrapper::P11SlotsWrapper(PKCS11_ctx_st* ctx_in) {
  ctx = ctx_in;
  if (ctx == nullptr) {
    wslots_ = nullptr;
    nslots = 0;
    return;
  }
  if (PKCS11_enumerate_slots(ctx, &wslots_, &nslots) != 0) {
    LOG_ERROR << "Couldn't enumerate slots"
              << ": " << ERR_error_string(ERR_get_error(), nullptr);
    throw std::runtime_error("PKCS11 error");
  }
}

P11SlotsWrapper::~P11SlotsWrapper() {
  if ((wslots_ != nullptr) && (nslots != 0u)) {
    PKCS11_release_all_slots(ctx, wslots_, nslots);
  }
}

P11Engine::P11Engine(P11Config config) : config_(std::move(config)), ctx_(config_.module), slots_(ctx_.get()) {
  if (config_.module.empty()) {
    return;
  }

  PKCS11_SLOT* slot = PKCS11_find_token(ctx_.get(), slots_.get_slots(), slots_.get_nslots());
  if ((slot == nullptr) || (slot->token == nullptr)) {
    throw std::runtime_error("Couldn't find pkcs11 token");
  }

  LOG_DEBUG << "Slot manufacturer......: " << slot->manufacturer;
  LOG_DEBUG << "Slot description.......: " << slot->description;
  LOG_DEBUG << "Slot token label.......: " << slot->token->label;
  LOG_DEBUG << "Slot token manufacturer: " << slot->token->manufacturer;
  LOG_DEBUG << "Slot token model.......: " << slot->token->model;
  LOG_DEBUG << "Slot token serialnr....: " << slot->token->serialnr;

  uri_prefix_ = std::string("pkcs11:serial=") + slot->token->serialnr + ";pin-value=" + config_.pass + ";id=%";

  ENGINE_load_builtin_engines();
  ENGINE* engine = ENGINE_by_id("dynamic");

  if (engine == nullptr) {
    throw std::runtime_error("SSL pkcs11 engine initialization failed");
  }

  try {
    const boost::filesystem::path pkcs11Path = findPkcsLibrary();
    LOG_INFO << "Loading PKCS#11 engine library: " << pkcs11Path.string();
    if (ENGINE_ctrl_cmd_string(engine, "SO_PATH", pkcs11Path.c_str(), 0) == 0) {
      throw std::runtime_error(std::string("Engine command failed: SO_PATH ") + pkcs11Path.string());
    }

    if (ENGINE_ctrl_cmd_string(engine, "ID", "pkcs11", 0) == 0) {
      throw std::runtime_error("Engine command failed: ID pksc11");
    }

    if (ENGINE_ctrl_cmd_string(engine, "LIST_ADD", "1", 0) == 0) {
      throw std::runtime_error("Engine command failed: LIST_ADD 1");
    }

    if (ENGINE_ctrl_cmd_string(engine, "LOAD", nullptr, 0) == 0) {
      throw std::runtime_error("Engine command failed: LOAD");
    }

    if (ENGINE_ctrl_cmd_string(engine, "MODULE_PATH", config_.module.c_str(), 0) == 0) {
      throw std::runtime_error(std::string("Engine command failed: MODULE_PATH ") + config_.module.string());
    }

    if (ENGINE_ctrl_cmd_string(engine, "PIN", config_.pass.c_str(), 0) == 0) {
      throw std::runtime_error(std::string("Engine command failed: PIN"));
    }

    if (ENGINE_init(engine) == 0) {
      throw std::runtime_error("Engine initialization failed");
    }
  } catch (const std::runtime_error& exc) {
    // Note: treat these in a special case, as ENGINE_finish cannot be called on
    // an engine which has not been fully initialized
    ENGINE_free(engine);
    ENGINE_cleanup();  // for openssl < 1.1
    throw;
  }

  ssl_engine_ = engine;
}

boost::filesystem::path P11Engine::findPkcsLibrary() {
#ifdef PKCS11_ENGINE_PATH
  const boost::filesystem::path custom_path = PKCS11_ENGINE_PATH;
#else
  const boost::filesystem::path custom_path;
#endif
  static const std::array<boost::filesystem::path, 3> engine_system_paths = {
    "/usr/lib/engines-1.1/pkcs11.so",
    "/usr/lib/engines/pkcs11.so",
    "/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so"
  };
  boost::filesystem::path engine_path;

  if (!custom_path.empty()) {
    engine_path = custom_path;
  } else {
    for (const auto& p : engine_system_paths) {
      LOG_DEBUG << "Trying pkcs11 engine " << p;
      if (boost::filesystem::exists(p)) {
        engine_path = p;
      }
    }
  }

  if (!boost::filesystem::exists(engine_path)) {
    LOG_ERROR << "PKCS11 engine not available (" << engine_path << ")";
  }

  return engine_path;
}

PKCS11_SLOT* P11Engine::findTokenSlot() const {
  PKCS11_SLOT* slot = PKCS11_find_token(ctx_.get(), slots_.get_slots(), slots_.get_nslots());
  if ((slot == nullptr) || (slot->token == nullptr)) {
    LOG_ERROR << "Couldn't find a token";
    return nullptr;
  }
  int rv;
  PKCS11_is_logged_in(slot, 1, &rv);
  if (rv == 0) {
    if (PKCS11_open_session(slot, 1) != 0) {
      LOG_ERROR << "Error creating rw session in to the slot: " << ERR_error_string(ERR_get_error(), nullptr);
    }

    if (PKCS11_login(slot, 0, config_.pass.c_str()) != 0) {
      LOG_ERROR << "Error logging in to the token: " << ERR_error_string(ERR_get_error(), nullptr);
      return nullptr;
    }
  }
  return slot;
}

bool P11Engine::readUptanePublicKey(std::string* key_out) {
  if (config_.module.empty()) {
    return false;
  }
  if ((config_.uptane_key_id.length() % 2) != 0u) {
    return false;  // id is a hex string
  }

  PKCS11_SLOT* slot = findTokenSlot();
  if (slot == nullptr) {
    return false;
  }

  PKCS11_KEY* keys;
  unsigned int nkeys;
  int rc = PKCS11_enumerate_public_keys(slot->token, &keys, &nkeys);
  if (rc < 0) {
    LOG_ERROR << "Error enumerating public keys in PKCS11 device: " << ERR_error_string(ERR_get_error(), nullptr);
    return false;
  }
  PKCS11_KEY* key = nullptr;
  {
    std::vector<unsigned char> id_hex;
    boost::algorithm::unhex(config_.uptane_key_id, std::back_inserter(id_hex));

    for (unsigned int i = 0; i < nkeys; i++) {
      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
      if ((keys[i].id_len == config_.uptane_key_id.length() / 2) &&
          // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
          (memcmp(keys[i].id, id_hex.data(), config_.uptane_key_id.length() / 2) == 0)) {
        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
        key = &keys[i];
        break;
      }
    }
  }
  if (key == nullptr) {
    LOG_ERROR << "Requested public key was not found";
    return false;
  }
  StructGuard<EVP_PKEY> evp_key(PKCS11_get_public_key(key), EVP_PKEY_free);
  StructGuard<BIO> mem(BIO_new(BIO_s_mem()), BIO_vfree);
  PEM_write_bio_PUBKEY(mem.get(), evp_key.get());

  char* pem_key = nullptr;
  long length = BIO_get_mem_data(mem.get(), &pem_key);  // NOLINT(google-runtime-int)
  key_out->assign(pem_key, static_cast<size_t>(length));

  return true;
}

bool P11Engine::generateUptaneKeyPair() {
  PKCS11_SLOT* slot = findTokenSlot();
  if (slot == nullptr) {
    return false;
  }

  std::vector<unsigned char> id_hex;
  boost::algorithm::unhex(config_.uptane_key_id, std::back_inserter(id_hex));

  // Manually generate a key and store it on the HSM
  // Note that libp11 has a dedicated function marked as deprecated, it
  // worked the same way in version <= 0.4.7 but tries to generate the
  // RSA key directly on the HSM from 0.4.8. As it would not work reliably
  // with openssl 1.1, we reimplemented it here.
  StructGuard<EVP_PKEY> pkey = Crypto::generateRSAKeyPairEVP(KeyType::kRSA2048);
  if (pkey == nullptr) {
    LOG_ERROR << "Error generating keypair on the device:" << ERR_error_string(ERR_get_error(), nullptr);
    return false;
  }

  if (PKCS11_store_private_key(slot->token, pkey.get(), nullptr, id_hex.data(), id_hex.size()) != 0) {
    return false;
  }
  if (PKCS11_store_public_key(slot->token, pkey.get(), nullptr, id_hex.data(), id_hex.size()) != 0) {
    return false;
  }

  return true;
}

bool P11Engine::readTlsCert(std::string* cert_out) const {
  const std::string& id = config_.tls_clientcert_id;

  if (config_.module.empty()) {
    return false;
  }
  if ((id.length() % 2) != 0u) {
    return false;  // id is a hex string
  }

  PKCS11_SLOT* slot = findTokenSlot();
  if (slot == nullptr) {
    return false;
  }

  PKCS11_CERT* certs;
  unsigned int ncerts;
  int rc = PKCS11_enumerate_certs(slot->token, &certs, &ncerts);
  if (rc < 0) {
    LOG_ERROR << "Error enumerating certificates in PKCS11 device: " << ERR_error_string(ERR_get_error(), nullptr);
    return false;
  }

  PKCS11_CERT* cert = nullptr;
  {
    std::vector<unsigned char> id_hex;
    boost::algorithm::unhex(id, std::back_inserter(id_hex));

    for (unsigned int i = 0; i < ncerts; i++) {
      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
      if ((certs[i].id_len == id.length() / 2) && (memcmp(certs[i].id, id_hex.data(), id.length() / 2) == 0)) {
        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
        cert = &certs[i];
        break;
      }
    }
  }
  if (cert == nullptr) {
    LOG_ERROR << "Requested certificate was not found";
    return false;
  }
  StructGuard<BIO> mem(BIO_new(BIO_s_mem()), BIO_vfree);
  PEM_write_bio_X509(mem.get(), cert->x509);

  char* pem_key = nullptr;
  long length = BIO_get_mem_data(mem.get(), &pem_key);  // NOLINT(google-runtime-int)
  cert_out->assign(pem_key, static_cast<size_t>(length));

  return true;
}
<commit_msg>Add helpful error messages in P11 key generation<commit_after>#include "p11engine.h"

#include <array>
#include <utility>
#include <vector>

#include <libp11.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <boost/algorithm/hex.hpp>
#include <boost/filesystem.hpp>
#include <boost/scoped_array.hpp>

#include "crypto/crypto.h"
#include "utilities/config_utils.h"
#include "utilities/utils.h"

P11Engine* P11EngineGuard::instance = nullptr;
int P11EngineGuard::ref_counter = 0;

P11ContextWrapper::P11ContextWrapper(const boost::filesystem::path& module) {
  if (module.empty()) {
    ctx = nullptr;
    return;
  }
  // never returns NULL
  ctx = PKCS11_CTX_new();
  if (PKCS11_CTX_load(ctx, module.c_str()) != 0) {
    PKCS11_CTX_free(ctx);
    LOG_ERROR << "Couldn't load PKCS11 module " << module.string() << ": "
              << ERR_error_string(ERR_get_error(), nullptr);
    throw std::runtime_error("PKCS11 error");
  }
}

P11ContextWrapper::~P11ContextWrapper() {
  if (ctx != nullptr) {
    PKCS11_CTX_unload(ctx);
    PKCS11_CTX_free(ctx);
  }
}

P11SlotsWrapper::P11SlotsWrapper(PKCS11_ctx_st* ctx_in) {
  ctx = ctx_in;
  if (ctx == nullptr) {
    wslots_ = nullptr;
    nslots = 0;
    return;
  }
  if (PKCS11_enumerate_slots(ctx, &wslots_, &nslots) != 0) {
    LOG_ERROR << "Couldn't enumerate slots"
              << ": " << ERR_error_string(ERR_get_error(), nullptr);
    throw std::runtime_error("PKCS11 error");
  }
}

P11SlotsWrapper::~P11SlotsWrapper() {
  if ((wslots_ != nullptr) && (nslots != 0u)) {
    PKCS11_release_all_slots(ctx, wslots_, nslots);
  }
}

P11Engine::P11Engine(P11Config config) : config_(std::move(config)), ctx_(config_.module), slots_(ctx_.get()) {
  if (config_.module.empty()) {
    return;
  }

  PKCS11_SLOT* slot = PKCS11_find_token(ctx_.get(), slots_.get_slots(), slots_.get_nslots());
  if ((slot == nullptr) || (slot->token == nullptr)) {
    throw std::runtime_error("Couldn't find pkcs11 token");
  }

  LOG_DEBUG << "Slot manufacturer......: " << slot->manufacturer;
  LOG_DEBUG << "Slot description.......: " << slot->description;
  LOG_DEBUG << "Slot token label.......: " << slot->token->label;
  LOG_DEBUG << "Slot token manufacturer: " << slot->token->manufacturer;
  LOG_DEBUG << "Slot token model.......: " << slot->token->model;
  LOG_DEBUG << "Slot token serialnr....: " << slot->token->serialnr;

  uri_prefix_ = std::string("pkcs11:serial=") + slot->token->serialnr + ";pin-value=" + config_.pass + ";id=%";

  ENGINE_load_builtin_engines();
  ENGINE* engine = ENGINE_by_id("dynamic");

  if (engine == nullptr) {
    throw std::runtime_error("SSL pkcs11 engine initialization failed");
  }

  try {
    const boost::filesystem::path pkcs11Path = findPkcsLibrary();
    LOG_INFO << "Loading PKCS#11 engine library: " << pkcs11Path.string();
    if (ENGINE_ctrl_cmd_string(engine, "SO_PATH", pkcs11Path.c_str(), 0) == 0) {
      throw std::runtime_error(std::string("Engine command failed: SO_PATH ") + pkcs11Path.string());
    }

    if (ENGINE_ctrl_cmd_string(engine, "ID", "pkcs11", 0) == 0) {
      throw std::runtime_error("Engine command failed: ID pksc11");
    }

    if (ENGINE_ctrl_cmd_string(engine, "LIST_ADD", "1", 0) == 0) {
      throw std::runtime_error("Engine command failed: LIST_ADD 1");
    }

    if (ENGINE_ctrl_cmd_string(engine, "LOAD", nullptr, 0) == 0) {
      throw std::runtime_error("Engine command failed: LOAD");
    }

    if (ENGINE_ctrl_cmd_string(engine, "MODULE_PATH", config_.module.c_str(), 0) == 0) {
      throw std::runtime_error(std::string("Engine command failed: MODULE_PATH ") + config_.module.string());
    }

    if (ENGINE_ctrl_cmd_string(engine, "PIN", config_.pass.c_str(), 0) == 0) {
      throw std::runtime_error(std::string("Engine command failed: PIN"));
    }

    if (ENGINE_init(engine) == 0) {
      throw std::runtime_error("Engine initialization failed");
    }
  } catch (const std::runtime_error& exc) {
    // Note: treat these in a special case, as ENGINE_finish cannot be called on
    // an engine which has not been fully initialized
    ENGINE_free(engine);
    ENGINE_cleanup();  // for openssl < 1.1
    throw;
  }

  ssl_engine_ = engine;
}

boost::filesystem::path P11Engine::findPkcsLibrary() {
#ifdef PKCS11_ENGINE_PATH
  const boost::filesystem::path custom_path = PKCS11_ENGINE_PATH;
#else
  const boost::filesystem::path custom_path;
#endif
  static const std::array<boost::filesystem::path, 3> engine_system_paths = {
    "/usr/lib/engines-1.1/pkcs11.so",
    "/usr/lib/engines/pkcs11.so",
    "/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so"
  };
  boost::filesystem::path engine_path;

  if (!custom_path.empty()) {
    engine_path = custom_path;
  } else {
    for (const auto& p : engine_system_paths) {
      LOG_DEBUG << "Trying pkcs11 engine " << p;
      if (boost::filesystem::exists(p)) {
        engine_path = p;
      }
    }
  }

  if (!boost::filesystem::exists(engine_path)) {
    LOG_ERROR << "PKCS11 engine not available (" << engine_path << ")";
  }

  return engine_path;
}

PKCS11_SLOT* P11Engine::findTokenSlot() const {
  PKCS11_SLOT* slot = PKCS11_find_token(ctx_.get(), slots_.get_slots(), slots_.get_nslots());
  if ((slot == nullptr) || (slot->token == nullptr)) {
    LOG_ERROR << "Couldn't find a token";
    return nullptr;
  }
  int rv;
  PKCS11_is_logged_in(slot, 1, &rv);
  if (rv == 0) {
    if (PKCS11_open_session(slot, 1) != 0) {
      LOG_ERROR << "Error creating rw session in to the slot: " << ERR_error_string(ERR_get_error(), nullptr);
    }

    if (PKCS11_login(slot, 0, config_.pass.c_str()) != 0) {
      LOG_ERROR << "Error logging in to the token: " << ERR_error_string(ERR_get_error(), nullptr);
      return nullptr;
    }
  }
  return slot;
}

bool P11Engine::readUptanePublicKey(std::string* key_out) {
  if (config_.module.empty()) {
    return false;
  }
  if ((config_.uptane_key_id.length() % 2) != 0u) {
    return false;  // id is a hex string
  }

  PKCS11_SLOT* slot = findTokenSlot();
  if (slot == nullptr) {
    return false;
  }

  PKCS11_KEY* keys;
  unsigned int nkeys;
  int rc = PKCS11_enumerate_public_keys(slot->token, &keys, &nkeys);
  if (rc < 0) {
    LOG_ERROR << "Error enumerating public keys in PKCS11 device: " << ERR_error_string(ERR_get_error(), nullptr);
    return false;
  }
  PKCS11_KEY* key = nullptr;
  {
    std::vector<unsigned char> id_hex;
    boost::algorithm::unhex(config_.uptane_key_id, std::back_inserter(id_hex));

    for (unsigned int i = 0; i < nkeys; i++) {
      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
      if ((keys[i].id_len == config_.uptane_key_id.length() / 2) &&
          // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
          (memcmp(keys[i].id, id_hex.data(), config_.uptane_key_id.length() / 2) == 0)) {
        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
        key = &keys[i];
        break;
      }
    }
  }
  if (key == nullptr) {
    LOG_ERROR << "Requested public key was not found";
    return false;
  }
  StructGuard<EVP_PKEY> evp_key(PKCS11_get_public_key(key), EVP_PKEY_free);
  StructGuard<BIO> mem(BIO_new(BIO_s_mem()), BIO_vfree);
  PEM_write_bio_PUBKEY(mem.get(), evp_key.get());

  char* pem_key = nullptr;
  long length = BIO_get_mem_data(mem.get(), &pem_key);  // NOLINT(google-runtime-int)
  key_out->assign(pem_key, static_cast<size_t>(length));

  return true;
}

bool P11Engine::generateUptaneKeyPair() {
  PKCS11_SLOT* slot = findTokenSlot();
  if (slot == nullptr) {
    return false;
  }

  std::vector<unsigned char> id_hex;
  boost::algorithm::unhex(config_.uptane_key_id, std::back_inserter(id_hex));

  // Manually generate a key and store it on the HSM
  // Note that libp11 has a dedicated function marked as deprecated, it
  // worked the same way in version <= 0.4.7 but tries to generate the
  // RSA key directly on the HSM from 0.4.8. As it would not work reliably
  // with openssl 1.1, we reimplemented it here.
  StructGuard<EVP_PKEY> pkey = Crypto::generateRSAKeyPairEVP(KeyType::kRSA2048);
  if (pkey == nullptr) {
    LOG_ERROR << "Error generating keypair on the device:" << ERR_error_string(ERR_get_error(), nullptr);
    return false;
  }

  if (PKCS11_store_private_key(slot->token, pkey.get(), nullptr, id_hex.data(), id_hex.size()) != 0) {
    LOG_ERROR << "Could not store private key on the token";
    return false;
  }
  if (PKCS11_store_public_key(slot->token, pkey.get(), nullptr, id_hex.data(), id_hex.size()) != 0) {
    LOG_ERROR << "Could not store public key on the token";
    return false;
  }

  return true;
}

bool P11Engine::readTlsCert(std::string* cert_out) const {
  const std::string& id = config_.tls_clientcert_id;

  if (config_.module.empty()) {
    return false;
  }
  if ((id.length() % 2) != 0u) {
    return false;  // id is a hex string
  }

  PKCS11_SLOT* slot = findTokenSlot();
  if (slot == nullptr) {
    return false;
  }

  PKCS11_CERT* certs;
  unsigned int ncerts;
  int rc = PKCS11_enumerate_certs(slot->token, &certs, &ncerts);
  if (rc < 0) {
    LOG_ERROR << "Error enumerating certificates in PKCS11 device: " << ERR_error_string(ERR_get_error(), nullptr);
    return false;
  }

  PKCS11_CERT* cert = nullptr;
  {
    std::vector<unsigned char> id_hex;
    boost::algorithm::unhex(id, std::back_inserter(id_hex));

    for (unsigned int i = 0; i < ncerts; i++) {
      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
      if ((certs[i].id_len == id.length() / 2) && (memcmp(certs[i].id, id_hex.data(), id.length() / 2) == 0)) {
        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
        cert = &certs[i];
        break;
      }
    }
  }
  if (cert == nullptr) {
    LOG_ERROR << "Requested certificate was not found";
    return false;
  }
  StructGuard<BIO> mem(BIO_new(BIO_s_mem()), BIO_vfree);
  PEM_write_bio_X509(mem.get(), cert->x509);

  char* pem_key = nullptr;
  long length = BIO_get_mem_data(mem.get(), &pem_key);  // NOLINT(google-runtime-int)
  cert_out->assign(pem_key, static_cast<size_t>(length));

  return true;
}
<|endoftext|>


<commit_before>#include "midiio.h"

#include<QGuiApplication>
#include <QSocketNotifier>
#include <QtDebug>

#include <exception>

MidiIO::MidiIO(QObject *parent) : QObject(parent),
    m_seq_handle(Q_NULLPTR),
    m_pfds(Q_NULLPTR),
    m_seq_port_in(-1),
    m_seq_port_out(-1)
{
    qDebug() << "Opening MIDI sequencer";

    if (snd_seq_open(&m_seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
        throw std::runtime_error("Failed opening sequencer");
    }

    // Try qUtf8Printable
    if (snd_seq_set_client_name(m_seq_handle, qPrintable(qApp->applicationName())) < 0) {
        throw std::runtime_error("Failed setting sequencer name");
    }

    // In port
    m_seq_port_in = snd_seq_create_simple_port(
                m_seq_handle,
                qPrintable(qGuiApp->applicationName() + ":in"),
                SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
                SND_SEQ_PORT_TYPE_APPLICATION);
    if (m_seq_port_in < 0) {
        throw std::runtime_error("Failed setting sequencer port IN");
    }

    // Out port
    m_seq_port_out = snd_seq_create_simple_port(
                m_seq_handle,
                qPrintable(qGuiApp->applicationName() + ":out"),
                SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,
                SND_SEQ_PORT_TYPE_APPLICATION);
    if (m_seq_port_out < 0) {
        throw std::runtime_error("Failed setting sequencer port OUT");
    }

    // Poll

    int npfd = snd_seq_poll_descriptors_count(m_seq_handle, POLLIN);
    m_pfds = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
    int npfdf = snd_seq_poll_descriptors(m_seq_handle, m_pfds, npfd, POLLIN);

    for (int i = 0 ; i < npfdf ; ++i) {
        qDebug() << "Enabling MIDI poll descriptor" << i;
        QSocketNotifier* n = new QSocketNotifier(m_pfds[i].fd, QSocketNotifier::Read);
        connect(qGuiApp,
                &QGuiApplication::aboutToQuit,
                [=]() {
                    qDebug() << "Disabling MIDI poll descriptor" << i;
                    n->setEnabled(false);
                }
        );
        connect(n,
                &QSocketNotifier::activated,
                this,
                &MidiIO::readEvents
        );
    }

    sendIdRequest();
}

MidiIO::~MidiIO() {
    qDebug() << "Closing MIDI sequencer";
    if (snd_seq_delete_simple_port(m_seq_handle, m_seq_port_in) < 0) {
        qWarning() << "Failed deleting sequencer port IN";
    }

    if (snd_seq_delete_simple_port(m_seq_handle, m_seq_port_out) < 0) {
        qWarning() << "Failed deleting sequencer port OUT";
    }

    if (snd_seq_close(m_seq_handle) < 0) {
        qWarning() << "Failed closing sequencer";
    }
}

void MidiIO::readEvents()
{
    int r = 99;
    while (r>0) {
        snd_seq_event_t *ev;
        r = snd_seq_event_input(m_seq_handle, &ev);
        qDebug() << "Received event" << ev->type;
        processEvent(ev);
    }
}

void MidiIO::processEvent(snd_seq_event_t* ev)
{
    switch (ev->type) {
    case SND_SEQ_EVENT_PORT_SUBSCRIBED:
        processPortSubscribed(ev);
        break;
    case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
        break;
    case SND_SEQ_EVENT_PORT_START:
        break;
    case SND_SEQ_EVENT_PORT_EXIT:
        break;
    case SND_SEQ_EVENT_PORT_CHANGE:
        break;
    case SND_SEQ_EVENT_SYSEX:
        processSysex(ev);
    default:
        break;
    }
}

void MidiIO::processPortSubscribed(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_PORT_SUBSCRIBED);

    sendIdRequest();
}

void MidiIO::processSysex(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_SYSEX);

    QByteArray s(
        static_cast<const char*>(ev->data.ext.ptr),
        ev->data.ext.len);
    qDebug() << "Received Sysex:"
             << s.length()
             << s;
    emit sysexReceived(s);
}

void MidiIO::sendIdRequest()
{
    const unsigned char b[] = {0xF0, 0x7E, 0x00, 0x06, 0x01, 0xF7};
    const QByteArray sysex(reinterpret_cast<const char*>(b), sizeof(b));
    sendSysex(sysex);
}

void MidiIO::sendSysex(QByteArray sysex) {
    snd_seq_event_t ev;
    snd_seq_ev_clear(&ev);
    snd_seq_ev_set_subs(&ev);
    snd_seq_ev_set_direct(&ev);
    snd_seq_ev_set_source(&ev, m_seq_port_out);
    snd_seq_ev_set_sysex(&ev, sysex.length(), sysex.data());

    int err = snd_seq_event_output_direct(m_seq_handle, &ev);
    if (err < 0) {
        throw std::runtime_error(snd_strerror(err));
    }
    err = 1;
    while (err > 0) {
        err = snd_seq_drain_output(m_seq_handle);
        if (err < 0) {
            throw std::runtime_error(snd_strerror(err));
        }
    }
}
<commit_msg>Properly flush input events<commit_after>#include "midiio.h"

#include<QGuiApplication>
#include <QSocketNotifier>
#include <QtDebug>

#include <exception>

MidiIO::MidiIO(QObject *parent) : QObject(parent),
    m_seq_handle(Q_NULLPTR),
    m_pfds(Q_NULLPTR),
    m_seq_port_in(-1),
    m_seq_port_out(-1)
{
    qDebug() << "Opening MIDI sequencer";

    if (snd_seq_open(&m_seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
        throw std::runtime_error("Failed opening sequencer");
    }

    // Try qUtf8Printable
    if (snd_seq_set_client_name(m_seq_handle, qPrintable(qApp->applicationName())) < 0) {
        throw std::runtime_error("Failed setting sequencer name");
    }

    // In port
    m_seq_port_in = snd_seq_create_simple_port(
                m_seq_handle,
                qPrintable(qGuiApp->applicationName() + ":in"),
                SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
                SND_SEQ_PORT_TYPE_APPLICATION);
    if (m_seq_port_in < 0) {
        throw std::runtime_error("Failed setting sequencer port IN");
    }

    // Out port
    m_seq_port_out = snd_seq_create_simple_port(
                m_seq_handle,
                qPrintable(qGuiApp->applicationName() + ":out"),
                SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ,
                SND_SEQ_PORT_TYPE_APPLICATION);
    if (m_seq_port_out < 0) {
        throw std::runtime_error("Failed setting sequencer port OUT");
    }

    // Poll

    int npfd = snd_seq_poll_descriptors_count(m_seq_handle, POLLIN);
    m_pfds = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
    int npfdf = snd_seq_poll_descriptors(m_seq_handle, m_pfds, npfd, POLLIN);

    for (int i = 0 ; i < npfdf ; ++i) {
        qDebug() << "Enabling MIDI poll descriptor" << i;
        QSocketNotifier* n = new QSocketNotifier(m_pfds[i].fd, QSocketNotifier::Read);
        connect(qGuiApp,
                &QGuiApplication::aboutToQuit,
                [=]() {
                    qDebug() << "Disabling MIDI poll descriptor" << i;
                    n->setEnabled(false);
                }
        );
        connect(n,
                &QSocketNotifier::activated,
                this,
                &MidiIO::readEvents
        );
    }

    sendIdRequest();
}

MidiIO::~MidiIO() {
    qDebug() << "Closing MIDI sequencer";
    if (snd_seq_delete_simple_port(m_seq_handle, m_seq_port_in) < 0) {
        qWarning() << "Failed deleting sequencer port IN";
    }

    if (snd_seq_delete_simple_port(m_seq_handle, m_seq_port_out) < 0) {
        qWarning() << "Failed deleting sequencer port OUT";
    }

    if (snd_seq_close(m_seq_handle) < 0) {
        qWarning() << "Failed closing sequencer";
    }
}

void MidiIO::readEvents()
{
    while (snd_seq_event_input_pending(m_seq_handle, 1) > 0) {
        snd_seq_event_t *ev;
        snd_seq_event_input(m_seq_handle, &ev);
        qDebug() << "Received event" << ev->type;
        processEvent(ev);
    }
    qDebug() << "readEvents done";
}

void MidiIO::processEvent(snd_seq_event_t* ev)
{
    switch (ev->type) {
    case SND_SEQ_EVENT_PORT_SUBSCRIBED:
        processPortSubscribed(ev);
        break;
    case SND_SEQ_EVENT_PORT_UNSUBSCRIBED:
        break;
    case SND_SEQ_EVENT_PORT_START:
        break;
    case SND_SEQ_EVENT_PORT_EXIT:
        break;
    case SND_SEQ_EVENT_PORT_CHANGE:
        break;
    case SND_SEQ_EVENT_SYSEX:
        processSysex(ev);
    default:
        break;
    }
}

void MidiIO::processPortSubscribed(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_PORT_SUBSCRIBED);

    sendIdRequest();
}

void MidiIO::processSysex(snd_seq_event_t* ev) {
    Q_CHECK_PTR(ev);
    Q_ASSERT(ev->type == SND_SEQ_EVENT_SYSEX);

    QByteArray s(
        static_cast<const char*>(ev->data.ext.ptr),
        ev->data.ext.len);
    qDebug() << "Received Sysex:"
             << s.length()
             << s;
    emit sysexReceived(s);
}

void MidiIO::sendIdRequest()
{
    const unsigned char b[] = {0xF0, 0x7E, 0x00, 0x06, 0x01, 0xF7};
    const QByteArray sysex(reinterpret_cast<const char*>(b), sizeof(b));
    sendSysex(sysex);
}

void MidiIO::sendSysex(QByteArray sysex) {
    snd_seq_event_t ev;
    snd_seq_ev_clear(&ev);
    snd_seq_ev_set_subs(&ev);
    snd_seq_ev_set_direct(&ev);
    snd_seq_ev_set_source(&ev, m_seq_port_out);
    snd_seq_ev_set_sysex(&ev, sysex.length(), sysex.data());

    int err = snd_seq_event_output_direct(m_seq_handle, &ev);
    if (err < 0) {
        throw std::runtime_error(snd_strerror(err));
    }
    err = 1;
    while (err > 0) {
        err = snd_seq_drain_output(m_seq_handle);
        if (err < 0) {
            throw std::runtime_error(snd_strerror(err));
        }
    }
}
<|endoftext|>


<commit_before>#ifndef MY_MIOPEN_HPP
#define MY_MIOPEN_HPP

#include <miopen/miopen.h>
#include <hipblas.h>
//#include <gperftools/profiler.h>

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <regex>
#include <dirent.h>

//#define WITH_CL

#define DEBUG(msg) std::cerr << "[DEBUG] " << msg << std::endl;
#define WARNING(msg) std::cerr << "[!WARNING!] " << msg << std::endl;
#define FATAL(msg) {std::cerr << "[!FATAL!] " << msg << std::endl; exit(EXIT_FAILURE);} while(0)
#define INFO(msg) std::cout << "[INFO]  " << msg << std::endl;

#ifdef WITH_CL // not supported anymore
#include <CL/cl.hpp>
#define device_mem_t cl_mem

struct ClHandle {
    static std::vector<cl::Platform> getPlatforms() {
        std::vector<cl::Platform> plats;
        cl::Platform::get(&plats);
        return plats;
    }

    static std::vector<cl::Device> getDevices(const std::vector<cl::Platform>& platforms) {
        std::vector<cl::Device> devs;
        platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devs);
        return devs;
    }

    static cl_context get_handle() {
        static std::vector<cl::Platform> platforms = getPlatforms();
        static std::vector<cl::Device> devices = getDevices(platforms);
        static cl::Context ctx = cl::Context(devices[0]);
        return ctx();
    }
};

device_mem_t device_alloc(size_t size) {
    cl_int err;
    cl_mem buf = clCreateBuffer(ClHandle::get_handle(), CL_MEM_READ_WRITE, size, NULL, &err);
    if (err) {
        fprintf(stderr, "error: opencl couldn't allocate buffer, error code: %i", err);
        exit(EXIT_FAILURE);
    }
    return buf;
}

void device_free(device_mem_t m) {
    cl_int err = clReleaseMemObject(m);
    if (err) {
        fprintf(stderr, "error: opencl couldn't allocate buffer");
        exit(EXIT_FAILURE);
    }
}

void device_init() {
}

#define CHECK_HIP(cmd)

#else
#include <hip/hip_runtime_api.h>

#define CHECK_HIP(cmd) \
{\
    hipError_t hip_error  = cmd;\
    if (hip_error != hipSuccess) { \
        fprintf(stderr, "error: '%s'(%d) at %s:%d\n", hipGetErrorString(hip_error), hip_error,__FILE__, __LINE__); \
        exit(EXIT_FAILURE);\
    }\
}

#define device_mem_t void*

device_mem_t device_alloc(size_t size) {
    void* ptr;
    CHECK_HIP(hipMalloc(&ptr, size));
    return ptr;
}

void device_free(device_mem_t m) {
    CHECK_HIP(hipFree(m));
}

std::vector<std::string> split(const std::string& str, char sep) {
    std::vector<std::string> strings;
    std::istringstream f(str);
    std::string s;
    while (std::getline(f, s, sep)) {
        strings.push_back(s);
    }
    return strings;
}

void print_file(const std::string& fname) {
    std::ifstream f(fname);
    std::string s;
    std::cout << "File: " << fname << ", status: " << f.good() << std::endl;
    while (std::getline(f, s)) {
        std::cout << ":: " << s << std::endl;
    }

}

std::vector<std::string> ls_dir(const std::string& dname) {
    std::vector<std::string> files;
    struct dirent* entry;
    DIR *dir = opendir(dname.c_str());
    if (dir == NULL) {
        return files;
    }

    while ((entry = readdir(dir)) != NULL) {
        std::string fname(entry->d_name);
        if (fname != "." && fname != "..")
            files.push_back(fname);
    }
    return files;
}

std::vector<std::string> ls_dir(const std::string& dname, const std::regex& match) {
    std::vector<std::string> files;
    struct dirent* entry;
    DIR *dir = opendir(dname.c_str());
    if (dir == NULL) {
        return files;
    }

    while ((entry = readdir(dir)) != NULL) {
        std::string fname(entry->d_name);
        if (fname != "." && fname != "..") {
            if (std::regex_match(fname, match)) {
                files.push_back(fname);
            }
        }
    }
    return files;
}

int read_current_mhz(const std::string& fname) {
    std::ifstream f(fname);
    std::string line;
    while (std::getline(f, line)) {
        if (line.back() == '*') {
            std::string mhzstr = line.substr(3, line.size()-3-5);
            std::istringstream iss(mhzstr);
            int mhz;
            iss >> mhz;
            return mhz;
        }
    }
    return -1;
}

struct Device {
    int hip_id;
    hipDeviceProp_t hip_props;
    std::string drm_path;
    std::string hwmon_path;

    /// Find the sysfs paths given that the device is initalized by hipGetDeviceProperties
    /// The paths are found using hiDeviceProp_t::pciBusID
    void init_sys_paths() {
        bool found = false;
        for (std::string cardname : ls_dir("/sys/class/drm", std::regex("card\\d+"))) {
            std::string carddir = "/sys/class/drm/" + cardname;
            std::string fname = carddir + "/device/uevent";
            std::ifstream f(fname);
            if (f.good() && f.is_open()) {
                std::string line;
                while (std::getline(f, line)) {
                    if (split(line, '=')[0] == "PCI_SLOT_NAME") {
                        std::string pciids = split(line, '=')[1];
                        std::vector<std::string> ids = split(pciids, ':');
                        //std::string busid = "0x" + ids[1];
                        int pci_busid = std::stoul("0x" + ids[1], nullptr, 16);
                        if (pci_busid == hip_props.pciBusID) {
                            drm_path = carddir;
                            // find hwmon path
                            std::vector<std::string> hwpaths = ls_dir(drm_path + "/device/hwmon", std::regex("hwmon\\d+"));
                            if (hwpaths.size() != 1) {
                                WARNING("No or multiple hwmon paths for " << drm_path);
                            }
                            if (hwpaths.size() > 0) {
                                hwmon_path = drm_path + "/device/hwmon/" + hwpaths[0];
                            }
                            found = true;
                        }
                        break;
                    }
                }
            }
            if (found)
                break;
        }
        if (!found) {
            WARNING("Can't find sysfs path for device " << hip_id);
        }
    }

    void print_info() {
        // print out device info
        INFO("Device " << hip_id << ": " << hip_props.name);
        INFO("\tArch:\t" << hip_props.gcnArch)
        INFO("\tGMem:\t" << hip_props.totalGlobalMem/1024/1024 << " MiB");
        INFO("\twarps:\t" << hip_props.warpSize);
        INFO("\tCUs:\t" << hip_props.multiProcessorCount);
        INFO("\tMaxClk:\t" << hip_props.clockRate);
        INFO("\tMemClk:\t" << hip_props.memoryClockRate);
        INFO("\tdrm:\t" << drm_path);
        INFO("\thwmon:\t" << hwmon_path);
        //INFO("\t\tpciDomainID:\t" << hip_props.pciDomainID);
        //INFO("\t\tpciBusID:\t" << hip_props.pciBusID);
        //INFO("\t\tpciDeviceID:\t" << hip_props.pciDeviceID);
#ifdef __HIP_PLATFORM_HCC__
#endif
    }

    float getTemp() {
        std::ifstream f(hwmon_path + "/temp1_input");
        //std::ifstream f("/sys/class/hwmon/hwmon0/temp1_input");
        int temp;
        f >> temp;
        return temp / 1000.f; // temp is in milli celsius
    }

    int getFanspeed() {
        //std::ifstream f("/sys/class/hwmon/hwmon0/pwm1");
        std::ifstream f(hwmon_path + "/pwm1");
        int fan;
        f >> fan;
        return fan;
    }

    int getClock() {
        return read_current_mhz(drm_path + "/device/pp_dpm_sclk");
    }

    int getMemClock() {
        return read_current_mhz(drm_path + "/device/pp_dpm_mclk");
    }
};

struct Devices {
    static std::vector<Device>& get_devices(bool from_init = false) {
        static bool is_init = false;
        static std::vector<Device> d;
        if (!is_init) {
            is_init = true;
            if (!from_init)
                init_devices();
        }
        return d;
    }

    static Device& get_default_device() {
        if (get_devices().size() == 0) {
            FATAL("No HIP Devices available.");
        }
        return get_devices()[0];
    }

    static void init_devices() {
        int devcount;
        CHECK_HIP(hipGetDeviceCount(&devcount));
        INFO("Number of HIP devices found: " << devcount);

        if (devcount == 0) {
            FATAL("No HIP devices found.");
        }

        std::vector<Device>& devs = get_devices(true);
        devs.resize(devcount);

        // init and get devices
        for (int d = 0; d < devcount; ++d) {
            devs[d].hip_id = d;
            CHECK_HIP(hipGetDeviceProperties(&devs[d].hip_props, d/*deviceID*/));
            devs[d].init_sys_paths();
            devs[d].print_info();
        }

    }

};

void device_init() {
    Devices::init_devices();
}

#endif

const char* mio_err[] = {
    "StatusSuccess        ",
    "StatusNotInitialized ",
    "StatusInvalidValue   ",
    "StatusBadParm        ",
    "StatusAllocFailed    ",
    "StatusInternalError  ",
    "StatusNotImplemented ",
    "StatusUnknownError   "
};

#define CHECK_MIO(cmd) \
{\
    miopenStatus_t miostat = cmd;\
    if (miostat != miopenStatusSuccess) { \
        fprintf(stderr, "error: '%s'(%d) at %s:%d\n", mio_err[(int)miostat], miostat,__FILE__, __LINE__); \
        exit(EXIT_FAILURE);\
    }\
}

// get miopenHandle globally via `mio::handle()`
struct mio {
private:
    // This is called once, the first time the MIOpen handle is retrieved
    static miopenHandle_t init_mio() {
        miopenHandle_t h;
        CHECK_HIP(hipSetDevice(Devices::get_default_device().hip_id));
        hipStream_t q;
        CHECK_HIP(hipStreamCreate(&q));
        CHECK_MIO(miopenCreateWithStream(&h, q));
        return h;
    }
public:
    static miopenHandle_t handle() {
        static miopenHandle_t h = init_mio();
        return h;
    }
};

float getTemp() {
    return Devices::get_default_device().getTemp();
}

int getFanspeed() {
    return Devices::get_default_device().getFanspeed();
}

int getClock() {
    return Devices::get_default_device().getClock();
}

int getMemClock() {
    return Devices::get_default_device().getMemClock();
}

#endif // MY_MIOPEN_HPP
<commit_msg>trying to fix issue #10<commit_after>#ifndef MY_MIOPEN_HPP
#define MY_MIOPEN_HPP

#include <miopen/miopen.h>
#include <hipblas.h>
//#include <gperftools/profiler.h>

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <regex>
#include <dirent.h>

//#define WITH_CL

#define DEBUG(msg) std::cerr << "[DEBUG] " << msg << std::endl;
#define WARNING(msg) std::cerr << "[!WARNING!] " << msg << std::endl;
#define FATAL(msg) {std::cerr << "[!FATAL!] " << msg << std::endl; exit(EXIT_FAILURE);} while(0)
#define INFO(msg) std::cout << "[INFO]  " << msg << std::endl;

#ifdef WITH_CL // not supported anymore
#include <CL/cl.hpp>
#define device_mem_t cl_mem

struct ClHandle {
    static std::vector<cl::Platform> getPlatforms() {
        std::vector<cl::Platform> plats;
        cl::Platform::get(&plats);
        return plats;
    }

    static std::vector<cl::Device> getDevices(const std::vector<cl::Platform>& platforms) {
        std::vector<cl::Device> devs;
        platforms[0].getDevices(CL_DEVICE_TYPE_ALL, &devs);
        return devs;
    }

    static cl_context get_handle() {
        static std::vector<cl::Platform> platforms = getPlatforms();
        static std::vector<cl::Device> devices = getDevices(platforms);
        static cl::Context ctx = cl::Context(devices[0]);
        return ctx();
    }
};

device_mem_t device_alloc(size_t size) {
    cl_int err;
    cl_mem buf = clCreateBuffer(ClHandle::get_handle(), CL_MEM_READ_WRITE, size, NULL, &err);
    if (err) {
        fprintf(stderr, "error: opencl couldn't allocate buffer, error code: %i", err);
        exit(EXIT_FAILURE);
    }
    return buf;
}

void device_free(device_mem_t m) {
    cl_int err = clReleaseMemObject(m);
    if (err) {
        fprintf(stderr, "error: opencl couldn't allocate buffer");
        exit(EXIT_FAILURE);
    }
}

void device_init() {
}

#define CHECK_HIP(cmd)

#else
#include <hip/hip_runtime_api.h>

#define CHECK_HIP(cmd) \
{\
    hipError_t hip_error  = cmd;\
    if (hip_error != hipSuccess) { \
        fprintf(stderr, "error: '%s'(%d) at %s:%d\n", hipGetErrorString(hip_error), hip_error,__FILE__, __LINE__); \
        exit(EXIT_FAILURE);\
    }\
}

#define device_mem_t void*

device_mem_t device_alloc(size_t size) {
    void* ptr;
    CHECK_HIP(hipMalloc(&ptr, size));
    return ptr;
}

void device_free(device_mem_t m) {
    CHECK_HIP(hipFree(m));
}

std::vector<std::string> split(const std::string& str, char sep) {
    std::vector<std::string> strings;
    std::istringstream f(str);
    std::string s;
    while (std::getline(f, s, sep)) {
        strings.push_back(s);
    }
    return strings;
}

void print_file(const std::string& fname) {
    std::ifstream f(fname);
    std::string s;
    std::cout << "File: " << fname << ", status: " << f.good() << std::endl;
    while (std::getline(f, s)) {
        std::cout << ":: " << s << std::endl;
    }

}

std::vector<std::string> ls_dir(const std::string& dname) {
    std::vector<std::string> files;
    struct dirent* entry;
    DIR *dir = opendir(dname.c_str());
    if (dir == NULL) {
        return files;
    }

    while ((entry = readdir(dir)) != NULL) {
        std::string fname(entry->d_name);
        if (fname != "." && fname != "..")
            files.push_back(fname);
    }
    return files;
}

std::vector<std::string> ls_dir(const std::string& dname, const std::regex& match) {
    std::vector<std::string> files;
    struct dirent* entry;
    DIR *dir = opendir(dname.c_str());
    if (dir == NULL) {
        return files;
    }

    while ((entry = readdir(dir)) != NULL) {
        std::string fname(entry->d_name);
        if (fname != "." && fname != "..") {
            if (std::regex_match(fname, match)) {
                files.push_back(fname);
            }
        }
    }
    return files;
}

int read_current_mhz(const std::string& fname) {
    std::ifstream f(fname);
    std::string line;
    while (std::getline(f, line)) {
        if (line.back() == '*') {
            std::string mhzstr = line.substr(3, line.size()-3-5);
            std::istringstream iss(mhzstr);
            int mhz;
            iss >> mhz;
            return mhz;
        }
    }
    return -1;
}

struct Device {
    int hip_id;
    hipDeviceProp_t hip_props;
    std::string drm_path;
    std::string hwmon_path;

    /// Find the sysfs paths given that the device is initalized by hipGetDeviceProperties
    /// The paths are found using hiDeviceProp_t::pciBusID
    void init_sys_paths() {
        bool found = false;
        std::regex card_re("card\\d+");
        for (std::string cardname : ls_dir("/sys/class/drm", card_re)) {
            std::string carddir = "/sys/class/drm/" + cardname;
            std::string fname = carddir + "/device/uevent";
            std::ifstream f(fname);
            if (f.good() && f.is_open()) {
                std::string line;
                while (std::getline(f, line)) {
                    if (split(line, '=')[0] == "PCI_SLOT_NAME") {
                        std::string pciids = split(line, '=')[1];
                        std::vector<std::string> ids = split(pciids, ':');
                        //std::string busid = "0x" + ids[1];
                        int pci_busid = std::stoul("0x" + ids[1], nullptr, 16);
                        if (pci_busid == hip_props.pciBusID) {
                            drm_path = carddir;
                            // find hwmon path
                            std::vector<std::string> hwpaths = ls_dir(drm_path + "/device/hwmon", std::regex("hwmon\\d+"));
                            if (hwpaths.size() != 1) {
                                WARNING("No or multiple hwmon paths for " << drm_path);
                            }
                            if (hwpaths.size() > 0) {
                                hwmon_path = drm_path + "/device/hwmon/" + hwpaths[0];
                            }
                            found = true;
                        }
                        break;
                    }
                }
            }
            if (found)
                break;
        }
        if (!found) {
            WARNING("Can't find sysfs path for device " << hip_id);
        }
    }

    void print_info() {
        // print out device info
        INFO("Device " << hip_id << ": " << hip_props.name);
        INFO("\tArch:\t" << hip_props.gcnArch)
        INFO("\tGMem:\t" << hip_props.totalGlobalMem/1024/1024 << " MiB");
        INFO("\twarps:\t" << hip_props.warpSize);
        INFO("\tCUs:\t" << hip_props.multiProcessorCount);
        INFO("\tMaxClk:\t" << hip_props.clockRate);
        INFO("\tMemClk:\t" << hip_props.memoryClockRate);
        INFO("\tdrm:\t" << drm_path);
        INFO("\thwmon:\t" << hwmon_path);
        //INFO("\t\tpciDomainID:\t" << hip_props.pciDomainID);
        //INFO("\t\tpciBusID:\t" << hip_props.pciBusID);
        //INFO("\t\tpciDeviceID:\t" << hip_props.pciDeviceID);
#ifdef __HIP_PLATFORM_HCC__
#endif
    }

    float getTemp() {
        std::ifstream f(hwmon_path + "/temp1_input");
        //std::ifstream f("/sys/class/hwmon/hwmon0/temp1_input");
        int temp;
        f >> temp;
        return temp / 1000.f; // temp is in milli celsius
    }

    int getFanspeed() {
        //std::ifstream f("/sys/class/hwmon/hwmon0/pwm1");
        std::ifstream f(hwmon_path + "/pwm1");
        int fan;
        f >> fan;
        return fan;
    }

    int getClock() {
        return read_current_mhz(drm_path + "/device/pp_dpm_sclk");
    }

    int getMemClock() {
        return read_current_mhz(drm_path + "/device/pp_dpm_mclk");
    }
};

struct Devices {
    static std::vector<Device>& get_devices(bool from_init = false) {
        static bool is_init = false;
        static std::vector<Device> d;
        if (!is_init) {
            is_init = true;
            if (!from_init)
                init_devices();
        }
        return d;
    }

    static Device& get_default_device() {
        if (get_devices().size() == 0) {
            FATAL("No HIP Devices available.");
        }
        return get_devices()[0];
    }

    static void init_devices() {
        int devcount;
        CHECK_HIP(hipGetDeviceCount(&devcount));
        INFO("Number of HIP devices found: " << devcount);

        if (devcount == 0) {
            FATAL("No HIP devices found.");
        }

        std::vector<Device>& devs = get_devices(true);
        devs.resize(devcount);

        // init and get devices
        for (int d = 0; d < devcount; ++d) {
            devs[d].hip_id = d;
            CHECK_HIP(hipGetDeviceProperties(&devs[d].hip_props, d/*deviceID*/));
            devs[d].init_sys_paths();
            devs[d].print_info();
        }

    }

};

void device_init() {
    Devices::init_devices();
}

#endif

const char* mio_err[] = {
    "StatusSuccess        ",
    "StatusNotInitialized ",
    "StatusInvalidValue   ",
    "StatusBadParm        ",
    "StatusAllocFailed    ",
    "StatusInternalError  ",
    "StatusNotImplemented ",
    "StatusUnknownError   "
};

#define CHECK_MIO(cmd) \
{\
    miopenStatus_t miostat = cmd;\
    if (miostat != miopenStatusSuccess) { \
        fprintf(stderr, "error: '%s'(%d) at %s:%d\n", mio_err[(int)miostat], miostat,__FILE__, __LINE__); \
        exit(EXIT_FAILURE);\
    }\
}

// get miopenHandle globally via `mio::handle()`
struct mio {
private:
    // This is called once, the first time the MIOpen handle is retrieved
    static miopenHandle_t init_mio() {
        miopenHandle_t h;
        CHECK_HIP(hipSetDevice(Devices::get_default_device().hip_id));
        hipStream_t q;
        CHECK_HIP(hipStreamCreate(&q));
        CHECK_MIO(miopenCreateWithStream(&h, q));
        return h;
    }
public:
    static miopenHandle_t handle() {
        static miopenHandle_t h = init_mio();
        return h;
    }
};

float getTemp() {
    return Devices::get_default_device().getTemp();
}

int getFanspeed() {
    return Devices::get_default_device().getFanspeed();
}

int getClock() {
    return Devices::get_default_device().getClock();
}

int getMemClock() {
    return Devices::get_default_device().getMemClock();
}

#endif // MY_MIOPEN_HPP
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, Alexander Fronkin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <cerrno>
#include <cstdio>
#include <cstring>
#include "marcrecord.h"
#include "marcrecord_tools.h"
#include "unimarcxml_writer.h"

using namespace marcrecord;

/*
 * Constructor.
 */
UnimarcXmlWriter::UnimarcXmlWriter(FILE *outputFile,
	const char *outputEncoding)
	: MarcWriter()
{
	// Clear member variables.
	m_iconvDesc = (iconv_t) -1;

	if (outputFile) {
		// Open output file.
		open(outputFile, outputEncoding);
	} else {
		// Clear object state.
		close();
	}
}

/*
 * Destructor.
 */
UnimarcXmlWriter::~UnimarcXmlWriter()
{
	// Close output file.
	close();
}

/*
 * Open output file.
 */
bool
UnimarcXmlWriter::open(FILE *outputFile, const char *outputEncoding)
{
	// Clear error code and message.
	m_errorCode = OK;
	m_errorMessage = "";

	// Initialize output stream parameters.
	m_outputFile = outputFile == NULL ? stdout : outputFile;
	m_outputEncoding = outputEncoding == NULL ? "" : outputEncoding;

	// Initialize encoding conversion.
	if (outputEncoding == NULL
		|| strcmp(outputEncoding, "UTF-8") == 0
		|| strcmp(outputEncoding, "utf-8") == 0)
	{
		m_iconvDesc = (iconv_t) -1;
	} else {
		// Create iconv descriptor for output encoding conversion.
		m_iconvDesc = iconv_open(outputEncoding, "UTF-8");
		if (m_iconvDesc == (iconv_t) -1) {
			m_errorCode = ERROR_ICONV;
			if (errno == EINVAL) {
				m_errorMessage =
					"encoding conversion is not supported";
			} else {
				m_errorMessage = "iconv initialization failed";
			}
			return false;
		}
	}

	return true;
}

/*
 * Close output file.
 */
void
UnimarcXmlWriter::close(void)
{
	// Finalize iconv.
	if (m_iconvDesc != (iconv_t) -1) {
		iconv_close(m_iconvDesc);
	}

	// Clear member variables.
	m_errorCode = OK;
	m_errorMessage = "";
	m_outputFile = NULL;
	m_outputEncoding = "";
	m_iconvDesc = (iconv_t) -1;
}

/*
 * Write record to output file.
 */
bool
UnimarcXmlWriter::write(MarcRecord &record)
{
	std::string recordBuf = "";

	// Append tag '<record>'.
	recordBuf += "  <record>\n";

	// Append record leader.
	recordBuf += "    <leader>     "
		+ std::string((char *) &record.m_leader + 5,
		(size_t) sizeof(MarcRecord::Leader) - 5)
		+ "</leader>\n";

	// Iterate all fields.
	for (MarcRecord::FieldIt fieldIt = record.m_fieldList.begin();
		fieldIt != record.m_fieldList.end(); fieldIt++)
	{
		std::string xmlData;

		if (fieldIt->m_tag < "010") {
			// Append control field.
			xmlData = serialize_xml(fieldIt->m_data);
			recordBuf += "    <controlfield tag=\""
				+ fieldIt->m_tag + "\">"
				+ xmlData + "</controlfield>\n";
		} else {
			// Append data field.
			appendDataField(recordBuf, fieldIt);
		}
	}

	// Append tag '<record>'.
	recordBuf += "  </record>\n";

	if (m_iconvDesc == (iconv_t) -1) {
		// Write UNIMARCXML record.
		if (fwrite(recordBuf.c_str(), recordBuf.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	} else {
		// Write UNIMARCXML record with encoding conversion.
		std::string iconvBuf;
		if (!iconv(m_iconvDesc, recordBuf, iconvBuf)) {
			m_errorCode = ERROR_ICONV;
			m_errorMessage = "encoding conversion failed";
			return false;
		}
		if (fwrite(iconvBuf.c_str(), iconvBuf.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	}

	return true;
}

/*
 * Write header to output file.
 */
bool
UnimarcXmlWriter::writeHeader(void)
{
	std::string header = "";

	// Create UNIMARCXML header.
	if (m_outputEncoding != "") {
		header += "<?xml version=\"1.0\" encoding=\""
			+ m_outputEncoding + "\"?>\n";
	} else {
		header = "<?xml version=\"1.0\"?>\n";
	}

	header += "<collection xmlns="
		"\"http://www.rusmarc.ru/shema/UNISlim.xsd\">\n";

	if (m_iconvDesc == (iconv_t) -1) {
		// Write UNIMARCXML header.
		if (fwrite(header.c_str(), header.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	} else {
		// Write UNIMARCXML header with encoding conversion.
		std::string iconvBuf;
		if (!iconv(m_iconvDesc, header, iconvBuf)) {
			m_errorCode = ERROR_ICONV;
			m_errorMessage = "encoding conversion failed";
			return false;
		}
		if (fwrite(iconvBuf.c_str(), iconvBuf.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	}

	return true;
}

/*
 * Write footer to output file.
 */
bool
UnimarcXmlWriter::writeFooter(void)
{
	std::string footer = "</collection>\n";

	if (m_iconvDesc == (iconv_t) -1) {
		// Write UNIMARCXML footer.
		if (fwrite(footer.c_str(), footer.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	} else {
		// Write UNIMARCXML footer with encoding conversion.
		std::string iconvBuf;
		if (!iconv(m_iconvDesc, footer, iconvBuf)) {
			m_errorCode = ERROR_ICONV;
			m_errorMessage = "encoding conversion failed";
			return false;
		}
		if (fwrite(iconvBuf.c_str(), iconvBuf.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	}

	return true;
}

/*
 * Append data field to UNIMARCXML file to record buffer.
 */
void
UnimarcXmlWriter::appendDataField(std::string &recordBuf,
	MarcRecord::FieldIt &fieldIt)
{
	// Append tag '<datafield>'.
	recordBuf += "    <datafield tag=\"" + fieldIt->m_tag
		+ "\" ind1=\"" + fieldIt->m_ind1
		+ "\" ind2=\"" + fieldIt->m_ind2 + "\">\n";

	// Iterate all subfields.
	MarcRecord::SubfieldIt subfieldIt = fieldIt->m_subfieldList.begin();
	bool isEmbeddedField = false;
	for (; subfieldIt != fieldIt->m_subfieldList.end();
		subfieldIt++)
	{
		std::string xmlData;

		if (subfieldIt->isEmbedded()) {
			if (isEmbeddedField) {
				// Append embedded field footer.
				recordBuf = recordBuf
					+ "        </datafield>\n"
					+ "      </s1>\n";
			}

			// Append embedded field header.
			std::string embeddedTag = subfieldIt->getEmbeddedTag();
			if (embeddedTag < "010") {
				// Append embedded control field.
				std::string embeddedData =
					subfieldIt->getEmbeddedData();
				xmlData = serialize_xml(embeddedData);
				recordBuf = recordBuf
					+ "      <s1>\n"
					+ "        <controlfield tag=\""
					+ embeddedTag + "\">"
					+ xmlData + "</controlfield>\n"
					+ "      </s1>\n";
			} else {
				isEmbeddedField = true;
				recordBuf = recordBuf
					+ "      <s1>\n"
					+ "        <datafield tag=\""
					+ embeddedTag
					+ "\" ind1=\""
					+ subfieldIt->getEmbeddedInd1()
					+ "\" ind2=\""
					+ subfieldIt->getEmbeddedInd2()
					+ "\">\n";
			}
			continue;
		}

		// Append indent for embedded field.
		if (isEmbeddedField) {
			recordBuf += "    ";
		}

		// Append subfield.
		xmlData = serialize_xml(subfieldIt->m_data);
		recordBuf = recordBuf
			+ "      <subfield code=\""
			+ subfieldIt->m_id + "\">"
			+ xmlData + "</subfield>\n";
	}

	// Append embedded field footer.
	if (isEmbeddedField) {
		recordBuf = recordBuf
			+ "        </datafield>\n"
			+ "      </s1>\n";
	}

	// Append tag '</datafield>'.
	recordBuf += "    </datafield>\n";
}
<commit_msg>Fixed embedded data field footer output in UnimarcXmlWriter<commit_after>/*
 * Copyright (c) 2013, Alexander Fronkin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <cerrno>
#include <cstdio>
#include <cstring>
#include "marcrecord.h"
#include "marcrecord_tools.h"
#include "unimarcxml_writer.h"

using namespace marcrecord;

/*
 * Constructor.
 */
UnimarcXmlWriter::UnimarcXmlWriter(FILE *outputFile,
	const char *outputEncoding)
	: MarcWriter()
{
	// Clear member variables.
	m_iconvDesc = (iconv_t) -1;

	if (outputFile) {
		// Open output file.
		open(outputFile, outputEncoding);
	} else {
		// Clear object state.
		close();
	}
}

/*
 * Destructor.
 */
UnimarcXmlWriter::~UnimarcXmlWriter()
{
	// Close output file.
	close();
}

/*
 * Open output file.
 */
bool
UnimarcXmlWriter::open(FILE *outputFile, const char *outputEncoding)
{
	// Clear error code and message.
	m_errorCode = OK;
	m_errorMessage = "";

	// Initialize output stream parameters.
	m_outputFile = outputFile == NULL ? stdout : outputFile;
	m_outputEncoding = outputEncoding == NULL ? "" : outputEncoding;

	// Initialize encoding conversion.
	if (outputEncoding == NULL
		|| strcmp(outputEncoding, "UTF-8") == 0
		|| strcmp(outputEncoding, "utf-8") == 0)
	{
		m_iconvDesc = (iconv_t) -1;
	} else {
		// Create iconv descriptor for output encoding conversion.
		m_iconvDesc = iconv_open(outputEncoding, "UTF-8");
		if (m_iconvDesc == (iconv_t) -1) {
			m_errorCode = ERROR_ICONV;
			if (errno == EINVAL) {
				m_errorMessage =
					"encoding conversion is not supported";
			} else {
				m_errorMessage = "iconv initialization failed";
			}
			return false;
		}
	}

	return true;
}

/*
 * Close output file.
 */
void
UnimarcXmlWriter::close(void)
{
	// Finalize iconv.
	if (m_iconvDesc != (iconv_t) -1) {
		iconv_close(m_iconvDesc);
	}

	// Clear member variables.
	m_errorCode = OK;
	m_errorMessage = "";
	m_outputFile = NULL;
	m_outputEncoding = "";
	m_iconvDesc = (iconv_t) -1;
}

/*
 * Write record to output file.
 */
bool
UnimarcXmlWriter::write(MarcRecord &record)
{
	std::string recordBuf = "";

	// Append tag '<record>'.
	recordBuf += "  <record>\n";

	// Append record leader.
	recordBuf += "    <leader>     "
		+ std::string((char *) &record.m_leader + 5,
		(size_t) sizeof(MarcRecord::Leader) - 5)
		+ "</leader>\n";

	// Iterate all fields.
	for (MarcRecord::FieldIt fieldIt = record.m_fieldList.begin();
		fieldIt != record.m_fieldList.end(); fieldIt++)
	{
		std::string xmlData;

		if (fieldIt->m_tag < "010") {
			// Append control field.
			xmlData = serialize_xml(fieldIt->m_data);
			recordBuf += "    <controlfield tag=\""
				+ fieldIt->m_tag + "\">"
				+ xmlData + "</controlfield>\n";
		} else {
			// Append data field.
			appendDataField(recordBuf, fieldIt);
		}
	}

	// Append tag '<record>'.
	recordBuf += "  </record>\n";

	if (m_iconvDesc == (iconv_t) -1) {
		// Write UNIMARCXML record.
		if (fwrite(recordBuf.c_str(), recordBuf.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	} else {
		// Write UNIMARCXML record with encoding conversion.
		std::string iconvBuf;
		if (!iconv(m_iconvDesc, recordBuf, iconvBuf)) {
			m_errorCode = ERROR_ICONV;
			m_errorMessage = "encoding conversion failed";
			return false;
		}
		if (fwrite(iconvBuf.c_str(), iconvBuf.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	}

	return true;
}

/*
 * Write header to output file.
 */
bool
UnimarcXmlWriter::writeHeader(void)
{
	std::string header = "";

	// Create UNIMARCXML header.
	if (m_outputEncoding != "") {
		header += "<?xml version=\"1.0\" encoding=\""
			+ m_outputEncoding + "\"?>\n";
	} else {
		header = "<?xml version=\"1.0\"?>\n";
	}

	header += "<collection xmlns="
		"\"http://www.rusmarc.ru/shema/UNISlim.xsd\">\n";

	if (m_iconvDesc == (iconv_t) -1) {
		// Write UNIMARCXML header.
		if (fwrite(header.c_str(), header.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	} else {
		// Write UNIMARCXML header with encoding conversion.
		std::string iconvBuf;
		if (!iconv(m_iconvDesc, header, iconvBuf)) {
			m_errorCode = ERROR_ICONV;
			m_errorMessage = "encoding conversion failed";
			return false;
		}
		if (fwrite(iconvBuf.c_str(), iconvBuf.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	}

	return true;
}

/*
 * Write footer to output file.
 */
bool
UnimarcXmlWriter::writeFooter(void)
{
	std::string footer = "</collection>\n";

	if (m_iconvDesc == (iconv_t) -1) {
		// Write UNIMARCXML footer.
		if (fwrite(footer.c_str(), footer.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	} else {
		// Write UNIMARCXML footer with encoding conversion.
		std::string iconvBuf;
		if (!iconv(m_iconvDesc, footer, iconvBuf)) {
			m_errorCode = ERROR_ICONV;
			m_errorMessage = "encoding conversion failed";
			return false;
		}
		if (fwrite(iconvBuf.c_str(), iconvBuf.size(), 1,
			m_outputFile) != 1)
		{
			m_errorCode = ERROR_IO;
			m_errorMessage = "i/o operation failed";
			return false;
		}
	}

	return true;
}

/*
 * Append data field to UNIMARCXML file to record buffer.
 */
void
UnimarcXmlWriter::appendDataField(std::string &recordBuf,
	MarcRecord::FieldIt &fieldIt)
{
	// Append tag '<datafield>'.
	recordBuf += "    <datafield tag=\"" + fieldIt->m_tag
		+ "\" ind1=\"" + fieldIt->m_ind1
		+ "\" ind2=\"" + fieldIt->m_ind2 + "\">\n";

	// Iterate all subfields.
	MarcRecord::SubfieldIt subfieldIt = fieldIt->m_subfieldList.begin();
	bool isEmbeddedDataField = false;
	for (; subfieldIt != fieldIt->m_subfieldList.end();
		subfieldIt++)
	{
		std::string xmlData;

		if (subfieldIt->isEmbedded()) {
			if (isEmbeddedDataField) {
				// Append embedded data field footer.
				recordBuf = recordBuf
					+ "        </datafield>\n"
					+ "      </s1>\n";
			}

			// Append embedded field header.
			std::string embeddedTag = subfieldIt->getEmbeddedTag();
			if (embeddedTag < "010") {
				// Append embedded control field.
				std::string embeddedData =
					subfieldIt->getEmbeddedData();
				xmlData = serialize_xml(embeddedData);
				recordBuf = recordBuf
					+ "      <s1>\n"
					+ "        <controlfield tag=\""
					+ embeddedTag + "\">"
					+ xmlData + "</controlfield>\n"
					+ "      </s1>\n";
				isEmbeddedDataField = false;
			} else {
				recordBuf = recordBuf
					+ "      <s1>\n"
					+ "        <datafield tag=\""
					+ embeddedTag
					+ "\" ind1=\""
					+ subfieldIt->getEmbeddedInd1()
					+ "\" ind2=\""
					+ subfieldIt->getEmbeddedInd2()
					+ "\">\n";
				isEmbeddedDataField = true;
			}
			continue;
		}

		// Append indent for embedded field.
		if (isEmbeddedDataField) {
			recordBuf += "    ";
		}

		// Append subfield.
		xmlData = serialize_xml(subfieldIt->m_data);
		recordBuf = recordBuf
			+ "      <subfield code=\""
			+ subfieldIt->m_id + "\">"
			+ xmlData + "</subfield>\n";
	}

	// Append embedded data field footer.
	if (isEmbeddedDataField) {
		recordBuf = recordBuf
			+ "        </datafield>\n"
			+ "      </s1>\n";
	}

	// Append tag '</datafield>'.
	recordBuf += "    </datafield>\n";
}
<|endoftext|>


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

#include <functional>
#include <memory>
#include <system_error>
#include <boost/asio.hpp>
#include <boost/date_time.hpp>
#include <bitcoin/bitcoin/error.hpp>
#include <bitcoin/bitcoin/utility/assert.hpp>
#include <bitcoin/bitcoin/network/channel.hpp>
#include <bitcoin/bitcoin/network/channel_proxy.hpp>
#include <bitcoin/bitcoin/network/network.hpp>
#include <bitcoin/bitcoin/utility/threadpool.hpp>

namespace libbitcoin {
namespace network {

using std::placeholders::_1;
using std::placeholders::_2;
using boost::asio::ip::tcp;
using boost::posix_time::time_duration;

static inline bool aborted(const boost::system::error_code& ec)
{
    return ec == boost::asio::error::operation_aborted;
}

connect_with_timeout::connect_with_timeout(threadpool& pool,
    const timeout& timeouts)
  : timer_(pool.service()),
    connection_timeout_(timeouts.connection),
    socket_(std::make_shared<tcp::socket>(pool.service())),
    proxy_(std::make_shared<channel_proxy>(pool, socket_, timeouts))
{
}

void connect_with_timeout::start(tcp::resolver::iterator endpoint_iterator,
    network::connect_handler handle_connect)
{
    timer_.expires_from_now(connection_timeout_);
    timer_.async_wait(
        std::bind(&connect_with_timeout::handle_timer,
            shared_from_this(), _1, handle_connect));

    boost::asio::async_connect(*socket_, endpoint_iterator,
        std::bind(&connect_with_timeout::call_handle_connect,
            shared_from_this(), _1, _2, handle_connect));
}

void connect_with_timeout::call_handle_connect(
    const boost::system::error_code& ec, tcp::resolver::iterator,
    network::connect_handler handle_connect)
{
    timer_.cancel();

    const auto error = error::boost_to_error_code(ec);
    if (error)
    {
        handle_connect(error, nullptr);
        return;
    }

    const auto channel_object = std::make_shared<channel>(proxy_);
    handle_connect(error, channel_object);
    proxy_->start();
}

void connect_with_timeout::handle_timer(const boost::system::error_code& ec,
    network::connect_handler handle_connect)
{
    // Did the timer fire because of cancelation?
    if (aborted(ec))
        return;

    auto error = error::boost_to_error_code(ec);
    if (!error)
    {
        // If there is no error the timer fired because of expiration.
        error = error::channel_timeout;
        proxy_->stop(error);
    }

    handle_connect(error, nullptr);
}

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

#include <functional>
#include <memory>
#include <system_error>
#include <boost/asio.hpp>
#include <boost/date_time.hpp>
#include <bitcoin/bitcoin/error.hpp>
#include <bitcoin/bitcoin/utility/assert.hpp>
#include <bitcoin/bitcoin/network/channel.hpp>
#include <bitcoin/bitcoin/network/channel_proxy.hpp>
#include <bitcoin/bitcoin/network/network.hpp>
#include <bitcoin/bitcoin/utility/threadpool.hpp>

namespace libbitcoin {
namespace network {

using std::placeholders::_1;
using std::placeholders::_2;
using boost::asio::ip::tcp;
using boost::posix_time::time_duration;

static inline bool aborted(const boost::system::error_code& ec)
{
    return ec == boost::asio::error::operation_aborted;
}

connect_with_timeout::connect_with_timeout(threadpool& pool,
    const timeout& timeouts)
  : timer_(pool.service()),
    connection_timeout_(timeouts.connection),
    socket_(std::make_shared<tcp::socket>(pool.service())),
    proxy_(std::make_shared<channel_proxy>(pool, socket_, timeouts))
{
}

void connect_with_timeout::start(tcp::resolver::iterator endpoint_iterator,
    network::connect_handler handle_connect)
{
    timer_.expires_from_now(connection_timeout_);
    timer_.async_wait(
        std::bind(&connect_with_timeout::handle_timer,
            shared_from_this(), _1, handle_connect));

    boost::asio::async_connect(*socket_, endpoint_iterator,
        std::bind(&connect_with_timeout::call_handle_connect,
            shared_from_this(), _1, _2, handle_connect));
}

void connect_with_timeout::call_handle_connect(
    const boost::system::error_code& ec, tcp::resolver::iterator,
    network::connect_handler handle_connect)
{
    timer_.cancel();

    const auto error = error::boost_to_error_code(ec);
    if (error)
    {
        handle_connect(error, nullptr);
        return;
    }

    const auto channel_object = std::make_shared<channel>(proxy_);
    handle_connect(error, channel_object);
    proxy_->start();
}

void connect_with_timeout::handle_timer(const boost::system::error_code& ec,
    network::connect_handler handle_connect)
{
    // Did the timer fire because of cancelation?
    if (aborted(ec))
        return;

    // If there is no error the timer fired because of expiration.
    using namespace error;
    const auto code = ec ? boost_to_error_code(ec) : channel_timeout;
    handle_connect(code, nullptr);
}

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


<commit_before>/** @file
    @brief Implementation

    @date 2014

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2014 Sensics, Inc.
//
// 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.

// Internal Includes
#include <osvr/Common/PathElementTypes.h>

// Library/third-party includes
// - none

// Standard includes
// - none

namespace osvr {
namespace common {
    namespace elements {

        /// This chunk of code checks at compile time that:
        ///
        /// - All the types in our PathElement variant are derived from
        /// ElementBase<T>
        /// - For every type T in that variant, it is derived from
        /// ElementBase<T> - stronger than the check we put in the constructor,
        /// though it doesn't help with types that aren't listed in the variant,
        /// hence why we keep both checks.
        namespace detail {
            struct CRTPChecker {
                template <typename T> struct apply {
                    typedef ElementBase<T> base_type;
                    static_assert(std::is_base_of<base_type, T>::value,
                                  "A given element type T must inherit from "
                                  "ElementBase<T> (the CRTP)!");
                    typedef void type;
                };
            };

            // Force instantiation of the types for static asserts.
            typedef boost::mpl::transform<PathElement::types, CRTPChecker>::type
                CRTPCheckDummy;
        } // namespace detail

        AliasElement::AliasElement(std::string const &source)
            : m_source(source) {}
        void AliasElement::setSource(std::string const &source) {
            /// @todo validation?
            m_source = source;
        }

        std::string &AliasElement::getSource() { return m_source; }
        std::string const &AliasElement::getSource() const { return m_source; }

        DeviceElement
        DeviceElement::createVRPNDeviceElement(std::string const &deviceName,
                                               std::string const &server) {
            DeviceElement ret;
            ret.m_devName = deviceName;
            ret.m_server = server;
            return ret;
        }

        std::string &DeviceElement::getDeviceName() { return m_devName; }
        std::string const &DeviceElement::getDeviceName() const {
            return m_devName;
        }

        std::string &DeviceElement::getServer() { return m_server; }
        std::string const &DeviceElement::getServer() const { return m_server; }

        std::string DeviceElement::getFullDeviceName() const {
            return getDeviceName() + "@" + getServer();
        }
    } // namespace elements
} // namespace common
} // namespace osvr
<commit_msg>Put dummy code for static assertion in an anonymous namespace.<commit_after>/** @file
    @brief Implementation

    @date 2014

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2014 Sensics, Inc.
//
// 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.

// Internal Includes
#include <osvr/Common/PathElementTypes.h>

// Library/third-party includes
// - none

// Standard includes
// - none

namespace osvr {
namespace common {
    namespace elements {

        /// This chunk of code checks at compile time that:
        ///
        /// - All the types in our PathElement variant are derived from
        /// ElementBase<T>
        /// - For every type T in that variant, it is derived from
        /// ElementBase<T> - stronger than the check we put in the constructor,
        /// though it doesn't help with types that aren't listed in the variant,
        /// hence why we keep both checks.
        namespace {
            struct CRTPChecker {
                template <typename T> struct apply {
                    typedef ElementBase<T> base_type;
                    static_assert(std::is_base_of<base_type, T>::value,
                                  "A given element type T must inherit from "
                                  "ElementBase<T> (the CRTP)!");
                    typedef void type;
                };
            };

            // Force instantiation of the types for static asserts.
            typedef boost::mpl::transform<PathElement::types, CRTPChecker>::type
                CRTPCheckDummy;
        } // namespace

        AliasElement::AliasElement(std::string const &source)
            : m_source(source) {}
        void AliasElement::setSource(std::string const &source) {
            /// @todo validation?
            m_source = source;
        }

        std::string &AliasElement::getSource() { return m_source; }
        std::string const &AliasElement::getSource() const { return m_source; }

        DeviceElement
        DeviceElement::createVRPNDeviceElement(std::string const &deviceName,
                                               std::string const &server) {
            DeviceElement ret;
            ret.m_devName = deviceName;
            ret.m_server = server;
            return ret;
        }

        std::string &DeviceElement::getDeviceName() { return m_devName; }
        std::string const &DeviceElement::getDeviceName() const {
            return m_devName;
        }

        std::string &DeviceElement::getServer() { return m_server; }
        std::string const &DeviceElement::getServer() const { return m_server; }

        std::string DeviceElement::getFullDeviceName() const {
            return getDeviceName() + "@" + getServer();
        }
    } // namespace elements
} // namespace common
} // namespace osvr
<|endoftext|>


<commit_before>
#include "firebasepush.hh"
#include <iostream>
#include <string.h>
#include <flexisip/logmanager.hh>

using namespace std;
using namespace flexisip;

/*
 * This supports the legacy http Firebase protocol:
 * https://firebase.google.com/docs/cloud-messaging/http-server-ref
 */

FirebasePushNotificationRequest::FirebasePushNotificationRequest(const PushInfo &pinfo)
: PushNotificationRequest(pinfo.mAppId, "firebase") {
	const string &deviceToken = pinfo.mDeviceToken;
	const string &apiKey = pinfo.mApiKey;
	const string &from = pinfo.mFromName.empty() ? pinfo.mFromUri : pinfo.mFromName;
	ostringstream httpBody;
	string date = getPushTimeStamp();

	httpBody << "{\"to\":\"" << deviceToken << "\", \"priority\":\"high\"" << ", \"uuid\":" << quoteStringIfNeeded(pinfo.mUid)
		<< ", \"call-id\":" << quoteStringIfNeeded(pinfo.mCallId)
		<< ", \"from\":" << quoteStringIfNeeded(from)
		<< ", \"send-time\":\"" << date << "\"}";
	mHttpBody = httpBody.str();
	LOGD("Push notification https post body is %s", mHttpBody.c_str());

	ostringstream httpHeader;
	httpHeader << "POST /fcm/send "
	"HTTP/1.1\r\nHost:fcm.googleapis.com\r\nContent-Type:application/json\r\nAuthorization:key="
	<< apiKey << "\r\nContent-Length:" << httpBody.str().size() << "\r\n\r\n";
	mHttpHeader = httpHeader.str();
	SLOGD << "PNR " << this << " https post header is " << mHttpHeader;
}

void FirebasePushNotificationRequest::createPushNotification() {
	int headerLength = mHttpHeader.length();
	int bodyLength = mHttpBody.length();

	mBuffer.clear();
	mBuffer.resize(headerLength + bodyLength);

	char *binaryMessageBuff = &mBuffer[0];
	char *binaryMessagePt = binaryMessageBuff;

	memcpy(binaryMessagePt, &mHttpHeader[0], headerLength);
	binaryMessagePt += headerLength;

	memcpy(binaryMessagePt, &mHttpBody[0], bodyLength);
	binaryMessagePt += bodyLength;
}

const vector<char> &FirebasePushNotificationRequest::getData() {
	createPushNotification();
	return mBuffer;
}

string FirebasePushNotificationRequest::isValidResponse(const string &str) {
	static const char expected[] = "HTTP/1.1 200";
	return strncmp(expected, str.c_str(), sizeof(expected) - 1) == 0 ? "" : "Unexpected HTTP response value (not 200 OK)";
}
<commit_msg>Firebase: put all our user fields of push notifications into a data json object, as required by google.<commit_after>
#include "firebasepush.hh"
#include <iostream>
#include <string.h>
#include <flexisip/logmanager.hh>

using namespace std;
using namespace flexisip;

/*
 * This supports the legacy http Firebase protocol:
 * https://firebase.google.com/docs/cloud-messaging/http-server-ref
 */

FirebasePushNotificationRequest::FirebasePushNotificationRequest(const PushInfo &pinfo)
: PushNotificationRequest(pinfo.mAppId, "firebase") {
	const string &deviceToken = pinfo.mDeviceToken;
	const string &apiKey = pinfo.mApiKey;
	const string &from = pinfo.mFromName.empty() ? pinfo.mFromUri : pinfo.mFromName;
	ostringstream httpBody;
	string date = getPushTimeStamp();

	httpBody << "{\"to\":\"" << deviceToken << "\", \"priority\":\"high\""
		<< ", \"data\":{"
			<< "\"uuid\":" << quoteStringIfNeeded(pinfo.mUid)
			<< ", \"call-id\":" << quoteStringIfNeeded(pinfo.mCallId)
			<< ", \"from\":" << quoteStringIfNeeded(from)
			<< ", \"send-time\":" << quoteStringIfNeeded(date) << "}"
		<< "}";
	mHttpBody = httpBody.str();
	LOGD("Push notification https post body is %s", mHttpBody.c_str());

	ostringstream httpHeader;
	httpHeader << "POST /fcm/send "
	"HTTP/1.1\r\nHost:fcm.googleapis.com\r\nContent-Type:application/json\r\nAuthorization:key="
	<< apiKey << "\r\nContent-Length:" << httpBody.str().size() << "\r\n\r\n";
	mHttpHeader = httpHeader.str();
	SLOGD << "PNR " << this << " https post header is " << mHttpHeader;
}

void FirebasePushNotificationRequest::createPushNotification() {
	int headerLength = mHttpHeader.length();
	int bodyLength = mHttpBody.length();

	mBuffer.clear();
	mBuffer.resize(headerLength + bodyLength);

	char *binaryMessageBuff = &mBuffer[0];
	char *binaryMessagePt = binaryMessageBuff;

	memcpy(binaryMessagePt, &mHttpHeader[0], headerLength);
	binaryMessagePt += headerLength;

	memcpy(binaryMessagePt, &mHttpBody[0], bodyLength);
	binaryMessagePt += bodyLength;
}

const vector<char> &FirebasePushNotificationRequest::getData() {
	createPushNotification();
	return mBuffer;
}

string FirebasePushNotificationRequest::isValidResponse(const string &str) {
	static const char expected[] = "HTTP/1.1 200";
	return strncmp(expected, str.c_str(), sizeof(expected) - 1) == 0 ? "" : "Unexpected HTTP response value (not 200 OK)";
}
<|endoftext|>