<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/transport_security_state.h"

#include "base/base64.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/sha2.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/values.h"
#include "googleurl/src/gurl.h"
#include "net/base/dns_util.h"

namespace net {

TransportSecurityState::TransportSecurityState()
    : delegate_(NULL) {
}

void TransportSecurityState::EnableHost(const std::string& host,
                                        const DomainState& state) {
  const std::string canonicalised_host = CanonicaliseHost(host);
  if (canonicalised_host.empty())
    return;

  bool temp;
  if (isPreloadedSTS(canonicalised_host, &temp))
    return;

  char hashed[base::SHA256_LENGTH];
  base::SHA256HashString(canonicalised_host, hashed, sizeof(hashed));

  // Use the original creation date if we already have this host.
  DomainState state_copy(state);
  DomainState existing_state;
  if (IsEnabledForHost(&existing_state, host))
    state_copy.created = existing_state.created;

  enabled_hosts_[std::string(hashed, sizeof(hashed))] = state_copy;
  DirtyNotify();
}

bool TransportSecurityState::IsEnabledForHost(DomainState* result,
                                              const std::string& host) {
  const std::string canonicalised_host = CanonicaliseHost(host);
  if (canonicalised_host.empty())
    return false;

  bool include_subdomains;
  if (isPreloadedSTS(canonicalised_host, &include_subdomains)) {
    result->created = result->expiry = base::Time::FromTimeT(0);
    result->mode = DomainState::MODE_STRICT;
    result->include_subdomains = include_subdomains;
    return true;
  }

  base::Time current_time(base::Time::Now());

  for (size_t i = 0; canonicalised_host[i]; i += canonicalised_host[i] + 1) {
    char hashed_domain[base::SHA256_LENGTH];

    base::SHA256HashString(&canonicalised_host[i], &hashed_domain,
                           sizeof(hashed_domain));
    std::map<std::string, DomainState>::iterator j =
        enabled_hosts_.find(std::string(hashed_domain, sizeof(hashed_domain)));
    if (j == enabled_hosts_.end())
      continue;

    if (current_time > j->second.expiry) {
      enabled_hosts_.erase(j);
      DirtyNotify();
      continue;
    }

    *result = j->second;

    // If we matched the domain exactly, it doesn't matter what the value of
    // include_subdomains is.
    if (i == 0)
      return true;

    return j->second.include_subdomains;
  }

  return false;
}

// "Strict-Transport-Security" ":"
//     "max-age" "=" delta-seconds [ ";" "includeSubDomains" ]
bool TransportSecurityState::ParseHeader(const std::string& value,
                                         int* max_age,
                                         bool* include_subdomains) {
  DCHECK(max_age);
  DCHECK(include_subdomains);

  int max_age_candidate;

  enum ParserState {
    START,
    AFTER_MAX_AGE_LABEL,
    AFTER_MAX_AGE_EQUALS,
    AFTER_MAX_AGE,
    AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER,
    AFTER_INCLUDE_SUBDOMAINS,
  } state = START;

  StringTokenizer tokenizer(value, " \t=;");
  tokenizer.set_options(StringTokenizer::RETURN_DELIMS);
  while (tokenizer.GetNext()) {
    DCHECK(!tokenizer.token_is_delim() || tokenizer.token().length() == 1);
    switch (state) {
      case START:
        if (IsAsciiWhitespace(*tokenizer.token_begin()))
          continue;
        if (!LowerCaseEqualsASCII(tokenizer.token(), "max-age"))
          return false;
        state = AFTER_MAX_AGE_LABEL;
        break;

      case AFTER_MAX_AGE_LABEL:
        if (IsAsciiWhitespace(*tokenizer.token_begin()))
          continue;
        if (*tokenizer.token_begin() != '=')
          return false;
        DCHECK(tokenizer.token().length() ==  1);
        state = AFTER_MAX_AGE_EQUALS;
        break;

      case AFTER_MAX_AGE_EQUALS:
        if (IsAsciiWhitespace(*tokenizer.token_begin()))
          continue;
        if (!StringToInt(tokenizer.token(), &max_age_candidate))
          return false;
        if (max_age_candidate < 0)
          return false;
        state = AFTER_MAX_AGE;
        break;

      case AFTER_MAX_AGE:
        if (IsAsciiWhitespace(*tokenizer.token_begin()))
          continue;
        if (*tokenizer.token_begin() != ';')
          return false;
        state = AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER;
        break;

      case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER:
        if (IsAsciiWhitespace(*tokenizer.token_begin()))
          continue;
        if (!LowerCaseEqualsASCII(tokenizer.token(), "includesubdomains"))
          return false;
        state = AFTER_INCLUDE_SUBDOMAINS;
        break;

      case AFTER_INCLUDE_SUBDOMAINS:
        if (!IsAsciiWhitespace(*tokenizer.token_begin()))
          return false;
        break;

      default:
        NOTREACHED();
    }
  }

  // We've consumed all the input.  Let's see what state we ended up in.
  switch (state) {
    case START:
    case AFTER_MAX_AGE_LABEL:
    case AFTER_MAX_AGE_EQUALS:
      return false;
    case AFTER_MAX_AGE:
      *max_age = max_age_candidate;
      *include_subdomains = false;
      return true;
    case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER:
      return false;
    case AFTER_INCLUDE_SUBDOMAINS:
      *max_age = max_age_candidate;
      *include_subdomains = true;
      return true;
    default:
      NOTREACHED();
      return false;
  }
}

void TransportSecurityState::SetDelegate(
    TransportSecurityState::Delegate* delegate) {
  delegate_ = delegate;
}

// This function converts the binary hashes, which we store in
// |enabled_hosts_|, to a base64 string which we can include in a JSON file.
static std::wstring HashedDomainToExternalString(const std::string& hashed) {
  std::string out;
  CHECK(base::Base64Encode(hashed, &out));
  return ASCIIToWide(out);
}

// This inverts |HashedDomainToExternalString|, above. It turns an external
// string (from a JSON file) into an internal (binary) string.
static std::string ExternalStringToHashedDomain(const std::wstring& external) {
  std::string external_ascii = WideToASCII(external);
  std::string out;
  if (!base::Base64Decode(external_ascii, &out) ||
      out.size() != base::SHA256_LENGTH) {
    return std::string();
  }

  return out;
}

bool TransportSecurityState::Serialise(std::string* output) {
  DictionaryValue toplevel;
  for (std::map<std::string, DomainState>::const_iterator
       i = enabled_hosts_.begin(); i != enabled_hosts_.end(); ++i) {
    DictionaryValue* state = new DictionaryValue;
    state->SetBoolean(L"include_subdomains", i->second.include_subdomains);
    state->SetReal(L"created", i->second.created.ToDoubleT());
    state->SetReal(L"expiry", i->second.expiry.ToDoubleT());

    switch (i->second.mode) {
      case DomainState::MODE_STRICT:
        state->SetString(L"mode", "strict");
        break;
      case DomainState::MODE_OPPORTUNISTIC:
        state->SetString(L"mode", "opportunistic");
        break;
      case DomainState::MODE_SPDY_ONLY:
        state->SetString(L"mode", "spdy-only");
        break;
      default:
        NOTREACHED() << "DomainState with unknown mode";
        delete state;
        continue;
    }

    toplevel.Set(HashedDomainToExternalString(i->first), state);
  }

  base::JSONWriter::Write(&toplevel, true /* pretty print */, output);
  return true;
}

bool TransportSecurityState::Deserialise(const std::string& input,
                                         bool* dirty) {
  enabled_hosts_.clear();

  scoped_ptr<Value> value(
      base::JSONReader::Read(input, false /* do not allow trailing commas */));
  if (!value.get() || !value->IsType(Value::TYPE_DICTIONARY))
    return false;

  DictionaryValue* dict_value = reinterpret_cast<DictionaryValue*>(value.get());
  const base::Time current_time(base::Time::Now());
  bool dirtied = false;

  for (DictionaryValue::key_iterator i = dict_value->begin_keys();
       i != dict_value->end_keys(); ++i) {
    DictionaryValue* state;
    if (!dict_value->GetDictionaryWithoutPathExpansion(*i, &state))
      continue;

    bool include_subdomains;
    std::string mode_string;
    double created;
    double expiry;

    if (!state->GetBoolean(L"include_subdomains", &include_subdomains) ||
        !state->GetString(L"mode", &mode_string) ||
        !state->GetReal(L"expiry", &expiry)) {
      continue;
    }

    DomainState::Mode mode;
    if (mode_string == "strict") {
      mode = DomainState::MODE_STRICT;
    } else if (mode_string == "opportunistic") {
      mode = DomainState::MODE_OPPORTUNISTIC;
    } else if (mode_string == "spdy-only") {
      mode = DomainState::MODE_SPDY_ONLY;
    } else {
      LOG(WARNING) << "Unknown TransportSecurityState mode string found: "
                   << mode_string;
      continue;
    }

    base::Time expiry_time = base::Time::FromDoubleT(expiry);
    base::Time created_time;
    if (state->GetReal(L"created", &created)) {
      created_time = base::Time::FromDoubleT(created);
    } else {
      // We're migrating an old entry with no creation date. Make sure we
      // write the new date back in a reasonable time frame.
      dirtied = true;
      created_time = base::Time::Now();
    }

    if (expiry_time <= current_time) {
      // Make sure we dirty the state if we drop an entry.
      dirtied = true;
      continue;
    }

    std::string hashed = ExternalStringToHashedDomain(*i);
    if (hashed.empty())
      continue;

    DomainState new_state;
    new_state.mode = mode;
    new_state.created = created_time;
    new_state.expiry = expiry_time;
    new_state.include_subdomains = include_subdomains;
    enabled_hosts_[hashed] = new_state;
  }

  *dirty = dirtied;
  return true;
}

void TransportSecurityState::DeleteSince(const base::Time& time) {
  bool dirtied = false;

  std::map<std::string, DomainState>::iterator i = enabled_hosts_.begin();
  while (i != enabled_hosts_.end()) {
    if (i->second.created >= time) {
      dirtied = true;
      enabled_hosts_.erase(i++);
    } else {
      i++;
    }
  }

  if (dirtied)
    DirtyNotify();
}

void TransportSecurityState::DirtyNotify() {
  if (delegate_)
    delegate_->StateIsDirty(this);
}

// static
std::string TransportSecurityState::CanonicaliseHost(const std::string& host) {
  // We cannot perform the operations as detailed in the spec here as |host|
  // has already undergone IDN processing before it reached us. Thus, we check
  // that there are no invalid characters in the host and lowercase the result.

  std::string new_host;
  if (!DNSDomainFromDot(host, &new_host)) {
    NOTREACHED();
    return std::string();
  }

  for (size_t i = 0; new_host[i]; i += new_host[i] + 1) {
    const unsigned label_length = static_cast<unsigned>(new_host[i]);
    if (!label_length)
      break;

    for (size_t j = 0; j < label_length; ++j) {
      // RFC 3490, 4.1, step 3
      if (!IsSTD3ASCIIValidCharacter(new_host[i + 1 + j]))
        return std::string();

      new_host[i + 1 + j] = tolower(new_host[i + 1 + j]);
    }

    // step 3(b)
    if (new_host[i + 1] == '-' ||
        new_host[i + label_length] == '-') {
      return std::string();
    }
  }

  return new_host;
}

// isPreloadedSTS returns true if the canonicalised hostname should always be
// considered to have STS enabled.
// static
bool TransportSecurityState::isPreloadedSTS(
    const std::string& canonicalised_host, bool *include_subdomains) {
  // In the medium term this list is likely to just be hardcoded here. This,
  // slightly odd, form removes the need for additional relocations records.
  static const struct {
    uint8 length;
    bool include_subdomains;
    char dns_name[30];
  } preloadedSTS[] = {
    {16, false, "\003www\006paypal\003com"},
    {16, false, "\003www\006elanex\003biz"},
  };
  static const size_t numPreloadedSTS =
      sizeof(preloadedSTS) / sizeof(preloadedSTS[0]);

  for (size_t i = 0; canonicalised_host[i]; i += canonicalised_host[i] + 1) {
    for (size_t j = 0; j < numPreloadedSTS; j++) {
      if (preloadedSTS[j].length == canonicalised_host.size() + 1 - i &&
          (preloadedSTS[j].include_subdomains || i == 0) &&
          memcmp(preloadedSTS[j].dns_name, &canonicalised_host[i],
                 preloadedSTS[j].length) == 0) {
        *include_subdomains = preloadedSTS[j].include_subdomains;
        return true;
      }
    }
  }

  return false;
}

}  // namespace
<commit_msg>net: add jottit.com to the STS preloaded list.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/transport_security_state.h"

