<commit_before>/* -*- indent-tabs-mode: nil -*- */
#include "log/cms_verifier.h"
#include "log/ct_extensions.h"

using std::string;
using std::unique_ptr;
using util::Status;

namespace cert_trans {
util::StatusOr<bool> CmsVerifier::IsCmsSignedByCert(BIO* cms_bio_in,
                                                     const Cert& cert) const {
  CHECK_NOTNULL(cms_bio_in);

  if (!cert.IsLoaded()) {
    LOG(ERROR) << "Can't check cert signer as it's not loaded";
    return Status(util::error::FAILED_PRECONDITION, "Cert not loaded");
  }

  CMS_ContentInfo* const cms_content_info = d2i_CMS_bio(cms_bio_in, nullptr);

  if (!cms_content_info) {
    LOG(ERROR) << "Could not parse CMS data";
    LOG_OPENSSL_ERRORS(WARNING);
    return Status(util::error::INVALID_ARGUMENT,
                  "CMS data could not be parsed");
  }

  // This stack must not be freed as it points into the CMS structure
  STACK_OF(CMS_SignerInfo) *
      const signers(CMS_get0_SignerInfos(cms_content_info));

  if (signers) {
    for (int s = 0; s < sk_CMS_SignerInfo_num(signers); ++s) {
      CMS_SignerInfo* const signer = sk_CMS_SignerInfo_value(signers, s);

      if (CMS_SignerInfo_cert_cmp(signer, cert.x509_) == 0) {
        CMS_ContentInfo_free(cms_content_info);
        return true;
      }
    }
  }

  CMS_ContentInfo_free(cms_content_info);
  return false;
}

util::StatusOr<bool> CmsVerifier::IsCmsSignedByCert(const string& cms_object,
                                                     const Cert* cert) const {
  CHECK_NOTNULL(cert);

  if (!cert->IsLoaded()) {
    LOG(ERROR) << "Can't check cert signer as it's not loaded";
    return Status(util::error::FAILED_PRECONDITION, "Cert not loaded");
  }

  // Load a source bio with the CMS signed data object and parse it
  BIO* source_bio = BIO_new(BIO_s_mem());
  BIO_write(source_bio, cms_object.c_str(), cms_object.length());

  CMS_ContentInfo* const cms_content_info = d2i_CMS_bio(source_bio, nullptr);
  BIO_free(source_bio);

  if (!cms_content_info) {
    LOG(ERROR) << "Could not parse CMS data";
    LOG_OPENSSL_ERRORS(WARNING);
    return Status(util::error::INVALID_ARGUMENT,
                  "CMS data could not be parsed");
  }

  // Now that we've got the CMS unpacked check it has a valid signature using
  // the same key as the cert. First create a certificate stack from our
  // expected signing cert that can be used by CMS_verify.
  STACK_OF(X509)* validation_chain = sk_X509_new(nullptr);

  sk_X509_push(validation_chain, cert->x509_);

  // Must set CMS_NOINTERN as the RFC says certs SHOULD be omitted from the
  // message but the client might not have obeyed this. CMS_BINARY is required
  // to avoid MIME-related translation. CMS_NO_SIGNER_CERT_VERIFY because we
  // will do our own checks that the chain is valid and the message may not
  // be signed directly by a trusted cert. We don't check it's a signed data
  // object CMS type as OpenSSL does this.
  int verified = CMS_verify(cms_content_info, validation_chain, nullptr,
                            nullptr, nullptr,
                            CMS_NO_SIGNER_CERT_VERIFY | CMS_NOINTERN
                            | CMS_BINARY);

  sk_X509_free(validation_chain);

  if (verified != 1) {
    // Most likely, was not CMS signed by the precert
    CMS_ContentInfo_free(cms_content_info);
    return false;
  }

  // This stack must not be freed as it points into the CMS structure
  STACK_OF(CMS_SignerInfo) *
      const signers(CMS_get0_SignerInfos(cms_content_info));

  if (signers) {
    for (int s = 0; s < sk_CMS_SignerInfo_num(signers); ++s) {
      CMS_SignerInfo* const signer = sk_CMS_SignerInfo_value(signers, s);

      if (CMS_SignerInfo_cert_cmp(signer, cert->x509_) == 0) {
        CMS_ContentInfo_free(cms_content_info);
        return true;
      }
    }
  }

  CMS_ContentInfo_free(cms_content_info);
  return false;
}

util::Status CmsVerifier::UnpackCmsDerBio(BIO* cms_bio_in, const Cert& cert,
                                           BIO* cms_bio_out) {
  CHECK_NOTNULL(cms_bio_in);

  if (!cert.IsLoaded()) {
    LOG(ERROR) << "Cert for CMS verify not loaded";
    return Status(util::error::FAILED_PRECONDITION, "Cert not loaded");
  }

  CMS_ContentInfo* const cms_content_info = d2i_CMS_bio(cms_bio_in, nullptr);

  if (!cms_content_info) {
    LOG(ERROR) << "Could not parse CMS data";
    LOG_OPENSSL_ERRORS(WARNING);
    return Status(util::error::INVALID_ARGUMENT,
                  "CMS data could not be parsed");
  }

  const ASN1_OBJECT* message_content_type(
      CMS_get0_eContentType(cms_content_info));
  int content_type_nid = OBJ_obj2nid(message_content_type);
  // TODO: Enforce content type here. This is not yet defined in the RFC.
  if (content_type_nid != NID_ctV2CmsPayloadContentType) {
    LOG(WARNING) << "CMS message content has unexpected type: "
                 << content_type_nid;
  }

  // Create a certificate stack from our expected signing cert that can be used
  // by CMS_verify.
  STACK_OF(X509)* validation_chain = sk_X509_new(nullptr);

  sk_X509_push(validation_chain, cert.x509_);

  // Must set CMS_NOINTERN as the RFC says certs SHOULD be omitted from the
  // message but the client might not have obeyed this. CMS_BINARY is required
  // to avoid MIME-related translation. CMS_NO_SIGNER_CERT_VERIFY because we
  // will do our own checks that the chain is valid and the message may not
  // be signed directly by a trusted cert. We don't check it's a signed data
  // object CMS type as OpenSSL does this.
  int verified = CMS_verify(cms_content_info, validation_chain, nullptr,
                            nullptr, cms_bio_out,
                            CMS_NO_SIGNER_CERT_VERIFY | CMS_NOINTERN
                            | CMS_BINARY);

  sk_X509_free(validation_chain);

  CMS_ContentInfo_free(cms_content_info);

  return (verified == 1) ? util::Status::OK
                         : util::Status(util::error::INVALID_ARGUMENT,
                                        "CMS verification failed");
}

util::Status CmsVerifier::UnpackCmsDerBio(BIO* cms_bio_in, BIO* cms_bio_out) {
  CHECK_NOTNULL(cms_bio_in);
  CHECK_NOTNULL(cms_bio_out);

  CMS_ContentInfo* const cms_content_info = d2i_CMS_bio(cms_bio_in, nullptr);

  if (!cms_content_info) {
    LOG(ERROR) << "Could not parse CMS data";
    LOG_OPENSSL_ERRORS(WARNING);
    return Status(util::error::INVALID_ARGUMENT,
                  "CMS data could not be parsed");
  }

  const ASN1_OBJECT* message_content_type(
      CMS_get0_eContentType(cms_content_info));
  int content_type_nid = OBJ_obj2nid(message_content_type);
  // TODO: Enforce content type here. This is not yet defined in the RFC.
  if (content_type_nid != NID_ctV2CmsPayloadContentType) {
    LOG(WARNING) << "CMS message content has unexpected type: "
                 << content_type_nid;
  }

  // Must set CMS_NOINTERN as the RFC says certs SHOULD be omitted from the
  // message but the client might not have obeyed this. CMS_BINARY is required
  // to avoid MIME-related translation. CMS_NO_SIGNER_CERT_VERIFY because we
  // will do our own checks that the chain is valid and the message may not
  // be signed directly by a trusted cert. CMS_NO_CONTENT_VERIFY because we
  // can't apply the RFC mandated signature checks until we have the unpacked
  // cert to examine. We don't check it's a signed data object CMS type as
  // OpenSSL does this.
  int verified = CMS_verify(cms_content_info, nullptr, nullptr,
                            nullptr, cms_bio_out,
                            CMS_NO_SIGNER_CERT_VERIFY | CMS_NOINTERN
                            | CMS_BINARY | CMS_NO_CONTENT_VERIFY);

  CMS_ContentInfo_free(cms_content_info);

  return (verified == 1) ? util::Status::OK
                         : util::Status(util::error::INVALID_ARGUMENT,
                                        "CMS unpack failed");
}

Cert* CmsVerifier::UnpackCmsSignedCertificate(BIO* cms_bio_in,
                                               const Cert& verify_cert) {
  CHECK_NOTNULL(cms_bio_in);
  BIO* unpacked_bio = BIO_new(BIO_s_mem());
  unique_ptr<Cert> cert(new Cert());

  if (UnpackCmsDerBio(cms_bio_in, verify_cert, unpacked_bio).ok()) {
    // The unpacked data should be a valid DER certificate.
    // TODO: The RFC does not yet define this as the format so this may
    // need to change.
    util::Status status = cert->LoadFromDerBio(unpacked_bio);

    if (!status.ok()) {
      LOG(WARNING) << "Could not unpack cert from CMS DER encoded data";
    }
  } else {
    LOG_OPENSSL_ERRORS(ERROR);
  }

  BIO_free(unpacked_bio);

  return cert.release();
}

Cert* CmsVerifier::UnpackCmsSignedCertificate(const string& cms_object) {
  // Load the source bio with the CMS signed data object
  BIO* source_bio = BIO_new(BIO_s_mem());
  BIO_write(source_bio, cms_object.c_str(), cms_object.length());

  BIO* unpacked_bio = BIO_new(BIO_s_mem());
  unique_ptr<Cert> cert(new Cert());

  if (UnpackCmsDerBio(source_bio, unpacked_bio).ok()) {
    // The unpacked data should be a valid DER certificate.
    // TODO: The RFC does not yet define this as the format so this may
    // need to change.
    util::Status status = cert->LoadFromDerBio(unpacked_bio);

    if (!status.ok()) {
      LOG(WARNING) << "Could not unpack cert from CMS DER encoded data";
    }
  } else {
    LOG_OPENSSL_ERRORS(ERROR);
  }

  BIO_free(source_bio);
  BIO_free(unpacked_bio);

  return cert.release();
}

}  // namespace cert_trans
<commit_msg>Fixed review issues.<commit_after>/* -*- indent-tabs-mode: nil -*- */
#include "log/cms_verifier.h"
#include "log/ct_extensions.h"

using std::string;
using std::unique_ptr;
using util::Status;
using util::StatusOr;

