<commit_before>//
// Copyright 2021 gRPC authors.
//
// 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 <grpc/support/port_platform.h>

#include "src/core/ext/filters/client_channel/resolver_registry.h"
#include "src/core/ext/xds/xds_client.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/http/httpcli.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"

namespace grpc_core {

namespace {

class GoogleCloud2ProdResolver : public Resolver {
 public:
  explicit GoogleCloud2ProdResolver(ResolverArgs args);

  void StartLocked() override;
  void RequestReresolutionLocked() override;
  void ResetBackoffLocked() override;
  void ShutdownLocked() override;

 private:
  // Represents an HTTP request to the metadata server.
  class MetadataQuery : public InternallyRefCounted<MetadataQuery> {
   public:
    MetadataQuery(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
                  const char* path, grpc_polling_entity* pollent);
    ~MetadataQuery() override;

    void Orphan() override;

   private:
    static void OnHttpRequestDone(void* arg, grpc_error_handle error);

    // Calls OnDone() if not already called.  Releases a ref.
    void MaybeCallOnDone(grpc_error_handle error);

    // If error is not GRPC_ERROR_NONE, then it's not safe to look at response.
    virtual void OnDone(GoogleCloud2ProdResolver* resolver,
                        const grpc_http_response* response,
                        grpc_error_handle error) = 0;

    RefCountedPtr<GoogleCloud2ProdResolver> resolver_;
    grpc_httpcli_context context_;
    grpc_httpcli_response response_;
    grpc_closure on_done_;
    Atomic<bool> on_done_called_{false};
  };

  // A metadata server query to get the zone.
  class ZoneQuery : public MetadataQuery {
   public:
    ZoneQuery(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
              grpc_polling_entity* pollent);

   private:
    void OnDone(GoogleCloud2ProdResolver* resolver,
                const grpc_http_response* response,
                grpc_error_handle error) override;
  };

  // A metadata server query to get the IPv6 address.
  class IPv6Query : public MetadataQuery {
   public:
    IPv6Query(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
              grpc_polling_entity* pollent);

   private:
    void OnDone(GoogleCloud2ProdResolver* resolver,
                const grpc_http_response* response,
                grpc_error_handle error) override;
  };

  void ZoneQueryDone(std::string zone);
  void IPv6QueryDone(bool ipv6_supported);
  void StartXdsResolver();

  std::shared_ptr<WorkSerializer> work_serializer_;
  grpc_polling_entity pollent_;
  bool using_dns_ = false;
  OrphanablePtr<Resolver> child_resolver_;

  OrphanablePtr<ZoneQuery> zone_query_;
  absl::optional<std::string> zone_;

  OrphanablePtr<IPv6Query> ipv6_query_;
  absl::optional<bool> supports_ipv6_;
};

//
// GoogleCloud2ProdResolver::MetadataQuery
//

GoogleCloud2ProdResolver::MetadataQuery::MetadataQuery(
    RefCountedPtr<GoogleCloud2ProdResolver> resolver, const char* path,
    grpc_polling_entity* pollent)
    : resolver_(std::move(resolver)) {
  grpc_httpcli_context_init(&context_);
  // Start HTTP request.
  GRPC_CLOSURE_INIT(&on_done_, OnHttpRequestDone, this, nullptr);
  Ref().release();  // Ref held by callback.
  grpc_httpcli_request request;
  memset(&request, 0, sizeof(grpc_httpcli_request));
  grpc_http_header header = {const_cast<char*>("Metadata-Flavor"),
                             const_cast<char*>("Google")};
  request.host = const_cast<char*>("metadata.google.internal");
  request.http.path = const_cast<char*>(path);
  request.http.hdr_count = 1;
  request.http.hdrs = &header;
  grpc_resource_quota* resource_quota =
      grpc_resource_quota_create("c2p_resolver");
  grpc_httpcli_get(&context_, pollent, resource_quota, &request,
                   ExecCtx::Get()->Now() + 10000,  // 10s timeout
                   &on_done_, &response_);
  grpc_resource_quota_unref_internal(resource_quota);
}

GoogleCloud2ProdResolver::MetadataQuery::~MetadataQuery() {
  grpc_httpcli_context_destroy(&context_);
  grpc_http_response_destroy(&response_);
}

void GoogleCloud2ProdResolver::MetadataQuery::Orphan() {
  // TODO(roth): Once the HTTP client library supports cancellation,
  // use that here.
  MaybeCallOnDone(GRPC_ERROR_CANCELLED);
}

void GoogleCloud2ProdResolver::MetadataQuery::OnHttpRequestDone(
    void* arg, grpc_error_handle error) {
  auto* self = static_cast<MetadataQuery*>(arg);
  self->MaybeCallOnDone(GRPC_ERROR_REF(error));
}

void GoogleCloud2ProdResolver::MetadataQuery::MaybeCallOnDone(
    grpc_error_handle error) {
  bool expected = false;
  if (!on_done_called_.CompareExchangeStrong(
          &expected, true, MemoryOrder::RELAXED, MemoryOrder::RELAXED)) {
    // We've already called OnDone(), so just clean up.
    GRPC_ERROR_UNREF(error);
    Unref();
    return;
  }
  // Hop back into WorkSerializer to call OnDone().
  // Note: We implicitly pass our ref to the callback here.
  resolver_->work_serializer_->Run(
      [this, error]() {
        OnDone(resolver_.get(), &response_, error);
        Unref();
      },
      DEBUG_LOCATION);
}

//
// GoogleCloud2ProdResolver::ZoneQuery
//

GoogleCloud2ProdResolver::ZoneQuery::ZoneQuery(
    RefCountedPtr<GoogleCloud2ProdResolver> resolver,
    grpc_polling_entity* pollent)
    : MetadataQuery(std::move(resolver), "/computeMetadata/v1/instance/zone",
                    pollent) {}

void GoogleCloud2ProdResolver::ZoneQuery::OnDone(
    GoogleCloud2ProdResolver* resolver, const grpc_http_response* response,
    grpc_error_handle error) {
  if (error != GRPC_ERROR_NONE) {
    gpr_log(GPR_ERROR, "error fetching zone from metadata server: %s",
            grpc_error_std_string(error).c_str());
  }
  std::string zone;
  if (error == GRPC_ERROR_NONE && response->status == 200) {
    absl::string_view body(response->body, response->body_length);
    size_t i = body.find_last_of('/');
    if (i == body.npos) {
      gpr_log(GPR_ERROR, "could not parse zone from metadata server: %s",
              std::string(body).c_str());
    } else {
      zone = std::string(body.substr(i));
    }
  }
  resolver->ZoneQueryDone(std::move(zone));
  GRPC_ERROR_UNREF(error);
}

//
// GoogleCloud2ProdResolver::IPv6Query
//

GoogleCloud2ProdResolver::IPv6Query::IPv6Query(
    RefCountedPtr<GoogleCloud2ProdResolver> resolver,
    grpc_polling_entity* pollent)
    : MetadataQuery(std::move(resolver),
                    "/computeMetadata/v1/instance/network-interfaces/0/ipv6s",
                    pollent) {}

void GoogleCloud2ProdResolver::IPv6Query::OnDone(
    GoogleCloud2ProdResolver* resolver, const grpc_http_response* response,
    grpc_error_handle error) {
  if (error != GRPC_ERROR_NONE) {
    gpr_log(GPR_ERROR, "error fetching IPv6 address from metadata server: %s",
            grpc_error_std_string(error).c_str());
  }
  resolver->IPv6QueryDone(error == GRPC_ERROR_NONE && response->status == 200);
  GRPC_ERROR_UNREF(error);
}

//
// GoogleCloud2ProdResolver
//

GoogleCloud2ProdResolver::GoogleCloud2ProdResolver(ResolverArgs args)
    : work_serializer_(std::move(args.work_serializer)),
      pollent_(grpc_polling_entity_create_from_pollset_set(args.pollset_set)) {
  absl::string_view name_to_resolve = absl::StripPrefix(args.uri.path(), "/");
  // If we're not running on GCP, we can't use DirectPath, so delegate
  // to the DNS resolver.
  if (!grpc_alts_is_running_on_gcp() ||
      // If the client is already using xDS, we can't use it here, because
      // they may be talking to a completely different xDS server than we
      // want to.
      // TODO(roth): When we implement xDS federation, remove this constraint.
      UniquePtr<char>(gpr_getenv("GRPC_XDS_BOOTSTRAP")) != nullptr ||
      UniquePtr<char>(gpr_getenv("GRPC_XDS_BOOTSTRAP_CONFIG")) != nullptr) {
    using_dns_ = true;
    child_resolver_ = ResolverRegistry::CreateResolver(
        absl::StrCat("dns:", name_to_resolve).c_str(), args.args,
        args.pollset_set, work_serializer_, std::move(args.result_handler));
    GPR_ASSERT(child_resolver_ != nullptr);
    return;
  }
  // Create xds resolver.
  child_resolver_ = ResolverRegistry::CreateResolver(
      absl::StrCat("xds:", name_to_resolve).c_str(), args.args,
      args.pollset_set, work_serializer_, std::move(args.result_handler));
  GPR_ASSERT(child_resolver_ != nullptr);
}

void GoogleCloud2ProdResolver::StartLocked() {
  if (using_dns_) {
    child_resolver_->StartLocked();
    return;
  }
  // Using xDS.  Start metadata server queries.
  zone_query_ = MakeOrphanable<ZoneQuery>(Ref(), &pollent_);
  ipv6_query_ = MakeOrphanable<IPv6Query>(Ref(), &pollent_);
}

void GoogleCloud2ProdResolver::RequestReresolutionLocked() {
  if (child_resolver_ != nullptr) {
    child_resolver_->RequestReresolutionLocked();
  }
}

void GoogleCloud2ProdResolver::ResetBackoffLocked() {
  if (child_resolver_ != nullptr) {
    child_resolver_->ResetBackoffLocked();
  }
}

void GoogleCloud2ProdResolver::ShutdownLocked() {
  zone_query_.reset();
  ipv6_query_.reset();
  child_resolver_.reset();
}

void GoogleCloud2ProdResolver::ZoneQueryDone(std::string zone) {
  zone_query_.reset();
  zone_ = std::move(zone);
  if (supports_ipv6_.has_value()) StartXdsResolver();
}

void GoogleCloud2ProdResolver::IPv6QueryDone(bool ipv6_supported) {
  ipv6_query_.reset();
  supports_ipv6_ = ipv6_supported;
  if (zone_.has_value()) StartXdsResolver();
}

void GoogleCloud2ProdResolver::StartXdsResolver() {
  // Construct bootstrap JSON.
  Json::Object node = {
      {"id", "C2P"},
  };
  if (!zone_->empty()) {
    node["locality"] = Json::Object{
        {"zone", *zone_},
    };
  };
  if (*supports_ipv6_) {
    node["metadata"] = Json::Object{
        {"TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE", true},
    };
  }
  // Allow the TD server uri to be overridden for testing purposes.
  UniquePtr<char> override_server(
      gpr_getenv("GRPC_TEST_ONLY_GOOGLE_C2P_RESOLVER_TRAFFIC_DIRECTOR_URI"));
  const char* server_uri =
      override_server != nullptr && strlen(override_server.get()) > 0
          ? override_server.get()
          : "directpath-trafficdirector.googleapis.com";
  Json bootstrap = Json::Object{
      {"xds_servers",
       Json::Array{
           Json::Object{
               {"server_uri", server_uri},
               {"channel_creds",
                Json::Array{
                    Json::Object{
                        {"type", "google_default"},
                    },
                }},
               {"server_features", Json::Array{"xds_v3"}},
           },
       }},
      {"node", std::move(node)},
  };
  // Inject bootstrap JSON as fallback config.
  internal::SetXdsFallbackBootstrapConfig(bootstrap.Dump().c_str());
  // Now start xDS resolver.
  child_resolver_->StartLocked();
}

//
// Factory
//

class GoogleCloud2ProdResolverFactory : public ResolverFactory {
 public:
  bool IsValidUri(const URI& uri) const override {
    if (GPR_UNLIKELY(!uri.authority().empty())) {
      gpr_log(GPR_ERROR, "google-c2p URI scheme does not support authorities");
      return false;
    }
    return true;
  }

  OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
    if (!IsValidUri(args.uri)) return nullptr;
    return MakeOrphanable<GoogleCloud2ProdResolver>(std::move(args));
  }

  const char* scheme() const override { return "google-c2p"; }
};

}  // namespace

void GoogleCloud2ProdResolverInit() {
  // TODO(roth): Remove env var protection once this code is proven stable.
  UniquePtr<char> value(gpr_getenv("GRPC_EXPERIMENTAL_GOOGLE_C2P_RESOLVER"));
  bool parsed_value;
  bool parse_succeeded = gpr_parse_bool_value(value.get(), &parsed_value);
  if (parse_succeeded && parsed_value) {
    ResolverRegistry::Builder::RegisterResolverFactory(
        absl::make_unique<GoogleCloud2ProdResolverFactory>());
  }
}

void GoogleCloud2ProdResolverShutdown() {}

}  // namespace grpc_core
<commit_msg>Correct the start index of zone parsing in C2P resolver (#26444)<commit_after>//
// Copyright 2021 gRPC authors.
//
// 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 <grpc/support/port_platform.h>

#include "src/core/ext/filters/client_channel/resolver_registry.h"
#include "src/core/ext/xds/xds_client.h"
#include "src/core/lib/gpr/env.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/http/httpcli.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/security/credentials/alts/check_gcp_environment.h"

namespace grpc_core {

namespace {

class GoogleCloud2ProdResolver : public Resolver {
 public:
  explicit GoogleCloud2ProdResolver(ResolverArgs args);

  void StartLocked() override;
  void RequestReresolutionLocked() override;
  void ResetBackoffLocked() override;
  void ShutdownLocked() override;

 private:
  // Represents an HTTP request to the metadata server.
  class MetadataQuery : public InternallyRefCounted<MetadataQuery> {
   public:
    MetadataQuery(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
                  const char* path, grpc_polling_entity* pollent);
    ~MetadataQuery() override;

    void Orphan() override;

   private:
    static void OnHttpRequestDone(void* arg, grpc_error_handle error);

    // Calls OnDone() if not already called.  Releases a ref.
    void MaybeCallOnDone(grpc_error_handle error);

    // If error is not GRPC_ERROR_NONE, then it's not safe to look at response.
    virtual void OnDone(GoogleCloud2ProdResolver* resolver,
                        const grpc_http_response* response,
                        grpc_error_handle error) = 0;

    RefCountedPtr<GoogleCloud2ProdResolver> resolver_;
    grpc_httpcli_context context_;
    grpc_httpcli_response response_;
    grpc_closure on_done_;
    Atomic<bool> on_done_called_{false};
  };

  // A metadata server query to get the zone.
  class ZoneQuery : public MetadataQuery {
   public:
    ZoneQuery(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
              grpc_polling_entity* pollent);

   private:
    void OnDone(GoogleCloud2ProdResolver* resolver,
                const grpc_http_response* response,
                grpc_error_handle error) override;
  };

  // A metadata server query to get the IPv6 address.
  class IPv6Query : public MetadataQuery {
   public:
    IPv6Query(RefCountedPtr<GoogleCloud2ProdResolver> resolver,
              grpc_polling_entity* pollent);

   private:
    void OnDone(GoogleCloud2ProdResolver* resolver,
                const grpc_http_response* response,
                grpc_error_handle error) override;
  };

  void ZoneQueryDone(std::string zone);
  void IPv6QueryDone(bool ipv6_supported);
  void StartXdsResolver();

  std::shared_ptr<WorkSerializer> work_serializer_;
  grpc_polling_entity pollent_;
  bool using_dns_ = false;
  OrphanablePtr<Resolver> child_resolver_;

  OrphanablePtr<ZoneQuery> zone_query_;
  absl::optional<std::string> zone_;

  OrphanablePtr<IPv6Query> ipv6_query_;
  absl::optional<bool> supports_ipv6_;
};

//
// GoogleCloud2ProdResolver::MetadataQuery
//

GoogleCloud2ProdResolver::MetadataQuery::MetadataQuery(
    RefCountedPtr<GoogleCloud2ProdResolver> resolver, const char* path,
    grpc_polling_entity* pollent)
    : resolver_(std::move(resolver)) {
  grpc_httpcli_context_init(&context_);
  // Start HTTP request.
  GRPC_CLOSURE_INIT(&on_done_, OnHttpRequestDone, this, nullptr);
  Ref().release();  // Ref held by callback.
  grpc_httpcli_request request;
  memset(&request, 0, sizeof(grpc_httpcli_request));
  grpc_http_header header = {const_cast<char*>("Metadata-Flavor"),
                             const_cast<char*>("Google")};
  request.host = const_cast<char*>("metadata.google.internal");
  request.http.path = const_cast<char*>(path);
  request.http.hdr_count = 1;
  request.http.hdrs = &header;
  grpc_resource_quota* resource_quota =
      grpc_resource_quota_create("c2p_resolver");
  grpc_httpcli_get(&context_, pollent, resource_quota, &request,
                   ExecCtx::Get()->Now() + 10000,  // 10s timeout
                   &on_done_, &response_);
  grpc_resource_quota_unref_internal(resource_quota);
}

GoogleCloud2ProdResolver::MetadataQuery::~MetadataQuery() {
  grpc_httpcli_context_destroy(&context_);
  grpc_http_response_destroy(&response_);
}

void GoogleCloud2ProdResolver::MetadataQuery::Orphan() {
  // TODO(roth): Once the HTTP client library supports cancellation,
  // use that here.
  MaybeCallOnDone(GRPC_ERROR_CANCELLED);
}

void GoogleCloud2ProdResolver::MetadataQuery::OnHttpRequestDone(
    void* arg, grpc_error_handle error) {
  auto* self = static_cast<MetadataQuery*>(arg);
  self->MaybeCallOnDone(GRPC_ERROR_REF(error));
}

void GoogleCloud2ProdResolver::MetadataQuery::MaybeCallOnDone(
    grpc_error_handle error) {
  bool expected = false;
  if (!on_done_called_.CompareExchangeStrong(
          &expected, true, MemoryOrder::RELAXED, MemoryOrder::RELAXED)) {
    // We've already called OnDone(), so just clean up.
    GRPC_ERROR_UNREF(error);
    Unref();
    return;
  }
  // Hop back into WorkSerializer to call OnDone().
  // Note: We implicitly pass our ref to the callback here.
  resolver_->work_serializer_->Run(
      [this, error]() {
        OnDone(resolver_.get(), &response_, error);
        Unref();
      },
      DEBUG_LOCATION);
}

//
// GoogleCloud2ProdResolver::ZoneQuery
//

GoogleCloud2ProdResolver::ZoneQuery::ZoneQuery(
    RefCountedPtr<GoogleCloud2ProdResolver> resolver,
    grpc_polling_entity* pollent)
    : MetadataQuery(std::move(resolver), "/computeMetadata/v1/instance/zone",
                    pollent) {}

void GoogleCloud2ProdResolver::ZoneQuery::OnDone(
    GoogleCloud2ProdResolver* resolver, const grpc_http_response* response,
    grpc_error_handle error) {
  if (error != GRPC_ERROR_NONE) {
    gpr_log(GPR_ERROR, "error fetching zone from metadata server: %s",
            grpc_error_std_string(error).c_str());
  }
  std::string zone;
  if (error == GRPC_ERROR_NONE && response->status == 200) {
    absl::string_view body(response->body, response->body_length);
    size_t i = body.find_last_of('/');
    if (i == body.npos) {
      gpr_log(GPR_ERROR, "could not parse zone from metadata server: %s",
              std::string(body).c_str());
    } else {
      zone = std::string(body.substr(i + 1));
    }
  }
  resolver->ZoneQueryDone(std::move(zone));
  GRPC_ERROR_UNREF(error);
}

//
// GoogleCloud2ProdResolver::IPv6Query
//

GoogleCloud2ProdResolver::IPv6Query::IPv6Query(
    RefCountedPtr<GoogleCloud2ProdResolver> resolver,
    grpc_polling_entity* pollent)
    : MetadataQuery(std::move(resolver),
                    "/computeMetadata/v1/instance/network-interfaces/0/ipv6s",
                    pollent) {}

void GoogleCloud2ProdResolver::IPv6Query::OnDone(
    GoogleCloud2ProdResolver* resolver, const grpc_http_response* response,
    grpc_error_handle error) {
  if (error != GRPC_ERROR_NONE) {
    gpr_log(GPR_ERROR, "error fetching IPv6 address from metadata server: %s",
            grpc_error_std_string(error).c_str());
  }
  resolver->IPv6QueryDone(error == GRPC_ERROR_NONE && response->status == 200);
  GRPC_ERROR_UNREF(error);
}

//
// GoogleCloud2ProdResolver
//

GoogleCloud2ProdResolver::GoogleCloud2ProdResolver(ResolverArgs args)
    : work_serializer_(std::move(args.work_serializer)),
      pollent_(grpc_polling_entity_create_from_pollset_set(args.pollset_set)) {
  absl::string_view name_to_resolve = absl::StripPrefix(args.uri.path(), "/");
  // If we're not running on GCP, we can't use DirectPath, so delegate
  // to the DNS resolver.
  if (!grpc_alts_is_running_on_gcp() ||
      // If the client is already using xDS, we can't use it here, because
      // they may be talking to a completely different xDS server than we
      // want to.
      // TODO(roth): When we implement xDS federation, remove this constraint.
      UniquePtr<char>(gpr_getenv("GRPC_XDS_BOOTSTRAP")) != nullptr ||
      UniquePtr<char>(gpr_getenv("GRPC_XDS_BOOTSTRAP_CONFIG")) != nullptr) {
    using_dns_ = true;
    child_resolver_ = ResolverRegistry::CreateResolver(
        absl::StrCat("dns:", name_to_resolve).c_str(), args.args,
        args.pollset_set, work_serializer_, std::move(args.result_handler));
    GPR_ASSERT(child_resolver_ != nullptr);
    return;
  }
  // Create xds resolver.
  child_resolver_ = ResolverRegistry::CreateResolver(
      absl::StrCat("xds:", name_to_resolve).c_str(), args.args,
      args.pollset_set, work_serializer_, std::move(args.result_handler));
  GPR_ASSERT(child_resolver_ != nullptr);
}

void GoogleCloud2ProdResolver::StartLocked() {
  if (using_dns_) {
    child_resolver_->StartLocked();
    return;
  }
  // Using xDS.  Start metadata server queries.
  zone_query_ = MakeOrphanable<ZoneQuery>(Ref(), &pollent_);
  ipv6_query_ = MakeOrphanable<IPv6Query>(Ref(), &pollent_);
}

void GoogleCloud2ProdResolver::RequestReresolutionLocked() {
  if (child_resolver_ != nullptr) {
    child_resolver_->RequestReresolutionLocked();
  }
}

void GoogleCloud2ProdResolver::ResetBackoffLocked() {
  if (child_resolver_ != nullptr) {
    child_resolver_->ResetBackoffLocked();
  }
}

void GoogleCloud2ProdResolver::ShutdownLocked() {
  zone_query_.reset();
  ipv6_query_.reset();
  child_resolver_.reset();
}

void GoogleCloud2ProdResolver::ZoneQueryDone(std::string zone) {
  zone_query_.reset();
  zone_ = std::move(zone);
  if (supports_ipv6_.has_value()) StartXdsResolver();
}

void GoogleCloud2ProdResolver::IPv6QueryDone(bool ipv6_supported) {
  ipv6_query_.reset();
  supports_ipv6_ = ipv6_supported;
  if (zone_.has_value()) StartXdsResolver();
}

void GoogleCloud2ProdResolver::StartXdsResolver() {
  // Construct bootstrap JSON.
  Json::Object node = {
      {"id", "C2P"},
  };
  if (!zone_->empty()) {
    node["locality"] = Json::Object{
        {"zone", *zone_},
    };
  };
  if (*supports_ipv6_) {
    node["metadata"] = Json::Object{
        {"TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE", true},
    };
  }
  // Allow the TD server uri to be overridden for testing purposes.
  UniquePtr<char> override_server(
      gpr_getenv("GRPC_TEST_ONLY_GOOGLE_C2P_RESOLVER_TRAFFIC_DIRECTOR_URI"));
  const char* server_uri =
      override_server != nullptr && strlen(override_server.get()) > 0
          ? override_server.get()
          : "directpath-trafficdirector.googleapis.com";
  Json bootstrap = Json::Object{
      {"xds_servers",
       Json::Array{
           Json::Object{
               {"server_uri", server_uri},
               {"channel_creds",
                Json::Array{
                    Json::Object{
                        {"type", "google_default"},
                    },
                }},
               {"server_features", Json::Array{"xds_v3"}},
           },
       }},
      {"node", std::move(node)},
  };
  // Inject bootstrap JSON as fallback config.
  internal::SetXdsFallbackBootstrapConfig(bootstrap.Dump().c_str());
  // Now start xDS resolver.
  child_resolver_->StartLocked();
}

//
// Factory
//

class GoogleCloud2ProdResolverFactory : public ResolverFactory {
 public:
  bool IsValidUri(const URI& uri) const override {
    if (GPR_UNLIKELY(!uri.authority().empty())) {
      gpr_log(GPR_ERROR, "google-c2p URI scheme does not support authorities");
      return false;
    }
    return true;
  }

  OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
    if (!IsValidUri(args.uri)) return nullptr;
    return MakeOrphanable<GoogleCloud2ProdResolver>(std::move(args));
  }

  const char* scheme() const override { return "google-c2p"; }
};

}  // namespace

void GoogleCloud2ProdResolverInit() {
  // TODO(roth): Remove env var protection once this code is proven stable.
  UniquePtr<char> value(gpr_getenv("GRPC_EXPERIMENTAL_GOOGLE_C2P_RESOLVER"));
  bool parsed_value;
  bool parse_succeeded = gpr_parse_bool_value(value.get(), &parsed_value);
  if (parse_succeeded && parsed_value) {
    ResolverRegistry::Builder::RegisterResolverFactory(
        absl::make_unique<GoogleCloud2ProdResolverFactory>());
  }
}

void GoogleCloud2ProdResolverShutdown() {}

}  // namespace grpc_core
<|endoftext|>