#include "base/base64.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "base/sha2.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "base/values.h"
#include "googleurl/src/gurl.h"
#include "net/base/dns_util.h"

namespace net {

TransportSecurityState::TransportSecurityState()
    : delegate_(NULL) {
}

void TransportSecurityState::EnableHost(const std::string& host,
                                        const DomainState& state) {
  const std::string canonicalised_host = CanonicaliseHost(host);
  if (canonicalised_host.empty())
    return;

  bool temp;
  if (isPreloadedSTS(canonicalised_host, &temp))
    return;

  char hashed[base::SHA256_LENGTH];
  base::SHA256HashString(canonicalised_host, hashed, sizeof(hashed));

  // Use the original creation date if we already have this host.
  DomainState state_copy(state);
  DomainState existing_state;
  if (IsEnabledForHost(&existing_state, host))
    state_copy.created = existing_state.created;

  enabled_hosts_[std::string(hashed, sizeof(hashed))] = state_copy;
  DirtyNotify();
}

bool TransportSecurityState::IsEnabledForHost(DomainState* result,
                                              const std::string& host) {
  const std::string canonicalised_host = CanonicaliseHost(host);
  if (canonicalised_host.empty())
    return false;

  bool include_subdomains;
  if (isPreloadedSTS(canonicalised_host, &include_subdomains)) {
    result->created = result->expiry = base::Time::FromTimeT(0);
    result->mode = DomainState::MODE_STRICT;
    result->include_subdomains = include_subdomains;
    return true;
  }

  base::Time current_time(base::Time::Now());

  for (size_t i = 0; canonicalised_host[i]; i += canonicalised_host[i] + 1) {
    char hashed_domain[base::SHA256_LENGTH];

    base::SHA256HashString(&canonicalised_host[i], &hashed_domain,
                           sizeof(hashed_domain));
    std::map<std::string, DomainState>::iterator j =
        enabled_hosts_.find(std::string(hashed_domain, sizeof(hashed_domain)));
    if (j == enabled_hosts_.end())
      continue;

    if (current_time > j->second.expiry) {
      enabled_hosts_.erase(j);
      DirtyNotify();
      continue;
    }

    *result = j->second;

    // If we matched the domain exactly, it doesn't matter what the value of
    // include_subdomains is.
    if (i == 0)
      return true;

    return j->second.include_subdomains;
  }

  return false;
}

// "Strict-Transport-Security" ":"
//     "max-age" "=" delta-seconds [ ";" "includeSubDomains" ]
bool TransportSecurityState::ParseHeader(const std::string& value,
                                         int* max_age,
                                         bool* include_subdomains) {
  DCHECK(max_age);
  DCHECK(include_subdomains);

  int max_age_candidate;

  enum ParserState {
    START,
    AFTER_MAX_AGE_LABEL,
    AFTER_MAX_AGE_EQUALS,
    AFTER_MAX_AGE,
    AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER,
    AFTER_INCLUDE_SUBDOMAINS,
  } state = START;

  StringTokenizer tokenizer(value, " \t=;");
  tokenizer.set_options(StringTokenizer::RETURN_DELIMS);
  while (tokenizer.GetNext()) {
    DCHECK(!tokenizer.token_is_delim() || tokenizer.token().length() == 1);
    switch (state) {
      case START:
        if (IsAsciiWhitespace(*tokenizer.token_begin()))
          continue;
        if (!LowerCaseEqualsASCII(tokenizer.token(), "max-age"))
          return false;
        state = AFTER_MAX_AGE_LABEL;
        break;

      case AFTER_MAX_AGE_LABEL:
        if (IsAsciiWhitespace(*tokenizer.token_begin()))
          continue;
        if (*tokenizer.token_begin() != '=')
          return false;
        DCHECK(tokenizer.token().length() ==  1);
        state = AFTER_MAX_AGE_EQUALS;
        break;

      case AFTER_MAX_AGE_EQUALS:
        if (IsAsciiWhitespace(*tokenizer.token_begin()))
          continue;
        if (!StringToInt(tokenizer.token(), &max_age_candidate))
          return false;
        if (max_age_candidate < 0)
          return false;
        state = AFTER_MAX_AGE;
        break;

      case AFTER_MAX_AGE:
        if (IsAsciiWhitespace(*tokenizer.token_begin()))
          continue;
        if (*tokenizer.token_begin() != ';')
          return false;
        state = AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER;
        break;

      case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER:
        if (IsAsciiWhitespace(*tokenizer.token_begin()))
          continue;
        if (!LowerCaseEqualsASCII(tokenizer.token(), "includesubdomains"))
          return false;
        state = AFTER_INCLUDE_SUBDOMAINS;
        break;

      case AFTER_INCLUDE_SUBDOMAINS:
        if (!IsAsciiWhitespace(*tokenizer.token_begin()))
          return false;
        break;

      default:
        NOTREACHED();
    }
  }

  // We've consumed all the input.  Let's see what state we ended up in.
  switch (state) {
    case START:
    case AFTER_MAX_AGE_LABEL:
    case AFTER_MAX_AGE_EQUALS:
      return false;
    case AFTER_MAX_AGE:
      *max_age = max_age_candidate;
      *include_subdomains = false;
      return true;
    case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER:
      return false;
    case AFTER_INCLUDE_SUBDOMAINS:
      *max_age = max_age_candidate;
      *include_subdomains = true;
      return true;
    default:
      NOTREACHED();
      return false;
  }
}

void TransportSecurityState::SetDelegate(
    TransportSecurityState::Delegate* delegate) {
  delegate_ = delegate;
}

// This function converts the binary hashes, which we store in
// |enabled_hosts_|, to a base64 string which we can include in a JSON file.
static std::wstring HashedDomainToExternalString(const std::string& hashed) {
  std::string out;
  CHECK(base::Base64Encode(hashed, &out));
  return ASCIIToWide(out);
}

// This inverts |HashedDomainToExternalString|, above. It turns an external
// string (from a JSON file) into an internal (binary) string.
static std::string ExternalStringToHashedDomain(const std::wstring& external) {
  std::string external_ascii = WideToASCII(external);
  std::string out;
  if (!base::Base64Decode(external_ascii, &out) ||
      out.size() != base::SHA256_LENGTH) {
    return std::string();
  }

  return out;
}

bool TransportSecurityState::Serialise(std::string* output) {
  DictionaryValue toplevel;
  for (std::map<std::string, DomainState>::const_iterator
       i = enabled_hosts_.begin(); i != enabled_hosts_.end(); ++i) {
    DictionaryValue* state = new DictionaryValue;
    state->SetBoolean(L"include_subdomains", i->second.include_subdomains);
    state->SetReal(L"created", i->second.created.ToDoubleT());
    state->SetReal(L"expiry", i->second.expiry.ToDoubleT());

    switch (i->second.mode) {
      case DomainState::MODE_STRICT:
        state->SetString(L"mode", "strict");
        break;
      case DomainState::MODE_OPPORTUNISTIC:
        state->SetString(L"mode", "opportunistic");
        break;
      case DomainState::MODE_SPDY_ONLY:
        state->SetString(L"mode", "spdy-only");
        break;
      default:
        NOTREACHED() << "DomainState with unknown mode";
        delete state;
        continue;
    }

    toplevel.Set(HashedDomainToExternalString(i->first), state);
  }

  base::JSONWriter::Write(&toplevel, true /* pretty print */, output);
  return true;
}

bool TransportSecurityState::Deserialise(const std::string& input,
                                         bool* dirty) {
  enabled_hosts_.clear();

  scoped_ptr<Value> value(
      base::JSONReader::Read(input, false /* do not allow trailing commas */));
  if (!value.get() || !value->IsType(Value::TYPE_DICTIONARY))
    return false;

  DictionaryValue* dict_value = reinterpret_cast<DictionaryValue*>(value.get());
  const base::Time current_time(base::Time::Now());
  bool dirtied = false;

  for (DictionaryValue::key_iterator i = dict_value->begin_keys();
       i != dict_value->end_keys(); ++i) {
    DictionaryValue* state;
    if (!dict_value->GetDictionaryWithoutPathExpansion(*i, &state))
      continue;

    bool include_subdomains;
    std::string mode_string;
    double created;
    double expiry;

    if (!state->GetBoolean(L"include_subdomains", &include_subdomains) ||
        !state->GetString(L"mode", &mode_string) ||
        !state->GetReal(L"expiry", &expiry)) {
      continue;
    }

    DomainState::Mode mode;
    if (mode_string == "strict") {
      mode = DomainState::MODE_STRICT;
    } else if (mode_string == "opportunistic") {
      mode = DomainState::MODE_OPPORTUNISTIC;
    } else if (mode_string == "spdy-only") {
      mode = DomainState::MODE_SPDY_ONLY;
    } else {
      LOG(WARNING) << "Unknown TransportSecurityState mode string found: "
                   << mode_string;
      continue;
    }

    base::Time expiry_time = base::Time::FromDoubleT(expiry);
    base::Time created_time;
    if (state->GetReal(L"created", &created)) {
      created_time = base::Time::FromDoubleT(created);
    } else {
      // We're migrating an old entry with no creation date. Make sure we
      // write the new date back in a reasonable time frame.
      dirtied = true;
      created_time = base::Time::Now();
    }

    if (expiry_time <= current_time) {
      // Make sure we dirty the state if we drop an entry.
      dirtied = true;
      continue;
    }

    std::string hashed = ExternalStringToHashedDomain(*i);
    if (hashed.empty())
      continue;

    DomainState new_state;
    new_state.mode = mode;
    new_state.created = created_time;
    new_state.expiry = expiry_time;
    new_state.include_subdomains = include_subdomains;
    enabled_hosts_[hashed] = new_state;
  }

  *dirty = dirtied;
  return true;
}

void TransportSecurityState::DeleteSince(const base::Time& time) {
  bool dirtied = false;

  std::map<std::string, DomainState>::iterator i = enabled_hosts_.begin();
  while (i != enabled_hosts_.end()) {
    if (i->second.created >= time) {
      dirtied = true;
      enabled_hosts_.erase(i++);
    } else {
      i++;
    }
  }

  if (dirtied)
    DirtyNotify();
}

void TransportSecurityState::DirtyNotify() {
  if (delegate_)
    delegate_->StateIsDirty(this);
}

// static
std::string TransportSecurityState::CanonicaliseHost(const std::string& host) {
  // We cannot perform the operations as detailed in the spec here as |host|
  // has already undergone IDN processing before it reached us. Thus, we check
  // that there are no invalid characters in the host and lowercase the result.

  std::string new_host;
  if (!DNSDomainFromDot(host, &new_host)) {
    NOTREACHED();
    return std::string();
  }

  for (size_t i = 0; new_host[i]; i += new_host[i] + 1) {
    const unsigned label_length = static_cast<unsigned>(new_host[i]);
    if (!label_length)
      break;

    for (size_t j = 0; j < label_length; ++j) {
      // RFC 3490, 4.1, step 3
      if (!IsSTD3ASCIIValidCharacter(new_host[i + 1 + j]))
        return std::string();

      new_host[i + 1 + j] = tolower(new_host[i + 1 + j]);
    }

    // step 3(b)
    if (new_host[i + 1] == '-' ||
        new_host[i + label_length] == '-') {
      return std::string();
    }
  }

  return new_host;
}

// isPreloadedSTS returns true if the canonicalised hostname should always be
// considered to have STS enabled.
// static
bool TransportSecurityState::isPreloadedSTS(
    const std::string& canonicalised_host, bool *include_subdomains) {
  // In the medium term this list is likely to just be hardcoded here. This,
  // slightly odd, form removes the need for additional relocations records.
  static const struct {
    uint8 length;
    bool include_subdomains;
    char dns_name[30];
  } kPreloadedSTS[] = {
    {16, false, "\003www\006paypal\003com"},
    {16, false, "\003www\006elanex\003biz"},
    {12, true,  "\006jottit\003com"},
  };
  static const size_t kNumPreloadedSTS = ARRAYSIZE_UNSAFE(kPreloadedSTS);

  for (size_t i = 0; canonicalised_host[i]; i += canonicalised_host[i] + 1) {
    for (size_t j = 0; j < kNumPreloadedSTS; j++) {
      if (kPreloadedSTS[j].length == canonicalised_host.size() + 1 - i &&
          (kPreloadedSTS[j].include_subdomains || i == 0) &&
          memcmp(kPreloadedSTS[j].dns_name, &canonicalised_host[i],
                 kPreloadedSTS[j].length) == 0) {
        *include_subdomains = kPreloadedSTS[j].include_subdomains;
        return true;
      }
    }
  }

  return false;
}

}  // namespace
<|endoftext|>