namespace cert_trans {
util::StatusOr<bool> CmsVerifier::IsCmsSignedByCert(BIO* cms_bio_in,
                                                     const Cert& cert) const {
  CHECK_NOTNULL(cms_bio_in);

  if (!cert.IsLoaded()) {
    LOG(ERROR) << "Can't check cert signer as it's not loaded";
    return Status(util::error::FAILED_PRECONDITION, "Cert not loaded");
  }

  CMS_ContentInfo* const cms_content_info = d2i_CMS_bio(cms_bio_in, nullptr);

  if (!cms_content_info) {
    LOG(ERROR) << "Could not parse CMS data";
    LOG_OPENSSL_ERRORS(WARNING);
    return Status(util::error::INVALID_ARGUMENT,
                  "CMS data could not be parsed");
  }

  // This stack must not be freed as it points into the CMS structure
  STACK_OF(CMS_SignerInfo) *
      const signers(CMS_get0_SignerInfos(cms_content_info));

  if (signers) {
    for (int s = 0; s < sk_CMS_SignerInfo_num(signers); ++s) {
      CMS_SignerInfo* const signer = sk_CMS_SignerInfo_value(signers, s);

      if (CMS_SignerInfo_cert_cmp(signer, cert.x509_) == 0) {
        CMS_ContentInfo_free(cms_content_info);
        return true;
      }
    }
  }

  CMS_ContentInfo_free(cms_content_info);
  return false;
}

StatusOr<bool> CmsVerifier::IsCmsSignedByCert(const string& cms_object,
                                              const Cert* cert) const {
  CHECK_NOTNULL(cert);

  if (!cert->IsLoaded()) {
    LOG(ERROR) << "Can't check cert signer as it's not loaded";
    return Status(util::error::FAILED_PRECONDITION, "Cert not loaded");
  }

  // Load a source bio with the CMS signed data object and parse it
  BIO* const source_bio = BIO_new(BIO_s_mem());
  BIO_write(source_bio, cms_object.c_str(), cms_object.length());

  CMS_ContentInfo* const cms_content_info = d2i_CMS_bio(source_bio, nullptr);
  BIO_free(source_bio);

  if (!cms_content_info) {
    LOG(ERROR) << "Could not parse CMS data";
    LOG_OPENSSL_ERRORS(WARNING);
    return Status(util::error::INVALID_ARGUMENT,
                  "CMS data could not be parsed");
  }

  // Now that we've got the CMS unpacked check it has a valid signature using
  // the same key as the cert. First create a certificate stack from our
  // expected signing cert that can be used by CMS_verify.
  STACK_OF(X509)* validation_chain = sk_X509_new(nullptr);

  sk_X509_push(validation_chain, cert->x509_);

  // Must set CMS_NOINTERN as the RFC says certs SHOULD be omitted from the
  // message but the client might not have obeyed this. CMS_BINARY is required
  // to avoid MIME-related translation. CMS_NO_SIGNER_CERT_VERIFY because we
  // will do our own checks that the chain is valid and the message may not
  // be signed directly by a trusted cert. We don't check it's a signed data
  // object CMS type as OpenSSL does this.
  const int verified =
      CMS_verify(cms_content_info, validation_chain, nullptr, nullptr, nullptr,
                 CMS_NO_SIGNER_CERT_VERIFY | CMS_NOINTERN | CMS_BINARY);

  sk_X509_free(validation_chain);

  if (verified != 1) {
    // Most likely, was not CMS signed by the precert
    CMS_ContentInfo_free(cms_content_info);
    return false;
  }

  // This stack must not be freed as it points into the CMS structure
  STACK_OF(CMS_SignerInfo) *
      const signers(CMS_get0_SignerInfos(cms_content_info));

  if (signers) {
    for (int s = 0; s < sk_CMS_SignerInfo_num(signers); ++s) {
      CMS_SignerInfo* const signer = sk_CMS_SignerInfo_value(signers, s);

      if (CMS_SignerInfo_cert_cmp(signer, cert->x509_) == 0) {
        CMS_ContentInfo_free(cms_content_info);
        return true;
      }
    }
  }

  CMS_ContentInfo_free(cms_content_info);
  return false;
}

util::Status CmsVerifier::UnpackCmsDerBio(BIO* cms_bio_in, const Cert& cert,
                                           BIO* cms_bio_out) {
  CHECK_NOTNULL(cms_bio_in);

  if (!cert.IsLoaded()) {
    LOG(ERROR) << "Cert for CMS verify not loaded";
    return Status(util::error::FAILED_PRECONDITION, "Cert not loaded");
  }

  CMS_ContentInfo* const cms_content_info = d2i_CMS_bio(cms_bio_in, nullptr);

  if (!cms_content_info) {
    LOG(ERROR) << "Could not parse CMS data";
    LOG_OPENSSL_ERRORS(WARNING);
    return Status(util::error::INVALID_ARGUMENT,
                  "CMS data could not be parsed");
  }

  const ASN1_OBJECT* message_content_type(
      CMS_get0_eContentType(cms_content_info));
  int content_type_nid = OBJ_obj2nid(message_content_type);
  // TODO: Enforce content type here. This is not yet defined in the RFC.
  if (content_type_nid != NID_ctV2CmsPayloadContentType) {
    LOG(WARNING) << "CMS message content has unexpected type: "
                 << content_type_nid;
  }

  // Create a certificate stack from our expected signing cert that can be used
  // by CMS_verify.
  STACK_OF(X509)* validation_chain = sk_X509_new(nullptr);

  sk_X509_push(validation_chain, cert.x509_);

  // Must set CMS_NOINTERN as the RFC says certs SHOULD be omitted from the
  // message but the client might not have obeyed this. CMS_BINARY is required
  // to avoid MIME-related translation. CMS_NO_SIGNER_CERT_VERIFY because we
  // will do our own checks that the chain is valid and the message may not
  // be signed directly by a trusted cert. We don't check it's a signed data
  // object CMS type as OpenSSL does this.
  int verified = CMS_verify(cms_content_info, validation_chain, nullptr,
                            nullptr, cms_bio_out,
                            CMS_NO_SIGNER_CERT_VERIFY | CMS_NOINTERN
                            | CMS_BINARY);

  sk_X509_free(validation_chain);

  CMS_ContentInfo_free(cms_content_info);

  return (verified == 1) ? util::Status::OK
                         : util::Status(util::error::INVALID_ARGUMENT,
                                        "CMS verification failed");
}

util::Status CmsVerifier::UnpackCmsDerBio(BIO* cms_bio_in, BIO* cms_bio_out) {
  CHECK_NOTNULL(cms_bio_in);
  CHECK_NOTNULL(cms_bio_out);

  CMS_ContentInfo* const cms_content_info = d2i_CMS_bio(cms_bio_in, nullptr);

  if (!cms_content_info) {
    LOG(ERROR) << "Could not parse CMS data";
    LOG_OPENSSL_ERRORS(WARNING);
    return Status(util::error::INVALID_ARGUMENT,
                  "CMS data could not be parsed");
  }

  const ASN1_OBJECT* message_content_type(
      CMS_get0_eContentType(cms_content_info));
  const int content_type_nid = OBJ_obj2nid(message_content_type);
  // TODO: Enforce content type here. This is not yet defined in the RFC.
  if (content_type_nid != NID_ctV2CmsPayloadContentType) {
    LOG(WARNING) << "CMS message content has unexpected type: "
                 << content_type_nid;
  }

  // Must set CMS_NOINTERN as the RFC says certs SHOULD be omitted from the
  // message but the client might not have obeyed this. CMS_BINARY is required
  // to avoid MIME-related translation. CMS_NO_SIGNER_CERT_VERIFY because we
  // will do our own checks that the chain is valid and the message may not
  // be signed directly by a trusted cert. CMS_NO_CONTENT_VERIFY because we
  // can't apply the RFC mandated signature checks until we have the unpacked
  // cert to examine. We don't check it's a signed data object CMS type as
  // OpenSSL does this.
  const int verified =
      CMS_verify(cms_content_info, nullptr, nullptr, nullptr, cms_bio_out,
                 CMS_NO_SIGNER_CERT_VERIFY | CMS_NOINTERN | CMS_BINARY |
                     CMS_NO_CONTENT_VERIFY);

  CMS_ContentInfo_free(cms_content_info);

  return (verified == 1) ? util::Status::OK
                         : util::Status(util::error::INVALID_ARGUMENT,
                                        "CMS unpack failed");
}

Cert* CmsVerifier::UnpackCmsSignedCertificate(BIO* cms_bio_in,
                                               const Cert& verify_cert) {
  CHECK_NOTNULL(cms_bio_in);
  BIO* unpacked_bio = BIO_new(BIO_s_mem());
  unique_ptr<Cert> cert(new Cert());

  if (UnpackCmsDerBio(cms_bio_in, verify_cert, unpacked_bio).ok()) {
    // The unpacked data should be a valid DER certificate.
    // TODO: The RFC does not yet define this as the format so this may
    // need to change.
    util::Status status = cert->LoadFromDerBio(unpacked_bio);

    if (!status.ok()) {
      LOG(WARNING) << "Could not unpack cert from CMS DER encoded data";
    }
  } else {
    LOG_OPENSSL_ERRORS(ERROR);
  }

  BIO_free(unpacked_bio);

  return cert.release();
}

Cert* CmsVerifier::UnpackCmsSignedCertificate(const string& cms_object) {
  // Load the source bio with the CMS signed data object
  BIO* source_bio = BIO_new(BIO_s_mem());
  BIO_write(source_bio, cms_object.c_str(), cms_object.length());

  BIO* unpacked_bio = BIO_new(BIO_s_mem());
  unique_ptr<Cert> cert(new Cert);

  if (UnpackCmsDerBio(source_bio, unpacked_bio).ok()) {
    // The unpacked data should be a valid DER certificate.
    // TODO: The RFC does not yet define this as the format so this may
    // need to change.
    const Status status = cert->LoadFromDerBio(unpacked_bio);

    if (!status.ok()) {
      LOG(WARNING) << "Could not unpack cert from CMS DER encoded data";
    }
  } else {
    LOG_OPENSSL_ERRORS(ERROR);
  }

  BIO_free(source_bio);
  BIO_free(unpacked_bio);

  return cert.release();
}

}  // namespace cert_trans
<|endoftext|>


<commit_before>/* -*- indent-tabs-mode: nil -*- */

#include <event2/thread.h>
#include <functional>
#include <gflags/gflags.h>
#include <iostream>
#include <memory>
#include <openssl/err.h>
#include <string>

#include "log/cert_checker.h"
#include "log/cert_submission_handler.h"
#include "log/cluster_state_controller.h"
#include "log/ct_extensions.h"
#include "log/etcd_consistent_store.h"
#include "log/file_db.h"
#include "log/file_storage.h"
#include "log/frontend.h"
#include "log/frontend_signer.h"
#include "log/log_lookup.h"
#include "log/log_signer.h"
#include "log/sqlite_db.h"
#include "log/strict_consistent_store.h"
#include "log/tree_signer.h"
#include "server/handler.h"
#include "util/etcd.h"
#include "util/fake_etcd.h"
#include "util/libevent_wrapper.h"
#include "util/masterelection.h"
#include "util/periodic_closure.h"
#include "util/read_key.h"
#include "util/status.h"
#include "util/thread_pool.h"
#include "util/uuid.h"

DEFINE_string(server, "localhost", "Server host");
DEFINE_int32(port, 9999, "Server port");
DEFINE_string(key, "", "PEM-encoded server private key file");
DEFINE_string(trusted_cert_file, "",
              "File for trusted CA certificates, in concatenated PEM format");
// TODO(alcutter): Just specify a root dir with a single flag.
DEFINE_string(cert_dir, "", "Storage directory for certificates");
DEFINE_string(tree_dir, "", "Storage directory for trees");
DEFINE_string(meta_dir, "", "Storage directory for meta info");
DEFINE_string(sqlite_db, "", "Database for certificate and tree storage");
// TODO(ekasper): sanity-check these against the directory structure.
DEFINE_int32(cert_storage_depth, 0,
             "Subdirectory depth for certificates; if the directory is not "
             "empty, must match the existing depth.");
DEFINE_int32(tree_storage_depth, 0,
             "Subdirectory depth for tree signatures; if the directory is not "
             "empty, must match the existing depth");
DEFINE_int32(log_stats_frequency_seconds, 3600,
             "Interval for logging summary statistics. Approximate: the "
             "server will log statistics if in the beginning of its select "
             "loop, at least this period has elapsed since the last log time. "
             "Must be greater than 0.");
DEFINE_int32(tree_signing_frequency_seconds, 600,
             "How often should we issue a new signed tree head. Approximate: "
             "the signer process will kick off if in the beginning of the "
             "server select loop, at least this period has elapsed since the "
             "last signing. Set this well below the MMD to ensure we sign in "
             "a timely manner. Must be greater than 0.");
DEFINE_double(guard_window_seconds, 60,
              "Unsequenced entries new than this "
              "number of seconds will not be sequenced.");
DEFINE_string(etcd_host, "", "Hostname of the etcd server");
DEFINE_int32(etcd_port, 0, "Port of the etcd server.");
DEFINE_int32(node_state_refresh_seconds, 10,
             "How often to refresh the ClusterNodeState entry for this node.");

namespace libevent = cert_trans::libevent;