<commit_before>/* Copyright 2014, Uwe L. Korn <uwelk@xhochy.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "Json.h"

// Qt version specific includes
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
    #include <QJsonDocument>
    #include <QMetaProperty>
#else
    #include <qjson/parser.h>
    #include <qjson/qobjecthelper.h>
    #include <qjson/serializer.h>
#endif

namespace QJsonWrapper
{

QVariantMap
qobject2qvariant( const QObject* object )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
    QVariantMap map;
    if ( object == NULL )
    {
        return map;
    }

    const QMetaObject* metaObject = object->metaObject();
    for ( int i = 0; i < metaObject->propertyCount(); ++i )
    {
        QMetaProperty metaproperty = metaObject->property( i );
        if ( metaproperty.isReadable() )
        {
            map[ QLatin1String( metaproperty.name() ) ] = object->property( metaproperty.name() );
        }
    }
    return map;
#else
    return QJson::QObjectHelper::qobject2qvariant( object );
#endif
}

void
qvariant2qobject( const QVariantMap& variant, QObject* object )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
    for ( QVariantMap::const_iterator iter = variant.begin(); iter != variant.end(); ++iter )
    {
        QVariant property = object->property( iter.key().toLatin1() );
        Q_ASSERT( property.isValid() );
        if ( property.isValid() )
        {
            QVariant value = iter.value();
            if ( value.canConvert( property.type() ) )
            {
                value.convert( property.type() );
                object->setProperty( iter.key().toLatin1(), value );
            } else if ( QString( QLatin1String("QVariant") ).compare( QLatin1String( property.typeName() ) ) == 0 ) {
                object->setProperty( iter.key().toLatin1(), value );
            }
        }
    }
#else
    QJson::QObjectHelper::qvariant2qobject( variant, object );
#endif
}

QVariant
parseJson( const QByteArray& jsonData, bool* ok )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson( jsonData, &error );
    if ( ok != NULL )
    {
        *ok = ( error.error == QJsonParseError::NoError );
    }
    return doc.toVariant();
#else
    QJson::Parser p;
    return p.parse( jsonData, ok );
#endif
}

QByteArray
toJson( const QVariant &variant, bool* ok )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
    QJsonDocument doc = QJsonDocument::fromVariant( variant );
    if ( ok != NULL )
    {
        *ok = true;
    }
    return doc.toJson( QJsonDocument::Compact );
#else
    QJson::Serializer serializer;
    return serializer.serialize( variant, ok );
#endif
}

}
<commit_msg>check if JsonDocument is null in JsonWrapper<commit_after>/* Copyright 2014, Uwe L. Korn <uwelk@xhochy.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "Json.h"

// Qt version specific includes
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
    #include <QJsonDocument>
    #include <QMetaProperty>
#else
    #include <qjson/parser.h>
    #include <qjson/qobjecthelper.h>
    #include <qjson/serializer.h>
#endif

namespace QJsonWrapper
{

QVariantMap
qobject2qvariant( const QObject* object )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
    QVariantMap map;
    if ( object == NULL )
    {
        return map;
    }

    const QMetaObject* metaObject = object->metaObject();
    for ( int i = 0; i < metaObject->propertyCount(); ++i )
    {
        QMetaProperty metaproperty = metaObject->property( i );
        if ( metaproperty.isReadable() )
        {
            map[ QLatin1String( metaproperty.name() ) ] = object->property( metaproperty.name() );
        }
    }
    return map;
#else
    return QJson::QObjectHelper::qobject2qvariant( object );
#endif
}

void
qvariant2qobject( const QVariantMap& variant, QObject* object )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
    for ( QVariantMap::const_iterator iter = variant.begin(); iter != variant.end(); ++iter )
    {
        QVariant property = object->property( iter.key().toLatin1() );
        Q_ASSERT( property.isValid() );
        if ( property.isValid() )
        {
            QVariant value = iter.value();
            if ( value.canConvert( property.type() ) )
            {
                value.convert( property.type() );
                object->setProperty( iter.key().toLatin1(), value );
            } else if ( QString( QLatin1String("QVariant") ).compare( QLatin1String( property.typeName() ) ) == 0 ) {
                object->setProperty( iter.key().toLatin1(), value );
            }
        }
    }
#else
    QJson::QObjectHelper::qvariant2qobject( variant, object );
#endif
}

QVariant
parseJson( const QByteArray& jsonData, bool* ok )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson( jsonData, &error );
    if ( ok != NULL )
    {
        *ok = ( error.error == QJsonParseError::NoError );
    }
    return doc.toVariant();
#else
    QJson::Parser p;
    return p.parse( jsonData, ok );
#endif
}

QByteArray
toJson( const QVariant &variant, bool* ok )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
    QJsonDocument doc = QJsonDocument::fromVariant( variant );
    if ( ok != NULL )
    {
        *ok = !doc.isNull();
    }
    return doc.toJson( QJsonDocument::Compact );
#else
    QJson::Serializer serializer;
    return serializer.serialize( variant, ok );
#endif
}

}
<|endoftext|>


<commit_before>#include "statisticspage.h"
#include "ui_statisticspage.h"
#include "main.h"
#include "wallet.h"
#include "init.h"
#include "base58.h"
#include "clientmodel.h"
#include "bitcoinrpc.h"
#include <sstream>
#include <string>

using namespace json_spirit;

StatisticsPage::StatisticsPage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::StatisticsPage)
{
    ui->setupUi(this);

    setFixedSize(400, 420);

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(timerCountDown()));
    timer->start(1000);

}

int heightPrevious = -1;
int connectionPrevious = -1;
int volumePrevious = -1;
double rewardPrevious = -1;
double netPawratePrevious = -1;
double pawratePrevious = -1;
double hardnessPrevious = -1;
double hardnessPrevious2 = -1;
int stakeminPrevious = -1;
int stakemaxPrevious = -1;
QString stakecPrevious = "";
int inc1 = 10;

void StatisticsPage::updateStatistics()
{
    double pHardness = GetDifficulty();
    double pHardness2 = GetDifficulty(GetLastBlockIndex(pindexBest, true));
    int pPawrate = GetPoWMHashPS();
    double pPawrate2 = 0.000;
    int nHeight = pindexBest->nHeight;
    double nSubsidy = 0;
    uint64_t nMinWeight = 0, nMaxWeight = 0, nWeight = 0;
    pwalletMain->GetStakeWeight(*pwalletMain, nMinWeight, nMaxWeight, nWeight);
    uint64_t nNetworkWeight = GetPoSKernelPS();
    int64 volume = ((pindexBest->nMoneySupply)/100000000);
    int peers = this->model->getNumConnections();
    pPawrate2 = (double)pPawrate;
    QString height = QString::number(nHeight);
    QString stakemin = QString::number(nMinWeight);
    QString stakemax = QString::number(nNetworkWeight);
    QString phase = "";
    phase = "Proof of Stake only";
    QString subsidy = QString::number(nSubsidy, 'f', 6);
    QString hardness = QString::number(pHardness, 'f', 6);
    QString hardness2 = QString::number(pHardness2, 'f', 6);
    QString pawrate = QString::number(pPawrate2, 'f', 3);
    QString Qlpawrate = model->getLastBlockDate().toString();

    QString QPeers = QString::number(peers);
    QString qVolume = QLocale(QLocale::English).toString(volume);

    if(nHeight > heightPrevious)
    {
        ui->heightBox->setText("" + height + "");
    } else {
    ui->heightBox->setText(height);
    }

    if(0 > stakeminPrevious)
    {
        ui->minBox->setText("" + stakemin + "");
    } else {
    ui->minBox->setText(stakemin);
    }
    if(0 > stakemaxPrevious)
    {
        ui->maxBox->setText("" + stakemax + "");
    } else {
    ui->maxBox->setText(stakemax);
    }

    if(phase != stakecPrevious)
    {
        ui->cBox->setText("" + phase + "");
    } else {
    ui->cBox->setText(phase);
    }

    if(nSubsidy < rewardPrevious)
    {
        ui->rewardBox->setText("" + subsidy + "");
    } else {
    ui->rewardBox->setText(subsidy);
    }

    if(pHardness > hardnessPrevious)
    {
        ui->diffBox->setText("" + hardness + "");
    } else if(pHardness < hardnessPrevious) {
        ui->diffBox->setText("" + hardness + "");
    } else {
        ui->diffBox->setText(hardness);
    }

    if(pHardness2 > hardnessPrevious2)
    {
        ui->diffBox2->setText("" + hardness2 + "");
    } else if(pHardness2 < hardnessPrevious2) {
        ui->diffBox2->setText("" + hardness2 + "");
    } else {
        ui->diffBox2->setText(hardness2);
    }

    if(pPawrate2 > netPawratePrevious)
    {
        ui->pawrateBox->setText("" + pawrate + " MH/s");
    } else if(pPawrate2 < netPawratePrevious) {
        ui->pawrateBox->setText("" + pawrate + " MH/s");
    } else {
        ui->pawrateBox->setText(pawrate + " MH/s");
    }

    if(Qlpawrate != pawratePrevious)
    {
        ui->localBox->setText("" + Qlpawrate + "");
    } else {
    ui->localBox->setText(Qlpawrate);
    }

    if(peers > connectionPrevious)
    {
        ui->connectionBox->setText("" + QPeers + "");
    } else if(peers < connectionPrevious) {
        ui->connectionBox->setText("" + QPeers + "");
    } else {
        ui->connectionBox->setText(QPeers);
    }

    if(volume > volumePrevious)
    {
        ui->volumeBox->setText("" + qVolume + " RBIES" + "");
    } else if(volume < volumePrevious) {
        ui->volumeBox->setText("" + qVolume + " RBIES" + "");
    } else {
        ui->volumeBox->setText(qVolume + " RBIES");
    }
    updatePrevious(nHeight, nMinWeight, nNetworkWeight, phase, nSubsidy, pHardness, pHardness2, pPawrate2, Qlpawrate, peers, volume);
}

void StatisticsPage::updatePrevious(int nHeight, int nMinWeight, int nNetworkWeight, QString phase, double nSubsidy, double pHardness, double pHardness2, double pPawrate2, QString Qlpawrate, int peers, int volume)
{
    heightPrevious = nHeight;
    stakeminPrevious = nMinWeight;
    stakemaxPrevious = nNetworkWeight;
    stakecPrevious = phase;
    rewardPrevious = nSubsidy;
    hardnessPrevious = pHardness;
    hardnessPrevious2 = pHardness2;
    netPawratePrevious = pPawrate2;
    pawratePrevious = Qlpawrate;
    connectionPrevious = peers;
    volumePrevious = volume;
}

void StatisticsPage::setModel(ClientModel *model)
{
    updateStatistics();
    this->model = model;
}

StatisticsPage::~StatisticsPage()
{
    delete ui;
}

void StatisticsPage::timerCountDown()
{
    inc1 = inc1 - 1;
    ui->labelCountDown->setText(QString::number(inc1) + "s");
    if (inc1 == 0)
    {
        updateStatistics();
        inc1 = 10;
    }
}

<commit_msg>Statistics page tweaks<commit_after>#include "statisticspage.h"
#include "ui_statisticspage.h"
#include "main.h"
#include "wallet.h"
#include "init.h"
#include "base58.h"
#include "clientmodel.h"
#include "bitcoinrpc.h"
#include <sstream>
#include <string>

using namespace json_spirit;

StatisticsPage::StatisticsPage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::StatisticsPage)
{
    ui->setupUi(this);

    setFixedSize(400, 420);

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(timerCountDown()));
    timer->start(1000);

}

int heightPrevious = -1;
int connectionPrevious = -1;
int volumePrevious = -1;
double rewardPrevious = -1;
double netPawratePrevious = -1;
double pawratePrevious = -1;
double hardnessPrevious = -1;
double hardnessPrevious2 = -1;
int stakeminPrevious = -1;
int stakemaxPrevious = -1;
QString stakecPrevious = "";
int inc1 = 10;

void StatisticsPage::updateStatistics()
{
    double pHardness = GetDifficulty();
    double pHardness2 = GetDifficulty(GetLastBlockIndex(pindexBest, true));
    int pPawrate = GetPoWMHashPS();
    double pPawrate2 = 0.000;
    int nHeight = pindexBest->nHeight;
    double nSubsidy = 0;
    uint64_t nMinWeight = 0, nMaxWeight = 0, nWeight = 0;
    pwalletMain->GetStakeWeight(*pwalletMain, nMinWeight, nMaxWeight, nWeight);
    uint64_t nNetworkWeight = GetPoSKernelPS();
    int64 volume = ((pindexBest->nMoneySupply)/100000000);
    int peers = this->model->getNumConnections();
    pPawrate2 = (double)pPawrate;
    QString height = QString::number(nHeight);
    QString stakemin = QString::number(nMinWeight);
    QString stakemax = QString::number(nNetworkWeight);
    QString phase = "";
    phase = "Proof of Stake only";
    QString subsidy = QString::number(nSubsidy, 'f', 8);
    QString hardness = QString::number(pHardness, 'f', 8);
    QString hardness2 = QString::number(pHardness2, 'f', 8);
    QString pawrate = QString::number(pPawrate2, 'f', 3);
    QString Qlpawrate = model->getLastBlockDate().toString();

    QString QPeers = QString::number(peers);
    QString qVolume = QLocale(QLocale::English).toString(volume);

    if(nHeight > heightPrevious)
    {
        ui->heightBox->setText("" + height + "");
    } else {
    ui->heightBox->setText(height);
    }

    if(0 > stakeminPrevious)
    {
        ui->minBox->setText("" + stakemin + "");
    } else {
    ui->minBox->setText(stakemin);
    }
    if(0 > stakemaxPrevious)
    {
        ui->maxBox->setText("" + stakemax + "");
    } else {
    ui->maxBox->setText(stakemax);
    }

    if(phase != stakecPrevious)
    {
        ui->cBox->setText("" + phase + "");
    } else {
    ui->cBox->setText(phase);
    }

    if(nSubsidy < rewardPrevious)
    {
        ui->rewardBox->setText("" + subsidy + "");
    } else {
    ui->rewardBox->setText(subsidy);
    }

    if(pHardness > hardnessPrevious)
    {
        ui->diffBox->setText("" + hardness + "");
    } else if(pHardness < hardnessPrevious) {
        ui->diffBox->setText("" + hardness + "");
    } else {
        ui->diffBox->setText(hardness);
    }

    if(pHardness2 > hardnessPrevious2)
    {
        ui->diffBox2->setText("" + hardness2 + "");
    } else if(pHardness2 < hardnessPrevious2) {
        ui->diffBox2->setText("" + hardness2 + "");
    } else {
        ui->diffBox2->setText(hardness2);
    }

    if(pPawrate2 > netPawratePrevious)
    {
        ui->pawrateBox->setText("" + pawrate + " MH/s");
    } else if(pPawrate2 < netPawratePrevious) {
        ui->pawrateBox->setText("" + pawrate + " MH/s");
    } else {
        ui->pawrateBox->setText(pawrate + " MH/s");
    }

    if(Qlpawrate != pawratePrevious)
    {
        ui->localBox->setText("" + Qlpawrate + "");
    } else {
    ui->localBox->setText(Qlpawrate);
    }

    if(peers > connectionPrevious)
    {
        ui->connectionBox->setText("" + QPeers + "");
    } else if(peers < connectionPrevious) {
        ui->connectionBox->setText("" + QPeers + "");
    } else {
        ui->connectionBox->setText(QPeers);
    }

    if(volume > volumePrevious)
    {
        ui->volumeBox->setText("" + qVolume + " RBIES" + "");
    } else if(volume < volumePrevious) {
        ui->volumeBox->setText("" + qVolume + " RBIES" + "");
    } else {
        ui->volumeBox->setText(qVolume + " RBIES");
    }
    updatePrevious(nHeight, nMinWeight, nNetworkWeight, phase, nSubsidy, pHardness, pHardness2, pPawrate2, Qlpawrate, peers, volume);
}

void StatisticsPage::updatePrevious(int nHeight, int nMinWeight, int nNetworkWeight, QString phase, double nSubsidy, double pHardness, double pHardness2, double pPawrate2, QString Qlpawrate, int peers, int volume)
{
    heightPrevious = nHeight;
    stakeminPrevious = nMinWeight;
    stakemaxPrevious = nNetworkWeight;
    stakecPrevious = phase;
    rewardPrevious = nSubsidy;
    hardnessPrevious = pHardness;
    hardnessPrevious2 = pHardness2;
    netPawratePrevious = pPawrate2;
    pawratePrevious = Qlpawrate;
    connectionPrevious = peers;
    volumePrevious = volume;
}

void StatisticsPage::setModel(ClientModel *model)
{
    updateStatistics();
    this->model = model;
}

StatisticsPage::~StatisticsPage()
{
    delete ui;
}

void StatisticsPage::timerCountDown()
{
    inc1 = inc1 - 1;
    ui->labelCountDown->setText(QString::number(inc1) + "s");
    if (inc1 == 0)
    {
        updateStatistics();
        inc1 = 10;
    }
}

<|endoftext|>


<commit_before>#include "qtfirebase_plugin.h"

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_ANALYTICS)
#include "src/qtfirebaseanalytics.h"
# endif // QTFIREBASE_BUILD_ANALYTICS

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_MESSAGING)
#include "src/qtfirebasemessaging.h"
# endif // QTFIREBASE_BUILD_MESSAGING

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_ADMOB)
#include "src/qtfirebaseadmob.h"
# endif // QTFIREBASE_BUILD_ADMOB

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_REMOTE_CONFIG)
#include "src/qtfirebaseremoteconfig.h"
# endif // QTFIREBASE_BUILD_REMOTE_CONFIG

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_AUTH)
#include "src/qtfirebaseauth.h"
# endif // QTFIREBASE_BUILD_AUTH

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_DATABASE)
#include "src/qtfirebasedb.h"
# endif // QTFIREBASE_BUILD_DATABASE

#include <qqml.h>

static QObject *QtFirebaseDbProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
    Q_UNUSED(engine)
    Q_UNUSED(scriptEngine)
    return qFirebaseDb;
}

void QtFirebasePlugin::registerTypes(const char *uri)
{
    // @uri QtFirebase

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_ANALYTICS)
    qmlRegisterType<QtFirebaseAnalytics>(uri, 1, 0, "Analytics");
#endif

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_MESSAGING)
    qmlRegisterType<QtFirebaseMessaging>(uri, 1, 0, "Messaging");
#endif

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_ADMOB)
    qmlRegisterType<QtFirebaseAdMob>(uri, 1, 0, "AdMob");
    qmlRegisterType<QtFirebaseAdMobRequest>(uri, 1, 0, "AdMobRequest");
    qmlRegisterType<QtFirebaseAdMobBanner>(uri, 1, 0, "AdMobBanner");
    qmlRegisterType<QtFirebaseAdMobNativeExpressAd>(uri, 1, 0, "AdMobNativeExpressAd");
    qmlRegisterType<QtFirebaseAdMobInterstitial>(uri, 1, 0, "AdMobInterstitial");
    qmlRegisterType<QtFirebaseAdMobRewardedVideoAd>(uri, 1, 0, "AdMobRewardedVideoAd");
#endif

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_REMOTE_CONFIG)
    qmlRegisterType<QtFirebaseRemoteConfig>(uri, 1, 0, "RemoteConfig");
#endif

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_AUTH)
    qmlRegisterType<QtFirebaseAuth>(uri, 1, 0, "Auth");
#endif

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_DATABASE)
    qmlRegisterSingletonType<QtFirebaseDb>(uri, 1, 0, "DataBase", QtFirebaseDbProvider);
    qmlRegisterUncreatableType<QtFirebaseDbQuery>(uri, 1, 0, "DbQuery", "Get query object from DbRequest, do not create it");
    qmlRegisterType<QtFirebaseDbRequest>(uri, 1, 0, "DbRequest");
    qmlRegisterUncreatableType<QtFirebaseDataSnapshot>(uri, 1, 0, "DataSnapshot", "Get snapshot object from DbRequest, do not create it");
#endif
}

<commit_msg>Fix plugin registration<commit_after>#include "qtfirebase_plugin.h"

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_ANALYTICS)
#include "src/qtfirebaseanalytics.h"
# endif // QTFIREBASE_BUILD_ANALYTICS

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_MESSAGING)
#include "src/qtfirebasemessaging.h"
# endif // QTFIREBASE_BUILD_MESSAGING

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_ADMOB)
#include "src/qtfirebaseadmob.h"
# endif // QTFIREBASE_BUILD_ADMOB

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_REMOTE_CONFIG)
#include "src/qtfirebaseremoteconfig.h"
# endif // QTFIREBASE_BUILD_REMOTE_CONFIG

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_AUTH)
#include "src/qtfirebaseauth.h"
# endif // QTFIREBASE_BUILD_AUTH

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_DATABASE)
#include "src/qtfirebasedatabase.h"
# endif // QTFIREBASE_BUILD_DATABASE

#include <qqml.h>

static QObject *QtFirebaseDatabaseProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
    Q_UNUSED(engine)
    Q_UNUSED(scriptEngine)
    return qFirebaseDb;
}

void QtFirebasePlugin::registerTypes(const char *uri)
{
    // @uri QtFirebase

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_ANALYTICS)
    qmlRegisterType<QtFirebaseAnalytics>(uri, 1, 0, "Analytics");
#endif

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_MESSAGING)
    qmlRegisterType<QtFirebaseMessaging>(uri, 1, 0, "Messaging");
#endif

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_ADMOB)
    qmlRegisterType<QtFirebaseAdMob>(uri, 1, 0, "AdMob");
    qmlRegisterType<QtFirebaseAdMobRequest>(uri, 1, 0, "AdMobRequest");
    qmlRegisterType<QtFirebaseAdMobBanner>(uri, 1, 0, "AdMobBanner");
    qmlRegisterType<QtFirebaseAdMobNativeExpressAd>(uri, 1, 0, "AdMobNativeExpressAd");
    qmlRegisterType<QtFirebaseAdMobInterstitial>(uri, 1, 0, "AdMobInterstitial");
    qmlRegisterType<QtFirebaseAdMobRewardedVideoAd>(uri, 1, 0, "AdMobRewardedVideoAd");
#endif

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_REMOTE_CONFIG)
    qmlRegisterType<QtFirebaseRemoteConfig>(uri, 1, 0, "RemoteConfig");
#endif

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_AUTH)
    qmlRegisterType<QtFirebaseAuth>(uri, 1, 0, "Auth");
#endif

#if defined(QTFIREBASE_BUILD_ALL) || defined(QTFIREBASE_BUILD_DATABASE)
    qmlRegisterSingletonType<QtFirebaseDatabase>(uri, 1, 0, "Database", QtFirebaseDatabaseProvider);
    qmlRegisterUncreatableType<QtFirebaseDatabaseQuery>(uri, 1, 0, "DatabaseQuery", "Get query object from DbRequest, do not create it");
    qmlRegisterType<QtFirebaseDatabaseRequest>(uri, 1, 0, "DatabaseRequest");
    qmlRegisterUncreatableType<QtFirebaseDataSnapshot>(uri, 1, 0, "DataSnapshot", "Get snapshot object from DbRequest, do not create it");
#endif
}

<|endoftext|>


<commit_before>/*
 Flexisip, a flexible SIP proxy server with media capabilities.
 Copyright (C) 2010  Belledonne Communications SARL.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as
 published by the Free Software Foundation, either version 3 of the
 License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "module.hh"
#include "agent.hh"
#include "entryfilter.hh"
#include "sofia-sip/auth_digest.h"

#include "expressionparser.hh"

#include <algorithm>
using namespace::std;

Module *ModuleInfoBase::create(Agent *ag){
	Module *mod=_create(ag);
	mod->setInfo(this);
	return mod;
}

ModuleFactory * ModuleFactory::sInstance = NULL;

ModuleFactory *ModuleFactory::get() {
	if (sInstance == NULL) {
		sInstance = new ModuleFactory();
	}
	return sInstance;
}

struct hasName {
	hasName(const string &ref) :
			match(ref) {
	}
	bool operator()(ModuleInfoBase *info) {
		return info->getModuleName() == match;
	}
	const string &match;
};

Module *ModuleFactory::createModuleInstance(Agent *ag, const string &modname) {
	list<ModuleInfoBase*>::iterator it;
	it = find_if(mModules.begin(), mModules.end(), hasName(modname));
	if (it != mModules.end()) {
		Module *m;
		ModuleInfoBase *i = *it;
		m = i->create(ag);
		LOGI("Creating module instance for [%s]", m->getModuleName().c_str());
		return m;
	}
	LOGE("Could not find any registered module with name %s", modname.c_str());
	return NULL;
}

void ModuleFactory::registerModule(ModuleInfoBase *m) {
	LOGI("Registering module %s", m->getModuleName().c_str());
	mModules.push_back(m);
}

Module::Module(Agent *ag) :
		mAgent(ag) {
	mFilter = new ConfigEntryFilter();
}

Module::~Module() {
	delete mFilter;
}

bool Module::doOnConfigStateChanged(const ConfigValue &conf, ConfigState state) {
	LOGD("Configuration of module %s changed for key %s to %s", mInfo->getModuleName().c_str(),
			conf.getName().c_str(), conf.get().c_str());
	switch (state) {
		case ConfigState::Check:
			return isValidNextConfig(conf);
		break;
		case ConfigState::Changed:
			mDirtyConfig=true;
			break;
		case ConfigState::Reset:
			mDirtyConfig=false;
			break;
		case ConfigState::Commited:
			if (mDirtyConfig) {
				LOGI("Reloading config of module %s", mInfo->getModuleName().c_str());
				reload();
				mDirtyConfig=false;
			}
			break;
		default:
			break;
	}
	return true;
}

void Module::setInfo(ModuleInfoBase *i) {
	mInfo = i;
}

Agent *Module::getAgent() const {
	return mAgent;
}

nta_agent_t *Module::getSofiaAgent()const{
	return mAgent->mAgent;
}

void Module::declare(GenericStruct *root){
	mModuleConfig=new GenericStruct("module::"+getModuleName(),mInfo->getModuleHelp(),mInfo->getOidIndex());
	mModuleConfig->setConfigListener(this);
	root->addChild(mModuleConfig);
	mFilter->declareConfig(mModuleConfig);
	onDeclare(mModuleConfig);
}

void Module::checkConfig() {
	list<GenericEntry *> children=mModuleConfig->getChildren();
	for (auto it=children.begin(); it != children.end(); ++it) {
		const ConfigValue *cv=dynamic_cast<ConfigValue *>(*it);
		if (cv && !isValidNextConfig(*cv)) {
			LOGF("Invalid config %s:%s=%s",
					getModuleName().c_str(),
					cv->getName().c_str(),
					cv->get().c_str());
		}
	}
}

void Module::load() {
	mFilter->loadConfig(mModuleConfig);
	if (mFilter->isEnabled())
		onLoad(mModuleConfig);
}

void Module::reload() {
	onUnload();
	load();
}

void Module::processRequest(shared_ptr<RequestSipEvent> &ev) {
	const shared_ptr<MsgSip> &ms = ev->getMsgSip();
	if (mFilter->canEnter(ms->getSip())) {
		LOGD("Invoking onRequest() on module %s", getModuleName().c_str());
		onRequest(ev);
	} else {
		LOGD("Skipping onRequest() on module %s", getModuleName().c_str());
	}
}

void Module::processResponse(shared_ptr<ResponseSipEvent> &ev) {
	const shared_ptr<MsgSip> &ms = ev->getMsgSip();
	if (mFilter->canEnter(ms->getSip())) {
		LOGD("Invoking onResponse() on module %s", getModuleName().c_str());
		onResponse(ev);
	} else {
		LOGD("Skipping onResponse() on module %s", getModuleName().c_str());
	}
}

void Module::processTransactionEvent(const shared_ptr<Transaction> &transaction, Transaction::Event event) {
	LOGD("Invoking onTransactionEvent() on module %s", getModuleName().c_str());
	onTransactionEvent(transaction, event);
}

void Module::idle() {
	if (mFilter->isEnabled()) {
		onIdle();
	}
}

const string &Module::getModuleName() const {
	return mInfo->getModuleName();
}

msg_auth_t *ModuleToolbox::findAuthorizationForRealm(su_home_t *home, msg_auth_t *au, const char *realm) {
	while (au!= NULL) {
		auth_response_t r;
		memset(&r, 0, sizeof(r));
		r.ar_size=sizeof(r);
		auth_digest_response_get(home, &r, au->au_params);
		LOGD("Examining auth digest response %s %s", r.ar_username, r.ar_realm);
		if (strcasecmp(r.ar_realm, realm) ==0) {
			LOGD("Right realm found : %s", r.ar_realm);
			return au;
		}
		au=au->au_next;
	}
	LOGD("authorization with right realm not found");
	return NULL;
}

bool ModuleToolbox::sipPortEquals(const char *p1, const char *p2){
	int n1,n2;
	n1=n2=5060;
	if (p1 && p1[0]!='\0')
		n1=atoi(p1);
	if (p2 && p2[0]!='\0')
		n2=atoi(p2);
	return n1==n2;
}

int ModuleToolbox::sipPortToInt(const char *port){
	if (port==NULL || port[0]=='\0') return 5060;
	else return atoi(port);
}

void ModuleToolbox::prependRoute(su_home_t *home, Agent *ag, msg_t *msg, sip_t *sip, const char *route){
	// removes top route headers if they matches us
	sip_route_t *r;
	r = sip_route_format(home, "%s", route);
	while (sip->sip_route != NULL && ag->isUs(sip->sip_route->r_url)) {
		sip_route_remove(msg, sip);
	}
	r->r_next = sip->sip_route;
	msg_header_remove_all(msg, (msg_pub_t*) sip, (msg_header_t*) sip->sip_route);
	msg_header_insert(msg, (msg_pub_t*) sip, (msg_header_t*) r);
	sip->sip_route = r;
}

void ModuleToolbox::addRecordRoute(su_home_t *home, Agent *ag, msg_t *msg, sip_t *sip, const char *transport) {
	sip_via_t *via = sip->sip_via;
	sip_record_route_t *rr;
	char lower_tport[16]={0};
	bool transport_given = (transport != NULL);

	if (transport == NULL)
		transport = sip_via_transport(via);

	for(int i=0;transport[i]!='\0';i++){
		lower_tport[i]=tolower(transport[i]);
	}

	if (strcasecmp(transport,"TLS")==0){
		int port = ag->getTlsPort();
		if (port != 5061) {
			rr = sip_record_route_format(home, "<sips:%s:%i;lr;transport=%s>", ag->getPublicIp().c_str(), port, lower_tport);
		} else {
			rr = sip_record_route_format(home, "<sips:%s;lr;transport=%s>", ag->getPublicIp().c_str(), lower_tport);
		}
	}
	else if (strcasecmp(transport, "UDP") != 0) {
		int port = ag->getPort();
		if (port != 5060) {
			rr = sip_record_route_format(home, "<sip:%s:%i;lr;transport=%s>", ag->getPublicIp().c_str(), port, lower_tport);
		} else {
			rr = sip_record_route_format(home, "<sip:%s;lr;transport=%s>", ag->getPublicIp().c_str(), lower_tport);
		}
	} else {
		if (ag->getPort() != 5060) {
			rr = sip_record_route_format(home, "<sip:%s:%i;lr>", ag->getPublicIp().c_str(), ag->getPort());
		} else {
			rr = sip_record_route_format(home, "<sip:%s;lr>", ag->getPublicIp().c_str());
		}
	}
	if (sip->sip_record_route == NULL) {
		sip->sip_record_route = rr;
	} else {
		/*make sure we are not already in*/
		if (!transport_given && sip->sip_record_route && ag->isUs(sip->sip_record_route->r_url, false))
			return;
		rr->r_next = sip->sip_record_route;
		msg_header_remove_all(msg, (msg_pub_t*) sip, (msg_header_t*) sip->sip_record_route);
		msg_header_insert(msg, (msg_pub_t*) sip, (msg_header_t*) rr);
		sip->sip_record_route = rr;
	}
}