<commit_before>#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include "DHT.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

#define DHTPIN 4
#define DHTTYPE DHT22

// Setup a DHT22 instance
DHT dht(DHTPIN, DHTTYPE);

bool connected = false;

void setup()
{
	pinMode(LED_BUILTIN, OUTPUT);
	Serial.begin(115200);
	WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
	dht.begin();
}

void blink(int time) {
	digitalWrite(LED_BUILTIN, HIGH);
	delay(time);
	digitalWrite(LED_BUILTIN, LOW);
	delay(time);
}

void retryWifi() {
	blink(1000);
	connected = false;
	WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}

void loop()
{
	wl_status_t status = WiFi.status();
	switch (status) {
		case WL_CONNECTED: // all good
			break;
		case WL_SCAN_COMPLETED:
		case WL_IDLE_STATUS:
			Serial.printf("Connecting to wifi (%d)\n", status);
			blink(500);
			return;

		case WL_NO_SSID_AVAIL:
			Serial.printf("Problem connecting to wifi: can't find SSID " WIFI_SSID "\n");
			retryWifi();
			return;

		case WL_DISCONNECTED:
		case WL_CONNECT_FAILED:
		case WL_CONNECTION_LOST:
			Serial.printf("Problem connecting to wifi: %d\n", status);
			retryWifi();
			return;

		case WL_NO_SHIELD:
			Serial.println("Can't find WiFi Shield!\n");
			blink(2000);
			return;
	}

	if (connected == false) {
		Serial.print("Connected to ");
		Serial.println(WIFI_SSID);
		Serial.print("IP address: ");
		Serial.println(WiFi.localIP());
		connected = true;
	}

	digitalWrite(LED_BUILTIN, HIGH);
	// Reading temperature or humidity takes about 250 milliseconds!
	// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
	float h = dht.readHumidity();
	// Read temperature as Celsius (the default)
	float t = dht.readTemperature();
	// Read temperature as Fahrenheit (isFahrenheit = true)
	float f = dht.readTemperature(true);
	digitalWrite(LED_BUILTIN, LOW);

	// Check if any reads failed and exit early (to try again).
	if (isnan(h) || isnan(t) || isnan(f)) {
		Serial.println("Failed to read from DHT sensor!");
		return;
	}

	// Compute heat index in Fahrenheit (the default)
	float hif = dht.computeHeatIndex(f, h);
	// Compute heat index in Celsius (isFahreheit = false)
	float hic = dht.computeHeatIndex(t, h, false);

	Serial.print("Humidity: ");
	Serial.print(h);
	Serial.print(" %\t");
	Serial.print("Temperature: ");
	Serial.print(t);
	Serial.print(" *C ");
	Serial.print(f);
	Serial.print(" *F\t");
	Serial.print("Heat index: ");
	Serial.print(hic);
	Serial.print(" *C ");
	Serial.print(hif);
	Serial.println(" *F");
}
<commit_msg>If DHT read fails, pause!<commit_after>#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include "DHT.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

#define DHTPIN 4
#define DHTTYPE DHT22

// Setup a DHT22 instance
DHT dht(DHTPIN, DHTTYPE);

bool connected = false;

void setup()
{
	pinMode(LED_BUILTIN, OUTPUT);
	Serial.begin(115200);
	WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
	dht.begin();
}

void blink(int time) {
	digitalWrite(LED_BUILTIN, HIGH);
	delay(time);
	digitalWrite(LED_BUILTIN, LOW);
	delay(time);
}

void retryWifi() {
	blink(1000);
	connected = false;
	WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}

void loop()
{
	wl_status_t status = WiFi.status();
	switch (status) {
		case WL_CONNECTED: // all good
			break;
		case WL_SCAN_COMPLETED:
		case WL_IDLE_STATUS:
			Serial.printf("Connecting to wifi (%d)\n", status);
			blink(500);
			return;

		case WL_NO_SSID_AVAIL:
			Serial.printf("Problem connecting to wifi: can't find SSID " WIFI_SSID "\n");
			retryWifi();
			return;

		case WL_DISCONNECTED:
		case WL_CONNECT_FAILED:
		case WL_CONNECTION_LOST:
			Serial.printf("Problem connecting to wifi: %d\n", status);
			retryWifi();
			return;

		case WL_NO_SHIELD:
			Serial.println("Can't find WiFi Shield!\n");
			blink(2000);
			return;
	}

	if (connected == false) {
		Serial.print("Connected to ");
		Serial.println(WIFI_SSID);
		Serial.print("IP address: ");
		Serial.println(WiFi.localIP());
		connected = true;
	}

	digitalWrite(LED_BUILTIN, HIGH);
	// Reading temperature or humidity takes about 250 milliseconds!
	// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
	float h = dht.readHumidity();
	// Read temperature as Celsius (the default)
	float t = dht.readTemperature();
	// Read temperature as Fahrenheit (isFahrenheit = true)
	float f = dht.readTemperature(true);
	digitalWrite(LED_BUILTIN, LOW);

	// Check if any reads failed and exit early (to try again).
	if (isnan(h) || isnan(t) || isnan(f)) {
		Serial.println("Failed to read from DHT sensor!");
		delay(2000);
		return;
	}

	// Compute heat index in Fahrenheit (the default)
	float hif = dht.computeHeatIndex(f, h);
	// Compute heat index in Celsius (isFahreheit = false)
	float hic = dht.computeHeatIndex(t, h, false);

	Serial.print("Humidity: ");
	Serial.print(h);
	Serial.print(" %\t");
	Serial.print("Temperature: ");
	Serial.print(t);
	Serial.print(" *C ");
	Serial.print(f);
	Serial.print(" *F\t");
	Serial.print("Heat index: ");
	Serial.print(hic);
	Serial.print(" *C ");
	Serial.print(hif);
	Serial.println(" *F");
}
<|endoftext|>


<commit_before>
#pragma once

#include "numerics/frequency_analysis.hpp"

#include <algorithm>
#include <functional>
#include <vector>

#include "base/tags.hpp"
#include "geometry/grassmann.hpp"
#include "geometry/hilbert.hpp"
#include "numerics/poisson_series_basis.hpp"
#include "numerics/root_finders.hpp"
#include "numerics/unbounded_arrays.hpp"
#include "quantities/elementary_functions.hpp"