using cert_trans::CertChecker;
using cert_trans::ClusterStateController;
using cert_trans::ContinuousFetcher;
using cert_trans::EtcdClient;
using cert_trans::EtcdConsistentStore;
using cert_trans::FakeEtcdClient;
using cert_trans::FileStorage;
using cert_trans::HttpHandler;
using cert_trans::LoggedCertificate;
using cert_trans::MasterElection;
using cert_trans::PeriodicClosure;
using cert_trans::ReadPrivateKey;
using cert_trans::StrictConsistentStore;
using cert_trans::ThreadPool;
using cert_trans::TreeSigner;
using cert_trans::Update;
using ct::ClusterNodeState;
using ct::SignedTreeHead;
using google::RegisterFlagValidator;
using std::bind;
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::seconds;
using std::chrono::steady_clock;
using std::function;
using std::make_shared;
using std::shared_ptr;
using std::string;
using std::thread;
using std::unique_ptr;

// Basic sanity checks on flag values.
static bool ValidatePort(const char* flagname, int port) {
  if (port <= 0 || port > 65535) {
    std::cout << "Port value " << port << " is invalid. " << std::endl;
    return false;
  }
  return true;
}

static const bool port_dummy =
    RegisterFlagValidator(&FLAGS_port, &ValidatePort);

static bool ValidateRead(const char* flagname, const string& path) {
  if (access(path.c_str(), R_OK) != 0) {
    std::cout << "Cannot access " << flagname << " at " << path << std::endl;
    return false;
  }
  return true;
}

static const bool key_dummy = RegisterFlagValidator(&FLAGS_key, &ValidateRead);

static const bool cert_dummy =
    RegisterFlagValidator(&FLAGS_trusted_cert_file, &ValidateRead);

static bool ValidateWrite(const char* flagname, const string& path) {
  if (path != "" && access(path.c_str(), W_OK) != 0) {
    std::cout << "Cannot modify " << flagname << " at " << path << std::endl;
    return false;
  }
  return true;
}

static const bool cert_dir_dummy =
    RegisterFlagValidator(&FLAGS_cert_dir, &ValidateWrite);

static const bool tree_dir_dummy =
    RegisterFlagValidator(&FLAGS_tree_dir, &ValidateWrite);

static bool ValidateIsNonNegative(const char* flagname, int value) {
  if (value < 0) {
    std::cout << flagname << " must not be negative" << std::endl;
    return false;
  }
  return true;
}

static const bool c_st_dummy =
    RegisterFlagValidator(&FLAGS_cert_storage_depth, &ValidateIsNonNegative);
static const bool t_st_dummy =
    RegisterFlagValidator(&FLAGS_tree_storage_depth, &ValidateIsNonNegative);

static bool ValidateIsPositive(const char* flagname, int value) {
  if (value <= 0) {
    std::cout << flagname << " must be greater than 0" << std::endl;
    return false;
  }
  return true;
}

static const bool stats_dummy =
    RegisterFlagValidator(&FLAGS_log_stats_frequency_seconds,
                          &ValidateIsPositive);

static const bool sign_dummy =
    RegisterFlagValidator(&FLAGS_tree_signing_frequency_seconds,
                          &ValidateIsPositive);

void SignMerkleTree(TreeSigner<LoggedCertificate>* tree_signer,
                    ClusterStateController<LoggedCertificate>* controller,
                    const MasterElection* election) {
  const steady_clock::duration period((seconds(FLAGS_tree_signing_frequency_seconds)));
  steady_clock::time_point target_run_time(steady_clock::now());

  while (true) {
    if (election->IsMaster()) {
      // TODO(alcutter): Probably don't need to blow up here
      CHECK_EQ(util::Status::OK, tree_signer->SequenceNewEntries())
          << "Problem sequencing new entries";
    }

    CHECK_EQ(tree_signer->UpdateTree(), TreeSigner<LoggedCertificate>::OK);
    controller->NewTreeHead(tree_signer->LatestSTH());

    const steady_clock::time_point now(steady_clock::now());
    while (target_run_time <= now) {
      target_run_time += period;
    }

    std::this_thread::sleep_for(target_run_time - now);
  }
}

int main(int argc, char* argv[]) {
  google::ParseCommandLineFlags(&argc, &argv, true);
  google::InitGoogleLogging(argv[0]);
  OpenSSL_add_all_algorithms();
  ERR_load_crypto_strings();
  cert_trans::LoadCtExtensions();

  util::StatusOr<EVP_PKEY*> pkey(ReadPrivateKey(FLAGS_key));
  CHECK_EQ(pkey.status(), util::Status::OK);
  LogSigner log_signer(pkey.ValueOrDie());

  CertChecker checker;
  CHECK(checker.LoadTrustedCertificates(FLAGS_trusted_cert_file))
      << "Could not load CA certs from " << FLAGS_trusted_cert_file;

  if (FLAGS_sqlite_db == "")
    CHECK_NE(FLAGS_cert_dir, FLAGS_tree_dir)
        << "Certificate directory and tree directory must differ";

  if ((FLAGS_cert_dir != "" || FLAGS_tree_dir != "") &&
      FLAGS_sqlite_db != "") {
    std::cerr << "Choose either file or sqlite database, not both"
              << std::endl;
    exit(1);
  }

  Database<LoggedCertificate>* db;

  if (FLAGS_sqlite_db != "")
    db = new SQLiteDB<LoggedCertificate>(FLAGS_sqlite_db);
  else
    db = new FileDB<LoggedCertificate>(
        new FileStorage(FLAGS_cert_dir, FLAGS_cert_storage_depth),
        new FileStorage(FLAGS_tree_dir, FLAGS_tree_storage_depth),
        new FileStorage(FLAGS_meta_dir, 0));

  std::string node_id;
  if (db->NodeId(&node_id) != Database<LoggedCertificate>::LOOKUP_OK) {
    node_id = cert_trans::UUID4();
    LOG(INFO) << "Initializing Node DB with UUID: " << node_id;
    db->InitializeNode(node_id);
  } else {
    LOG(INFO) << "Found DB with Node UUID: " << node_id;
  }

  evthread_use_pthreads();
  const shared_ptr<libevent::Base> event_base(make_shared<libevent::Base>());
  // Temporary event pump for while we're setting things up and haven't yet
  // entered the event loop at the bottom:
  std::unique_ptr<libevent::EventPumpThread> pump(
      new libevent::EventPumpThread(event_base));

  const bool stand_alone_mode(FLAGS_etcd_host.empty());

  LOG(INFO) << "Running in "
            << (stand_alone_mode ? "STAND-ALONE" : "CLUSTERED") << " mode.";

  std::unique_ptr<EtcdClient> etcd_client(
      stand_alone_mode
          ? new FakeEtcdClient(event_base)
          : new EtcdClient(event_base, FLAGS_etcd_host, FLAGS_etcd_port));

  // No real reason to let this be configurable per node; you can really
  // shoot yourself in the foot that way by effectively running multiple
  // distinct elections.
  const string kLockDir("/election");
  MasterElection election(event_base, etcd_client.get(), kLockDir, node_id);

  // For now, run with a dedicated thread pool as the executor for our
  // consistent store to avoid the possibility of DoS through thread starvation
  // via HTTP.
  ThreadPool internal_pool(4);
  StrictConsistentStore<LoggedCertificate> consistent_store(
      &election,
      new EtcdConsistentStore<LoggedCertificate>(&internal_pool,
                                                 etcd_client.get(), &election,
                                                 "/root", node_id));

  TreeSigner<LoggedCertificate> tree_signer(std::chrono::duration<double>(
                                                FLAGS_guard_window_seconds),
                                            db, &consistent_store,
                                            &log_signer);

  if (stand_alone_mode) {
    // Set up a simple single-node environment.
    //
    // Put a sensible single-node config into FakeEtcd. For a real clustered
    // log
    // we'd expect a ClusterConfig already to be present within etcd as part of
    // the provisioning of the log.
    //
    // TODO(alcutter): Note that we're currently broken wrt to restarting the
    // log server when there's data in the log.  It's a temporary thing though,
    // so fear ye not.
    ct::ClusterConfig config;
    config.set_minimum_serving_nodes(1);
    config.set_minimum_serving_fraction(1);
    LOG(INFO) << "Setting default single-node ClusterConfig:\n"
              << config.DebugString();
    consistent_store.SetClusterConfig(config);

    // Since we're a single node cluster, we'll settle that we're the
    // master here, so that we can populate the initial STH
    // (StrictConsistentStore won't allow us to do so unless we're master.)
    election.StartElection();
    election.WaitToBecomeMaster();

    // Do an initial signing run to get the initial STH, again this is
    // temporary until we re-populate FakeEtcd from the DB.
    CHECK_EQ(tree_signer.UpdateTree(), TreeSigner<LoggedCertificate>::OK);

    // Need to boot-strap the Serving STH too because we consider it an error
    // if it's not set, which in turn causes us to not attempt to become
    // master:
    consistent_store.SetServingSTH(tree_signer.LatestSTH());
  } else {
    CHECK(!FLAGS_server.empty());
  }

  const unique_ptr<ContinuousFetcher> fetcher(
      ContinuousFetcher::New(event_base.get(), db));
  ClusterStateController<LoggedCertificate> cluster_controller(
      &internal_pool, event_base, db, &consistent_store, &election,
      fetcher.get());
  // Publish this node's hostname:port info
  cluster_controller.SetNodeHostPort(FLAGS_server, FLAGS_port);

  // Just separate this out from the lambda below to try to be clear that this
  // is the *only* interaction with TreeSigner that we're allowing there.
  const function<SignedTreeHead(void)> get_latest_sth(
      bind(&TreeSigner<LoggedCertificate>::LatestSTH, &tree_signer));
  // Periodically refresh our ClusterNodeState entry so it doesn't get deleted.
  // TODO(alcutter): Figure out if we actually need this here now, the signer
  // thread above will refresh the entry, but potentially not frequently
  // enough.
  PeriodicClosure node_state_refresh(
      event_base, std::chrono::seconds(FLAGS_node_state_refresh_seconds),
      [&db, &cluster_controller, &internal_pool, &get_latest_sth]() {
        // Actually run this on the thread pool, since this periodic closure is
        // calling back on the eventloop thread.
        internal_pool.Add([&db, &cluster_controller, &get_latest_sth]() {
          cluster_controller.NewTreeHead(get_latest_sth());
        });
      });

  Frontend frontend(new CertSubmissionHandler(&checker),
                    new FrontendSigner(db, &consistent_store, &log_signer));
  LogLookup<LoggedCertificate> log_lookup(db);

  // TODO(pphaneuf): We should be remaining in an "unhealthy state"
  // (either not accepting any requests, or returning some internal
  // server error) until we have an STH to serve.
  thread signer(&SignMerkleTree, &tree_signer, &cluster_controller, &election);
  ThreadPool pool;
  HttpHandler handler(&log_lookup, db, &checker, &frontend, &pool);

  libevent::HttpServer server(*event_base);
  handler.Add(&server);
  server.Bind(NULL, FLAGS_port);

  std::cout << "READY" << std::endl;

  // Ding the temporary event pump because we're about to enter the event loop
  pump.reset();
  event_base->Dispatch();

  return 0;
}
<commit_msg>Install a signal handler to get stack traces.<commit_after>/* -*- indent-tabs-mode: nil -*- */

#include <event2/thread.h>
#include <functional>
#include <gflags/gflags.h>
#include <iostream>
#include <memory>
#include <openssl/err.h>
#include <string>

#include "log/cert_checker.h"
#include "log/cert_submission_handler.h"
#include "log/cluster_state_controller.h"
#include "log/ct_extensions.h"
#include "log/etcd_consistent_store.h"
#include "log/file_db.h"
#include "log/file_storage.h"
#include "log/frontend.h"
#include "log/frontend_signer.h"
#include "log/log_lookup.h"
#include "log/log_signer.h"
#include "log/sqlite_db.h"
#include "log/strict_consistent_store.h"
#include "log/tree_signer.h"
#include "server/handler.h"
#include "util/etcd.h"
#include "util/fake_etcd.h"
#include "util/libevent_wrapper.h"
#include "util/masterelection.h"
#include "util/periodic_closure.h"
#include "util/read_key.h"
#include "util/status.h"
#include "util/thread_pool.h"
#include "util/uuid.h"