bool ModuleToolbox::fromMatch(const sip_from_t *from1, const sip_from_t *from2) {
	if (url_cmp(from1->a_url, from2->a_url) == 0) {
		if (from1->a_tag && from2->a_tag && strcmp(from1->a_tag, from2->a_tag) == 0)
			return true;
		if (from1->a_tag == NULL && from2->a_tag == NULL)
			return true;
	}
	return false;
}

bool ModuleToolbox::matchesOneOf(const char *item, const list<string> &set) {
	list<string>::const_iterator it;
	for (it = set.begin(); it != set.end(); ++it) {
		const char *tmp = (*it).c_str();
		if (tmp[0] == '*') {
			/*the wildcard matches everything*/
			return true;
		} else {
			if (strcmp(item, tmp) == 0)
				return true;
		}
	}
	return false;
}

bool ModuleToolbox::fixAuthChallengeForSDP(su_home_t *home, msg_t *msg, sip_t *sip) {
	sip_auth_t *auth;
	msg_param_t *par;
	auth = sip->sip_www_authenticate;
	if (auth == NULL)
		auth = sip->sip_proxy_authenticate;
	if (auth == NULL)
		return true;
	if (auth->au_params == NULL)
		return true;
	par = msg_params_find_slot((msg_param_t*) auth->au_params, "qop");
	if (par != NULL) {
		if (strstr(*par, "auth-int")) {
			LOGD("Authentication header has qop with 'auth-int', replacing by 'auth'");
			//if the qop contains "auth-int", replace it by "auth" so that it allows to modify the SDP
			*par = su_strdup(home, "qop=\"auth\"");
		}
	}
	return true;
}