namespace principia {
namespace numerics {
namespace frequency_analysis {
namespace internal_frequency_analysis {

using base::uninitialized;
using geometry::Hilbert;
using geometry::Vector;
using quantities::Abs;
using quantities::Inverse;
using quantities::IsFinite;
using quantities::Sqrt;
using quantities::Square;
using quantities::SquareRoot;

template<typename Function,
         int aperiodic_wdegree, int periodic_wdegree,
         template<typename, typename, int> class Evaluator>
AngularFrequency PreciseMode(
    Interval<AngularFrequency> const& fft_mode,
    Function const& function,
    PoissonSeries<double,
                  aperiodic_wdegree, periodic_wdegree,
                  Evaluator> const& weight) {
  auto const weighted_function = weight * function;
  auto const weighted_function_spectrum = weighted_function.FourierTransform();

  auto power =
      [&weighted_function_spectrum](AngularFrequency const& ω) {
        return weighted_function_spectrum(ω).Norm²();
      };

  return Brent(power,
               fft_mode.min,
               fft_mode.max,
               std::greater<>());
}

template<int aperiodic_degree, int periodic_degree,
         typename Function,
         int aperiodic_wdegree, int periodic_wdegree,
         template<typename, typename, int> class Evaluator>
PoissonSeries<std::invoke_result_t<Function, Instant>,
              aperiodic_degree, periodic_degree,
              Evaluator>
Projection(Function const& function,
           AngularFrequency const& ω,
           PoissonSeries<double,
                         aperiodic_wdegree, periodic_wdegree,
                         Evaluator> const& weight,
           Instant const& t_min,
           Instant const& t_max) {
  std::optional<AngularFrequency> optional_ω = ω;

  // A calculator that returns optional_ω once and then stops.
  auto angular_frequency_calculator = [&optional_ω](auto const& residual) {
    auto const result = optional_ω;
    optional_ω = std::nullopt;
    return result;
  };

  return IncrementalProjection<aperiodic_degree, periodic_degree>(
      function,
      angular_frequency_calculator,
      weight,
      t_min, t_max);
}

template<int aperiodic_degree, int periodic_degree,
         typename Function,
         typename AngularFrequencyCalculator,
         int aperiodic_wdegree, int periodic_wdegree,
         template<typename, typename, int> class Evaluator>
PoissonSeries<std::invoke_result_t<Function, Instant>,
              aperiodic_degree, periodic_degree,
              Evaluator>
IncrementalProjection(Function const& function,
                      AngularFrequencyCalculator const& calculator,
                      PoissonSeries<double,
                                    aperiodic_wdegree, periodic_wdegree,
                                    Evaluator> const& weight,
                      Instant const& t_min,
                      Instant const& t_max) {
  using Value = std::invoke_result_t<Function, Instant>;
  using Norm = typename Hilbert<Value>::NormType;
  using Normalized = typename Hilbert<Value>::NormalizedType;
  using Series = PoissonSeries<Value,
                               aperiodic_degree, periodic_degree,
                               Evaluator>;

  // This code follows [Kud07], section 2.  Our indices start at 0, unlike those
  // of Кудрявцев which start at 1.

  Instant const& t0 = weight.origin();

  std::optional<AngularFrequency> ω = calculator(function);
  CHECK(ω.has_value());

  std::vector<Series> basis;
  // The Poisson series basis[k] belongs to the subspace basis_subspaces[k];
  // this remains true after orthonormalization, i.e., q[k] belongs to the
  // subspace basis_subspaces[k] below.
  std::vector<PoissonSeriesSubspace> basis_subspaces;

  int basis_size;
  // TODO(phl): This is replicated below.
  if (ω.value() == AngularFrequency{}) {
    auto const ω_basis =
        PoissonSeriesBasisGenerator<Series,
                                    aperiodic_degree>::Basis(t0);
    auto const ω_basis_subspaces =
        PoissonSeriesBasisGenerator<Series, aperiodic_degree>::Subspaces(t0);
    basis_size = std::tuple_size_v<decltype(ω_basis)>;
    std::move(ω_basis.begin(), ω_basis.end(), std::back_inserter(basis));
    std::move(ω_basis_subspaces.begin(),
              ω_basis_subspaces.end(),
              std::back_inserter(basis_subspaces));
  } else {
    auto const ω_basis =
        PoissonSeriesBasisGenerator<Series,
                                    periodic_degree>::Basis(ω.value(), t0);
    auto const ω_basis_subspaces =
        PoissonSeriesBasisGenerator<Series, periodic_degree>::Subspaces(
            ω.value(), t0);
    basis_size = std::tuple_size_v<decltype(ω_basis)>;
    std::move(ω_basis.begin(), ω_basis.end(), std::back_inserter(basis));
    std::move(ω_basis_subspaces.begin(),
              ω_basis_subspaces.end(),
              std::back_inserter(basis_subspaces));
  }

  // This is logically Q in the QR decomposition of basis.
  std::vector<PoissonSeries<Normalized,
                            aperiodic_degree, periodic_degree,
                            Evaluator>> q;

  auto const& a₀ = basis[0];
  auto const r₀₀ = a₀.Norm(weight, t_min, t_max);
  CHECK(IsFinite(r₀₀)) << a₀;
  q.push_back(a₀ / r₀₀);

  auto const A₀ = InnerProduct(function, q[0], weight, t_min, t_max);

  Series F = A₀ * q[0];
  auto f = function - F;

  int m_begin = 1;
  for (;;) {
    for (int m = m_begin; m < basis_size; ++m) {
      auto const& aₘ = basis[m];

      // This code follows Björk, Numerics of Gram-Schmidt Orthogonalization,
      // Algorithm 6.1.
      static constexpr double α = 0.5;
      Series q̂ₘ = aₘ;

      // Formal integration works for a single basis element.
      Norm q̂ₘ_norm = Sqrt(
          (PointwiseInnerProduct(q̂ₘ, q̂ₘ) * weight).Integrate(t_min, t_max) /
          (t_max - t_min));

      // Loop on p.
      Series previous_q̂ₘ = q̂ₘ;
      Norm previous_q̂ₘ_norm;
      do {
        previous_q̂ₘ = q̂ₘ;
        previous_q̂ₘ_norm = q̂ₘ_norm;
        for (int i = 0; i < m; ++i) {
          if (!PoissonSeriesSubspace::orthogonal(basis_subspaces[i],
                                                 basis_subspaces[m])) {
            auto const sᵖₘ =
                InnerProduct(q[i], previous_q̂ₘ, weight, t_min, t_max);
            q̂ₘ -= sᵖₘ * q[i];
          }
        }
        q̂ₘ_norm = q̂ₘ.Norm(weight, t_min, t_max);

        if (!IsFinite(q̂ₘ_norm)) {
          return F;
        }
      } while (q̂ₘ_norm < α * previous_q̂ₘ_norm);

      q.push_back(q̂ₘ / q̂ₘ_norm);
      DCHECK_EQ(m + 1, q.size());

      Norm const Aₘ = InnerProduct(f, q[m], weight, t_min, t_max);

      auto const Aₘqₘ = Aₘ * q[m];
      f -= Aₘqₘ;
      F += Aₘqₘ;
    }

    ω = calculator(f);
    if (!ω.has_value()) {
      return F;
    }

    int ω_basis_size;
    if (ω.value() == AngularFrequency{}) {
      auto const ω_basis =
          PoissonSeriesBasisGenerator<Series,
                                      aperiodic_degree>::Basis(t0);
      auto const ω_basis_subspaces =
          PoissonSeriesBasisGenerator<Series, aperiodic_degree>::Subspaces(t0);
      ω_basis_size = std::tuple_size_v<decltype(ω_basis)>;
      std::move(ω_basis.begin(), ω_basis.end(), std::back_inserter(basis));
      std::move(ω_basis_subspaces.begin(),
                ω_basis_subspaces.end(),
                std::back_inserter(basis_subspaces));
    } else {
      auto const ω_basis =
          PoissonSeriesBasisGenerator<Series,
                                      periodic_degree>::Basis(ω.value(), t0);
      auto const ω_basis_subspaces =
          PoissonSeriesBasisGenerator<Series, periodic_degree>::Subspaces(
              ω.value(), t0);
      ω_basis_size = std::tuple_size_v<decltype(ω_basis)>;
      std::move(ω_basis.begin(), ω_basis.end(), std::back_inserter(basis));
      std::move(ω_basis_subspaces.begin(),
                ω_basis_subspaces.end(),
                std::back_inserter(basis_subspaces));
    }
    m_begin = basis_size;
    basis_size += ω_basis_size;
  }
}

}  // namespace internal_frequency_analysis
}  // namespace frequency_analysis
}  // namespace numerics
}  // namespace principia
<commit_msg>Cleanup.<commit_after>
#pragma once

#include "numerics/frequency_analysis.hpp"

#include <algorithm>
#include <functional>
#include <vector>

#include "base/tags.hpp"
#include "geometry/grassmann.hpp"
#include "geometry/hilbert.hpp"
#include "numerics/poisson_series_basis.hpp"
#include "numerics/root_finders.hpp"
#include "numerics/unbounded_arrays.hpp"
#include "quantities/elementary_functions.hpp"

namespace principia {
namespace numerics {
namespace frequency_analysis {
namespace internal_frequency_analysis {

using base::uninitialized;
using geometry::Hilbert;
using geometry::Vector;
using quantities::Inverse;
using quantities::IsFinite;
using quantities::Sqrt;
using quantities::Square;
using quantities::SquareRoot;

template<typename Function,
         int aperiodic_wdegree, int periodic_wdegree,
         template<typename, typename, int> class Evaluator>
AngularFrequency PreciseMode(
    Interval<AngularFrequency> const& fft_mode,
    Function const& function,
    PoissonSeries<double,
                  aperiodic_wdegree, periodic_wdegree,
                  Evaluator> const& weight) {
  auto const weighted_function = weight * function;
  auto const weighted_function_spectrum = weighted_function.FourierTransform();

  auto power =
      [&weighted_function_spectrum](AngularFrequency const& ω) {
        return weighted_function_spectrum(ω).Norm²();
      };

  return Brent(power,
               fft_mode.min,
               fft_mode.max,
               std::greater<>());
}

template<int aperiodic_degree, int periodic_degree,
         typename Function,
         int aperiodic_wdegree, int periodic_wdegree,
         template<typename, typename, int> class Evaluator>
PoissonSeries<std::invoke_result_t<Function, Instant>,
              aperiodic_degree, periodic_degree,
              Evaluator>
Projection(Function const& function,
           AngularFrequency const& ω,
           PoissonSeries<double,
                         aperiodic_wdegree, periodic_wdegree,
                         Evaluator> const& weight,
           Instant const& t_min,
           Instant const& t_max) {
  std::optional<AngularFrequency> optional_ω = ω;

  // A calculator that returns optional_ω once and then stops.
  auto angular_frequency_calculator = [&optional_ω](auto const& residual) {
    auto const result = optional_ω;
    optional_ω = std::nullopt;
    return result;
  };

  return IncrementalProjection<aperiodic_degree, periodic_degree>(
      function,
      angular_frequency_calculator,
      weight,
      t_min, t_max);
}

template<int aperiodic_degree, int periodic_degree,
         typename Function,
         typename AngularFrequencyCalculator,
         int aperiodic_wdegree, int periodic_wdegree,
         template<typename, typename, int> class Evaluator>
PoissonSeries<std::invoke_result_t<Function, Instant>,
              aperiodic_degree, periodic_degree,
              Evaluator>
IncrementalProjection(Function const& function,
                      AngularFrequencyCalculator const& calculator,
                      PoissonSeries<double,
                                    aperiodic_wdegree, periodic_wdegree,
                                    Evaluator> const& weight,
                      Instant const& t_min,
                      Instant const& t_max) {
  using Value = std::invoke_result_t<Function, Instant>;
  using Norm = typename Hilbert<Value>::NormType;
  using Normalized = typename Hilbert<Value>::NormalizedType;
  using Series = PoissonSeries<Value,
                               aperiodic_degree, periodic_degree,
                               Evaluator>;

  // This code follows [Kud07], section 2.  Our indices start at 0, unlike those
  // of Кудрявцев which start at 1.

  Instant const& t0 = weight.origin();

  std::optional<AngularFrequency> ω = calculator(function);
  CHECK(ω.has_value());

  std::vector<Series> basis;
  // The Poisson series basis[k] belongs to the subspace basis_subspaces[k];
  // this remains true after orthonormalization, i.e., q[k] belongs to the
  // subspace basis_subspaces[k] below.
  std::vector<PoissonSeriesSubspace> basis_subspaces;

  int basis_size;
  // TODO(phl): This is replicated below.
  if (ω.value() == AngularFrequency{}) {
    auto const ω_basis =
        PoissonSeriesBasisGenerator<Series,
                                    aperiodic_degree>::Basis(t0);
    auto const ω_basis_subspaces =
        PoissonSeriesBasisGenerator<Series, aperiodic_degree>::Subspaces(t0);
    basis_size = std::tuple_size_v<decltype(ω_basis)>;
    std::move(ω_basis.begin(), ω_basis.end(), std::back_inserter(basis));
    std::move(ω_basis_subspaces.begin(),
              ω_basis_subspaces.end(),
              std::back_inserter(basis_subspaces));
  } else {
    auto const ω_basis =
        PoissonSeriesBasisGenerator<Series,
                                    periodic_degree>::Basis(ω.value(), t0);
    auto const ω_basis_subspaces =
        PoissonSeriesBasisGenerator<Series, periodic_degree>::Subspaces(
            ω.value(), t0);
    basis_size = std::tuple_size_v<decltype(ω_basis)>;
    std::move(ω_basis.begin(), ω_basis.end(), std::back_inserter(basis));
    std::move(ω_basis_subspaces.begin(),
              ω_basis_subspaces.end(),
              std::back_inserter(basis_subspaces));
  }

  // This is logically Q in the QR decomposition of basis.
  std::vector<PoissonSeries<Normalized,
                            aperiodic_degree, periodic_degree,
                            Evaluator>> q;

  auto const& a₀ = basis[0];
  auto const r₀₀ = a₀.Norm(weight, t_min, t_max);
  CHECK(IsFinite(r₀₀)) << a₀;
  q.push_back(a₀ / r₀₀);

  auto const A₀ = InnerProduct(function, q[0], weight, t_min, t_max);

  Series F = A₀ * q[0];
  auto f = function - F;

  int m_begin = 1;
  for (;;) {
    for (int m = m_begin; m < basis_size; ++m) {
      auto const& aₘ = basis[m];

      // This code follows Björk, Numerics of Gram-Schmidt Orthogonalization,
      // Algorithm 6.1.
      static constexpr double α = 0.5;
      Series q̂ₘ = aₘ;

      // Formal integration works for a single basis element.
      Norm q̂ₘ_norm = Sqrt(
          (PointwiseInnerProduct(q̂ₘ, q̂ₘ) * weight).Integrate(t_min, t_max) /
          (t_max - t_min));

      // Loop on p.
      Series previous_q̂ₘ = q̂ₘ;
      Norm previous_q̂ₘ_norm;
      do {
        previous_q̂ₘ = q̂ₘ;
        previous_q̂ₘ_norm = q̂ₘ_norm;
        for (int i = 0; i < m; ++i) {
          if (!PoissonSeriesSubspace::orthogonal(basis_subspaces[i],
                                                 basis_subspaces[m])) {
            auto const sᵖₘ =
                InnerProduct(q[i], previous_q̂ₘ, weight, t_min, t_max);
            q̂ₘ -= sᵖₘ * q[i];
          }
        }
        q̂ₘ_norm = q̂ₘ.Norm(weight, t_min, t_max);

        if (!IsFinite(q̂ₘ_norm)) {
          return F;
        }
      } while (q̂ₘ_norm < α * previous_q̂ₘ_norm);

      q.push_back(q̂ₘ / q̂ₘ_norm);
      DCHECK_EQ(m + 1, q.size());

      Norm const Aₘ = InnerProduct(f, q[m], weight, t_min, t_max);

      auto const Aₘqₘ = Aₘ * q[m];
      f -= Aₘqₘ;
      F += Aₘqₘ;
    }

    ω = calculator(f);
    if (!ω.has_value()) {
      return F;
    }

    int ω_basis_size;
    if (ω.value() == AngularFrequency{}) {
      auto const ω_basis =
          PoissonSeriesBasisGenerator<Series,
                                      aperiodic_degree>::Basis(t0);
      auto const ω_basis_subspaces =
          PoissonSeriesBasisGenerator<Series, aperiodic_degree>::Subspaces(t0);
      ω_basis_size = std::tuple_size_v<decltype(ω_basis)>;
      std::move(ω_basis.begin(), ω_basis.end(), std::back_inserter(basis));
      std::move(ω_basis_subspaces.begin(),
                ω_basis_subspaces.end(),
                std::back_inserter(basis_subspaces));
    } else {
      auto const ω_basis =
          PoissonSeriesBasisGenerator<Series,
                                      periodic_degree>::Basis(ω.value(), t0);
      auto const ω_basis_subspaces =
          PoissonSeriesBasisGenerator<Series, periodic_degree>::Subspaces(
              ω.value(), t0);
      ω_basis_size = std::tuple_size_v<decltype(ω_basis)>;
      std::move(ω_basis.begin(), ω_basis.end(), std::back_inserter(basis));
      std::move(ω_basis_subspaces.begin(),
                ω_basis_subspaces.end(),
                std::back_inserter(basis_subspaces));
    }
    m_begin = basis_size;
    basis_size += ω_basis_size;
  }
}

}  // namespace internal_frequency_analysis
}  // namespace frequency_analysis
}  // namespace numerics
}  // namespace principia
<|endoftext|>