DEFINE_string(server, "localhost", "Server host");
DEFINE_int32(port, 9999, "Server port");
DEFINE_string(key, "", "PEM-encoded server private key file");
DEFINE_string(trusted_cert_file, "",
              "File for trusted CA certificates, in concatenated PEM format");
// TODO(alcutter): Just specify a root dir with a single flag.
DEFINE_string(cert_dir, "", "Storage directory for certificates");
DEFINE_string(tree_dir, "", "Storage directory for trees");
DEFINE_string(meta_dir, "", "Storage directory for meta info");
DEFINE_string(sqlite_db, "", "Database for certificate and tree storage");
// TODO(ekasper): sanity-check these against the directory structure.
DEFINE_int32(cert_storage_depth, 0,
             "Subdirectory depth for certificates; if the directory is not "
             "empty, must match the existing depth.");
DEFINE_int32(tree_storage_depth, 0,
             "Subdirectory depth for tree signatures; if the directory is not "
             "empty, must match the existing depth");
DEFINE_int32(log_stats_frequency_seconds, 3600,
             "Interval for logging summary statistics. Approximate: the "
             "server will log statistics if in the beginning of its select "
             "loop, at least this period has elapsed since the last log time. "
             "Must be greater than 0.");
DEFINE_int32(tree_signing_frequency_seconds, 600,
             "How often should we issue a new signed tree head. Approximate: "
             "the signer process will kick off if in the beginning of the "
             "server select loop, at least this period has elapsed since the "
             "last signing. Set this well below the MMD to ensure we sign in "
             "a timely manner. Must be greater than 0.");
DEFINE_double(guard_window_seconds, 60,
              "Unsequenced entries new than this "
              "number of seconds will not be sequenced.");
DEFINE_string(etcd_host, "", "Hostname of the etcd server");
DEFINE_int32(etcd_port, 0, "Port of the etcd server.");
DEFINE_int32(node_state_refresh_seconds, 10,
             "How often to refresh the ClusterNodeState entry for this node.");

namespace libevent = cert_trans::libevent;

using cert_trans::CertChecker;
using cert_trans::ClusterStateController;
using cert_trans::ContinuousFetcher;
using cert_trans::EtcdClient;
using cert_trans::EtcdConsistentStore;
using cert_trans::FakeEtcdClient;
using cert_trans::FileStorage;
using cert_trans::HttpHandler;
using cert_trans::LoggedCertificate;
using cert_trans::MasterElection;
using cert_trans::PeriodicClosure;
using cert_trans::ReadPrivateKey;
using cert_trans::StrictConsistentStore;
using cert_trans::ThreadPool;
using cert_trans::TreeSigner;
using cert_trans::Update;
using ct::ClusterNodeState;
using ct::SignedTreeHead;
using google::RegisterFlagValidator;
using std::bind;
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::seconds;
using std::chrono::steady_clock;
using std::function;
using std::make_shared;
using std::shared_ptr;
using std::string;
using std::thread;
using std::unique_ptr;

// Basic sanity checks on flag values.
static bool ValidatePort(const char* flagname, int port) {
  if (port <= 0 || port > 65535) {
    std::cout << "Port value " << port << " is invalid. " << std::endl;
    return false;
  }
  return true;
}

static const bool port_dummy =
    RegisterFlagValidator(&FLAGS_port, &ValidatePort);

static bool ValidateRead(const char* flagname, const string& path) {
  if (access(path.c_str(), R_OK) != 0) {
    std::cout << "Cannot access " << flagname << " at " << path << std::endl;
    return false;
  }
  return true;
}

static const bool key_dummy = RegisterFlagValidator(&FLAGS_key, &ValidateRead);

static const bool cert_dummy =
    RegisterFlagValidator(&FLAGS_trusted_cert_file, &ValidateRead);

static bool ValidateWrite(const char* flagname, const string& path) {
  if (path != "" && access(path.c_str(), W_OK) != 0) {
    std::cout << "Cannot modify " << flagname << " at " << path << std::endl;
    return false;
  }
  return true;
}

static const bool cert_dir_dummy =
    RegisterFlagValidator(&FLAGS_cert_dir, &ValidateWrite);

static const bool tree_dir_dummy =
    RegisterFlagValidator(&FLAGS_tree_dir, &ValidateWrite);

static bool ValidateIsNonNegative(const char* flagname, int value) {
  if (value < 0) {
    std::cout << flagname << " must not be negative" << std::endl;
    return false;
  }
  return true;
}

static const bool c_st_dummy =
    RegisterFlagValidator(&FLAGS_cert_storage_depth, &ValidateIsNonNegative);
static const bool t_st_dummy =
    RegisterFlagValidator(&FLAGS_tree_storage_depth, &ValidateIsNonNegative);

static bool ValidateIsPositive(const char* flagname, int value) {
  if (value <= 0) {
    std::cout << flagname << " must be greater than 0" << std::endl;
    return false;
  }
  return true;
}

static const bool stats_dummy =
    RegisterFlagValidator(&FLAGS_log_stats_frequency_seconds,
                          &ValidateIsPositive);

static const bool sign_dummy =
    RegisterFlagValidator(&FLAGS_tree_signing_frequency_seconds,
                          &ValidateIsPositive);

void SignMerkleTree(TreeSigner<LoggedCertificate>* tree_signer,
                    ClusterStateController<LoggedCertificate>* controller,
                    const MasterElection* election) {
  const steady_clock::duration period((seconds(FLAGS_tree_signing_frequency_seconds)));
  steady_clock::time_point target_run_time(steady_clock::now());

  while (true) {
    if (election->IsMaster()) {
      // TODO(alcutter): Probably don't need to blow up here
      CHECK_EQ(util::Status::OK, tree_signer->SequenceNewEntries())
          << "Problem sequencing new entries";
    }

    CHECK_EQ(tree_signer->UpdateTree(), TreeSigner<LoggedCertificate>::OK);
    controller->NewTreeHead(tree_signer->LatestSTH());

    const steady_clock::time_point now(steady_clock::now());
    while (target_run_time <= now) {
      target_run_time += period;
    }

    std::this_thread::sleep_for(target_run_time - now);
  }
}

int main(int argc, char* argv[]) {
  google::ParseCommandLineFlags(&argc, &argv, true);
  google::InitGoogleLogging(argv[0]);
  google::InstallFailureSignalHandler();
  OpenSSL_add_all_algorithms();
  ERR_load_crypto_strings();
  cert_trans::LoadCtExtensions();

  util::StatusOr<EVP_PKEY*> pkey(ReadPrivateKey(FLAGS_key));
  CHECK_EQ(pkey.status(), util::Status::OK);
  LogSigner log_signer(pkey.ValueOrDie());

  CertChecker checker;
  CHECK(checker.LoadTrustedCertificates(FLAGS_trusted_cert_file))
      << "Could not load CA certs from " << FLAGS_trusted_cert_file;

  if (FLAGS_sqlite_db == "")
    CHECK_NE(FLAGS_cert_dir, FLAGS_tree_dir)
        << "Certificate directory and tree directory must differ";

  if ((FLAGS_cert_dir != "" || FLAGS_tree_dir != "") &&
      FLAGS_sqlite_db != "") {
    std::cerr << "Choose either file or sqlite database, not both"
              << std::endl;
    exit(1);
  }

  Database<LoggedCertificate>* db;

  if (FLAGS_sqlite_db != "")
    db = new SQLiteDB<LoggedCertificate>(FLAGS_sqlite_db);
  else
    db = new FileDB<LoggedCertificate>(
        new FileStorage(FLAGS_cert_dir, FLAGS_cert_storage_depth),
        new FileStorage(FLAGS_tree_dir, FLAGS_tree_storage_depth),
        new FileStorage(FLAGS_meta_dir, 0));

  std::string node_id;
  if (db->NodeId(&node_id) != Database<LoggedCertificate>::LOOKUP_OK) {
    node_id = cert_trans::UUID4();
    LOG(INFO) << "Initializing Node DB with UUID: " << node_id;
    db->InitializeNode(node_id);
  } else {
    LOG(INFO) << "Found DB with Node UUID: " << node_id;
  }

  evthread_use_pthreads();
  const shared_ptr<libevent::Base> event_base(make_shared<libevent::Base>());
  // Temporary event pump for while we're setting things up and haven't yet
  // entered the event loop at the bottom:
  std::unique_ptr<libevent::EventPumpThread> pump(
      new libevent::EventPumpThread(event_base));

  const bool stand_alone_mode(FLAGS_etcd_host.empty());

  LOG(INFO) << "Running in "
            << (stand_alone_mode ? "STAND-ALONE" : "CLUSTERED") << " mode.";

  std::unique_ptr<EtcdClient> etcd_client(
      stand_alone_mode
          ? new FakeEtcdClient(event_base)
          : new EtcdClient(event_base, FLAGS_etcd_host, FLAGS_etcd_port));

  // No real reason to let this be configurable per node; you can really
  // shoot yourself in the foot that way by effectively running multiple
  // distinct elections.
  const string kLockDir("/election");
  MasterElection election(event_base, etcd_client.get(), kLockDir, node_id);

  // For now, run with a dedicated thread pool as the executor for our
  // consistent store to avoid the possibility of DoS through thread starvation
  // via HTTP.
  ThreadPool internal_pool(4);
  StrictConsistentStore<LoggedCertificate> consistent_store(
      &election,
      new EtcdConsistentStore<LoggedCertificate>(&internal_pool,
                                                 etcd_client.get(), &election,
                                                 "/root", node_id));

  TreeSigner<LoggedCertificate> tree_signer(std::chrono::duration<double>(
                                                FLAGS_guard_window_seconds),
                                            db, &consistent_store,
                                            &log_signer);

  if (stand_alone_mode) {
    // Set up a simple single-node environment.
    //
    // Put a sensible single-node config into FakeEtcd. For a real clustered
    // log
    // we'd expect a ClusterConfig already to be present within etcd as part of
    // the provisioning of the log.
    //
    // TODO(alcutter): Note that we're currently broken wrt to restarting the
    // log server when there's data in the log.  It's a temporary thing though,
    // so fear ye not.
    ct::ClusterConfig config;
    config.set_minimum_serving_nodes(1);
    config.set_minimum_serving_fraction(1);
    LOG(INFO) << "Setting default single-node ClusterConfig:\n"
              << config.DebugString();
    consistent_store.SetClusterConfig(config);

    // Since we're a single node cluster, we'll settle that we're the
    // master here, so that we can populate the initial STH
    // (StrictConsistentStore won't allow us to do so unless we're master.)
    election.StartElection();
    election.WaitToBecomeMaster();

    // Do an initial signing run to get the initial STH, again this is
    // temporary until we re-populate FakeEtcd from the DB.
    CHECK_EQ(tree_signer.UpdateTree(), TreeSigner<LoggedCertificate>::OK);

    // Need to boot-strap the Serving STH too because we consider it an error
    // if it's not set, which in turn causes us to not attempt to become
    // master:
    consistent_store.SetServingSTH(tree_signer.LatestSTH());
  } else {
    CHECK(!FLAGS_server.empty());
  }

  const unique_ptr<ContinuousFetcher> fetcher(
      ContinuousFetcher::New(event_base.get(), db));
  ClusterStateController<LoggedCertificate> cluster_controller(
      &internal_pool, event_base, db, &consistent_store, &election,
      fetcher.get());
  // Publish this node's hostname:port info
  cluster_controller.SetNodeHostPort(FLAGS_server, FLAGS_port);

  // Just separate this out from the lambda below to try to be clear that this
  // is the *only* interaction with TreeSigner that we're allowing there.
  const function<SignedTreeHead(void)> get_latest_sth(
      bind(&TreeSigner<LoggedCertificate>::LatestSTH, &tree_signer));
  // Periodically refresh our ClusterNodeState entry so it doesn't get deleted.
  // TODO(alcutter): Figure out if we actually need this here now, the signer
  // thread above will refresh the entry, but potentially not frequently
  // enough.
  PeriodicClosure node_state_refresh(
      event_base, std::chrono::seconds(FLAGS_node_state_refresh_seconds),
      [&db, &cluster_controller, &internal_pool, &get_latest_sth]() {
        // Actually run this on the thread pool, since this periodic closure is
        // calling back on the eventloop thread.
        internal_pool.Add([&db, &cluster_controller, &get_latest_sth]() {
          cluster_controller.NewTreeHead(get_latest_sth());
        });
      });

  Frontend frontend(new CertSubmissionHandler(&checker),
                    new FrontendSigner(db, &consistent_store, &log_signer));
  LogLookup<LoggedCertificate> log_lookup(db);

  // TODO(pphaneuf): We should be remaining in an "unhealthy state"
  // (either not accepting any requests, or returning some internal
  // server error) until we have an STH to serve.
  thread signer(&SignMerkleTree, &tree_signer, &cluster_controller, &election);
  ThreadPool pool;
  HttpHandler handler(&log_lookup, db, &checker, &frontend, &pool);

  libevent::HttpServer server(*event_base);
  handler.Add(&server);
  server.Bind(NULL, FLAGS_port);

  std::cout << "READY" << std::endl;

  // Ding the temporary event pump because we're about to enter the event loop
  pump.reset();
  event_base->Dispatch();

  return 0;
}
<|endoftext|>