bool ModuleToolbox::transportEquals(const char *tr1, const char *tr2) {
	if (tr1 == NULL || tr1[0] == 0)
		tr1 = "UDP";
	if (tr2 == NULL || tr2[0] == 0)
		tr2 = "UDP";
	return strcasecmp(tr1, tr2) == 0;
}

<commit_msg>Improve logs in module tool for realm search<commit_after>/*
 Flexisip, a flexible SIP proxy server with media capabilities.
 Copyright (C) 2010  Belledonne Communications SARL.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as
 published by the Free Software Foundation, either version 3 of the
 License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "module.hh"
#include "agent.hh"
#include "entryfilter.hh"
#include "sofia-sip/auth_digest.h"

#include "expressionparser.hh"

#include <algorithm>
using namespace::std;

Module *ModuleInfoBase::create(Agent *ag){
	Module *mod=_create(ag);
	mod->setInfo(this);
	return mod;
}

ModuleFactory * ModuleFactory::sInstance = NULL;

ModuleFactory *ModuleFactory::get() {
	if (sInstance == NULL) {
		sInstance = new ModuleFactory();
	}
	return sInstance;
}

struct hasName {
	hasName(const string &ref) :
			match(ref) {
	}
	bool operator()(ModuleInfoBase *info) {
		return info->getModuleName() == match;
	}
	const string &match;
};

Module *ModuleFactory::createModuleInstance(Agent *ag, const string &modname) {
	list<ModuleInfoBase*>::iterator it;
	it = find_if(mModules.begin(), mModules.end(), hasName(modname));
	if (it != mModules.end()) {
		Module *m;
		ModuleInfoBase *i = *it;
		m = i->create(ag);
		LOGI("Creating module instance for [%s]", m->getModuleName().c_str());
		return m;
	}
	LOGE("Could not find any registered module with name %s", modname.c_str());
	return NULL;
}

void ModuleFactory::registerModule(ModuleInfoBase *m) {
	LOGI("Registering module %s", m->getModuleName().c_str());
	mModules.push_back(m);
}

Module::Module(Agent *ag) :
		mAgent(ag) {
	mFilter = new ConfigEntryFilter();
}

Module::~Module() {
	delete mFilter;
}

bool Module::doOnConfigStateChanged(const ConfigValue &conf, ConfigState state) {
	LOGD("Configuration of module %s changed for key %s to %s", mInfo->getModuleName().c_str(),
			conf.getName().c_str(), conf.get().c_str());
	switch (state) {
		case ConfigState::Check:
			return isValidNextConfig(conf);
		break;
		case ConfigState::Changed:
			mDirtyConfig=true;
			break;
		case ConfigState::Reset:
			mDirtyConfig=false;
			break;
		case ConfigState::Commited:
			if (mDirtyConfig) {
				LOGI("Reloading config of module %s", mInfo->getModuleName().c_str());
				reload();
				mDirtyConfig=false;
			}
			break;
		default:
			break;
	}
	return true;
}

void Module::setInfo(ModuleInfoBase *i) {
	mInfo = i;
}

Agent *Module::getAgent() const {
	return mAgent;
}

nta_agent_t *Module::getSofiaAgent()const{
	return mAgent->mAgent;
}

void Module::declare(GenericStruct *root){
	mModuleConfig=new GenericStruct("module::"+getModuleName(),mInfo->getModuleHelp(),mInfo->getOidIndex());
	mModuleConfig->setConfigListener(this);
	root->addChild(mModuleConfig);
	mFilter->declareConfig(mModuleConfig);
	onDeclare(mModuleConfig);
}

void Module::checkConfig() {
	list<GenericEntry *> children=mModuleConfig->getChildren();
	for (auto it=children.begin(); it != children.end(); ++it) {
		const ConfigValue *cv=dynamic_cast<ConfigValue *>(*it);
		if (cv && !isValidNextConfig(*cv)) {
			LOGF("Invalid config %s:%s=%s",
					getModuleName().c_str(),
					cv->getName().c_str(),
					cv->get().c_str());
		}
	}
}

void Module::load() {
	mFilter->loadConfig(mModuleConfig);
	if (mFilter->isEnabled())
		onLoad(mModuleConfig);
}

void Module::reload() {
	onUnload();
	load();
}

void Module::processRequest(shared_ptr<RequestSipEvent> &ev) {
	const shared_ptr<MsgSip> &ms = ev->getMsgSip();
	if (mFilter->canEnter(ms->getSip())) {
		LOGD("Invoking onRequest() on module %s", getModuleName().c_str());
		onRequest(ev);
	} else {
		LOGD("Skipping onRequest() on module %s", getModuleName().c_str());
	}
}

void Module::processResponse(shared_ptr<ResponseSipEvent> &ev) {
	const shared_ptr<MsgSip> &ms = ev->getMsgSip();
	if (mFilter->canEnter(ms->getSip())) {
		LOGD("Invoking onResponse() on module %s", getModuleName().c_str());
		onResponse(ev);
	} else {
		LOGD("Skipping onResponse() on module %s", getModuleName().c_str());
	}
}

void Module::processTransactionEvent(const shared_ptr<Transaction> &transaction, Transaction::Event event) {
	LOGD("Invoking onTransactionEvent() on module %s", getModuleName().c_str());
	onTransactionEvent(transaction, event);
}

void Module::idle() {
	if (mFilter->isEnabled()) {
		onIdle();
	}
}

const string &Module::getModuleName() const {
	return mInfo->getModuleName();
}

msg_auth_t *ModuleToolbox::findAuthorizationForRealm(su_home_t *home, msg_auth_t *au, const char *realm) {
	while (au!= NULL) {
		auth_response_t r;
		memset(&r, 0, sizeof(r));
		r.ar_size=sizeof(r);
		auth_digest_response_get(home, &r, au->au_params);
		LOGD("Examining auth digest response %s %s", r.ar_username, r.ar_realm);
		if (strcasecmp(r.ar_realm, realm) ==0) {
			LOGD("Expected realm found : %s", r.ar_realm);
			return au;
		}
		au=au->au_next;
	}
	LOGD("authorization with expected realm '%s' not found", realm);
	return NULL;
}

bool ModuleToolbox::sipPortEquals(const char *p1, const char *p2){
	int n1,n2;
	n1=n2=5060;
	if (p1 && p1[0]!='\0')
		n1=atoi(p1);
	if (p2 && p2[0]!='\0')
		n2=atoi(p2);
	return n1==n2;
}

int ModuleToolbox::sipPortToInt(const char *port){
	if (port==NULL || port[0]=='\0') return 5060;
	else return atoi(port);
}

void ModuleToolbox::prependRoute(su_home_t *home, Agent *ag, msg_t *msg, sip_t *sip, const char *route){
	// removes top route headers if they matches us
	sip_route_t *r;
	r = sip_route_format(home, "%s", route);
	while (sip->sip_route != NULL && ag->isUs(sip->sip_route->r_url)) {
		sip_route_remove(msg, sip);
	}
	r->r_next = sip->sip_route;
	msg_header_remove_all(msg, (msg_pub_t*) sip, (msg_header_t*) sip->sip_route);
	msg_header_insert(msg, (msg_pub_t*) sip, (msg_header_t*) r);
	sip->sip_route = r;
}

void ModuleToolbox::addRecordRoute(su_home_t *home, Agent *ag, msg_t *msg, sip_t *sip, const char *transport) {
	sip_via_t *via = sip->sip_via;
	sip_record_route_t *rr;
	char lower_tport[16]={0};
	bool transport_given = (transport != NULL);

	if (transport == NULL)
		transport = sip_via_transport(via);

	for(int i=0;transport[i]!='\0';i++){
		lower_tport[i]=tolower(transport[i]);
	}

	if (strcasecmp(transport,"TLS")==0){
		int port = ag->getTlsPort();
		if (port != 5061) {
			rr = sip_record_route_format(home, "<sips:%s:%i;lr;transport=%s>", ag->getPublicIp().c_str(), port, lower_tport);
		} else {
			rr = sip_record_route_format(home, "<sips:%s;lr;transport=%s>", ag->getPublicIp().c_str(), lower_tport);
		}
	}
	else if (strcasecmp(transport, "UDP") != 0) {
		int port = ag->getPort();
		if (port != 5060) {
			rr = sip_record_route_format(home, "<sip:%s:%i;lr;transport=%s>", ag->getPublicIp().c_str(), port, lower_tport);
		} else {
			rr = sip_record_route_format(home, "<sip:%s;lr;transport=%s>", ag->getPublicIp().c_str(), lower_tport);
		}
	} else {
		if (ag->getPort() != 5060) {
			rr = sip_record_route_format(home, "<sip:%s:%i;lr>", ag->getPublicIp().c_str(), ag->getPort());
		} else {
			rr = sip_record_route_format(home, "<sip:%s;lr>", ag->getPublicIp().c_str());
		}
	}
	if (sip->sip_record_route == NULL) {
		sip->sip_record_route = rr;
	} else {
		/*make sure we are not already in*/
		if (!transport_given && sip->sip_record_route && ag->isUs(sip->sip_record_route->r_url, false))
			return;
		rr->r_next = sip->sip_record_route;
		msg_header_remove_all(msg, (msg_pub_t*) sip, (msg_header_t*) sip->sip_record_route);
		msg_header_insert(msg, (msg_pub_t*) sip, (msg_header_t*) rr);
		sip->sip_record_route = rr;
	}
}