<commit_before>/*
 *  Scriptorium.cpp
 *  openc2e
 *
 *  Created by Alyssa Milburn on 05/11/2004.
 *  Copyright 2004 __MyCompanyName__. All rights reserved.
 *
 */

#include "Scriptorium.h"
#include <iostream>

inline unsigned int Scriptorium::calculateValue(unsigned char family, unsigned char genus, unsigned short species) {
	return (family + (genus << 8) + (species << 16));
}

void Scriptorium::addScript(unsigned char family, unsigned char genus, unsigned short species, unsigned short event, script *s) {
	std::map<unsigned short, script *> &m = getScripts(calculateValue(family, genus, species));
	if (m[event])
		m[event]->release();
	std::cerr << "map script " << (int)family << " " << (int)genus << " " <<
		species << " " << event << " to " << (void *)s << " was "
		<< (void *)m[event] << std::endl;
	m[event] = s;
	s->retain();
}

void Scriptorium::delScript(unsigned char family, unsigned char genus, unsigned short species, unsigned short event) {
	std::map<unsigned short, script *> &i = getScripts(calculateValue(family, genus, species));
	if (i[event])
		i[event]->release();
	i.erase(i.find(event));
	// todo: zap from the main map if there is none left of that value
}

script *Scriptorium::getScript(unsigned char family, unsigned char genus, unsigned short species, unsigned short event) {
	return getScripts(calculateValue(family, genus, species))[event];
}
/* vim: set noet: */
<commit_msg>kill some old debug<commit_after>/*
 *  Scriptorium.cpp
 *  openc2e
 *
 *  Created by Alyssa Milburn on 05/11/2004.
 *  Copyright 2004 __MyCompanyName__. All rights reserved.
 *
 */

#include "Scriptorium.h"
#include <iostream>

inline unsigned int Scriptorium::calculateValue(unsigned char family, unsigned char genus, unsigned short species) {
	return (family + (genus << 8) + (species << 16));
}

void Scriptorium::addScript(unsigned char family, unsigned char genus, unsigned short species, unsigned short event, script *s) {
	std::map<unsigned short, script *> &m = getScripts(calculateValue(family, genus, species));
	if (m[event])
		m[event]->release();
	m[event] = s;
	s->retain();
}

void Scriptorium::delScript(unsigned char family, unsigned char genus, unsigned short species, unsigned short event) {
	std::map<unsigned short, script *> &i = getScripts(calculateValue(family, genus, species));
	if (i[event])
		i[event]->release();
	i.erase(i.find(event));
	// todo: zap from the main map if there is none left of that value
}

script *Scriptorium::getScript(unsigned char family, unsigned char genus, unsigned short species, unsigned short event) {
	return getScripts(calculateValue(family, genus, species))[event];
}
/* vim: set noet: */
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#if defined(OS_WIN)
#include <windows.h>
#endif

#include "content/gpu/gpu_watchdog_thread.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/files/file_util.h"
#include "base/power_monitor/power_monitor.h"
#include "base/process/process.h"
#include "build/build_config.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"

namespace content {
namespace {
const int64 kCheckPeriodMs = 2000;
#if defined(OS_CHROMEOS)
const base::FilePath::CharType
    kTtyFilePath[] = FILE_PATH_LITERAL("/sys/class/tty/tty0/active");
#endif
#if defined(USE_X11)
const unsigned char text[20] = "check";
#endif
}  // namespace

GpuWatchdogThread::GpuWatchdogThread(int timeout)
    : base::Thread("Watchdog"),
      watched_message_loop_(base::MessageLoop::current()),
      timeout_(base::TimeDelta::FromMilliseconds(timeout)),
      armed_(false),
#if defined(OS_WIN)
      watched_thread_handle_(0),
      arm_cpu_time_(),
#endif
      task_observer_(this),
      suspended_(false),
#if defined(USE_X11)
      display_(NULL),
      window_(0),
      atom_(None),
#endif
      weak_factory_(this) {
  DCHECK(timeout >= 0);

#if defined(OS_WIN)
  // GetCurrentThread returns a pseudo-handle that cannot be used by one thread
  // to identify another. DuplicateHandle creates a "real" handle that can be
  // used for this purpose.
  BOOL result = DuplicateHandle(GetCurrentProcess(),
                                GetCurrentThread(),
                                GetCurrentProcess(),
                                &watched_thread_handle_,
                                THREAD_QUERY_INFORMATION,
                                FALSE,
                                0);
  DCHECK(result);
#endif

#if defined(OS_CHROMEOS)
  tty_file_ = base::OpenFile(base::FilePath(kTtyFilePath), "r");
#endif
#if defined(USE_X11)
  SetupXServer();
#endif
  watched_message_loop_->AddTaskObserver(&task_observer_);
}

void GpuWatchdogThread::PostAcknowledge() {
  // Called on the monitored thread. Responds with OnAcknowledge. Cannot use
  // the method factory. Rely on reference counting instead.
  message_loop()->PostTask(
      FROM_HERE,
      base::Bind(&GpuWatchdogThread::OnAcknowledge, this));
}

void GpuWatchdogThread::CheckArmed() {
  // Acknowledge the watchdog if it has armed itself. The watchdog will not
  // change its armed state until it is acknowledged.
  if (armed()) {
    PostAcknowledge();
  }
}

void GpuWatchdogThread::Init() {
  // Schedule the first check.
  OnCheck(false);
}

void GpuWatchdogThread::CleanUp() {
  weak_factory_.InvalidateWeakPtrs();
}

GpuWatchdogThread::GpuWatchdogTaskObserver::GpuWatchdogTaskObserver(
    GpuWatchdogThread* watchdog)
    : watchdog_(watchdog) {
}

GpuWatchdogThread::GpuWatchdogTaskObserver::~GpuWatchdogTaskObserver() {
}

void GpuWatchdogThread::GpuWatchdogTaskObserver::WillProcessTask(
    const base::PendingTask& pending_task) {
  watchdog_->CheckArmed();
}

void GpuWatchdogThread::GpuWatchdogTaskObserver::DidProcessTask(
    const base::PendingTask& pending_task) {
  watchdog_->CheckArmed();
}

GpuWatchdogThread::~GpuWatchdogThread() {
  // Verify that the thread was explicitly stopped. If the thread is stopped
  // implicitly by the destructor, CleanUp() will not be called.
  DCHECK(!weak_factory_.HasWeakPtrs());

#if defined(OS_WIN)
  CloseHandle(watched_thread_handle_);
#endif

  base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
  if (power_monitor)
    power_monitor->RemoveObserver(this);

#if defined(OS_CHROMEOS)
  if (tty_file_)
    fclose(tty_file_);
#endif

#if defined(USE_X11)
  XDestroyWindow(display_, window_);
  XCloseDisplay(display_);
#endif

  watched_message_loop_->RemoveTaskObserver(&task_observer_);
}

void GpuWatchdogThread::OnAcknowledge() {
  CHECK(base::PlatformThread::CurrentId() == thread_id());

  // The check has already been acknowledged and another has already been
  // scheduled by a previous call to OnAcknowledge. It is normal for a
  // watched thread to see armed_ being true multiple times before
  // the OnAcknowledge task is run on the watchdog thread.
  if (!armed_)
    return;

  // Revoke any pending hang termination.
  weak_factory_.InvalidateWeakPtrs();
  armed_ = false;

  if (suspended_)
    return;

  // If it took a long time for the acknowledgement, assume the computer was
  // recently suspended.
  bool was_suspended = (base::Time::Now() > suspension_timeout_);

  // The monitored thread has responded. Post a task to check it again.
  message_loop()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&GpuWatchdogThread::OnCheck, weak_factory_.GetWeakPtr(),
          was_suspended),
      base::TimeDelta::FromMilliseconds(kCheckPeriodMs));
}

void GpuWatchdogThread::OnCheck(bool after_suspend) {
  CHECK(base::PlatformThread::CurrentId() == thread_id());

  // Do not create any new termination tasks if one has already been created
  // or the system is suspended.
  if (armed_ || suspended_)
    return;

  // Must set armed before posting the task. This task might be the only task
  // that will activate the TaskObserver on the watched thread and it must not
  // miss the false -> true transition.
  armed_ = true;

#if defined(OS_WIN)
  arm_cpu_time_ = GetWatchedThreadTime();
#endif

  // Immediately after the computer is woken up from being suspended it might
  // be pretty sluggish, so allow some extra time before the next timeout.
  base::TimeDelta timeout = timeout_ * (after_suspend ? 3 : 1);
  suspension_timeout_ = base::Time::Now() + timeout * 2;

  // Post a task to the monitored thread that does nothing but wake up the
  // TaskObserver. Any other tasks that are pending on the watched thread will
  // also wake up the observer. This simply ensures there is at least one.
  watched_message_loop_->PostTask(
      FROM_HERE,
      base::Bind(&base::DoNothing));

  // Post a task to the watchdog thread to exit if the monitored thread does
  // not respond in time.
  message_loop()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
                 weak_factory_.GetWeakPtr()),
      timeout);
}