<commit_before>/*****************************************************************************
* MediaPlayerCX.cpp: MediaPlayer API
*****************************************************************************
* Copyright  2014 the VideoLAN team
*
* Authors: Hugo Beauze-Luyssen <hugo@beauzee.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/

#include "MediaPlayerCX.hpp"
#include "MediaCX.hpp"
#include "InstanceCX.hpp"
#include "EventManagerCX.hpp"

#include "Helpers.h"

namespace libVLCX
{
    MediaPlayer::MediaPlayer(Instance^ instance)
        : m_mp(VLC::MediaPlayer(instance->m_instance))
    {
    }

    MediaPlayer::MediaPlayer(Media^ md)
        : m_mp(VLC::MediaPlayer(md->m_media))
    {
    }

    void MediaPlayer::setMedia(Media^ md)
    {
        m_mp.setMedia(md->m_media);
    }

    Media^ MediaPlayer::media()
    {
        return ref new Media(*m_mp.media().get());
    }

    MediaPlayerEventManager^ MediaPlayer::eventManager()
    {
        if (m_eventManager == nullptr)
            m_eventManager = ref new MediaPlayerEventManager(m_mp.eventManager());
        return m_eventManager;

    }

    bool MediaPlayer::isPlaying()
    {
        return m_mp.isPlaying();
    }

    int MediaPlayer::play()
    {
        return m_mp.play();
    }

    void MediaPlayer::setPause(int do_pause)
    {
        m_mp.setPause(do_pause);
    }

    void MediaPlayer::pause()
    {
        m_mp.pause();
    }

    void MediaPlayer::stop()
    {
        m_mp.stop();
    }

    void MediaPlayer::setHwnd(uint64 drawable)
    {
        m_mp.setHwnd((void*) drawable);
    }

    uint64 MediaPlayer::hwnd()
    {
        return (uint64)m_mp.hwnd();
    }

    libvlc_time_t MediaPlayer::length()
    {
        return m_mp.length();
    }

    libvlc_time_t MediaPlayer::time()
    {
        return m_mp.time();
    }

    void MediaPlayer::setTime(libvlc_time_t i_time)
    {
        m_mp.setTime(i_time);
    }

    float MediaPlayer::position()
    {
        return m_mp.position();
    }

    void MediaPlayer::setPosition(float f_pos)
    {
        m_mp.setPosition(f_pos);
    }

    void MediaPlayer::setChapter(int i_chapter)
    {
        m_mp.setChapter(i_chapter);
    }

    int MediaPlayer::chapter()
    {
        return m_mp.chapter();
    }

    int MediaPlayer::chapterCount()
    {
        return m_mp.chapterCount();
    }

    bool MediaPlayer::willPlay()
    {
        return m_mp.willPlay();
    }

    int MediaPlayer::chapterCountForTitle(int i_title)
    {
        return m_mp.chapterCountForTitle(i_title);
    }

    void MediaPlayer::setTitle(int i_title)
    {
        m_mp.setTitle(i_title);
    }

    int MediaPlayer::title()
    {
        return m_mp.title();
    }

    int MediaPlayer::titleCount()
    {
        return m_mp.titleCount();
    }

    void MediaPlayer::previousChapter()
    {
        m_mp.previousChapter();
    }
    void MediaPlayer::nextChapter()
    {
        m_mp.nextChapter();
    }

    float MediaPlayer::rate()
    {
        return m_mp.rate();
    }

    int MediaPlayer::setRate(float rate)
    {
        return m_mp.setRate(rate);
    }

    MediaState MediaPlayer::state()
    {
        return (MediaState)m_mp.state();
    }

    float MediaPlayer::fps()
    {
        return m_mp.fps();
    }

    unsigned MediaPlayer::hasVout()
    {
        return m_mp.hasVout();
    }

    bool MediaPlayer::isSeekable()
    {
        return m_mp.isSeekable();
    }

    bool MediaPlayer::canPause()
    {
        return m_mp.canPause();
    }

    bool MediaPlayer::programScrambled()
    {
        return m_mp.programScrambled();
    }

    void MediaPlayer::nextFrame()
    {
        m_mp.nextFrame();
    }

    void MediaPlayer::navigate(unsigned int nav)
    {
        m_mp.navigate(nav);
    }

    void MediaPlayer::setVideoTitleDisplay(TitlePosition position, unsigned int timeout)
    {
        m_mp.setVideoTitleDisplay((libvlc_position_t)position, timeout);
    }

    void MediaPlayer::toggleFullscreen()
    {
        m_mp.toggleFullscreen();
    }

    void MediaPlayer::setFullscreen(int b_fullscreen)
    {
        m_mp.setFullscreen(b_fullscreen);
    }

    bool MediaPlayer::fullscreen()
    {
        return m_mp.fullscreen();
    }

    void MediaPlayer::toggleTeletext()
    {
        m_mp.toggleTeletext();
    }

    /*int MediaPlayer::setEqualizer(libvlc_equalizer_t * p_equalizer)
    {
    m_mp.setEqualizer(p_equalizer);
    }*/

    //void setAudioCallbacks(libvlc_audio_play_cb play, libvlc_audio_pause_cb pause, libvlc_audio_resume_cb resume, libvlc_audio_flush_cb flush, libvlc_audio_drain_cb drain, void * opaque);

    //void setVolumeCallback(libvlc_audio_set_volume_cb set_volume);

    //void setAudioFormatCallbacks(libvlc_audio_setup_cb setup, libvlc_audio_cleanup_cb cleanup);

    //void setAudioFormat(Platform::String^ format, unsigned rate, unsigned channels);

    int MediaPlayer::setAudioOutput(Platform::String^ psz_name)
    {
        return m_mp.setAudioOutput(VLCString(psz_name));
    }

    Windows::Foundation::Collections::IVector<AudioOutputDeviceDescription^>^ MediaPlayer::outputDeviceEnum()
    {
        return MarshallVector<AudioOutputDeviceDescription, VLC::AudioOutputDeviceDescription>(m_mp.outputDeviceEnum());
    }

    void MediaPlayer::outputDeviceSet(Platform::String^ module, Platform::String^ device_id)
    {
        m_mp.outputDeviceSet(VLCString(module), VLCString(device_id));
    }

    void MediaPlayer::toggleMute()
    {
        m_mp.toggleMute();
    }

    int MediaPlayer::mute()
    {
        return m_mp.mute();
    }

    void MediaPlayer::setMute(int status)
    {
        m_mp.setMute(status);
    }

    int MediaPlayer::volume()
    {
        return m_mp.volume();
    }

    int MediaPlayer::setVolume(int i_volume)
    {
        return m_mp.setVolume(i_volume);
    }

    int MediaPlayer::audioTrackCount()
    {
        return m_mp.audioTrackCount();
    }

    Windows::Foundation::Collections::IVector<TrackDescription^>^ MediaPlayer::audioTrackDescription()
    {
        return MarshallVector<TrackDescription, VLC::TrackDescription>(m_mp.audioTrackDescription());
    }

    int MediaPlayer::audioTrack()
    {
        return m_mp.audioTrack();
    }

    int MediaPlayer::setAudioTrack(int i_track)
    {
        return m_mp.setAudioTrack(i_track);
    }

    int MediaPlayer::channel()
    {
        return m_mp.channel();
    }

    int MediaPlayer::setChannel(int channel)
    {
        return m_mp.setChannel(channel);
    }

    int64_t MediaPlayer::audioDelay()
    {
        return m_mp.audioDelay();
    }

    int MediaPlayer::setAudioDelay(int64_t i_delay)
    {
        return m_mp.setAudioDelay(i_delay);
    }

    //void setVideoCallbacks(libvlc_video_lock_cb lock, libvlc_video_unlock_cb unlock, libvlc_video_display_cb display, void * opaque);

    //void setVideoFormat(Platform::String^ chroma, unsigned width, unsigned height, unsigned pitch);

    //void setVideoFormatCallbacks(libvlc_video_format_cb setup, libvlc_video_cleanup_cb cleanup);

    void MediaPlayer::setKeyInput(unsigned on)
    {
        m_mp.setKeyInput(on);
    }

    void MediaPlayer::setMouseInput(unsigned on)
    {
        m_mp.setMouseInput(on);
    }

    int MediaPlayer::size(unsigned num, unsigned * px, unsigned * py)
    {
        return m_mp.size(num, px, py);
    }

    int MediaPlayer::cursor(unsigned num, int * px, int * py)
    {
        return m_mp.cursor(num, px, py);
    }

    float MediaPlayer::scale()
    {
        return m_mp.scale();
    }

    void MediaPlayer::setScale(float f_factor)
    {
        m_mp.setScale(f_factor);
    }

    Platform::String^ MediaPlayer::aspectRatio()
    {
        return ToPlatformString(m_mp.aspectRatio());
    }

    void MediaPlayer::setAspectRatio(Platform::String^ psz_aspect)
    {
        m_mp.setAspectRatio(VLCString(psz_aspect));
    }

    int MediaPlayer::spu()
    {
        return m_mp.spu();
    }

    int MediaPlayer::spuCount()
    {
        return m_mp.spuCount();
    }

    Windows::Foundation::Collections::IVector<TrackDescription^>^ MediaPlayer::spuDescription()
    {
        return MarshallVector<TrackDescription, VLC::TrackDescription>(m_mp.spuDescription());
    }

    int MediaPlayer::setSpu(int i_spu)
    {
        return m_mp.setSpu(i_spu);
    }

    int MediaPlayer::setSubtitleFile(Platform::String^ psz_subtitle)
    {
        return m_mp.setSubtitleFile(VLCString(psz_subtitle));
    }

    int64_t MediaPlayer::spuDelay()
    {
        return m_mp.spuDelay();
    }

    int MediaPlayer::setSpuDelay(int64_t i_delay)
    {
        return m_mp.setSpuDelay(i_delay);
    }

    Windows::Foundation::Collections::IVector<TitleDescription^>^ MediaPlayer::titleDescription()
    {
        return MarshallVector<TitleDescription, VLC::TitleDescription>(m_mp.titleDescription());
    }

    Windows::Foundation::Collections::IVector<ChapterDescription^>^ MediaPlayer::chapterDescription(int i_title)
    {
        return MarshallVector<ChapterDescription, VLC::ChapterDescription>(m_mp.chapterDescription(i_title));
    }

    Platform::String^ MediaPlayer::cropGeometry()
    {
        return ToPlatformString(m_mp.cropGeometry());
    }

    void MediaPlayer::setCropGeometry(Platform::String^ psz_geometry)
    {
        m_mp.setCropGeometry(VLCString(psz_geometry));
    }

    int MediaPlayer::teletext()
    {
        return m_mp.teletext();
    }

    void MediaPlayer::setTeletext(int i_page)
    {
        m_mp.setTeletext(i_page);
    }

    int MediaPlayer::videoTrackCount()
    {
        return m_mp.videoTrackCount();
    }

    Windows::Foundation::Collections::IVector<TrackDescription^>^ MediaPlayer::videoTrackDescription()
    {
        return MarshallVector<TrackDescription, VLC::TrackDescription>(m_mp.videoTrackDescription());
    }

    int MediaPlayer::videoTrack()
    {
        return m_mp.videoTrack();
    }

    int MediaPlayer::setVideoTrack(int i_track)
    {
        return m_mp.setVideoTrack(i_track);
    }

    int MediaPlayer::takeSnapshot(unsigned num, Platform::String^ psz_filepath, unsigned int i_width, unsigned int i_height)
    {
        return m_mp.takeSnapshot(num, VLCString(psz_filepath), i_width, i_height);
    }

    void MediaPlayer::setDeinterlace(Platform::String^ psz_mode)
    {
        m_mp.setDeinterlace(VLCString(psz_mode));
    }

    int MediaPlayer::marqueeInt(unsigned option)
    {
        return m_mp.marqueeInt(option);
    }

    Platform::String^ MediaPlayer::marqueeString(unsigned option)
    {
        return ToPlatformString(m_mp.marqueeString(option));
    }

    void MediaPlayer::setMarqueeInt(unsigned option, int i_val)
    {
        m_mp.setMarqueeInt(option, i_val);
    }

    void MediaPlayer::setMarqueeString(unsigned option, Platform::String^ psz_text)
    {
        m_mp.setMarqueeString(option, VLCString(psz_text));
    }

    int MediaPlayer::logoInt(unsigned option)
    {
        return m_mp.logoInt(option);
    }

    void MediaPlayer::setLogoInt(unsigned option, int value)
    {
        m_mp.setLogoInt(option, value);
    }

    void MediaPlayer::setLogoString(unsigned option, Platform::String^ psz_value)
    {
        m_mp.setLogoString(option, VLCString(psz_value));
    }

    int MediaPlayer::adjustInt(unsigned option)
    {
        return m_mp.adjustInt(option);
    }

    void MediaPlayer::setAdjustInt(unsigned option, int value)
    {
        m_mp.setAdjustInt(option, value);
    }

    float MediaPlayer::adjustFloat(unsigned option)
    {
        return m_mp.adjustFloat(option);
    }

    void MediaPlayer::setAdjustFloat(unsigned option, float value)
    {
        m_mp.setAdjustFloat(option, value);
    }

} // namespace VLC