bool ModuleToolbox::fromMatch(const sip_from_t *from1, const sip_from_t *from2) {
	if (url_cmp(from1->a_url, from2->a_url) == 0) {
		if (from1->a_tag && from2->a_tag && strcmp(from1->a_tag, from2->a_tag) == 0)
			return true;
		if (from1->a_tag == NULL && from2->a_tag == NULL)
			return true;
	}
	return false;
}

bool ModuleToolbox::matchesOneOf(const char *item, const list<string> &set) {
	list<string>::const_iterator it;
	for (it = set.begin(); it != set.end(); ++it) {
		const char *tmp = (*it).c_str();
		if (tmp[0] == '*') {
			/*the wildcard matches everything*/
			return true;
		} else {
			if (strcmp(item, tmp) == 0)
				return true;
		}
	}
	return false;
}

bool ModuleToolbox::fixAuthChallengeForSDP(su_home_t *home, msg_t *msg, sip_t *sip) {
	sip_auth_t *auth;
	msg_param_t *par;
	auth = sip->sip_www_authenticate;
	if (auth == NULL)
		auth = sip->sip_proxy_authenticate;
	if (auth == NULL)
		return true;
	if (auth->au_params == NULL)
		return true;
	par = msg_params_find_slot((msg_param_t*) auth->au_params, "qop");
	if (par != NULL) {
		if (strstr(*par, "auth-int")) {
			LOGD("Authentication header has qop with 'auth-int', replacing by 'auth'");
			//if the qop contains "auth-int", replace it by "auth" so that it allows to modify the SDP
			*par = su_strdup(home, "qop=\"auth\"");
		}
	}
	return true;
}