// Use the --disable-gpu-watchdog command line switch to disable this.
void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() {
  // Should not get here while the system is suspended.
  DCHECK(!suspended_);

#if defined(OS_WIN)
  // Defer termination until a certain amount of CPU time has elapsed on the
  // watched thread.
  base::TimeDelta time_since_arm = GetWatchedThreadTime() - arm_cpu_time_;
  if (time_since_arm < timeout_) {
    message_loop()->PostDelayedTask(
        FROM_HERE,
        base::Bind(
            &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
            weak_factory_.GetWeakPtr()),
        timeout_ - time_since_arm);
    return;
  }
#endif

  // If the watchdog woke up significantly behind schedule, disarm and reset
  // the watchdog check. This is to prevent the watchdog thread from terminating
  // when a machine wakes up from sleep or hibernation, which would otherwise
  // appear to be a hang.
  if (base::Time::Now() > suspension_timeout_) {
    armed_ = false;
    OnCheck(true);
    return;
  }

#if defined(USE_X11)
  XWindowAttributes attributes;
  XGetWindowAttributes(display_, window_, &attributes);

  XSelectInput(display_, window_, PropertyChangeMask);
  SetupXChangeProp();

  XFlush(display_);

  // We wait for the property change event with a timeout. If it arrives we know
  // that X is responsive and is not the cause of the watchdog trigger, so we
  // should
  // terminate. If it times out, it may be due to X taking a long time, but
  // terminating won't help, so ignore the watchdog trigger.
  XEvent event_return;
  base::TimeTicks deadline = base::TimeTicks::Now() + timeout_;
  while (true) {
    base::TimeDelta delta = deadline - base::TimeTicks::Now();
    if (delta < base::TimeDelta()) {
      return;
    } else {
      while (XCheckWindowEvent(display_, window_, PropertyChangeMask,
                               &event_return)) {
        if (MatchXEventAtom(&event_return))
          break;
      }
      struct pollfd fds[1];
      fds[0].fd = XConnectionNumber(display_);
      fds[0].events = POLLIN;
      int status = poll(fds, 1, delta.InMilliseconds());
      if (status == -1) {
        if (errno == EINTR) {
          continue;
        } else {
          LOG(FATAL) << "Lost X connection, aborting.";
          break;
        }
      } else if (status == 0) {
        return;
      } else {
        continue;
      }
    }
  }
#endif

  // For minimal developer annoyance, don't keep terminating. You need to skip
  // the call to base::Process::Terminate below in a debugger for this to be
  // useful.
  static bool terminated = false;
  if (terminated)
    return;

#if defined(OS_WIN)
  if (IsDebuggerPresent())
    return;
#endif

#if defined(OS_CHROMEOS)
  // Don't crash if we're not on tty1. This avoids noise in the GPU process
  // crashes caused by people who use VT2 but still enable crash reporting.
  char tty_string[8] = {0};
  if (tty_file_ &&
      !fseek(tty_file_, 0, SEEK_SET) &&
      fread(tty_string, 1, 7, tty_file_)) {
    int tty_number = -1;
    int num_res = sscanf(tty_string, "tty%d", &tty_number);
    if (num_res == 1 && tty_number != 1)
      return;
  }
#endif

  LOG(ERROR) << "The GPU process hung. Terminating after "
             << timeout_.InMilliseconds() << " ms.";

  // Deliberately crash the process to create a crash dump.
  *((volatile int*)0) = 0x1337;

  terminated = true;
}

#if defined(USE_X11)
void GpuWatchdogThread::SetupXServer() {
  display_ = XOpenDisplay(NULL);
  window_ = XCreateWindow(display_, DefaultRootWindow(display_), 0, 0, 1, 1, 0,
                          CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
  atom_ = XInternAtom(display_, "CHECK", False);
}

void GpuWatchdogThread::SetupXChangeProp() {
  XChangeProperty(display_, window_, atom_, XA_STRING, 8, PropModeReplace, text,
                  (arraysize(text) - 1));
}

bool GpuWatchdogThread::MatchXEventAtom(XEvent* event) {
  if (event->xproperty.window == window_ && event->type == PropertyNotify &&
      event->xproperty.atom == atom_)
    return true;

  return false;
}

#endif
void GpuWatchdogThread::AddPowerObserver() {
  message_loop()->PostTask(
      FROM_HERE,
      base::Bind(&GpuWatchdogThread::OnAddPowerObserver, this));
}

void GpuWatchdogThread::OnAddPowerObserver() {
  base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
  DCHECK(power_monitor);
  power_monitor->AddObserver(this);
}

void GpuWatchdogThread::OnSuspend() {
  suspended_ = true;

  // When suspending force an acknowledgement to cancel any pending termination
  // tasks.
  OnAcknowledge();
}

void GpuWatchdogThread::OnResume() {
  suspended_ = false;

  // After resuming jump-start the watchdog again.
  armed_ = false;
  OnCheck(true);
}

#if defined(OS_WIN)
base::TimeDelta GpuWatchdogThread::GetWatchedThreadTime() {
  FILETIME creation_time;
  FILETIME exit_time;
  FILETIME user_time;
  FILETIME kernel_time;
  BOOL result = GetThreadTimes(watched_thread_handle_,
                               &creation_time,
                               &exit_time,
                               &kernel_time,
                               &user_time);
  DCHECK(result);

  ULARGE_INTEGER user_time64;
  user_time64.HighPart = user_time.dwHighDateTime;
  user_time64.LowPart = user_time.dwLowDateTime;

  ULARGE_INTEGER kernel_time64;
  kernel_time64.HighPart = kernel_time.dwHighDateTime;
  kernel_time64.LowPart = kernel_time.dwLowDateTime;

  // Time is reported in units of 100 nanoseconds. Kernel and user time are
  // summed to deal with to kinds of hangs. One is where the GPU process is
  // stuck in user level, never calling into the kernel and kernel time is
  // not increasing. The other is where either the kernel hangs and never
  // returns to user level or where user level code
  // calls into kernel level repeatedly, giving up its quanta before it is
  // tracked, for example a loop that repeatedly Sleeps.
  return base::TimeDelta::FromMilliseconds(static_cast<int64>(
      (user_time64.QuadPart + kernel_time64.QuadPart) / 10000));
}
#endif

}  // namespace content
<commit_msg>Reduce GPU watchdog polling frequency<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#if defined(OS_WIN)
#include <windows.h>
#endif

#include "content/gpu/gpu_watchdog_thread.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/files/file_util.h"
#include "base/power_monitor/power_monitor.h"
#include "base/process/process.h"
#include "build/build_config.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"

namespace content {
namespace {
#if defined(OS_CHROMEOS)
const base::FilePath::CharType
    kTtyFilePath[] = FILE_PATH_LITERAL("/sys/class/tty/tty0/active");
#endif
#if defined(USE_X11)
const unsigned char text[20] = "check";
#endif
}  // namespace

GpuWatchdogThread::GpuWatchdogThread(int timeout)
    : base::Thread("Watchdog"),
      watched_message_loop_(base::MessageLoop::current()),
      timeout_(base::TimeDelta::FromMilliseconds(timeout)),
      armed_(false),
#if defined(OS_WIN)
      watched_thread_handle_(0),
      arm_cpu_time_(),
#endif
      task_observer_(this),
      suspended_(false),
#if defined(USE_X11)
      display_(NULL),
      window_(0),
      atom_(None),
#endif
      weak_factory_(this) {
  DCHECK(timeout >= 0);

#if defined(OS_WIN)
  // GetCurrentThread returns a pseudo-handle that cannot be used by one thread
  // to identify another. DuplicateHandle creates a "real" handle that can be
  // used for this purpose.
  BOOL result = DuplicateHandle(GetCurrentProcess(),
                                GetCurrentThread(),
                                GetCurrentProcess(),
                                &watched_thread_handle_,
                                THREAD_QUERY_INFORMATION,
                                FALSE,
                                0);
  DCHECK(result);
#endif

#if defined(OS_CHROMEOS)
  tty_file_ = base::OpenFile(base::FilePath(kTtyFilePath), "r");
#endif
#if defined(USE_X11)
  SetupXServer();
#endif
  watched_message_loop_->AddTaskObserver(&task_observer_);
}

void GpuWatchdogThread::PostAcknowledge() {
  // Called on the monitored thread. Responds with OnAcknowledge. Cannot use
  // the method factory. Rely on reference counting instead.
  message_loop()->PostTask(
      FROM_HERE,
      base::Bind(&GpuWatchdogThread::OnAcknowledge, this));
}

void GpuWatchdogThread::CheckArmed() {
  // Acknowledge the watchdog if it has armed itself. The watchdog will not
  // change its armed state until it is acknowledged.
  if (armed()) {
    PostAcknowledge();
  }
}

void GpuWatchdogThread::Init() {
  // Schedule the first check.
  OnCheck(false);
}

void GpuWatchdogThread::CleanUp() {
  weak_factory_.InvalidateWeakPtrs();
}

GpuWatchdogThread::GpuWatchdogTaskObserver::GpuWatchdogTaskObserver(
    GpuWatchdogThread* watchdog)
    : watchdog_(watchdog) {
}

GpuWatchdogThread::GpuWatchdogTaskObserver::~GpuWatchdogTaskObserver() {
}

void GpuWatchdogThread::GpuWatchdogTaskObserver::WillProcessTask(
    const base::PendingTask& pending_task) {
  watchdog_->CheckArmed();
}

void GpuWatchdogThread::GpuWatchdogTaskObserver::DidProcessTask(
    const base::PendingTask& pending_task) {
}

GpuWatchdogThread::~GpuWatchdogThread() {
  // Verify that the thread was explicitly stopped. If the thread is stopped
  // implicitly by the destructor, CleanUp() will not be called.
  DCHECK(!weak_factory_.HasWeakPtrs());

#if defined(OS_WIN)
  CloseHandle(watched_thread_handle_);
#endif

  base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
  if (power_monitor)
    power_monitor->RemoveObserver(this);

#if defined(OS_CHROMEOS)
  if (tty_file_)
    fclose(tty_file_);
#endif

#if defined(USE_X11)
  XDestroyWindow(display_, window_);
  XCloseDisplay(display_);
#endif

  watched_message_loop_->RemoveTaskObserver(&task_observer_);
}

void GpuWatchdogThread::OnAcknowledge() {
  CHECK(base::PlatformThread::CurrentId() == thread_id());

  // The check has already been acknowledged and another has already been
  // scheduled by a previous call to OnAcknowledge. It is normal for a
  // watched thread to see armed_ being true multiple times before
  // the OnAcknowledge task is run on the watchdog thread.
  if (!armed_)
    return;

  // Revoke any pending hang termination.
  weak_factory_.InvalidateWeakPtrs();
  armed_ = false;

  if (suspended_)
    return;

  // If it took a long time for the acknowledgement, assume the computer was
  // recently suspended.
  bool was_suspended = (base::Time::Now() > suspension_timeout_);

  // The monitored thread has responded. Post a task to check it again.
  message_loop()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&GpuWatchdogThread::OnCheck, weak_factory_.GetWeakPtr(),
          was_suspended),
      0.5 * timeout_);
}

void GpuWatchdogThread::OnCheck(bool after_suspend) {
  CHECK(base::PlatformThread::CurrentId() == thread_id());

  // Do not create any new termination tasks if one has already been created
  // or the system is suspended.
  if (armed_ || suspended_)
    return;

  // Must set armed before posting the task. This task might be the only task
  // that will activate the TaskObserver on the watched thread and it must not
  // miss the false -> true transition.
  armed_ = true;

#if defined(OS_WIN)
  arm_cpu_time_ = GetWatchedThreadTime();
#endif

  // Immediately after the computer is woken up from being suspended it might
  // be pretty sluggish, so allow some extra time before the next timeout.
  base::TimeDelta timeout = timeout_ * (after_suspend ? 3 : 1);
  suspension_timeout_ = base::Time::Now() + timeout * 2;

  // Post a task to the monitored thread that does nothing but wake up the
  // TaskObserver. Any other tasks that are pending on the watched thread will
  // also wake up the observer. This simply ensures there is at least one.
  watched_message_loop_->PostTask(
      FROM_HERE,
      base::Bind(&base::DoNothing));

  // Post a task to the watchdog thread to exit if the monitored thread does
  // not respond in time.
  message_loop()->PostDelayedTask(
      FROM_HERE,
      base::Bind(&GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
                 weak_factory_.GetWeakPtr()),
      timeout);
}