<commit_msg>MediaPlayerCX: Fix an implicit cast warning<commit_after>/*****************************************************************************
* MediaPlayerCX.cpp: MediaPlayer API
*****************************************************************************
* Copyright  2014 the VideoLAN team
*
* Authors: Hugo Beauze-Luyssen <hugo@beauzee.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/

#include "MediaPlayerCX.hpp"
#include "MediaCX.hpp"
#include "InstanceCX.hpp"
#include "EventManagerCX.hpp"

#include "Helpers.h"

namespace libVLCX
{
    MediaPlayer::MediaPlayer(Instance^ instance)
        : m_mp(VLC::MediaPlayer(instance->m_instance))
    {
    }

    MediaPlayer::MediaPlayer(Media^ md)
        : m_mp(VLC::MediaPlayer(md->m_media))
    {
    }

    void MediaPlayer::setMedia(Media^ md)
    {
        m_mp.setMedia(md->m_media);
    }

    Media^ MediaPlayer::media()
    {
        return ref new Media(*m_mp.media().get());
    }

    MediaPlayerEventManager^ MediaPlayer::eventManager()
    {
        if (m_eventManager == nullptr)
            m_eventManager = ref new MediaPlayerEventManager(m_mp.eventManager());
        return m_eventManager;

    }

    bool MediaPlayer::isPlaying()
    {
        return m_mp.isPlaying();
    }

    int MediaPlayer::play()
    {
        return m_mp.play();
    }

    void MediaPlayer::setPause(int do_pause)
    {
        m_mp.setPause((bool)do_pause);
    }

    void MediaPlayer::pause()
    {
        m_mp.pause();
    }

    void MediaPlayer::stop()
    {
        m_mp.stop();
    }

    void MediaPlayer::setHwnd(uint64 drawable)
    {
        m_mp.setHwnd((void*) drawable);
    }

    uint64 MediaPlayer::hwnd()
    {
        return (uint64)m_mp.hwnd();
    }

    libvlc_time_t MediaPlayer::length()
    {
        return m_mp.length();
    }

    libvlc_time_t MediaPlayer::time()
    {
        return m_mp.time();
    }

    void MediaPlayer::setTime(libvlc_time_t i_time)
    {
        m_mp.setTime(i_time);
    }

    float MediaPlayer::position()
    {
        return m_mp.position();
    }

    void MediaPlayer::setPosition(float f_pos)
    {
        m_mp.setPosition(f_pos);
    }

    void MediaPlayer::setChapter(int i_chapter)
    {
        m_mp.setChapter(i_chapter);
    }

    int MediaPlayer::chapter()
    {
        return m_mp.chapter();
    }

    int MediaPlayer::chapterCount()
    {
        return m_mp.chapterCount();
    }

    bool MediaPlayer::willPlay()
    {
        return m_mp.willPlay();
    }

    int MediaPlayer::chapterCountForTitle(int i_title)
    {
        return m_mp.chapterCountForTitle(i_title);
    }

    void MediaPlayer::setTitle(int i_title)
    {
        m_mp.setTitle(i_title);
    }

    int MediaPlayer::title()
    {
        return m_mp.title();
    }

    int MediaPlayer::titleCount()
    {
        return m_mp.titleCount();
    }

    void MediaPlayer::previousChapter()
    {
        m_mp.previousChapter();
    }
    void MediaPlayer::nextChapter()
    {
        m_mp.nextChapter();
    }

    float MediaPlayer::rate()
    {
        return m_mp.rate();
    }

    int MediaPlayer::setRate(float rate)
    {
        return m_mp.setRate(rate);
    }

    MediaState MediaPlayer::state()
    {
        return (MediaState)m_mp.state();
    }

    float MediaPlayer::fps()
    {
        return m_mp.fps();
    }

    unsigned MediaPlayer::hasVout()
    {
        return m_mp.hasVout();
    }

    bool MediaPlayer::isSeekable()
    {
        return m_mp.isSeekable();
    }

    bool MediaPlayer::canPause()
    {
        return m_mp.canPause();
    }

    bool MediaPlayer::programScrambled()
    {
        return m_mp.programScrambled();
    }

    void MediaPlayer::nextFrame()
    {
        m_mp.nextFrame();
    }

    void MediaPlayer::navigate(unsigned int nav)
    {
        m_mp.navigate(nav);
    }

    void MediaPlayer::setVideoTitleDisplay(TitlePosition position, unsigned int timeout)
    {
        m_mp.setVideoTitleDisplay((libvlc_position_t)position, timeout);
    }

    void MediaPlayer::toggleFullscreen()
    {
        m_mp.toggleFullscreen();
    }

    void MediaPlayer::setFullscreen(int b_fullscreen)
    {
        m_mp.setFullscreen(b_fullscreen);
    }

    bool MediaPlayer::fullscreen()
    {
        return m_mp.fullscreen();
    }

    void MediaPlayer::toggleTeletext()
    {
        m_mp.toggleTeletext();
    }

    /*int MediaPlayer::setEqualizer(libvlc_equalizer_t * p_equalizer)
    {
    m_mp.setEqualizer(p_equalizer);
    }*/

    //void setAudioCallbacks(libvlc_audio_play_cb play, libvlc_audio_pause_cb pause, libvlc_audio_resume_cb resume, libvlc_audio_flush_cb flush, libvlc_audio_drain_cb drain, void * opaque);

    //void setVolumeCallback(libvlc_audio_set_volume_cb set_volume);

    //void setAudioFormatCallbacks(libvlc_audio_setup_cb setup, libvlc_audio_cleanup_cb cleanup);

    //void setAudioFormat(Platform::String^ format, unsigned rate, unsigned channels);

    int MediaPlayer::setAudioOutput(Platform::String^ psz_name)
    {
        return m_mp.setAudioOutput(VLCString(psz_name));
    }

    Windows::Foundation::Collections::IVector<AudioOutputDeviceDescription^>^ MediaPlayer::outputDeviceEnum()
    {
        return MarshallVector<AudioOutputDeviceDescription, VLC::AudioOutputDeviceDescription>(m_mp.outputDeviceEnum());
    }

    void MediaPlayer::outputDeviceSet(Platform::String^ module, Platform::String^ device_id)
    {
        m_mp.outputDeviceSet(VLCString(module), VLCString(device_id));
    }

    void MediaPlayer::toggleMute()
    {
        m_mp.toggleMute();
    }

    int MediaPlayer::mute()
    {
        return m_mp.mute();
    }

    void MediaPlayer::setMute(int status)
    {
        m_mp.setMute(status);
    }

    int MediaPlayer::volume()
    {
        return m_mp.volume();
    }

    int MediaPlayer::setVolume(int i_volume)
    {
        return m_mp.setVolume(i_volume);
    }

    int MediaPlayer::audioTrackCount()
    {
        return m_mp.audioTrackCount();
    }

    Windows::Foundation::Collections::IVector<TrackDescription^>^ MediaPlayer::audioTrackDescription()
    {
        return MarshallVector<TrackDescription, VLC::TrackDescription>(m_mp.audioTrackDescription());
    }

    int MediaPlayer::audioTrack()
    {
        return m_mp.audioTrack();
    }

    int MediaPlayer::setAudioTrack(int i_track)
    {
        return m_mp.setAudioTrack(i_track);
    }

    int MediaPlayer::channel()
    {
        return m_mp.channel();
    }

    int MediaPlayer::setChannel(int channel)
    {
        return m_mp.setChannel(channel);
    }

    int64_t MediaPlayer::audioDelay()
    {
        return m_mp.audioDelay();
    }

    int MediaPlayer::setAudioDelay(int64_t i_delay)
    {
        return m_mp.setAudioDelay(i_delay);
    }

    //void setVideoCallbacks(libvlc_video_lock_cb lock, libvlc_video_unlock_cb unlock, libvlc_video_display_cb display, void * opaque);

    //void setVideoFormat(Platform::String^ chroma, unsigned width, unsigned height, unsigned pitch);

    //void setVideoFormatCallbacks(libvlc_video_format_cb setup, libvlc_video_cleanup_cb cleanup);

    void MediaPlayer::setKeyInput(unsigned on)
    {
        m_mp.setKeyInput(on);
    }

    void MediaPlayer::setMouseInput(unsigned on)
    {
        m_mp.setMouseInput(on);
    }

    int MediaPlayer::size(unsigned num, unsigned * px, unsigned * py)
    {
        return m_mp.size(num, px, py);
    }

    int MediaPlayer::cursor(unsigned num, int * px, int * py)
    {
        return m_mp.cursor(num, px, py);
    }

    float MediaPlayer::scale()
    {
        return m_mp.scale();
    }

    void MediaPlayer::setScale(float f_factor)
    {
        m_mp.setScale(f_factor);
    }

    Platform::String^ MediaPlayer::aspectRatio()
    {
        return ToPlatformString(m_mp.aspectRatio());
    }

    void MediaPlayer::setAspectRatio(Platform::String^ psz_aspect)
    {
        m_mp.setAspectRatio(VLCString(psz_aspect));
    }

    int MediaPlayer::spu()
    {
        return m_mp.spu();
    }

    int MediaPlayer::spuCount()
    {
        return m_mp.spuCount();
    }

    Windows::Foundation::Collections::IVector<TrackDescription^>^ MediaPlayer::spuDescription()
    {
        return MarshallVector<TrackDescription, VLC::TrackDescription>(m_mp.spuDescription());
    }

    int MediaPlayer::setSpu(int i_spu)
    {
        return m_mp.setSpu(i_spu);
    }

    int MediaPlayer::setSubtitleFile(Platform::String^ psz_subtitle)
    {
        return m_mp.setSubtitleFile(VLCString(psz_subtitle));
    }

    int64_t MediaPlayer::spuDelay()
    {
        return m_mp.spuDelay();
    }

    int MediaPlayer::setSpuDelay(int64_t i_delay)
    {
        return m_mp.setSpuDelay(i_delay);
    }

    Windows::Foundation::Collections::IVector<TitleDescription^>^ MediaPlayer::titleDescription()
    {
        return MarshallVector<TitleDescription, VLC::TitleDescription>(m_mp.titleDescription());
    }

    Windows::Foundation::Collections::IVector<ChapterDescription^>^ MediaPlayer::chapterDescription(int i_title)
    {
        return MarshallVector<ChapterDescription, VLC::ChapterDescription>(m_mp.chapterDescription(i_title));
    }

    Platform::String^ MediaPlayer::cropGeometry()
    {
        return ToPlatformString(m_mp.cropGeometry());
    }

    void MediaPlayer::setCropGeometry(Platform::String^ psz_geometry)
    {
        m_mp.setCropGeometry(VLCString(psz_geometry));
    }

    int MediaPlayer::teletext()
    {
        return m_mp.teletext();
    }

    void MediaPlayer::setTeletext(int i_page)
    {
        m_mp.setTeletext(i_page);
    }

    int MediaPlayer::videoTrackCount()
    {
        return m_mp.videoTrackCount();
    }

    Windows::Foundation::Collections::IVector<TrackDescription^>^ MediaPlayer::videoTrackDescription()
    {
        return MarshallVector<TrackDescription, VLC::TrackDescription>(m_mp.videoTrackDescription());
    }

    int MediaPlayer::videoTrack()
    {
        return m_mp.videoTrack();
    }

    int MediaPlayer::setVideoTrack(int i_track)
    {
        return m_mp.setVideoTrack(i_track);
    }

    int MediaPlayer::takeSnapshot(unsigned num, Platform::String^ psz_filepath, unsigned int i_width, unsigned int i_height)
    {
        return m_mp.takeSnapshot(num, VLCString(psz_filepath), i_width, i_height);
    }

    void MediaPlayer::setDeinterlace(Platform::String^ psz_mode)
    {
        m_mp.setDeinterlace(VLCString(psz_mode));
    }

    int MediaPlayer::marqueeInt(unsigned option)
    {
        return m_mp.marqueeInt(option);
    }

    Platform::String^ MediaPlayer::marqueeString(unsigned option)
    {
        return ToPlatformString(m_mp.marqueeString(option));
    }

    void MediaPlayer::setMarqueeInt(unsigned option, int i_val)
    {
        m_mp.setMarqueeInt(option, i_val);
    }

    void MediaPlayer::setMarqueeString(unsigned option, Platform::String^ psz_text)
    {
        m_mp.setMarqueeString(option, VLCString(psz_text));
    }

    int MediaPlayer::logoInt(unsigned option)
    {
        return m_mp.logoInt(option);
    }

    void MediaPlayer::setLogoInt(unsigned option, int value)
    {
        m_mp.setLogoInt(option, value);
    }

    void MediaPlayer::setLogoString(unsigned option, Platform::String^ psz_value)
    {
        m_mp.setLogoString(option, VLCString(psz_value));
    }

    int MediaPlayer::adjustInt(unsigned option)
    {
        return m_mp.adjustInt(option);
    }

    void MediaPlayer::setAdjustInt(unsigned option, int value)
    {
        m_mp.setAdjustInt(option, value);
    }

    float MediaPlayer::adjustFloat(unsigned option)
    {
        return m_mp.adjustFloat(option);
    }

    void MediaPlayer::setAdjustFloat(unsigned option, float value)
    {
        m_mp.setAdjustFloat(option, value);
    }

} // namespace VLC