bool ModuleToolbox::transportEquals(const char *tr1, const char *tr2) {
	if (tr1 == NULL || tr1[0] == 0)
		tr1 = "UDP";
	if (tr2 == NULL || tr2[0] == 0)
		tr2 = "UDP";
	return strcasecmp(tr1, tr2) == 0;
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: connection.hpp 17 2005-03-08 23:58:43Z pavlenko $

#ifndef CONNECTION_HPP
#define CONNECTION_HPP

#include <mapnik/datasource.hpp>

extern "C"
{
#include "libpq-fe.h"
}

#include "resultset.hpp"

class ResultSet;
class Connection
{
   private:
      PGconn *conn_;
      int cursorId;
      bool closed_;
   public:
      Connection(std::string const& connection_str)
         :cursorId(0),
         closed_(false)
      {
         conn_=PQconnectdb(connection_str.c_str());
         if (PQstatus(conn_) != CONNECTION_OK)
         {
             std::ostringstream s("Postgis Plugin: PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s << ":\n" << msg.substr( 0, msg.size() - 1 );
                 }
             }
             throw mapnik::datasource_exception( s.str() );
         }
      }

      bool execute(const std::string& sql) const
      {
         PGresult *result=PQexec(conn_,sql.c_str());
         bool ok=(result && PQresultStatus(result)==PGRES_COMMAND_OK);
         PQclear(result);
         return ok;
      }

      boost::shared_ptr<ResultSet> executeQuery(const std::string& sql,int type=0) const
      {
         PGresult *result=0;
         if (type==1)
         {
             result=PQexecParams(conn_,sql.c_str(),0,0,0,0,0,1);
         }
         else
         {
             result=PQexec(conn_,sql.c_str());
         }
         if(!result || PQresultStatus(result) != PGRES_TUPLES_OK)
         {
             std::ostringstream s("Postgis Plugin: PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s << ":\n" <<  msg.substr( 0, msg.size() - 1 );
                 }

                 s << "\nFull sql was: '" <<  sql << "'\n";
             }
             throw mapnik::datasource_exception( s.str() );
         }

         return boost::shared_ptr<ResultSet>(new ResultSet(result));
      }

      std::string client_encoding() const
      {
         return PQparameterStatus(conn_,"client_encoding");
      }

      bool isOK() const
      {
         return (PQstatus(conn_)!=CONNECTION_BAD);
      }

      void close()
      {
         if (!closed_)
         {
             PQfinish(conn_);
#ifdef MAPNIK_DEBUG
             std::clog << "PostGIS: datasource closed, also closing connection - " << conn_ << std::endl;
#endif
             closed_ = true;
         }
      }

      std::string new_cursor_name()
      {
          std::ostringstream s;
          s << "mapnik_" << (cursorId++);
          return s.str();
      }

      ~Connection()
      {
         if (!closed_)
         {
             PQfinish(conn_);
#ifdef MAPNIK_DEBUG
             std::clog << "PostGIS: postgresql connection closed - " << conn_ << std::endl;
#endif
             closed_ = true;
         }
      }
};

#endif //CONNECTION_HPP
<commit_msg>postgis: clear the result before throwing<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

//$Id: connection.hpp 17 2005-03-08 23:58:43Z pavlenko $

#ifndef CONNECTION_HPP
#define CONNECTION_HPP

#include <mapnik/datasource.hpp>

extern "C"
{
#include "libpq-fe.h"
}

#include "resultset.hpp"

class ResultSet;
class Connection
{
   private:
      PGconn *conn_;
      int cursorId;
      bool closed_;
   public:
      Connection(std::string const& connection_str)
         :cursorId(0),
         closed_(false)
      {
         conn_=PQconnectdb(connection_str.c_str());
         if (PQstatus(conn_) != CONNECTION_OK)
         {
             std::ostringstream s("Postgis Plugin: PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s << ":\n" << msg.substr( 0, msg.size() - 1 );
                 }
             }
             throw mapnik::datasource_exception( s.str() );
         }
      }

      bool execute(const std::string& sql) const
      {
         PGresult *result=PQexec(conn_,sql.c_str());
         bool ok=(result && PQresultStatus(result)==PGRES_COMMAND_OK);
         PQclear(result);
         return ok;
      }

      boost::shared_ptr<ResultSet> executeQuery(const std::string& sql,int type=0) const
      {
         PGresult *result=0;
         if (type==1)
         {
             result=PQexecParams(conn_,sql.c_str(),0,0,0,0,0,1);
         }
         else
         {
             result=PQexec(conn_,sql.c_str());
         }
         if(!result || PQresultStatus(result) != PGRES_TUPLES_OK)
         {
             std::ostringstream s("Postgis Plugin: PSQL error");
             if (conn_ )
             {
                 std::string msg = PQerrorMessage( conn_ );
                 if ( ! msg.empty() )
                 {
                     s << ":\n" <<  msg.substr( 0, msg.size() - 1 );
                 }

                 s << "\nFull sql was: '" <<  sql << "'\n";
             }
             if (result)
                 PQclear(result);
             throw mapnik::datasource_exception( s.str() );
         }

         return boost::shared_ptr<ResultSet>(new ResultSet(result));
      }

      std::string client_encoding() const
      {
         return PQparameterStatus(conn_,"client_encoding");
      }

      bool isOK() const
      {
         return (PQstatus(conn_)!=CONNECTION_BAD);
      }

      void close()
      {
         if (!closed_)
         {
             PQfinish(conn_);
#ifdef MAPNIK_DEBUG
             std::clog << "PostGIS: datasource closed, also closing connection - " << conn_ << std::endl;
#endif
             closed_ = true;
         }
      }

      std::string new_cursor_name()
      {
          std::ostringstream s;
          s << "mapnik_" << (cursorId++);
          return s.str();
      }

      ~Connection()
      {
         if (!closed_)
         {
             PQfinish(conn_);
#ifdef MAPNIK_DEBUG
             std::clog << "PostGIS: postgresql connection closed - " << conn_ << std::endl;
#endif
             closed_ = true;
         }
      }
};

#endif //CONNECTION_HPP
<|endoftext|>


<commit_before>#include "ofApp.h"
#include "ofxArgParser.h"

//--------------------------------------------------------------
void ofApp::setup(){
	// Global settings.
	ofSetWindowTitle("Presenter");
	ofSetVerticalSync(true);
	ofEnableSmoothing();
	ofSetFrameRate(60);

	// Position the window in the centre of the screen.
	ofSetWindowPosition((ofGetScreenWidth() - ofGetWindowWidth()) / 2, (ofGetScreenHeight() - ofGetWindowHeight()) / 2);

	// Set status to Welcome screen.
	status = PRESENTER_STATUS_WELCOME;

	// Load logo for welcome screen.
	logo.load("logo.png");
	if(logo.getWidth()>1000){
		logo.resize(1000, logo.getHeight() / logo.getWidth() * 1000);
	}

	// Setup Menu.
	menu = new Menu();
	ofAddListener(menu->onMenuClick, this, &ofApp::menuClick);

#if defined(TARGET_RASPBERRY_PI)
	ofHideCursor();
#else
	// Pars Command Line Arguments
	if (ofxArgParser::hasKey("presentation")) {
		// Load Presentation
		menuClick(ofxArgParser::getValue("presentation"));
	}
#endif

	// Setup Key Press detection
	ofAddListener(ofGetWindowPtr()->events().keyPressed, this, &ofApp::keycodePressed);

}