// Use the --disable-gpu-watchdog command line switch to disable this.
void GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang() {
  // Should not get here while the system is suspended.
  DCHECK(!suspended_);

#if defined(OS_WIN)
  // Defer termination until a certain amount of CPU time has elapsed on the
  // watched thread.
  base::TimeDelta time_since_arm = GetWatchedThreadTime() - arm_cpu_time_;
  if (time_since_arm < timeout_) {
    message_loop()->PostDelayedTask(
        FROM_HERE,
        base::Bind(
            &GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
            weak_factory_.GetWeakPtr()),
        timeout_ - time_since_arm);
    return;
  }
#endif

  // If the watchdog woke up significantly behind schedule, disarm and reset
  // the watchdog check. This is to prevent the watchdog thread from terminating
  // when a machine wakes up from sleep or hibernation, which would otherwise
  // appear to be a hang.
  if (base::Time::Now() > suspension_timeout_) {
    armed_ = false;
    OnCheck(true);
    return;
  }

#if defined(USE_X11)
  XWindowAttributes attributes;
  XGetWindowAttributes(display_, window_, &attributes);

  XSelectInput(display_, window_, PropertyChangeMask);
  SetupXChangeProp();

  XFlush(display_);

  // We wait for the property change event with a timeout. If it arrives we know
  // that X is responsive and is not the cause of the watchdog trigger, so we
  // should
  // terminate. If it times out, it may be due to X taking a long time, but
  // terminating won't help, so ignore the watchdog trigger.
  XEvent event_return;
  base::TimeTicks deadline = base::TimeTicks::Now() + timeout_;
  while (true) {
    base::TimeDelta delta = deadline - base::TimeTicks::Now();
    if (delta < base::TimeDelta()) {
      return;
    } else {
      while (XCheckWindowEvent(display_, window_, PropertyChangeMask,
                               &event_return)) {
        if (MatchXEventAtom(&event_return))
          break;
      }
      struct pollfd fds[1];
      fds[0].fd = XConnectionNumber(display_);
      fds[0].events = POLLIN;
      int status = poll(fds, 1, delta.InMilliseconds());
      if (status == -1) {
        if (errno == EINTR) {
          continue;
        } else {
          LOG(FATAL) << "Lost X connection, aborting.";
          break;
        }
      } else if (status == 0) {
        return;
      } else {
        continue;
      }
    }
  }
#endif

  // For minimal developer annoyance, don't keep terminating. You need to skip
  // the call to base::Process::Terminate below in a debugger for this to be
  // useful.
  static bool terminated = false;
  if (terminated)
    return;

#if defined(OS_WIN)
  if (IsDebuggerPresent())
    return;
#endif

#if defined(OS_CHROMEOS)
  // Don't crash if we're not on tty1. This avoids noise in the GPU process
  // crashes caused by people who use VT2 but still enable crash reporting.
  char tty_string[8] = {0};
  if (tty_file_ &&
      !fseek(tty_file_, 0, SEEK_SET) &&
      fread(tty_string, 1, 7, tty_file_)) {
    int tty_number = -1;
    int num_res = sscanf(tty_string, "tty%d", &tty_number);
    if (num_res == 1 && tty_number != 1)
      return;
  }
#endif

  LOG(ERROR) << "The GPU process hung. Terminating after "
             << timeout_.InMilliseconds() << " ms.";

  // Deliberately crash the process to create a crash dump.
  *((volatile int*)0) = 0x1337;

  terminated = true;
}

#if defined(USE_X11)
void GpuWatchdogThread::SetupXServer() {
  display_ = XOpenDisplay(NULL);
  window_ = XCreateWindow(display_, DefaultRootWindow(display_), 0, 0, 1, 1, 0,
                          CopyFromParent, InputOutput, CopyFromParent, 0, NULL);
  atom_ = XInternAtom(display_, "CHECK", False);
}

void GpuWatchdogThread::SetupXChangeProp() {
  XChangeProperty(display_, window_, atom_, XA_STRING, 8, PropModeReplace, text,
                  (arraysize(text) - 1));
}

bool GpuWatchdogThread::MatchXEventAtom(XEvent* event) {
  if (event->xproperty.window == window_ && event->type == PropertyNotify &&
      event->xproperty.atom == atom_)
    return true;

  return false;
}

#endif
void GpuWatchdogThread::AddPowerObserver() {
  message_loop()->PostTask(
      FROM_HERE,
      base::Bind(&GpuWatchdogThread::OnAddPowerObserver, this));
}

void GpuWatchdogThread::OnAddPowerObserver() {
  base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
  DCHECK(power_monitor);
  power_monitor->AddObserver(this);
}

void GpuWatchdogThread::OnSuspend() {
  suspended_ = true;

  // When suspending force an acknowledgement to cancel any pending termination
  // tasks.
  OnAcknowledge();
}

void GpuWatchdogThread::OnResume() {
  suspended_ = false;

  // After resuming jump-start the watchdog again.
  armed_ = false;
  OnCheck(true);
}

#if defined(OS_WIN)
base::TimeDelta GpuWatchdogThread::GetWatchedThreadTime() {
  FILETIME creation_time;
  FILETIME exit_time;
  FILETIME user_time;
  FILETIME kernel_time;
  BOOL result = GetThreadTimes(watched_thread_handle_,
                               &creation_time,
                               &exit_time,
                               &kernel_time,
                               &user_time);
  DCHECK(result);

  ULARGE_INTEGER user_time64;
  user_time64.HighPart = user_time.dwHighDateTime;
  user_time64.LowPart = user_time.dwLowDateTime;

  ULARGE_INTEGER kernel_time64;
  kernel_time64.HighPart = kernel_time.dwHighDateTime;
  kernel_time64.LowPart = kernel_time.dwLowDateTime;

  // Time is reported in units of 100 nanoseconds. Kernel and user time are
  // summed to deal with to kinds of hangs. One is where the GPU process is
  // stuck in user level, never calling into the kernel and kernel time is
  // not increasing. The other is where either the kernel hangs and never
  // returns to user level or where user level code
  // calls into kernel level repeatedly, giving up its quanta before it is
  // tracked, for example a loop that repeatedly Sleeps.
  return base::TimeDelta::FromMilliseconds(static_cast<int64>(
      (user_time64.QuadPart + kernel_time64.QuadPart) / 10000));
}
#endif

}  // namespace content
<|endoftext|>


<commit_before>#include "al_OpenCLEngine.hpp"

namespace al {
namespace cl {

OpenCLEngine :: ~OpenCLEngine() {
	while(! mDeviceQueues.empty()) {
		map<cl_device_id, OpenCLCommandQueue *>::iterator it = mDeviceQueues.begin();
		OpenCLCommandQueue *queue = it->second;
		mDeviceQueues.erase(it);
		delete queue;
	}

	while(! mPrograms.empty()) {
		map<string, OpenCLProgram *>::iterator it = mPrograms.begin();
		OpenCLProgram *program = it->second;
		mPrograms.erase(it);
		delete program;
	}

	mContext.destroy();
}

OpenCLDevice * OpenCLEngine :: default_device() {
	if(! mContext.get_context()) {
		if(! create_context()) {
			return NULL;
		}
	}

	return mPlatforms.front().default_device();
}

OpenCLDevice * OpenCLEngine :: cpu_device() {
	if(! mContext.get_context()) {
		if(! create_context()) {
			return NULL;
		}
	}

	return mPlatforms.front().cpu_device();
}

OpenCLDevice * OpenCLEngine :: gpu_device() {
	if(! mContext.get_context()) {
		if(! create_context()) {
			return NULL;
		}
	}

	return mPlatforms.front().gpu_device();
}

void OpenCLEngine :: compile_source(const char *name, const char *source) {
	if(! mContext.get_context()) {
		if(! create_context()) {
			return;
		}
	}

	map<string, OpenCLProgram *>::iterator it = mPrograms.find(string(name));
	if(it != mPrograms.end()) {
		OpenCLProgram *old_program = it->second;
		mPrograms.erase(it);
		delete old_program;
	}

	OpenCLProgram *program = new OpenCLProgram();
	program->create(mContext, source);
	if(program->get_program() != 0) {
		program->build(mPlatforms.front().get_devices());
		mPrograms.insert(std::pair<string, OpenCLProgram *>(string(name), program));
	}
	else {
		delete program;
	}
}

OpenCLKernel * OpenCLEngine :: get_kernel(const char *name, const char *kernel_name) {
	map<string, OpenCLProgram *>::iterator it = mPrograms.find(string(name));
	if(it == mPrograms.end()) {
		return NULL;
	}

	OpenCLProgram *program = it->second;
	if(kernel_name) {
		return OpenCLKernel::create(*program, kernel_name);
	}
	else {
		vector<OpenCLKernel *> kers;
		OpenCLKernel::create(*program, kers);
		if(kers.size() > 0) {
			OpenCLKernel *kernel = kers.front();
			for(unsigned int i=1; i < kers.size(); i++) {
				delete kers[i];
			}
			return kernel;
		}
		else {
			return NULL;
		}
	}
}

OpenCLEvent OpenCLEngine :: enqueue_kernel(
	const OpenCLDevice &dev,
	const OpenCLKernel *ker,
	cl_uint ndim,
	size_t *global,
	size_t *local
)
{
	OpenCLCommandQueue *queue = queue_for_device(dev);
	if(queue) {
		return queue->enqueueKernel(*ker, ndim, global, local);
	}
	else {
		return OpenCLEvent();
	}
}

OpenCLEvent OpenCLEngine :: enqueue_read(
	const OpenCLDevice &dev,
	const OpenCLMemoryBuffer *mem,
	bool block,
	size_t offset,
	size_t size,
	void *ptr
)
{
	OpenCLCommandQueue *queue = queue_for_device(dev);
	if(queue) {
		return queue->enqueueRead(*mem, block, offset, size, ptr);
	}
	else {
		return OpenCLEvent();
	}
}

OpenCLMemoryBuffer * OpenCLEngine :: create_memory_buffer(cl_mem_flags usage, size_t size, void *ptr) {
	if(! mContext.get_context()) {
		if(! create_context()) {
			return NULL;
		}
	}

	OpenCLMemoryBuffer *mem = new OpenCLMemoryBuffer();
	mem->create(mContext, usage, size, ptr);
	return mem;
}

bool OpenCLEngine :: create_context() {
	OpenCLPlatform::get_platforms(mPlatforms);
	if(mPlatforms.size() <= 0) {
		return false;
	}

	OpenCLPlatform &platform = mPlatforms.front();
	const vector<OpenCLDevice> &devices =  platform.get_devices();
	mContext.create(devices);

	return mContext.get_context() != 0;
}

OpenCLCommandQueue * OpenCLEngine :: queue_for_device(const OpenCLDevice &dev) {
	map<cl_device_id, OpenCLCommandQueue *>::iterator it =	mDeviceQueues.find(dev.get_device());
	OpenCLCommandQueue *queue = NULL;
	if(it == mDeviceQueues.end()) {
		queue = new OpenCLCommandQueue();
		queue->create(mContext, dev);
		if(queue->get_command_queue() == 0) {
			delete queue;
			return NULL;
		}

		mDeviceQueues.insert(
			std::pair<cl_device_id, OpenCLCommandQueue *>(
				dev.get_device(),
				queue
			)
		);
	}
	else {
		queue = it->second;
	}

	return queue;
}

}	// cl::
}	// al::
<commit_msg>opencl updates<commit_after>#include "al_OpenCLEngine.hpp"