<|endoftext|>


<commit_before>#ifndef SEGMENTLAYER_HPP_
#define SEGMENTLAYER_HPP_

#include "HyPerLayer.hpp"

namespace PV {

class SegmentLayer: public PV::HyPerLayer {
public:
   SegmentLayer(const char * name, HyPerCol * hc);
   virtual int communicateInitInfo();
   virtual int allocateDataStructures();
   virtual bool activityIsSpiking() { return false; }
   virtual ~SegmentLayer();

protected:
   SegmentLayer();
   int initialize(const char * name, HyPerCol * hc);
   int ioParamsFillGroup(enum ParamsIOFlag ioFlag);
   void ioParam_originalLayerName(enum ParamsIOFlag ioFlag);
   void ioParam_segmentMethod(enum ParamsIOFlag ioFlag);
   virtual int initializeActivity();

   virtual int allocateV();
   virtual int initializeV();

   virtual int updateState(double timef, double dt);

   //int growLabelBuffers(int newSize);

private:
   int initialize_base();
   int checkLabelBufSize(int newSize);
   int loadLabelBuf();
   int loadCenterIdxMap(int batchIdx, int numLabels);

   int checkIdxBufSize(int newSize);

   //Data structures to keep track of segmentation labels and centroid idx
   char * segmentMethod;
   char * originalLayerName;
   HyPerLayer* originalLayer;

protected:

   int labelBufSize;
   int* labelBuf;
   int* maxXBuf;
   int* maxYBuf;
   int* minXBuf;
   int* minYBuf;

   int centerIdxBufSize;
   int* allLabelsBuf;
   int* centerIdxBuf;

   //Maps which go from segment label to max x/y global res index
   std::map<int, int> maxX;
   std::map<int, int> maxY;
   std::map<int, int> minX;
   std::map<int, int> minY;

   //Stores centriod linear index as global res
   std::vector<std::map<int, int> > centerIdx;

};

} /* namespace PV */
#endif
<commit_msg>SegmentLayer needs <map> header<commit_after>#ifndef SEGMENTLAYER_HPP_
#define SEGMENTLAYER_HPP_

#include "HyPerLayer.hpp"
#include <map>

namespace PV {

class SegmentLayer: public PV::HyPerLayer {
public:
   SegmentLayer(const char * name, HyPerCol * hc);
   virtual int communicateInitInfo();
   virtual int allocateDataStructures();
   virtual bool activityIsSpiking() { return false; }
   virtual ~SegmentLayer();

protected:
   SegmentLayer();
   int initialize(const char * name, HyPerCol * hc);
   int ioParamsFillGroup(enum ParamsIOFlag ioFlag);
   void ioParam_originalLayerName(enum ParamsIOFlag ioFlag);
   void ioParam_segmentMethod(enum ParamsIOFlag ioFlag);
   virtual int initializeActivity();

   virtual int allocateV();
   virtual int initializeV();

   virtual int updateState(double timef, double dt);

   //int growLabelBuffers(int newSize);

private:
   int initialize_base();
   int checkLabelBufSize(int newSize);
   int loadLabelBuf();
   int loadCenterIdxMap(int batchIdx, int numLabels);

   int checkIdxBufSize(int newSize);

   //Data structures to keep track of segmentation labels and centroid idx
   char * segmentMethod;
   char * originalLayerName;
   HyPerLayer* originalLayer;

protected:

   int labelBufSize;
   int* labelBuf;
   int* maxXBuf;
   int* maxYBuf;
   int* minXBuf;
   int* minYBuf;

   int centerIdxBufSize;
   int* allLabelsBuf;
   int* centerIdxBuf;

   //Maps which go from segment label to max x/y global res index
   std::map<int, int> maxX;
   std::map<int, int> maxY;
   std::map<int, int> minX;
   std::map<int, int> minY;

   //Stores centriod linear index as global res
   std::vector<std::map<int, int> > centerIdx;

};

} /* namespace PV */
#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_ERR_ELEMENTWISE_ERROR_CHECKER_HPP
#define STAN_MATH_PRIM_ERR_ELEMENTWISE_ERROR_CHECKER_HPP

#include <stan/math/prim/err/throw_domain_error.hpp>
#include <stan/math/prim/fun/get.hpp>
#include <stan/math/prim/fun/size.hpp>
#include <stan/math/prim/fun/value_of_rec.hpp>
#include <stan/math/prim/meta/is_eigen.hpp>
#include <stan/math/prim/meta/is_var_matrix.hpp>
#include <stan/math/prim/meta/is_vector.hpp>
#include <stan/math/prim/meta/is_stan_scalar.hpp>
#include <string>
#include <sstream>
#include <vector>

namespace stan {
namespace math {
namespace internal {

/** Apply an error check to a container, signal failure with `false`.
 * Apply a predicate like is_positive to the double underlying every scalar in a
 * container, producing true if the predicate holds everywhere and `false` if it
 * fails anywhere.
 * @tparam F type of predicate
 */
template <typename F>
class Iser {
  const F& is_good;

 public:
  /**
   * @param is_good predicate to check, must accept doubles and produce bools
   */
  explicit Iser(const F& is_good) : is_good(is_good) {}

  /**
   * Check the scalar.
   * @tparam T type of scalar
   * @param x scalar
   * @return `false` if the scalar fails the error check
   */
  template <typename T, typename = require_stan_scalar_t<T>>
  bool is(const T& x) {
    return is_good(value_of_rec(x));
  }

  /**
   * Check all the scalars inside the container.
   * @tparam T type of scalar
   * @param x container
   * @return `false` if any of the scalars fail the error check
   */
  template <typename T, typename = require_not_stan_scalar_t<T>,
            typename = void>
  bool is(const T& x) {
    for (size_t i = 0; i < stan::math::size(x); ++i)
      if (!is(stan::get(x, i)))
        return false;
    return true;
  }
};

/**
 * No-op.
 */
inline void pipe_in(std::stringstream& ss) {}
/**
 * Pipes given arguments into a stringstream. Integral arguments (indices) are
 * increased by 1 before.
 *
 * @tparam Arg0 type of the first argument
 * @tparam Args types of remaining arguments
 * @param ss stringstream to pipe arguments in
 * @param arg0 the first argument
 * @param args remining arguments
 */
template <typename Arg0, typename... Args>
inline void pipe_in(std::stringstream& ss, Arg0 arg0, const Args... args) {
  if (std::is_integral<Arg0>::value) {
    ss << arg0 + 1;
  } else {
    ss << arg0;
  }
  pipe_in(ss, args...);
}

}  // namespace internal

/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively.
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <typename F, typename T, typename... Indexings,
          require_stan_scalar_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings... indexings) {
  if (unlikely(!is_good(value_of_rec(x)))) {
    std::stringstream ss{};
    ss << function << ": " << name;
    internal::pipe_in(ss, indexings...);
    ss << "is " << x << ", but must be " << must_be << "!";
    throw std::domain_error(ss.str());
  }
}
template <typename F, typename T, typename... Indexings,
          require_eigen_t<T>* = nullptr,
          std::enable_if_t<static_cast<bool>(Eigen::internal::traits<T>::Flags&(
              Eigen::LinearAccessBit | Eigen::DirectAccessBit))>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings... indexings) {
  for (size_t i = 0; i < x.size(); i++) {
    auto scal = value_of_rec(x.coeff(i));
    if (unlikely(!is_good(scal))) {
      std::stringstream ss{};
      ss << function << ": " << name;
      internal::pipe_in(ss, indexings...);
      if (is_eigen_vector<T>::value) {
        ss << "[" << i + 1 << "] is " << scal << ", but must be " << must_be
           << "!";
      } else if (Eigen::internal::traits<T>::Flags & Eigen::RowMajorBit) {
        ss << "[" << i / x.rows() + 1 << ", " << i % x.rows() + 1 << "] is "
           << scal << ", but must be " << must_be << "!";
      } else {
        ss << "[" << i % x.cols() + 1 << ", " << i / x.cols() + 1 << "] is "
           << scal << ", but must be " << must_be << "!";
      }
      throw std::domain_error(ss.str());
    }
  }
}
template <
    typename F, typename T, typename... Indexings,
    require_eigen_t<T>* = nullptr,
    std::enable_if_t<!(Eigen::internal::traits<T>::Flags
                       & (Eigen::LinearAccessBit | Eigen::DirectAccessBit))
                     && !(Eigen::internal::traits<T>::Flags
                          & Eigen::RowMajorBit)>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings... indexings) {
  for (size_t i = 0; i < x.rows(); i++) {
    for (size_t j = 0; j < x.cols(); j++) {
      auto scal = value_of_rec(x.coeff(i, j));
      if (unlikely(!is_good(scal))) {
        std::stringstream ss{};
        ss << function << ": " << name;
        internal::pipe_in(ss, indexings...);
        ss << "[" << i + 1 << ", " << j + 1 << "] is " << scal
           << ", but must be " << must_be << "!";
        throw std::domain_error(ss.str());
      }
    }
  }
}
template <
    typename F, typename T, typename... Indexings,
    require_eigen_t<T>* = nullptr,
    std::enable_if_t<!(Eigen::internal::traits<T>::Flags
                       & (Eigen::LinearAccessBit | Eigen::DirectAccessBit))
                     && static_cast<bool>(Eigen::internal::traits<T>::Flags
                                          & Eigen::RowMajorBit)>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings... indexings) {
  for (size_t j = 0; j < x.cols(); j++) {
    for (size_t i = 0; i < x.rows(); i++) {
      auto scal = value_of_rec(x.coeff(i, j));
      if (unlikely(!is_good(scal))) {
        std::stringstream ss{};
        ss << function << ": " << name;
        internal::pipe_in(ss, indexings...);
        ss << "[" << i + 1 << ", " << j + 1 << "] is " << scal
           << ", but must be " << must_be << "!";
        throw std::domain_error(ss.str());
      }
    }
  }
}
template <typename F, typename T, typename... Indexings,
          require_std_vector_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings... indexings) {
  for (size_t j = 0; j < x.size(); j++) {
    elementwise_check(is_good, function, name, x[j], must_be, indexings..., "[",
                      j, "]");
  }
}
template <typename F, typename T, typename... Indexings,
          require_var_matrix_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings... indexings) {
  elementwise_check(is_good, function, name, x.val(), must_be, indexings...);
}