void ofApp::menuClick(string &path){
	// load presentation xml file.
	presentation = new Presentation(path);

	// set the status and hide the gui on welcome screen.
	status = PRESENTER_STATUS_PRESENTATION;
#if !defined(TARGET_RASPBERRY_PI)
	ofHideCursor();
#endif
	menu->hide();

	// cout << name << endl;
}

//--------------------------------------------------------------
void ofApp::update(){
	if(status == PRESENTER_STATUS_WELCOME){

	} else if (status == PRESENTER_STATUS_PRESENTATION){
		if(presentation != NULL){
			presentation->update();
		}
	}
}

//--------------------------------------------------------------
void ofApp::draw(){
	if(status == PRESENTER_STATUS_WELCOME){
		// White background
		ofSetColor(ofColor::white);
		ofBackground(ofColor::white);

		// LUKE Theatre Group logo
		logo.draw(100,(ofGetHeight() - logo.getHeight())/2);

		// Presenter version
		ofSetColor(ofColor(ofColor::dimGrey));
		ofDrawBitmapString("2.0.0", ofGetWidth() - 100, ofGetHeight() - 100);
	} else if (status == PRESENTER_STATUS_PRESENTATION){
		if(presentation != NULL){
			presentation->draw();
		}
	}
}

//--------------------------------------------------------------
void ofApp::exit()
{
    delete menu;

}

void ofApp::endPresentation(){
	status = PRESENTER_STATUS_WELCOME;
#if !defined(TARGET_RASPBERRY_PI)
	ofShowCursor();
#endif
	menu->unhide();
	delete presentation;
	presentation = NULL;
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key)
{

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::keycodePressed(ofKeyEventArgs& e) {
	//cout << "KEY: " << ofToString(e.key) << endl;

#if defined(TARGET_RASPBERRY_PI)
	// Check if Ctrl key is pressed
	if (e.hasModifier(OF_KEY_CONTROL)) {
		// Check for Q (ctrl + q)
		if (e.key == 17) {
			// Shutdown the system
			cout << "SHUTDOWN" << endl;
			system("shutdown now");
		}

		// Check for R (ctrl + r)
		if (e.key == 18) {
			// Reboot system
			cout << "REBOOT" << endl;
			system("shutdown -r now");
		}

	}
#endif

	switch (e.key)
	{
	case 'x':
		if (status == PRESENTER_STATUS_PRESENTATION) {
			presentation->exit();
			endPresentation();
		}
		break;
	case OF_KEY_RIGHT:
		if (status == PRESENTER_STATUS_PRESENTATION) {
			if (presentation->next() == 0) {
				endPresentation();
			}
		}
		break;
	case OF_KEY_LEFT:
		if (status == PRESENTER_STATUS_PRESENTATION) {
			if (presentation->previous() == 0) {
				endPresentation();
			}
		}
		break;
	default:
		break;
	}

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
	switch (button)
    {
		case OF_MOUSE_BUTTON_RIGHT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->next()==0){
					endPresentation();
				}
			}
            break;
		case OF_MOUSE_BUTTON_LEFT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->previous()==0){
					endPresentation();
				}
			}
            break;
        default:
            break;
    }
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<commit_msg>Release 2.0.1<commit_after>#include "ofApp.h"
#include "ofxArgParser.h"

//--------------------------------------------------------------
void ofApp::setup(){
	// Global settings.
	ofSetWindowTitle("Presenter");
	ofSetVerticalSync(true);
	ofEnableSmoothing();
	ofSetFrameRate(60);

	// Position the window in the centre of the screen.
	ofSetWindowPosition((ofGetScreenWidth() - ofGetWindowWidth()) / 2, (ofGetScreenHeight() - ofGetWindowHeight()) / 2);

	// Set status to Welcome screen.
	status = PRESENTER_STATUS_WELCOME;

	// Load logo for welcome screen.
	logo.load("logo.png");
	if(logo.getWidth()>1000){
		logo.resize(1000, logo.getHeight() / logo.getWidth() * 1000);
	}

	// Setup Menu.
	menu = new Menu();
	ofAddListener(menu->onMenuClick, this, &ofApp::menuClick);

#if defined(TARGET_RASPBERRY_PI)
	ofHideCursor();
#else
	// Pars Command Line Arguments
	if (ofxArgParser::hasKey("presentation")) {
		// Load Presentation
		menuClick(ofxArgParser::getValue("presentation"));
	}
#endif

	// Setup Key Press detection
	ofAddListener(ofGetWindowPtr()->events().keyPressed, this, &ofApp::keycodePressed);

}

void ofApp::menuClick(string &path){
	// load presentation xml file.
	presentation = new Presentation(path);

	// set the status and hide the gui on welcome screen.
	status = PRESENTER_STATUS_PRESENTATION;
#if !defined(TARGET_RASPBERRY_PI)
	ofHideCursor();
#endif
	menu->hide();

	// cout << name << endl;
}

//--------------------------------------------------------------
void ofApp::update(){
	if(status == PRESENTER_STATUS_WELCOME){

	} else if (status == PRESENTER_STATUS_PRESENTATION){
		if(presentation != NULL){
			presentation->update();
		}
	}
}

//--------------------------------------------------------------
void ofApp::draw(){
	if(status == PRESENTER_STATUS_WELCOME){
		// White background
		ofSetColor(ofColor::white);
		ofBackground(ofColor::white);

		// LUKE Theatre Group logo
		logo.draw(100,(ofGetHeight() - logo.getHeight())/2);

		// Presenter version
		ofSetColor(ofColor(ofColor::dimGrey));
		ofDrawBitmapString("2.0.1", ofGetWidth() - 100, ofGetHeight() - 100);
	} else if (status == PRESENTER_STATUS_PRESENTATION){
		if(presentation != NULL){
			presentation->draw();
		}
	}
}

//--------------------------------------------------------------
void ofApp::exit()
{
    delete menu;

}

void ofApp::endPresentation(){
	status = PRESENTER_STATUS_WELCOME;
#if !defined(TARGET_RASPBERRY_PI)
	ofShowCursor();
#endif
	menu->unhide();
	delete presentation;
	presentation = NULL;
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key)
{

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::keycodePressed(ofKeyEventArgs& e) {
	//cout << "KEY: " << ofToString(e.key) << endl;

#if defined(TARGET_RASPBERRY_PI)
	// Check if Ctrl key is pressed
	if (e.hasModifier(OF_KEY_CONTROL)) {
		// Check for Q (ctrl + q)
		if (e.key == 17) {
			// Shutdown the system
			cout << "SHUTDOWN" << endl;
			system("shutdown now");
		}

		// Check for R (ctrl + r)
		if (e.key == 18) {
			// Reboot system
			cout << "REBOOT" << endl;
			system("shutdown -r now");
		}

	}
#endif

	switch (e.key)
	{
	case 'x':
		if (status == PRESENTER_STATUS_PRESENTATION) {
			presentation->exit();
			endPresentation();
		}
		break;
	case OF_KEY_RIGHT:
		if (status == PRESENTER_STATUS_PRESENTATION) {
			if (presentation->next() == 0) {
				endPresentation();
			}
		}
		break;
	case OF_KEY_LEFT:
		if (status == PRESENTER_STATUS_PRESENTATION) {
			if (presentation->previous() == 0) {
				endPresentation();
			}
		}
		break;
	default:
		break;
	}

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
	switch (button)
    {
		case OF_MOUSE_BUTTON_RIGHT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->next()==0){
					endPresentation();
				}
			}
            break;
		case OF_MOUSE_BUTTON_LEFT:
			if (status == PRESENTER_STATUS_PRESENTATION){
				if(presentation->previous()==0){
					endPresentation();
				}
			}
            break;
        default:
            break;
    }
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <set>
#include <string>
#include <iostream>
#include <unistd.h>
#include "Compile.h"
#include "Parser.h"

int run_on_bash(std::istream &is) {
    FILE *bash = popen("bash", "w");
    char buf[4096];

    do {
        is.read(buf, sizeof(buf));
        fwrite(buf, 1, is.gcount(), bash);
    } while (is.gcount() > 0);

    fflush(bash);

    // pclose returns the exit status of the process,
    // but shifted to the left by 8 bits.
    int e = pclose(bash) >> 8;
    return e;
}

void usage(char *argv0) {
    std::cerr << "USAGE: " << argv0 << " [-r] <INPUT>\n";
    std::cerr << "  Compiles Bish file <INPUT> to bash.\n";
    std::cerr << "\nOPTIONS:\n";
    std::cerr << "  -r: compiles and runs the file.\n";
}

int main(int argc, char **argv) {
    if (argc < 2) {
        usage(argv[0]);
        return 1;
    }

    int c;
    bool run_after_compile = false;
    while ((c = getopt(argc,argv, "r")) != -1) {
        switch (c) {
        case 'r':
            run_after_compile = true;
            break;
        default:
            break;
        }
    }

    if (optind == argc && run_after_compile) {
        std::cerr << "-r needs a filename" << std::endl;
        return 1;
    }

    std::string path(argv[optind]);
    Bish::Parser p;
    Bish::Module *m = p.parse(path);

    std::stringstream s;
    Bish::compile_to_bash(run_after_compile ? s : std::cout, m);
    if (run_after_compile) {
        int exit_status = 0;
        exit_status = run_on_bash(s);
        exit(exit_status);
    }

    return 0;
}
<commit_msg>Condense definition and setting of exit_status<commit_after>#include <stdio.h>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <set>
#include <string>
#include <iostream>
#include <unistd.h>
#include "Compile.h"
#include "Parser.h"

int run_on_bash(std::istream &is) {
    FILE *bash = popen("bash", "w");
    char buf[4096];

    do {
        is.read(buf, sizeof(buf));
        fwrite(buf, 1, is.gcount(), bash);
    } while (is.gcount() > 0);

    fflush(bash);

    // pclose returns the exit status of the process,
    // but shifted to the left by 8 bits.
    int e = pclose(bash) >> 8;
    return e;
}

void usage(char *argv0) {
    std::cerr << "USAGE: " << argv0 << " [-r] <INPUT>\n";
    std::cerr << "  Compiles Bish file <INPUT> to bash.\n";
    std::cerr << "\nOPTIONS:\n";
    std::cerr << "  -r: compiles and runs the file.\n";
}

int main(int argc, char **argv) {
    if (argc < 2) {
        usage(argv[0]);
        return 1;
    }

    int c;
    bool run_after_compile = false;
    while ((c = getopt(argc,argv, "r")) != -1) {
        switch (c) {
        case 'r':
            run_after_compile = true;
            break;
        default:
            break;
        }
    }

    if (optind == argc && run_after_compile) {
        std::cerr << "-r needs a filename" << std::endl;
        return 1;
    }

    std::string path(argv[optind]);
    Bish::Parser p;
    Bish::Module *m = p.parse(path);

    std::stringstream s;
    Bish::compile_to_bash(run_after_compile ? s : std::cout, m);
    if (run_after_compile) {
        int exit_status = run_on_bash(s);
        exit(exit_status);
    }

    return 0;
}
<|endoftext|>