namespace al {
namespace cl {

OpenCLEngine :: ~OpenCLEngine() {
	while(! mDeviceQueues.empty()) {
		map<cl_device_id, OpenCLCommandQueue *>::iterator it = mDeviceQueues.begin();
		OpenCLCommandQueue *queue = it->second;
		mDeviceQueues.erase(it);
		delete queue;
	}

	while(! mPrograms.empty()) {
		map<string, OpenCLProgram *>::iterator it = mPrograms.begin();
		OpenCLProgram *program = it->second;
		mPrograms.erase(it);
		delete program;
	}

	mContext.destroy();
}

OpenCLDevice * OpenCLEngine :: default_device() {
	if(! mContext.get_context()) {
		if(! create_context()) {
			return NULL;
		}
	}

	return mPlatforms.front().default_device();
}

OpenCLDevice * OpenCLEngine :: cpu_device() {
	if(! mContext.get_context()) {
		if(! create_context()) {
			return NULL;
		}
	}

	return mPlatforms.front().cpu_device();
}

OpenCLDevice * OpenCLEngine :: gpu_device() {
	if(! mContext.get_context()) {
		if(! create_context()) {
			return NULL;
		}
	}

	return mPlatforms.front().gpu_device();
}

void OpenCLEngine :: compile_source(const char *name, const char *source) {
	if(! mContext.get_context()) {
		if(! create_context()) {
			return;
		}
	}

	map<string, OpenCLProgram *>::iterator it = mPrograms.find(string(name));
	if(it != mPrograms.end()) {
		OpenCLProgram *old_program = it->second;
		mPrograms.erase(it);
		delete old_program;
	}

	OpenCLProgram *program = new OpenCLProgram();
	program->create(mContext, source);
	if(program->get_program() != 0) {
		program->build(mPlatforms.front().get_devices());
		mPrograms.insert(std::pair<string, OpenCLProgram *>(string(name), program));
	}
	else {
		delete program;
	}
}

OpenCLKernel * OpenCLEngine :: get_kernel(const char *name, const char *kernel_name) {
	map<string, OpenCLProgram *>::iterator it = mPrograms.find(string(name));
	if(it == mPrograms.end()) {
		return NULL;
	}

	OpenCLProgram *program = it->second;
	if(kernel_name) {
		return OpenCLKernel::create(*program, kernel_name);
	}
	else {
		vector<OpenCLKernel *> kers;
		OpenCLKernel::create(*program, kers);
		if(kers.size() > 0) {
			OpenCLKernel *kernel = kers.front();
			for(unsigned int i=1; i < kers.size(); i++) {
				delete kers[i];
			}
			return kernel;
		}
		else {
			return NULL;
		}
	}
}

OpenCLEvent OpenCLEngine :: enqueue_kernel(
	const OpenCLDevice &dev,
	const OpenCLKernel *ker,
	cl_uint ndim,
	size_t *global,
	size_t *local
)
{
	OpenCLCommandQueue *queue = queue_for_device(dev);
	if(queue) {
		return queue->enqueueKernel(*ker, ndim, global, local);
	}
	else {
		return OpenCLEvent();
	}
}

OpenCLEvent OpenCLEngine :: enqueue_read(
	const OpenCLDevice &dev,
	const OpenCLMemoryBuffer *mem,
	bool block,
	size_t offset,
	size_t size,
	void *ptr
)
{
	OpenCLCommandQueue *queue = queue_for_device(dev);
	if(queue) {
		return queue->enqueueRead(*mem, block, offset, size, ptr);
	}
	else {
		return OpenCLEvent();
	}
}

OpenCLMemoryBuffer * OpenCLEngine :: create_memory_buffer(cl_mem_flags usage, size_t size, void *ptr) {
	if(! mContext.get_context()) {
		if(! create_context()) {
			return NULL;
		}
	}

	OpenCLMemoryBuffer *mem = new OpenCLMemoryBuffer();
	mem->create(mContext, usage, size, ptr);
	return mem;
}

bool OpenCLEngine :: create_context() {
	OpenCLPlatform::get_platforms(mPlatforms);
	if(mPlatforms.size() <= 0) {
		return false;
	}

	OpenCLPlatform &platform = mPlatforms.front();
	const vector<OpenCLDevice> &devices =  platform.get_devices();
	mContext.create(devices);

	return mContext.get_context() != 0;
}

OpenCLCommandQueue * OpenCLEngine :: queue_for_device(const OpenCLDevice &dev) {
	if(! mContext.get_context()) {
		if(! create_context()) {
			return NULL;
		}
	}

	map<cl_device_id, OpenCLCommandQueue *>::iterator it =	mDeviceQueues.find(dev.get_device());
	OpenCLCommandQueue *queue = NULL;
	if(it == mDeviceQueues.end()) {
		queue = new OpenCLCommandQueue();
		queue->create(mContext, dev);
		if(queue->get_command_queue() == 0) {
			delete queue;
			return NULL;
		}

		mDeviceQueues.insert(
			std::pair<cl_device_id, OpenCLCommandQueue *>(
				dev.get_device(),
				queue
			)
		);
	}
	else {
		queue = it->second;
	}

	return queue;
}

}	// cl::
}	// al::
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org)             */
/*                                                                            */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
/* not use this file except in compliance with the License. You may obtain    */
/* a copy of the License at                                                   */
/*                                                                            */
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
/*                                                                            */
/* Unless required by applicable law or agreed to in writing, software        */
/* distributed under the License is distributed on an "AS IS" BASIS,          */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
/* See the License for the specific language governing permissions and        */
/* limitations under the License.                                             */
/* -------------------------------------------------------------------------- */

#include "RequestManager.h"

#include "NebulaLog.h"
#include "Nebula.h"

#include "AuthManager.h"

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

void RequestManager::ImagePersistent::execute(
    xmlrpc_c::paramList const& paramList,
    xmlrpc_c::value *   const  retval)
{
    string              session;

    int                 iid;
    bool                persistent_flag;
    int                 uid;

    int                 image_owner;
    bool                is_persistent;

    Image             * image;

    ostringstream       oss;

    bool                response;

    const string        method_name = "ImagePersistent";

    vector<xmlrpc_c::value> arrayData;
    xmlrpc_c::value_array * arrayresult;

    NebulaLog::log("ReM",Log::DEBUG,"ImagePersistent invoked");

    session         = xmlrpc_c::value_string (paramList.getString(0));
    iid             = xmlrpc_c::value_int    (paramList.getInt(1));
    persistent_flag = xmlrpc_c::value_boolean(paramList.getBoolean(2));

    // First, we need to authenticate the user
    uid = ImagePersistent::upool->authenticate(session);

    if ( uid == -1 )
    {
        goto error_authenticate;
    }

    // Get image from the ImagePool
    image = ImagePersistent::ipool->get(iid,true);

    if ( image == 0 )
    {
        goto error_image_get;
    }

    image_owner    = image->get_uid();
    is_persistent  = image->isPersistent();

    image->unlock();

    //Authorize the operation
    if ( uid != 0 ) // uid == 0 means oneadmin
    {
        AuthRequest ar(uid);

        ar.add_auth(AuthRequest::IMAGE,
                    iid,
                    AuthRequest::MANAGE,
                    image_owner,
                    false);

        if (UserPool::authorize(ar) == -1)
        {
            goto error_authorize;
        }
    }

    // Get the image locked again
    image = ImagePersistent::ipool->get(iid,true);

    if ( image == 0 )
    {
        goto error_image_get;
    }

    response = image->persistent(persistent_flag);

    if (!response)
    {
        goto error_persistent;
    }

    ImagePersistent::ipool->update(image);

    image->unlock();

    arrayData.push_back(xmlrpc_c::value_boolean(true));
    arrayData.push_back(xmlrpc_c::value_int(iid));

    // Copy arrayresult into retval mem space
    arrayresult = new xmlrpc_c::value_array(arrayData);
    *retval = *arrayresult;

    delete arrayresult; // and get rid of the original

    return;

error_authenticate:
    oss.str(authenticate_error(method_name));
    goto error_common;

error_image_get:
    oss.str(get_error(method_name, "IMAGE", iid));
    goto error_common;

error_authorize:
    oss.str(authorization_error(method_name, "MANAGE", "IMAGE", uid, iid));
    goto error_common;

error_persistent:
    oss << action_error(method_name, "MANAGE", "IMAGE", iid, NULL)
        << " Is the image public? An Image cannot be public and persistent.";
    goto error_common;

error_common:
    arrayData.push_back(xmlrpc_c::value_boolean(false));  // FAILURE
    arrayData.push_back(xmlrpc_c::value_string(oss.str()));

    NebulaLog::log("ReM",Log::ERROR,oss);

    xmlrpc_c::value_array arrayresult_error(arrayData);

    *retval = arrayresult_error;

    return;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
<commit_msg>bug #295: Auth of persistency operation over image takes public flag into account<commit_after>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.org)             */
/*                                                                            */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
/* not use this file except in compliance with the License. You may obtain    */
/* a copy of the License at                                                   */
/*                                                                            */
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
/*                                                                            */
/* Unless required by applicable law or agreed to in writing, software        */
/* distributed under the License is distributed on an "AS IS" BASIS,          */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
/* See the License for the specific language governing permissions and        */
/* limitations under the License.                                             */
/* -------------------------------------------------------------------------- */

#include "RequestManager.h"

#include "NebulaLog.h"
#include "Nebula.h"

#include "AuthManager.h"

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

void RequestManager::ImagePersistent::execute(
    xmlrpc_c::paramList const& paramList,
    xmlrpc_c::value *   const  retval)
{
    string              session;

    int                 iid;
    bool                persistent_flag;
    int                 uid;

    int                 image_owner;
    bool                is_public;

    Image             * image;

    ostringstream       oss;

    bool                response;

    const string        method_name = "ImagePersistent";

    vector<xmlrpc_c::value> arrayData;
    xmlrpc_c::value_array * arrayresult;

    NebulaLog::log("ReM",Log::DEBUG,"ImagePersistent invoked");

    session         = xmlrpc_c::value_string (paramList.getString(0));
    iid             = xmlrpc_c::value_int    (paramList.getInt(1));
    persistent_flag = xmlrpc_c::value_boolean(paramList.getBoolean(2));

    // First, we need to authenticate the user
    uid = ImagePersistent::upool->authenticate(session);

    if ( uid == -1 )
    {
        goto error_authenticate;
    }

    // Get image from the ImagePool
    image = ImagePersistent::ipool->get(iid,true);

    if ( image == 0 )
    {
        goto error_image_get;
    }

    image_owner  = image->get_uid();
    is_public    = image->isPublic();

    image->unlock();

    //Authorize the operation
    if ( uid != 0 ) // uid == 0 means oneadmin
    {
        AuthRequest ar(uid);

        ar.add_auth(AuthRequest::IMAGE,
                    iid,
                    AuthRequest::MANAGE,
                    image_owner,
                    is_public);

        if (UserPool::authorize(ar) == -1)
        {
            goto error_authorize;
        }
    }

    // Get the image locked again
    image = ImagePersistent::ipool->get(iid,true);

    if ( image == 0 )
    {
        goto error_image_get;
    }

    response = image->persistent(persistent_flag);

    if (!response)
    {
        goto error_persistent;
    }

    ImagePersistent::ipool->update(image);

    image->unlock();

    arrayData.push_back(xmlrpc_c::value_boolean(true));
    arrayData.push_back(xmlrpc_c::value_int(iid));

    // Copy arrayresult into retval mem space
    arrayresult = new xmlrpc_c::value_array(arrayData);
    *retval = *arrayresult;

    delete arrayresult; // and get rid of the original

    return;

error_authenticate:
    oss.str(authenticate_error(method_name));
    goto error_common;

error_image_get:
    oss.str(get_error(method_name, "IMAGE", iid));
    goto error_common;

error_authorize:
    oss.str(authorization_error(method_name, "MANAGE", "IMAGE", uid, iid));
    goto error_common;

error_persistent:
    oss << action_error(method_name, "MANAGE", "IMAGE", iid, NULL)
        << " Is the image public? An Image cannot be public and persistent.";
    goto error_common;

error_common:
    arrayData.push_back(xmlrpc_c::value_boolean(false));  // FAILURE
    arrayData.push_back(xmlrpc_c::value_string(oss.str()));

    NebulaLog::log("ReM",Log::ERROR,oss);

    xmlrpc_c::value_array arrayresult_error(arrayData);

    *retval = arrayresult_error;

    return;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
<|endoftext|>