/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively.
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @return `false` if any of the scalars fail the error check
 */
template <typename F, typename T>
inline bool elementwise_is(const F& is_good, const T& x) {
  return internal::Iser<F>{is_good}.is(x);
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>fix performance regression<commit_after>#ifndef STAN_MATH_PRIM_ERR_ELEMENTWISE_ERROR_CHECKER_HPP
#define STAN_MATH_PRIM_ERR_ELEMENTWISE_ERROR_CHECKER_HPP

#include <stan/math/prim/err/throw_domain_error.hpp>
#include <stan/math/prim/fun/get.hpp>
#include <stan/math/prim/fun/size.hpp>
#include <stan/math/prim/fun/value_of_rec.hpp>
#include <stan/math/prim/meta/is_eigen.hpp>
#include <stan/math/prim/meta/is_var_matrix.hpp>
#include <stan/math/prim/meta/is_vector.hpp>
#include <stan/math/prim/meta/is_stan_scalar.hpp>
#include <string>
#include <sstream>
#include <vector>

namespace stan {
namespace math {
namespace internal {

/** Apply an error check to a container, signal failure with `false`.
 * Apply a predicate like is_positive to the double underlying every scalar in a
 * container, producing true if the predicate holds everywhere and `false` if it
 * fails anywhere.
 * @tparam F type of predicate
 */
template <typename F>
class Iser {
  const F& is_good;

 public:
  /**
   * @param is_good predicate to check, must accept doubles and produce bools
   */
  explicit Iser(const F& is_good) : is_good(is_good) {}

  /**
   * Check the scalar.
   * @tparam T type of scalar
   * @param x scalar
   * @return `false` if the scalar fails the error check
   */
  template <typename T, typename = require_stan_scalar_t<T>>
  bool is(const T& x) {
    return is_good(value_of_rec(x));
  }

  /**
   * Check all the scalars inside the container.
   * @tparam T type of scalar
   * @param x container
   * @return `false` if any of the scalars fail the error check
   */
  template <typename T, typename = require_not_stan_scalar_t<T>,
            typename = void>
  bool is(const T& x) {
    for (size_t i = 0; i < stan::math::size(x); ++i)
      if (!is(stan::get(x, i)))
        return false;
    return true;
  }
};

/**
 * No-op.
 */
inline void pipe_in(std::stringstream& ss) {}
/**
 * Pipes given arguments into a stringstream. Integral arguments (indices) are
 * increased by 1 before.
 *
 * @tparam Arg0 type of the first argument
 * @tparam Args types of remaining arguments
 * @param ss stringstream to pipe arguments in
 * @param arg0 the first argument
 * @param args remining arguments
 */
template <typename Arg0, typename... Args>
inline void pipe_in(std::stringstream& ss, Arg0 arg0, const Args... args) {
  if (std::is_integral<Arg0>::value) {
    ss << arg0 + 1;
  } else {
    ss << arg0;
  }
  pipe_in(ss, args...);
}

/**
 * Throws domain error with concatenation of arguments for the error message.
 * Integer arguments (indices) are increased by 1 to get 1-based indexing in
 * error message.
 * @tparam Args types of arguments
 * @param args arguments
 */
template <typename... Args>
void throw_domain_error(const Args... args) {
  std::stringstream ss;
  pipe_in(ss, args...);
  throw std::domain_error(ss.str());
}

}  // namespace internal

/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively.
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @tparam Indexings types of `indexings`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param function function name (for error messages)
 * @param name variable name (for error messages)
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @param must_be message describing what the value should be
 * @param indexings any additional indexing to print. Intended for internal use
 * in `elementwise_check` only.
 * @throws `std::domain_error` if `is_good` returns `false` for the value
 * of any element in `x`
 */
template <typename F, typename T, typename... Indexings,
          require_stan_scalar_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  if (unlikely(!is_good(value_of_rec(x)))) {
    internal::throw_domain_error(function, ": ", name, indexings..., "is ", x,
                                 ", but must be ", must_be, "!");
  }
}
template <typename F, typename T, typename... Indexings,
          require_eigen_t<T>* = nullptr,
          std::enable_if_t<static_cast<bool>(Eigen::internal::traits<T>::Flags&(
              Eigen::LinearAccessBit | Eigen::DirectAccessBit))>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t i = 0; i < x.size(); i++) {
    auto scal = value_of_rec(x.coeff(i));
    if (unlikely(!is_good(scal))) {
      if (is_eigen_vector<T>::value) {
        internal::throw_domain_error(function, ": ", name, indexings..., "[", i,
                                     "] is ", scal, ", but must be ", must_be,
                                     "!");
      } else if (Eigen::internal::traits<T>::Flags & Eigen::RowMajorBit) {
        internal::throw_domain_error(function, ": ", name, indexings..., "[",
                                     i / x.rows(), ", ", i % x.rows(), "] is ",
                                     scal, ", but must be ", must_be, "!");
      } else {
        internal::throw_domain_error(function, ": ", name, indexings..., "[",
                                     i % x.cols(), ", ", i / x.cols(), "] is ",
                                     scal, ", but must be ", must_be, "!");
      }
    }
  }
}
template <
    typename F, typename T, typename... Indexings,
    require_eigen_t<T>* = nullptr,
    std::enable_if_t<!(Eigen::internal::traits<T>::Flags
                       & (Eigen::LinearAccessBit | Eigen::DirectAccessBit))
                     && !(Eigen::internal::traits<T>::Flags
                          & Eigen::RowMajorBit)>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t i = 0; i < x.rows(); i++) {
    for (size_t j = 0; j < x.cols(); j++) {
      auto scal = value_of_rec(x.coeff(i, j));
      if (unlikely(!is_good(scal))) {
        internal::throw_domain_error(function, ": ", name, indexings..., "[", i,
                                     ", ", j, "] is ", scal, ", but must be ",
                                     must_be, "!");
      }
    }
  }
}
template <
    typename F, typename T, typename... Indexings,
    require_eigen_t<T>* = nullptr,
    std::enable_if_t<!(Eigen::internal::traits<T>::Flags
                       & (Eigen::LinearAccessBit | Eigen::DirectAccessBit))
                     && static_cast<bool>(Eigen::internal::traits<T>::Flags
                                          & Eigen::RowMajorBit)>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t j = 0; j < x.cols(); j++) {
    for (size_t i = 0; i < x.rows(); i++) {
      auto scal = value_of_rec(x.coeff(i, j));
      if (unlikely(!is_good(scal))) {
        internal::throw_domain_error(function, ": ", name, indexings..., "[", i,
                                     ", ", j, "] is ", scal, ", but must be ",
                                     must_be, "!");
      }
    }
  }
}
template <typename F, typename T, typename... Indexings,
          require_std_vector_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  for (size_t j = 0; j < x.size(); j++) {
    elementwise_check(is_good, function, name, x[j], must_be, indexings..., "[",
                      j, "]");
  }
}
template <typename F, typename T, typename... Indexings,
          require_var_matrix_t<T>* = nullptr>
inline void elementwise_check(const F& is_good, const char* function,
                              const char* name, const T& x, const char* must_be,
                              const Indexings&... indexings) {
  elementwise_check(is_good, function, name, x.val(), must_be, indexings...);
}

/**
 * Check that the predicate holds for the value of `x`, working elementwise on
 * containers. If `x` is a scalar, check the double underlying the scalar. If
 * `x` is a container, check each element inside `x`, recursively.
 * @tparam F type of predicate
 * @tparam T type of `x`
 * @param is_good predicate to check, must accept doubles and produce bools
 * @param x variable to check, can be a scalar, a container of scalars, a
 * container of containers of scalars, etc
 * @return `false` if any of the scalars fail the error check
 */
template <typename F, typename T>
inline bool elementwise_is(const F& is_good, const T& x) {
  return internal::Iser<F>{is_good}.is(x);
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_SCAL_ERR_CHECK_FINITE_HPP
#define STAN_MATH_PRIM_SCAL_ERR_CHECK_FINITE_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/scal/err/throw_domain_error.hpp>
#include <stan/math/prim/scal/err/throw_domain_error_vec.hpp>
#include <stan/math/prim/scal/fun/value_of_rec.hpp>
#include <cmath>

namespace stan {
namespace math {

namespace internal {
template <typename T_y, bool is_vec>
struct finite {
  static void check(const char* function, const char* name, const T_y& y) {
    if (!std::isfinite(value_of_rec(y))) {
      throw_domain_error(function, name, y, "is ", ", but must be finite!");
    }
  }
};

template <typename T_y>
struct finite<T_y, true> {
  static void check(const char* function, const char* name, const T_y& y) {
    for (size_t n = 0; n < size(y); n++) {
      if (!std::isfinite(value_of_rec(stan::get(y, n)))) {
        throw_domain_error_vec(function, name, y, n, "is ",
                               ", but must be finite!");
      }
    }
  }
};
}  // namespace internal

/**
 * Check if y is finite.
 * This function is vectorized and will check each element of
 * y.
 * @tparam T_y Type of y
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @throw domain_error if y is infinity, -infinity, or NaN
 */
template <typename T_y>
inline void check_finite(const char* function, const char* name, const T_y& y) {
  internal::finite<T_y, is_vector_like<T_y>::value>::check(function, name, y);
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>Use is_scal_finite instead of std::isfinite plus value_of_rec<commit_after>#ifndef STAN_MATH_PRIM_SCAL_ERR_CHECK_FINITE_HPP
#define STAN_MATH_PRIM_SCAL_ERR_CHECK_FINITE_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/scal/err/is_scal_finite.hpp>
#include <stan/math/prim/scal/err/throw_domain_error.hpp>
#include <stan/math/prim/scal/err/throw_domain_error_vec.hpp>
#include <cmath>

namespace stan {
namespace math {

namespace internal {
template <typename T_y, bool is_vec>
struct finite {
  static void check(const char* function, const char* name, const T_y& y) {
    if (!is_scal_finite(y)) {
      throw_domain_error(function, name, y, "is ", ", but must be finite!");
    }
  }
};

template <typename T_y>
struct finite<T_y, true> {
  static void check(const char* function, const char* name, const T_y& y) {
    for (size_t n = 0; n < size(y); n++) {
      if (!is_scal_finite(stan::get(y, n))) {
        throw_domain_error_vec(function, name, y, n, "is ",
                               ", but must be finite!");
      }
    }
  }
};
}  // namespace internal

/**
 * Check if y is finite.
 * This function is vectorized and will check each element of
 * y.
 * @tparam T_y Type of y
 * @param function Function name (for error messages)
 * @param name Variable name (for error messages)
 * @param y Variable to check
 * @throw domain_error if y is infinity, -infinity, or NaN
 */
template <typename T_y>
inline void check_finite(const char* function, const char* name, const T_y& y) {
  internal::finite<T_y, is_vector_like<T_y>::value>::check(function, name, y);
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>