<commit_before>#include "llvm/ADT/Triple.h"
#include "llvm/ExecutionEngine/Orc/CloneSubModule.h"
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/IRBuilder.h"
#include <set>

using namespace llvm;

namespace llvm {
namespace orc {

GlobalVariable* createImplPointer(Function &F, const Twine &Name,
                                  Constant *Initializer) {
  assert(F.getParent() && "Function isn't in a module.");
  if (!Initializer)
    Initializer = Constant::getNullValue(F.getType());
  Module &M = *F.getParent();
  return new GlobalVariable(M, F.getType(), false, GlobalValue::ExternalLinkage,
                            Initializer, Name, nullptr,
                            GlobalValue::NotThreadLocal, 0, true);
}

void makeStub(Function &F, GlobalVariable &ImplPointer) {
  assert(F.isDeclaration() && "Can't turn a definition into a stub.");
  assert(F.getParent() && "Function isn't in a module.");
  Module &M = *F.getParent();
  BasicBlock *EntryBlock = BasicBlock::Create(M.getContext(), "entry", &F);
  IRBuilder<> Builder(EntryBlock);
  LoadInst *ImplAddr = Builder.CreateLoad(&ImplPointer);
  std::vector<Value*> CallArgs;
  for (auto &A : F.args())
    CallArgs.push_back(&A);
  CallInst *Call = Builder.CreateCall(ImplAddr, CallArgs);
  Call->setTailCall();
  Builder.CreateRet(Call);
}

void partition(Module &M, const ModulePartitionMap &PMap) {

  for (auto &KVPair : PMap) {

    auto ExtractGlobalVars =
      [&](GlobalVariable &New, const GlobalVariable &Orig,
          ValueToValueMapTy &VMap) {
        if (KVPair.second.count(&Orig)) {
          copyGVInitializer(New, Orig, VMap);
        }
        if (New.getLinkage() == GlobalValue::PrivateLinkage) {
          New.setLinkage(GlobalValue::ExternalLinkage);
          New.setVisibility(GlobalValue::HiddenVisibility);
        }
      };

    auto ExtractFunctions =
      [&](Function &New, const Function &Orig, ValueToValueMapTy &VMap) {
        if (KVPair.second.count(&Orig))
          copyFunctionBody(New, Orig, VMap);
        if (New.getLinkage() == GlobalValue::InternalLinkage) {
          New.setLinkage(GlobalValue::ExternalLinkage);
          New.setVisibility(GlobalValue::HiddenVisibility);
        }
      };

    CloneSubModule(*KVPair.first, M, ExtractGlobalVars, ExtractFunctions,
                   false);
  }
}

FullyPartitionedModule fullyPartition(Module &M) {
  FullyPartitionedModule MP;

  ModulePartitionMap PMap;

  for (auto &F : M) {

    if (F.isDeclaration())
      continue;

    std::string NewModuleName = (M.getName() + "." + F.getName()).str();
    MP.Functions.push_back(
      llvm::make_unique<Module>(NewModuleName, M.getContext()));
    MP.Functions.back()->setDataLayout(M.getDataLayout());
    PMap[MP.Functions.back().get()].insert(&F);
  }

  MP.GlobalVars =
    llvm::make_unique<Module>((M.getName() + ".globals_and_stubs").str(),
                              M.getContext());
  MP.GlobalVars->setDataLayout(M.getDataLayout());

  MP.Commons =
    llvm::make_unique<Module>((M.getName() + ".commons").str(), M.getContext());
  MP.Commons->setDataLayout(M.getDataLayout());

  // Make sure there's at least an empty set for the stubs map or we'll fail
  // to clone anything for it (including the decls).
  PMap[MP.GlobalVars.get()] = ModulePartitionMap::mapped_type();
  for (auto &GV : M.globals())
    if (GV.getLinkage() == GlobalValue::CommonLinkage)
      PMap[MP.Commons.get()].insert(&GV);
    else
      PMap[MP.GlobalVars.get()].insert(&GV);

  partition(M, PMap);

  return MP;
}

} // End namespace orc.
} // End namespace llvm.
<commit_msg>[Orc] Add header comment to IndirectionUtils.cpp.<commit_after>//===---- IndirectionUtils.cpp - Utilities for call indirection in Orc ----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/Triple.h"
#include "llvm/ExecutionEngine/Orc/CloneSubModule.h"
#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/IRBuilder.h"
#include <set>

using namespace llvm;

namespace llvm {
namespace orc {

GlobalVariable* createImplPointer(Function &F, const Twine &Name,
                                  Constant *Initializer) {
  assert(F.getParent() && "Function isn't in a module.");
  if (!Initializer)
    Initializer = Constant::getNullValue(F.getType());
  Module &M = *F.getParent();
  return new GlobalVariable(M, F.getType(), false, GlobalValue::ExternalLinkage,
                            Initializer, Name, nullptr,
                            GlobalValue::NotThreadLocal, 0, true);
}

void makeStub(Function &F, GlobalVariable &ImplPointer) {
  assert(F.isDeclaration() && "Can't turn a definition into a stub.");
  assert(F.getParent() && "Function isn't in a module.");
  Module &M = *F.getParent();
  BasicBlock *EntryBlock = BasicBlock::Create(M.getContext(), "entry", &F);
  IRBuilder<> Builder(EntryBlock);
  LoadInst *ImplAddr = Builder.CreateLoad(&ImplPointer);
  std::vector<Value*> CallArgs;
  for (auto &A : F.args())
    CallArgs.push_back(&A);
  CallInst *Call = Builder.CreateCall(ImplAddr, CallArgs);
  Call->setTailCall();
  Builder.CreateRet(Call);
}

void partition(Module &M, const ModulePartitionMap &PMap) {

  for (auto &KVPair : PMap) {

    auto ExtractGlobalVars =
      [&](GlobalVariable &New, const GlobalVariable &Orig,
          ValueToValueMapTy &VMap) {
        if (KVPair.second.count(&Orig)) {
          copyGVInitializer(New, Orig, VMap);
        }
        if (New.getLinkage() == GlobalValue::PrivateLinkage) {
          New.setLinkage(GlobalValue::ExternalLinkage);
          New.setVisibility(GlobalValue::HiddenVisibility);
        }
      };

    auto ExtractFunctions =
      [&](Function &New, const Function &Orig, ValueToValueMapTy &VMap) {
        if (KVPair.second.count(&Orig))
          copyFunctionBody(New, Orig, VMap);
        if (New.getLinkage() == GlobalValue::InternalLinkage) {
          New.setLinkage(GlobalValue::ExternalLinkage);
          New.setVisibility(GlobalValue::HiddenVisibility);
        }
      };

    CloneSubModule(*KVPair.first, M, ExtractGlobalVars, ExtractFunctions,
                   false);
  }
}

FullyPartitionedModule fullyPartition(Module &M) {
  FullyPartitionedModule MP;

  ModulePartitionMap PMap;

  for (auto &F : M) {

    if (F.isDeclaration())
      continue;

    std::string NewModuleName = (M.getName() + "." + F.getName()).str();
    MP.Functions.push_back(
      llvm::make_unique<Module>(NewModuleName, M.getContext()));
    MP.Functions.back()->setDataLayout(M.getDataLayout());
    PMap[MP.Functions.back().get()].insert(&F);
  }

  MP.GlobalVars =
    llvm::make_unique<Module>((M.getName() + ".globals_and_stubs").str(),
                              M.getContext());
  MP.GlobalVars->setDataLayout(M.getDataLayout());

  MP.Commons =
    llvm::make_unique<Module>((M.getName() + ".commons").str(), M.getContext());
  MP.Commons->setDataLayout(M.getDataLayout());

  // Make sure there's at least an empty set for the stubs map or we'll fail
  // to clone anything for it (including the decls).
  PMap[MP.GlobalVars.get()] = ModulePartitionMap::mapped_type();
  for (auto &GV : M.globals())
    if (GV.getLinkage() == GlobalValue::CommonLinkage)
      PMap[MP.Commons.get()].insert(&GV);
    else
      PMap[MP.GlobalVars.get()].insert(&GV);

  partition(M, PMap);

  return MP;
}

} // End namespace orc.
} // End namespace llvm.
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Matthew Harvey
 *
 * 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 "gui/about_dialog.hpp"
#include "app.hpp"
#include "gui/sizing.hpp"
#include <boost/filesystem.hpp>
#include <jewel/assert.hpp>
#include <jewel/log.hpp>
#include <wx/hyperlink.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/string.h>
#include <wx/utils.h>
#include <wx/window.h>

namespace filesystem = boost::filesystem;

namespace dcm
{
namespace gui
{

AboutDialog::AboutDialog
(	wxAboutDialogInfo const& p_info,
	wxWindow* p_parent,
	wxString const& p_developer_credits,
	wxString const& p_artist_credits
):
	m_developer_credits(p_developer_credits),
	m_artist_credits(p_artist_credits)
{
	Create(p_info, p_parent);
}

AboutDialog::~AboutDialog() = default;

void
AboutDialog::DoAddCustomControls()
{
	JEWEL_LOG_TRACE();
	auto developers_summary = new wxStaticText
	(	this,
		wxID_ANY,
		m_developer_credits,
		wxDefaultPosition,
		wxDefaultSize,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL
	);
	AddControl
	(	developers_summary,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL | wxEXPAND
	);
	auto artists_summary = new wxStaticText
	(	this,
		wxID_ANY,
		m_artist_credits,
		wxDefaultPosition,
		wxDefaultSize,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL
	);
	AddControl
	(	artists_summary,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL | wxEXPAND
	);
	auto license_summary = new wxStaticText
	(	this,
		wxID_ANY,
		App::application_name() +
			" is made available under the Apache License, Version 2.0, " +
			"which can be viewed at:",
		wxDefaultPosition,
		wxDefaultSize,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL
	);
	AddControl
	(	license_summary,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL | wxEXPAND
	);
	auto license_url = new wxHyperlinkCtrl
	(	this,
		wxID_ANY,
		wxEmptyString,
		"http://www.apache.org/licenses/LICENSE-2.0",
		wxDefaultPosition,
		wxDefaultSize
	);
	AddControl
	(	license_url,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL | wxEXPAND
	);
	JEWEL_LOG_TRACE();
	return;
}

}  // namespace gui
}  // namespace dcm
<commit_msg>Added a TODO re. text positioning in AboutDialog.<commit_after>/*
 * Copyright 2013 Matthew Harvey
 *
 * 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 "gui/about_dialog.hpp"
#include "app.hpp"
#include "gui/sizing.hpp"
#include <boost/filesystem.hpp>
#include <jewel/assert.hpp>
#include <jewel/log.hpp>
#include <wx/hyperlink.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/string.h>
#include <wx/utils.h>
#include <wx/window.h>

// TODO In this control, alignment of text is unsightly, and some text doesn't
// fit (at least not on some builds).

namespace filesystem = boost::filesystem;

namespace dcm
{
namespace gui
{

AboutDialog::AboutDialog
(	wxAboutDialogInfo const& p_info,
	wxWindow* p_parent,
	wxString const& p_developer_credits,
	wxString const& p_artist_credits
):
	m_developer_credits(p_developer_credits),
	m_artist_credits(p_artist_credits)
{
	Create(p_info, p_parent);
}

AboutDialog::~AboutDialog() = default;

void
AboutDialog::DoAddCustomControls()
{
	JEWEL_LOG_TRACE();
	auto developers_summary = new wxStaticText
	(	this,
		wxID_ANY,
		m_developer_credits,
		wxDefaultPosition,
		wxDefaultSize,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL
	);
	AddControl
	(	developers_summary,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL | wxEXPAND
	);
	auto artists_summary = new wxStaticText
	(	this,
		wxID_ANY,
		m_artist_credits,
		wxDefaultPosition,
		wxDefaultSize,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL
	);
	AddControl
	(	artists_summary,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL | wxEXPAND
	);
	auto license_summary = new wxStaticText
	(	this,
		wxID_ANY,
		App::application_name() +
			" is made available under the Apache License, Version 2.0, " +
			"which can be viewed at:",
		wxDefaultPosition,
		wxDefaultSize,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL
	);
	AddControl
	(	license_summary,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL | wxEXPAND
	);
	auto license_url = new wxHyperlinkCtrl
	(	this,
		wxID_ANY,
		wxEmptyString,
		"http://www.apache.org/licenses/LICENSE-2.0",
		wxDefaultPosition,
		wxDefaultSize
	);
	AddControl
	(	license_url,
		wxALIGN_CENTRE | wxALIGN_CENTRE_VERTICAL | wxEXPAND
	);
	JEWEL_LOG_TRACE();
	return;
}

}  // namespace gui
}  // namespace dcm
<|endoftext|>


<commit_before>// Copyright (c) 2010 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/keygen_handler.h"

#include "build/build_config.h" // Needs to be imported early for USE_NSS

#if defined(USE_NSS)
#include <private/pprthred.h>  // PR_DetachThread
#endif

#include <string>

#include "base/base64.h"
#include "base/logging.h"
#include "base/nss_util.h"
#include "base/task.h"
#include "base/waitable_event.h"
#include "base/worker_pool.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace net {

namespace {

class KeygenHandlerTest : public ::testing::Test {
 public:
  KeygenHandlerTest() {}
  virtual ~KeygenHandlerTest() {}

  virtual void SetUp() {
#if defined(OS_CHROMEOS)
  base::OpenPersistentNSSDB();
#endif
  }
};

// Assert that |result| is a valid output for KeygenHandler given challenge
// string of |challenge|.
void AssertValidSignedPublicKeyAndChallenge(const std::string& result,
                                            const std::string& challenge) {
  ASSERT_GT(result.length(), 0U);

  // Verify it's valid base64:
  std::string spkac;
  ASSERT_TRUE(base::Base64Decode(result, &spkac));
  // In lieu of actually parsing and validating the DER data,
  // just check that it exists and has a reasonable length.
  // (It's almost always 590 bytes, but the DER encoding of the random key
  // and signature could sometimes be a few bytes different.)
  ASSERT_GE(spkac.length(), 580U);
  ASSERT_LE(spkac.length(), 600U);

  // NOTE:
  // The value of |result| can be validated by prefixing 'SPKAC=' to it
  // and piping it through
  //   openssl spkac -verify
  // whose output should look like:
  //   Netscape SPKI:
  //     Public Key Algorithm: rsaEncryption
  //     RSA Public Key: (2048 bit)
  //     Modulus (2048 bit):
  //         00:b6:cc:14:c9:43:b5:2d:51:65:7e:11:8b:80:9e: .....
  //     Exponent: 65537 (0x10001)
  //     Challenge String: some challenge
  //     Signature Algorithm: md5WithRSAEncryption
  //         92:f3:cc:ff:0b:d3:d0:4a:3a:4c:ba:ff:d6:38:7f:a5:4b:b5: .....
  //   Signature OK
  //
  // The value of |spkac| can be ASN.1-parsed with:
  //    openssl asn1parse -inform DER
}

TEST_F(KeygenHandlerTest, FLAKY_SmokeTest) {
  KeygenHandler handler(2048, "some challenge");
  handler.set_stores_key(false);  // Don't leave the key-pair behind
  std::string result = handler.GenKeyAndSignChallenge();
  LOG(INFO) << "KeygenHandler produced: " << result;
  AssertValidSignedPublicKeyAndChallenge(result, "some challenge");
}

class ConcurrencyTestTask : public Task {
 public:
  ConcurrencyTestTask(base::WaitableEvent* event,
                      const std::string& challenge, std::string* result)
      : event_(event),
        challenge_(challenge),
        result_(result) {
  }

  virtual void Run() {
    KeygenHandler handler(2048, "some challenge");
    handler.set_stores_key(false); // Don't leave the key-pair behind.
    *result_ = handler.GenKeyAndSignChallenge();
    event_->Signal();
#if defined(USE_NSS)
    // Detach the thread from NSPR.
    // Calling NSS functions attaches the thread to NSPR, which stores
    // the NSPR thread ID in thread-specific data.
    // The threads in our thread pool terminate after we have called
    // PR_Cleanup.  Unless we detach them from NSPR, net_unittests gets
    // segfaults on shutdown when the threads' thread-specific data
    // destructors run.
    PR_DetachThread();
#endif
  }

 private:
  base::WaitableEvent* event_;
  std::string challenge_;
  std::string* result_;
};

// We asynchronously generate the keys so as not to hang up the IO thread. This
// test tries to catch concurrency problems in the keygen implementation.
TEST_F(KeygenHandlerTest, ConcurrencyTest) {
  const int NUM_HANDLERS = 5;
  base::WaitableEvent* events[NUM_HANDLERS] = { NULL };
  std::string results[NUM_HANDLERS];
  for (int i = 0; i < NUM_HANDLERS; i++) {
    events[i] = new base::WaitableEvent(false, false);
    WorkerPool::PostTask(FROM_HERE,
                         new ConcurrencyTestTask(events[i], "some challenge",
                                                 &results[i]),
                         true);
  }

  for (int i = 0; i < NUM_HANDLERS; i++) {
    // Make sure the job completed
    bool signaled = events[i]->Wait();
    EXPECT_TRUE(signaled);
    delete events[i];
    events[i] = NULL;

    LOG(INFO) << "KeygenHandler " << i << " produced: " << results[i];
    AssertValidSignedPublicKeyAndChallenge(results[i], "some challenge");
  }
}

}  // namespace

}  // namespace net
<commit_msg>Make KeygenHandlerTest.ConcurrencyTest flaky on mac.<commit_after>// Copyright (c) 2010 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/keygen_handler.h"

#include "build/build_config.h" // Needs to be imported early for USE_NSS

#if defined(USE_NSS)
#include <private/pprthred.h>  // PR_DetachThread
#endif

#include <string>

#include "base/base64.h"
#include "base/logging.h"
#include "base/nss_util.h"
#include "base/task.h"
#include "base/waitable_event.h"
#include "base/worker_pool.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace net {

namespace {

class KeygenHandlerTest : public ::testing::Test {
 public:
  KeygenHandlerTest() {}
  virtual ~KeygenHandlerTest() {}

  virtual void SetUp() {
#if defined(OS_CHROMEOS)
  base::OpenPersistentNSSDB();
#endif
  }
};

// Assert that |result| is a valid output for KeygenHandler given challenge
// string of |challenge|.
void AssertValidSignedPublicKeyAndChallenge(const std::string& result,
                                            const std::string& challenge) {
  ASSERT_GT(result.length(), 0U);

  // Verify it's valid base64:
  std::string spkac;
  ASSERT_TRUE(base::Base64Decode(result, &spkac));
  // In lieu of actually parsing and validating the DER data,
  // just check that it exists and has a reasonable length.
  // (It's almost always 590 bytes, but the DER encoding of the random key
  // and signature could sometimes be a few bytes different.)
  ASSERT_GE(spkac.length(), 580U);
  ASSERT_LE(spkac.length(), 600U);

  // NOTE:
  // The value of |result| can be validated by prefixing 'SPKAC=' to it
  // and piping it through
  //   openssl spkac -verify
  // whose output should look like:
  //   Netscape SPKI:
  //     Public Key Algorithm: rsaEncryption
  //     RSA Public Key: (2048 bit)
  //     Modulus (2048 bit):
  //         00:b6:cc:14:c9:43:b5:2d:51:65:7e:11:8b:80:9e: .....
  //     Exponent: 65537 (0x10001)
  //     Challenge String: some challenge
  //     Signature Algorithm: md5WithRSAEncryption
  //         92:f3:cc:ff:0b:d3:d0:4a:3a:4c:ba:ff:d6:38:7f:a5:4b:b5: .....
  //   Signature OK
  //
  // The value of |spkac| can be ASN.1-parsed with:
  //    openssl asn1parse -inform DER
}

TEST_F(KeygenHandlerTest, FLAKY_SmokeTest) {
  KeygenHandler handler(2048, "some challenge");
  handler.set_stores_key(false);  // Don't leave the key-pair behind
  std::string result = handler.GenKeyAndSignChallenge();
  LOG(INFO) << "KeygenHandler produced: " << result;
  AssertValidSignedPublicKeyAndChallenge(result, "some challenge");
}

class ConcurrencyTestTask : public Task {
 public:
  ConcurrencyTestTask(base::WaitableEvent* event,
                      const std::string& challenge, std::string* result)
      : event_(event),
        challenge_(challenge),
        result_(result) {
  }

  virtual void Run() {
    KeygenHandler handler(2048, "some challenge");
    handler.set_stores_key(false); // Don't leave the key-pair behind.
    *result_ = handler.GenKeyAndSignChallenge();
    event_->Signal();
#if defined(USE_NSS)
    // Detach the thread from NSPR.
    // Calling NSS functions attaches the thread to NSPR, which stores
    // the NSPR thread ID in thread-specific data.
    // The threads in our thread pool terminate after we have called
    // PR_Cleanup.  Unless we detach them from NSPR, net_unittests gets
    // segfaults on shutdown when the threads' thread-specific data
    // destructors run.
    PR_DetachThread();
#endif
  }

 private:
  base::WaitableEvent* event_;
  std::string challenge_;
  std::string* result_;
};

// See crbug.com/48006
#if defined(OS_MACOSX)
#define MAYBE_ConcurrencyTest FLAKY_ConcurrencyTest
#else
#define MAYBE_ConcurrencyTest ConcurrencyTest
#endif

// We asynchronously generate the keys so as not to hang up the IO thread. This
// test tries to catch concurrency problems in the keygen implementation.
TEST_F(KeygenHandlerTest, MAYBE_ConcurrencyTest) {
  const int NUM_HANDLERS = 5;
  base::WaitableEvent* events[NUM_HANDLERS] = { NULL };
  std::string results[NUM_HANDLERS];
  for (int i = 0; i < NUM_HANDLERS; i++) {
    events[i] = new base::WaitableEvent(false, false);
    WorkerPool::PostTask(FROM_HERE,
                         new ConcurrencyTestTask(events[i], "some challenge",
                                                 &results[i]),
                         true);
  }

  for (int i = 0; i < NUM_HANDLERS; i++) {
    // Make sure the job completed
    bool signaled = events[i]->Wait();
    EXPECT_TRUE(signaled);
    delete events[i];
    events[i] = NULL;

    LOG(INFO) << "KeygenHandler " << i << " produced: " << results[i];
    AssertValidSignedPublicKeyAndChallenge(results[i], "some challenge");
  }
}

}  // namespace

}  // namespace net
<|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.

#include "content/browser/renderer_host/redirect_to_file_resource_handler.h"

#include "base/bind.h"
#include "base/file_util.h"
#include "base/file_util_proxy.h"
#include "base/logging.h"
#include "base/message_loop_proxy.h"
#include "base/platform_file.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/renderer_host/resource_dispatcher_host_impl.h"
#include "content/public/common/resource_response.h"
#include "net/base/file_stream.h"
#include "net/base/io_buffer.h"
#include "net/base/mime_sniffer.h"
#include "net/base/net_errors.h"
#include "webkit/blob/shareable_file_reference.h"

using webkit_blob::ShareableFileReference;

namespace content {

static const int kInitialReadBufSize = 32768;
static const int kMaxReadBufSize = 524288;

RedirectToFileResourceHandler::RedirectToFileResourceHandler(
    scoped_ptr<ResourceHandler> next_handler,
    int process_id,
    ResourceDispatcherHostImpl* host)
    : LayeredResourceHandler(next_handler.Pass()),
      ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
      host_(host),
      process_id_(process_id),
      request_id_(-1),
      buf_(new net::GrowableIOBuffer()),
      buf_write_pending_(false),
      write_cursor_(0),
      write_callback_pending_(false),
      next_buffer_size_(kInitialReadBufSize),
      did_defer_(false),
      completed_during_write_(false) {
}

RedirectToFileResourceHandler::~RedirectToFileResourceHandler() {
  // It is possible for |file_stream_| to be NULL if the URLRequest was closed
  // before the temporary file creation finished.
  if (file_stream_.get()) {
    // We require this explicit call to Close since file_stream_ was constructed
    // directly from a PlatformFile.
    // Close() performs file IO. crbug.com/112474.
    base::ThreadRestrictions::ScopedAllowIO allow_io;
    file_stream_->CloseSync();
    file_stream_.reset();
  }
}

bool RedirectToFileResourceHandler::OnResponseStarted(
    int request_id,
    ResourceResponse* response,
    bool* defer) {
  if (response->head.error_code == net::OK ||
      response->head.error_code == net::ERR_IO_PENDING) {
    DCHECK(deletable_file_ && !deletable_file_->path().empty());
    response->head.download_file_path = deletable_file_->path();
  }
  return next_handler_->OnResponseStarted(request_id, response, defer);
}

bool RedirectToFileResourceHandler::OnWillStart(int request_id,
                                                const GURL& url,
                                                bool* defer) {
  request_id_ = request_id;
  if (!deletable_file_) {
    // Defer starting the request until we have created the temporary file.
    // TODO(darin): This is sub-optimal.  We should not delay starting the
    // network request like this.
    did_defer_ = *defer = true;
    base::FileUtilProxy::CreateTemporary(
        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
        base::PLATFORM_FILE_ASYNC,
        base::Bind(&RedirectToFileResourceHandler::DidCreateTemporaryFile,
                   weak_factory_.GetWeakPtr()));
    return true;
  }
  return next_handler_->OnWillStart(request_id, url, defer);
}

bool RedirectToFileResourceHandler::OnWillRead(int request_id,
                                               net::IOBuffer** buf,
                                               int* buf_size,
                                               int min_size) {
  DCHECK_EQ(-1, min_size);

  if (buf_->capacity() < next_buffer_size_)
    buf_->SetCapacity(next_buffer_size_);

  // We should have paused this network request already if the buffer is full.
  DCHECK(!BufIsFull());

  *buf = buf_;
  *buf_size = buf_->RemainingCapacity();

  buf_write_pending_ = true;
  return true;
}

bool RedirectToFileResourceHandler::OnReadCompleted(int request_id,
                                                    int bytes_read,
                                                    bool* defer) {
  DCHECK(buf_write_pending_);
  buf_write_pending_ = false;

  // We use the buffer's offset field to record the end of the buffer.
  int new_offset = buf_->offset() + bytes_read;
  DCHECK(new_offset <= buf_->capacity());
  buf_->set_offset(new_offset);

  if (BufIsFull()) {
    did_defer_ = *defer = true;

    if (buf_->capacity() == bytes_read) {
      // The network layer has saturated our buffer in one read. Next time, we
      // should give it a bigger buffer for it to fill.
      next_buffer_size_ = std::min(next_buffer_size_ * 2, kMaxReadBufSize);
    }
  }

  return WriteMore();
}

bool RedirectToFileResourceHandler::OnResponseCompleted(
    int request_id,
    const net::URLRequestStatus& status,
    const std::string& security_info) {
  if (write_callback_pending_) {
    completed_during_write_ = true;
    completed_status_ = status;
    completed_security_info_ = security_info;
    return false;
  }
  return next_handler_->OnResponseCompleted(request_id, status, security_info);
}

void RedirectToFileResourceHandler::DidCreateTemporaryFile(
    base::PlatformFileError /*error_code*/,
    base::PassPlatformFile file_handle,
    const FilePath& file_path) {
  deletable_file_ = ShareableFileReference::GetOrCreate(
      file_path, ShareableFileReference::DELETE_ON_FINAL_RELEASE,
      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
  file_stream_.reset(new net::FileStream(file_handle.ReleaseValue(),
                                         base::PLATFORM_FILE_WRITE |
                                         base::PLATFORM_FILE_ASYNC,
                                         NULL));
  host_->RegisterDownloadedTempFile(
      process_id_, request_id_, deletable_file_.get());
  ResumeIfDeferred();
}

void RedirectToFileResourceHandler::DidWriteToFile(int result) {
  write_callback_pending_ = false;

  bool failed = false;
  if (result > 0) {
    next_handler_->OnDataDownloaded(request_id_, result);
    write_cursor_ += result;
    failed = !WriteMore();
  } else {
    failed = true;
  }

  if (failed) {
    ResumeIfDeferred();
  } else if (completed_during_write_) {
    if (next_handler_->OnResponseCompleted(request_id_, completed_status_,
                                           completed_security_info_)) {
      ResumeIfDeferred();
    }
  }
}

bool RedirectToFileResourceHandler::WriteMore() {
  DCHECK(file_stream_.get());
  for (;;) {
    if (write_cursor_ == buf_->offset()) {
      // We've caught up to the network load, but it may be in the process of
      // appending more data to the buffer.
      if (!buf_write_pending_) {
        if (BufIsFull())
          ResumeIfDeferred();
        buf_->set_offset(0);
        write_cursor_ = 0;
      }
      return true;
    }
    if (write_callback_pending_)
      return true;
    DCHECK(write_cursor_ < buf_->offset());

    // Create a temporary drainable buffer that can be passed to
    // Write(). Temporarily reset the buf_ offset to 0 so that the
    // drainable buffer can point to the the beginning of the buf_.
    int offset = buf_->offset();
    buf_->set_offset(0);
    scoped_refptr<net::DrainableIOBuffer>
        drainable = new net::DrainableIOBuffer(buf_, offset);
    drainable->DidConsume(write_cursor_);
    buf_->set_offset(offset);

    int rv = file_stream_->Write(
        drainable,
        drainable->BytesRemaining(),
        base::Bind(&RedirectToFileResourceHandler::DidWriteToFile,
                   base::Unretained(this)));
    if (rv == net::ERR_IO_PENDING) {
      write_callback_pending_ = true;
      return true;
    }
    if (rv <= 0)
      return false;
    next_handler_->OnDataDownloaded(request_id_, rv);
    write_cursor_ += rv;
  }
}

bool RedirectToFileResourceHandler::BufIsFull() const {
  // This is a hack to workaround BufferedResourceHandler's inability to
  // deal with a ResourceHandler that returns a buffer size of less than
  // 2 * net::kMaxBytesToSniff from its OnWillRead method.
  // TODO(darin): Fix this retardation!
  return buf_->RemainingCapacity() <= (2 * net::kMaxBytesToSniff);
}

void RedirectToFileResourceHandler::ResumeIfDeferred() {
  if (did_defer_) {
    did_defer_ = false;
    controller()->Resume();
  }
}

}  // namespace content
<commit_msg>Fix race condition in RedirectToFileResourceHandler that was corrupting NaCl executables.<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.

#include "content/browser/renderer_host/redirect_to_file_resource_handler.h"

#include "base/bind.h"
#include "base/file_util.h"
#include "base/file_util_proxy.h"
#include "base/logging.h"
#include "base/message_loop_proxy.h"
#include "base/platform_file.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/renderer_host/resource_dispatcher_host_impl.h"
#include "content/public/common/resource_response.h"
#include "net/base/file_stream.h"
#include "net/base/io_buffer.h"
#include "net/base/mime_sniffer.h"
#include "net/base/net_errors.h"
#include "webkit/blob/shareable_file_reference.h"

using webkit_blob::ShareableFileReference;

namespace {

// This class is similar to identically named classes in AsyncResourceHandler
// and BufferedResourceHandler, but not quite.
// TODO(ncbray) generalize and unify these cases?
// In general, it's a bad idea to point to a subbuffer (particularly with
// GrowableIOBuffer) because the backing IOBuffer may realloc its data.  In this
// particular case we know RedirectToFileResourceHandler will not realloc its
// buffer while a write is occurring, so we should be safe.  This property is
// somewhat fragile, however, and depending on it is dangerous.  A more
// principled approach would require significant refactoring, however, so for
// the moment we're relying on fragile properties.
class DependentIOBuffer : public net::WrappedIOBuffer {
 public:
  DependentIOBuffer(net::IOBuffer* backing, char* memory)
      : net::WrappedIOBuffer(memory),
        backing_(backing) {
  }
 private:
  virtual ~DependentIOBuffer() {}

  scoped_refptr<net::IOBuffer> backing_;
};

}

namespace content {

static const int kInitialReadBufSize = 32768;
static const int kMaxReadBufSize = 524288;

RedirectToFileResourceHandler::RedirectToFileResourceHandler(
    scoped_ptr<ResourceHandler> next_handler,
    int process_id,
    ResourceDispatcherHostImpl* host)
    : LayeredResourceHandler(next_handler.Pass()),
      ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
      host_(host),
      process_id_(process_id),
      request_id_(-1),
      buf_(new net::GrowableIOBuffer()),
      buf_write_pending_(false),
      write_cursor_(0),
      write_callback_pending_(false),
      next_buffer_size_(kInitialReadBufSize),
      did_defer_(false),
      completed_during_write_(false) {
}

RedirectToFileResourceHandler::~RedirectToFileResourceHandler() {
  // It is possible for |file_stream_| to be NULL if the URLRequest was closed
  // before the temporary file creation finished.
  if (file_stream_.get()) {
    // We require this explicit call to Close since file_stream_ was constructed
    // directly from a PlatformFile.
    // Close() performs file IO. crbug.com/112474.
    base::ThreadRestrictions::ScopedAllowIO allow_io;
    file_stream_->CloseSync();
    file_stream_.reset();
  }
}

bool RedirectToFileResourceHandler::OnResponseStarted(
    int request_id,
    ResourceResponse* response,
    bool* defer) {
  if (response->head.error_code == net::OK ||
      response->head.error_code == net::ERR_IO_PENDING) {
    DCHECK(deletable_file_ && !deletable_file_->path().empty());
    response->head.download_file_path = deletable_file_->path();
  }
  return next_handler_->OnResponseStarted(request_id, response, defer);
}

bool RedirectToFileResourceHandler::OnWillStart(int request_id,
                                                const GURL& url,
                                                bool* defer) {
  request_id_ = request_id;
  if (!deletable_file_) {
    // Defer starting the request until we have created the temporary file.
    // TODO(darin): This is sub-optimal.  We should not delay starting the
    // network request like this.
    did_defer_ = *defer = true;
    base::FileUtilProxy::CreateTemporary(
        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
        base::PLATFORM_FILE_ASYNC,
        base::Bind(&RedirectToFileResourceHandler::DidCreateTemporaryFile,
                   weak_factory_.GetWeakPtr()));
    return true;
  }
  return next_handler_->OnWillStart(request_id, url, defer);
}

bool RedirectToFileResourceHandler::OnWillRead(int request_id,
                                               net::IOBuffer** buf,
                                               int* buf_size,
                                               int min_size) {
  DCHECK_EQ(-1, min_size);

  if (buf_->capacity() < next_buffer_size_)
    buf_->SetCapacity(next_buffer_size_);

  // We should have paused this network request already if the buffer is full.
  DCHECK(!BufIsFull());

  *buf = buf_;
  *buf_size = buf_->RemainingCapacity();

  buf_write_pending_ = true;
  return true;
}

bool RedirectToFileResourceHandler::OnReadCompleted(int request_id,
                                                    int bytes_read,
                                                    bool* defer) {
  DCHECK(buf_write_pending_);
  buf_write_pending_ = false;

  // We use the buffer's offset field to record the end of the buffer.
  int new_offset = buf_->offset() + bytes_read;
  DCHECK(new_offset <= buf_->capacity());
  buf_->set_offset(new_offset);

  if (BufIsFull()) {
    did_defer_ = *defer = true;

    if (buf_->capacity() == bytes_read) {
      // The network layer has saturated our buffer in one read. Next time, we
      // should give it a bigger buffer for it to fill.
      next_buffer_size_ = std::min(next_buffer_size_ * 2, kMaxReadBufSize);
    }
  }

  return WriteMore();
}

bool RedirectToFileResourceHandler::OnResponseCompleted(
    int request_id,
    const net::URLRequestStatus& status,
    const std::string& security_info) {
  if (write_callback_pending_) {
    completed_during_write_ = true;
    completed_status_ = status;
    completed_security_info_ = security_info;
    return false;
  }
  return next_handler_->OnResponseCompleted(request_id, status, security_info);
}

void RedirectToFileResourceHandler::DidCreateTemporaryFile(
    base::PlatformFileError /*error_code*/,
    base::PassPlatformFile file_handle,
    const FilePath& file_path) {
  deletable_file_ = ShareableFileReference::GetOrCreate(
      file_path, ShareableFileReference::DELETE_ON_FINAL_RELEASE,
      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
  file_stream_.reset(new net::FileStream(file_handle.ReleaseValue(),
                                         base::PLATFORM_FILE_WRITE |
                                         base::PLATFORM_FILE_ASYNC,
                                         NULL));
  host_->RegisterDownloadedTempFile(
      process_id_, request_id_, deletable_file_.get());
  ResumeIfDeferred();
}

void RedirectToFileResourceHandler::DidWriteToFile(int result) {
  write_callback_pending_ = false;

  bool failed = false;
  if (result > 0) {
    next_handler_->OnDataDownloaded(request_id_, result);
    write_cursor_ += result;
    failed = !WriteMore();
  } else {
    failed = true;
  }

  if (failed) {
    ResumeIfDeferred();
  } else if (completed_during_write_) {
    if (next_handler_->OnResponseCompleted(request_id_, completed_status_,
                                           completed_security_info_)) {
      ResumeIfDeferred();
    }
  }
}

bool RedirectToFileResourceHandler::WriteMore() {
  DCHECK(file_stream_.get());
  for (;;) {
    if (write_cursor_ == buf_->offset()) {
      // We've caught up to the network load, but it may be in the process of
      // appending more data to the buffer.
      if (!buf_write_pending_) {
        if (BufIsFull())
          ResumeIfDeferred();
        buf_->set_offset(0);
        write_cursor_ = 0;
      }
      return true;
    }
    if (write_callback_pending_)
      return true;
    DCHECK(write_cursor_ < buf_->offset());

    // Create a temporary buffer pointing to a subsection of the data buffer so
    // that it can be passed to Write.  This code makes some crazy scary
    // assumptions about object lifetimes, thread sharing, and that buf_ will
    // not realloc durring the write due to how the state machine in this class
    // works.
    // Note that buf_ is also shared with the code that writes data into the
    // cache, so modifying it can cause some pretty subtle race conditions:
    // https://code.google.com/p/chromium/issues/detail?id=152076
    // We're using DependentIOBuffer instead of DrainableIOBuffer to dodge some
    // of these issues, for the moment.
    // TODO(ncbray) make this code less crazy scary.
    // Also note that Write may increase the refcount of "wrapped" deep in the
    // bowels of its implementation, the use of scoped_refptr here is not
    // spurious.
    scoped_refptr<DependentIOBuffer> wrapped = new DependentIOBuffer(
        buf_, buf_->StartOfBuffer() + write_cursor_);
    int write_len = buf_->offset() - write_cursor_;

    int rv = file_stream_->Write(
        wrapped,
        write_len,
        base::Bind(&RedirectToFileResourceHandler::DidWriteToFile,
                   base::Unretained(this)));
    if (rv == net::ERR_IO_PENDING) {
      write_callback_pending_ = true;
      return true;
    }
    if (rv <= 0)
      return false;
    next_handler_->OnDataDownloaded(request_id_, rv);
    write_cursor_ += rv;
  }
}

bool RedirectToFileResourceHandler::BufIsFull() const {
  // This is a hack to workaround BufferedResourceHandler's inability to
  // deal with a ResourceHandler that returns a buffer size of less than
  // 2 * net::kMaxBytesToSniff from its OnWillRead method.
  // TODO(darin): Fix this retardation!
  return buf_->RemainingCapacity() <= (2 * net::kMaxBytesToSniff);
}

void RedirectToFileResourceHandler::ResumeIfDeferred() {
  if (did_defer_) {
    did_defer_ = false;
    controller()->Resume();
  }
}

}  // namespace content
<|endoftext|>


<commit_before>#include <iostream>
#include <stdlib.h>

#include <vector>
#include <queue>

#include <google/protobuf/descriptor.h>

#include <boost/asio.hpp>
#include <boost/chrono.hpp>

#include <boost/thread.hpp>
#include <boost/thread/shared_mutex.hpp>

#include <boost/thread/condition_variable.hpp>

#include "vtrc-server/vtrc-application.h"
#include "vtrc-server/vtrc-endpoint-iface.h"
#include "vtrc-server/vtrc-endpoint-tcp.h"

#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-thread-pool.h"
#include "vtrc-common/vtrc-sizepack-policy.h"
#include "vtrc-common/vtrc-exception.h"

#include "vtrc-common/vtrc-hash-iface.h"

#include "vtrc-common/vtrc-data-queue.h"
#include "vtrc-common/vtrc-condition-queues.h"
#include "vtrc-common/vtrc-rpc-service-wrapper.h"
#include "vtrc-common/vtrc-protocol-layer.h"
#include "vtrc-common/vtrc-call-context.h"
#include "vtrc-common/vtrc-connection-iface.h"

#include "protocol/vtrc-errors.pb.h"
#include "protocol/vtrc-auth.pb.h"
#include "protocol/vtrc-rpc-lowlevel.pb.h"
#include "protocol/vtrc-service.pb.h"

#include "vtrc-memory.h"
#include "vtrc-chrono.h"

#include "vtrc-server/vtrc-unicast-channels.h"

namespace ba = boost::asio;

using namespace vtrc;

struct work_time {
    typedef boost::chrono::high_resolution_clock::time_point time_point;
    time_point start_;
    work_time( )
        :start_(boost::chrono::high_resolution_clock::now( ))
    {}
    ~work_time( )
    {
        time_point stop(boost::chrono::high_resolution_clock::now( ));
        std::cout << "call time: " << stop - start_ << "\n";
    }
};

void test_send( common::connection_iface *connection )
{
    vtrc::shared_ptr<google::protobuf::RpcChannel> ev(
                vtrc::server
                ::channels::unicast
                ::create_event_channel(connection->shared_from_this( ),
                                       true));

//    const vtrc_rpc_lowlevel::lowlevel_unit *llu =
//            connection->get_protocol( ).
//            get_call_context( )->get_lowlevel_message( );

    vtrc_rpc_lowlevel::lowlevel_unit llu;
    connection->get_protocol( ).send_message( llu );

//    vtrc_service::internal::Stub ping( ev.get( ));
//    vtrc_service::ping_req preq;
//    vtrc_service::pong_res pres;

//    ping.ping( NULL, &preq, &pres, NULL );

}

class teat_impl: public vtrc_service::test_rpc {

    common::connection_iface *connection_;
    unsigned id_;

public:

    teat_impl(common::connection_iface *c )
        :connection_(c)
        ,id_(0)
    { }

    void test(::google::protobuf::RpcController* controller,
              const ::vtrc_rpc_lowlevel::message_info* request,
              ::vtrc_rpc_lowlevel::message_info* response,
              ::google::protobuf::Closure* done)
    {
//        std::cout << "test was called :] context: \n"
//                  << connection_->get_protocol( )
//                     .get_call_context( )
//                     ->get_lowlevel_message( )
//                     ->DebugString( );
        //boost::this_thread::sleep_for( vtrc::chrono::milliseconds(900) );
        response->set_message_type( id_++ );
        if( (id_ % 100) == 0 )
            throw std::runtime_error( "oops 10 =)" );

        test_send( connection_ );

        if( done ) done->Run( );
    }
};

class main_app: public vtrc::server::application
{

public:

    main_app( )
    { }

private:

    void on_endpoint_started( vtrc::server::endpoint_iface *ep )
    {
        std::cout << "Start endpoint: " << ep->string( ) << "\n";
    }

    void on_endpoint_stopped( vtrc::server::endpoint_iface *ep )
    {
        std::cout << "Stop endpoint: " << ep->string( ) << "\n";
    }

    void on_endpoint_exception( vtrc::server::endpoint_iface *ep )
    {
        try {
            throw;
        } catch( const std::exception &ex ) {
            std::cout << "Endpoint exception '" << ep->string( )
                      << "': " << ex.what( ) << "\n";
        } catch( ... ) {
            throw;
        }
    }

    void on_new_connection_accepted(
                    vtrc::common::connection_iface* connection )
    {
        std::cout << "connection accepted\n";
    }

    void on_new_connection_ready(
                            vtrc::common::connection_iface* connection )
    {
        std::cout << "connection ready\n";
    }

    void on_connection_die( vtrc::common::connection_iface* connection )
    {
        std::cout << "connection die\n";
    }

    google::protobuf::Service *create_service(
            const std::string &name, vtrc::common::connection_iface* connection)
    {
        return NULL;
    }

    vtrc::common::rpc_service_wrapper_sptr get_service_by_name(
                                    vtrc::common::connection_iface *connection,
                                    const std::string &service_name)
    {
        if( service_name == teat_impl::descriptor( )->full_name( ) ) {
            return common::rpc_service_wrapper_sptr(
                        new common::rpc_service_wrapper(
                                new teat_impl(connection) ) );
        }

        return common::rpc_service_wrapper_sptr( );
    }

};

int main( ) try {

    main_app app;
    vtrc::common::thread_pool poll(app.get_io_service( ), 4);

    vtrc::shared_ptr<vtrc::server::endpoint_iface> tcp_ep
            (vtrc::server::endpoints::tcp::create(app, "0.0.0.0", 44667));

    tcp_ep->start( );

    boost::this_thread::sleep_for( vtrc::chrono::milliseconds(12000) );

    std::cout << "Stoppped. Wait ... \n";

    tcp_ep->stop( );

    poll.stop( );
    poll.join_all( );

    return 0;

} catch( ... ) {

    return 0;
}
<commit_msg>protocol<commit_after>#include <iostream>
#include <stdlib.h>

#include <vector>
#include <queue>

#include <google/protobuf/descriptor.h>

#include <boost/asio.hpp>
#include <boost/chrono.hpp>

#include <boost/thread.hpp>
#include <boost/thread/shared_mutex.hpp>

#include <boost/thread/condition_variable.hpp>

#include "vtrc-server/vtrc-application.h"
#include "vtrc-server/vtrc-endpoint-iface.h"
#include "vtrc-server/vtrc-endpoint-tcp.h"

#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-thread-pool.h"
#include "vtrc-common/vtrc-sizepack-policy.h"
#include "vtrc-common/vtrc-exception.h"

#include "vtrc-common/vtrc-hash-iface.h"

#include "vtrc-common/vtrc-data-queue.h"
#include "vtrc-common/vtrc-condition-queues.h"
#include "vtrc-common/vtrc-rpc-service-wrapper.h"
#include "vtrc-common/vtrc-protocol-layer.h"
#include "vtrc-common/vtrc-call-context.h"
#include "vtrc-common/vtrc-connection-iface.h"

#include "protocol/vtrc-errors.pb.h"
#include "protocol/vtrc-auth.pb.h"
#include "protocol/vtrc-rpc-lowlevel.pb.h"
#include "protocol/vtrc-service.pb.h"

#include "vtrc-memory.h"
#include "vtrc-chrono.h"

#include "vtrc-server/vtrc-unicast-channels.h"

namespace ba = boost::asio;

using namespace vtrc;

struct work_time {
    typedef boost::chrono::high_resolution_clock::time_point time_point;
    time_point start_;
    work_time( )
        :start_(boost::chrono::high_resolution_clock::now( ))
    {}
    ~work_time( )
    {
        time_point stop(boost::chrono::high_resolution_clock::now( ));
        std::cout << "call time: " << stop - start_ << "\n";
    }
};

void test_send( common::connection_iface *connection )
{
    vtrc::shared_ptr<google::protobuf::RpcChannel> ev(
                vtrc::server
                ::channels::unicast
                ::create_event_channel(connection->shared_from_this( ),
                                       true));

//    const vtrc_rpc_lowlevel::lowlevel_unit *llu =
//            connection->get_protocol( ).
//            get_call_context( )->get_lowlevel_message( );

//    vtrc_rpc_lowlevel::lowlevel_unit llu;
//    connection->get_protocol( ).send_message( llu );

    vtrc_service::internal::Stub ping( ev.get( ));
    vtrc_service::ping_req preq;
    vtrc_service::pong_res pres;

    try {
        for( ;; ) {
            ping.ping( NULL, &preq, &pres, NULL );
            //boost::this_thread::sleep_for( vtrc::chrono::milliseconds(10) );

        }
    } catch( ... ) { }

}

class teat_impl: public vtrc_service::test_rpc {

    common::connection_iface *connection_;
    unsigned id_;

public:

    teat_impl(common::connection_iface *c )
        :connection_(c)
        ,id_(0)
    { }

    void test(::google::protobuf::RpcController* controller,
              const ::vtrc_rpc_lowlevel::message_info* request,
              ::vtrc_rpc_lowlevel::message_info* response,
              ::google::protobuf::Closure* done)
    {
//        std::cout << "test was called :] context: \n"
//                  << connection_->get_protocol( )
//                     .get_call_context( )
//                     ->get_lowlevel_message( )
//                     ->DebugString( );
        //boost::this_thread::sleep_for( vtrc::chrono::milliseconds(900) );

        response->set_message_type( id_++ );
        if( (id_ % 100) == 0 )
            throw std::runtime_error( "oops 10 =)" );

        static boost::thread tr(test_send, connection_);
        if( tr.joinable( ) ) tr.detach( );

        if( done ) done->Run( );
    }
};

class main_app: public vtrc::server::application
{

public:

    main_app( )
    { }

private:

    void on_endpoint_started( vtrc::server::endpoint_iface *ep )
    {
        std::cout << "Start endpoint: " << ep->string( ) << "\n";
    }

    void on_endpoint_stopped( vtrc::server::endpoint_iface *ep )
    {
        std::cout << "Stop endpoint: " << ep->string( ) << "\n";
    }

    void on_endpoint_exception( vtrc::server::endpoint_iface *ep )
    {
        try {
            throw;
        } catch( const std::exception &ex ) {
            std::cout << "Endpoint exception '" << ep->string( )
                      << "': " << ex.what( ) << "\n";
        } catch( ... ) {
            throw;
        }
    }

    void on_new_connection_accepted(
                    vtrc::common::connection_iface* connection )
    {
        std::cout << "connection accepted\n";
    }

    void on_new_connection_ready(
                            vtrc::common::connection_iface* connection )
    {
        std::cout << "connection ready\n";
    }

    void on_connection_die( vtrc::common::connection_iface* connection )
    {
        std::cout << "connection die\n";
    }

    google::protobuf::Service *create_service(
            const std::string &name, vtrc::common::connection_iface* connection)
    {
        return NULL;
    }

    vtrc::common::rpc_service_wrapper_sptr get_service_by_name(
                                    vtrc::common::connection_iface *connection,
                                    const std::string &service_name)
    {
        if( service_name == teat_impl::descriptor( )->full_name( ) ) {
            return common::rpc_service_wrapper_sptr(
                        new common::rpc_service_wrapper(
                                new teat_impl(connection) ) );
        }

        return common::rpc_service_wrapper_sptr( );
    }

};

int main( ) try {

    main_app app;
    vtrc::common::thread_pool poll(app.get_io_service( ), 4);

    vtrc::shared_ptr<vtrc::server::endpoint_iface> tcp_ep
            (vtrc::server::endpoints::tcp::create(app, "0.0.0.0", 44667));

    tcp_ep->start( );

    boost::this_thread::sleep_for( vtrc::chrono::milliseconds(12000) );

    std::cout << "Stoppped. Wait ... \n";

    tcp_ep->stop( );

    poll.stop( );
    poll.join_all( );

    return 0;

} catch( ... ) {

    return 0;
}
<|endoftext|>


<commit_before>#include <gmpxx.h>
#include <iostream>
#include <sstream>

#define SUCCESS 0
#define FAILURE 1

#define MAX_ARR_SIZE 16777216
#define MAX_PRECISION 65536

#define LOG_INFO

using namespace std;

/**
 * Calc mean Vak
 */
mpf_class meanVal(const mpf_class* arr, size_t size, size_t acc) {

  mpf_class sum(0, acc), length(size, acc), result(0, acc);
  for (int i=0;i<length;i++)
  {
        sum += arr[i];
  }
   result = sum/length;
   return result;
}

mpf_class varVal(const mpf_class* arr, const size_t& size, const size_t& acc,
                 const mpf_class& meanValueSquare) {

  mpf_class sum2(0, acc), length(size, acc), result(0, acc);

  mpf_class temp(0, acc);
  for (int i=0; i< length; i++) {
    temp = arr[i] - meanValueSquare;
    sum2 += temp;
  }

  result = (sum2/length);
  return result;
}

mpf_class periodVal(const mpf_class* arr, size_t size, size_t acc) {

  mpf_class sum(0, acc), sum2(0, acc), length(size, acc), result(0, acc);
  for (int i=0; i< length; i++)
    sum += arr[i];

  sum = (sum / length);

  for (int i=0; i< length; i++) {
    mpf_class temp(0, acc);
    temp = arr[i] - sum;
    sum2 +=  temp * temp;
  }

  result = (sum2/length);
  return result;
}

const vector<mpf_class> getStream(size_t acc) {
  vector<mpf_class> vec;

  string line;
#ifdef LOG_INFO
  cout << "Enter input in one line:" << endl;
#endif
  std::getline(cin, line);
  stringstream lineStream(line);

  while (true)
  {
    mpf_class input_val;
    if(!(lineStream >> input_val)) break;
    input_val.set_prec(acc);

    vec.push_back(input_val);
  }

  return vec;
}

mpf_class* getArrStream(size_t acc, size_t& size) {
  mpf_class* arr = new mpf_class[MAX_ARR_SIZE];
  size_t i = 0;

  string line;
#ifdef LOG_INFO
  cout << "Enter input in one line:" << endl;
#endif
  std::getline(cin, line);
  stringstream lineStream(line);

  while (true)
  {
    mpf_class input_val;
    if(!(lineStream >> input_val)) break;
    input_val.set_prec(acc);

    arr[i] = input_val;
    i++;
  }

  size = i;
  return arr;
}

void debugPrintArr(const mpf_class* arr, long size) {
  cout << "Debug array print:" << endl;
  for (long i = 0; i < size; i++) {
    cout << arr[i] << " ";
  }
  cout << endl;

}

void printUsage(char **argv) {
  cout <<"usage: "<< argv[0] <<" <accuracy>\n";
}

int main (int argc, char **argv) {
  // Cin && cout optimization.
  std::ios_base::sync_with_stdio(false);
  // Max acc: 2^16 = 65536
  // Max size of array: 2^24 = 16777216
  // Max elem | value |: 2^64 = 18446744073709551616
  int accuracy = MAX_PRECISION; // Default accuracy.

  if ( argc > 1 ) {
    if (!strcmp(argv[1], "-h")) {
      printUsage(argv);
      return SUCCESS;
    }

    accuracy = atoi(argv[1]);
    if (accuracy < 1  && accuracy > MAX_PRECISION)
      return FAILURE;
  }

  mpf_class meanValue(0, accuracy);
  mpf_class varianceVal(0, accuracy);
  mpf_class periodicVal(0, accuracy);
  mpf_class meanValueSquare(0, accuracy);
  mpf_class sum(0, accuracy);

  // Our array.
  mpf_class* arr = new mpf_class[MAX_ARR_SIZE];
  size_t i = 0;

  string line;
#ifdef LOG_INFO
  cout << "Enter input in one line:" << endl;
#endif
  std::getline(cin, line);
  stringstream lineStream(line);

  mpf_class input_val;
  input_val.set_prec(accuracy);
  while (true)
  {
    if(!(lineStream >> input_val)) break;
    sum += input_val;
    arr[i] = input_val*input_val;
    i++;
  }

  meanValue = sum / i;
  meanValueSquare = meanValue * meanValue;
#ifdef LOG_INFO
  cout << "Starting prog" << endl;
#endif
//debugPrintArr(&vec[0], vec.size());

  cout.precision(accuracy);
  cout << meanValue << endl;

  cout << varVal(arr, i, accuracy, meanValueSquare) << endl;

  //cout << varVal(arr, i, accuracy, meanValue) << endl;

  delete[](arr);
  return 0;
}
<commit_msg>Refactored code, added TODO.<commit_after>#include <gmpxx.h>
#include <iostream>
#include <sstream>

#define SUCCESS 0
#define FAILURE 1

#define MAX_ARR_SIZE 16777216
#define MAX_PRECISION 65536

#define LOG_INFO

using namespace std;

/**
 * Variance calculation.
 */
mpf_class varVal(const mpf_class* arr, const size_t& size, const size_t& acc,
                 const mpf_class& meanValueSquare) {

  mpf_class sum2(0, acc), length(size, acc), result(0, acc);

  mpf_class temp(0, acc);
  for (int i=0; i< length; i++) {
    temp = arr[i] - meanValueSquare;
    sum2 += temp;
  }

  result = (sum2/length);
  return result;
}

/**
 * Not yet implemented.
 */
mpf_class periodVal(const mpf_class* arr, size_t size, size_t acc) {
  mpf_class result(0, acc);
  // TODO: DO task3 INLINE.
  return result;
}

/**
 * Not used, since we want to use this loop to do some initial calculations.
 */
mpf_class* getArrStream(size_t acc, size_t& size) {
  mpf_class* arr = new mpf_class[MAX_ARR_SIZE];
  size_t i = 0;

  string line;
#ifdef LOG_INFO
  cout << "Enter input in one line:" << endl;
#endif
  std::getline(cin, line);
  stringstream lineStream(line);

  mpf_class input_val;
  input_val.set_prec(acc);
  while (true)
  {

    if(!(lineStream >> input_val)) break;
    arr[i] = input_val;
    i++;
  }

  size = i;
  return arr;
}

/**
 * Debug only.
 */
void debugPrintArr(const mpf_class* arr, long size) {
  cout << "Debug array print:" << endl;
  for (long i = 0; i < size; i++) {
    cout << arr[i] << " ";
  }
  cout << endl;

}

/**
 * Print usage.
 */
void printUsage(char **argv) {
  cout <<"usage: "<< argv[0] <<" <accuracy>\n";
}

/**
 * Main function.
 * Current time for test2: 11s
 */
int main (int argc, char **argv) {
  // Cin && cout optimization.
  std::ios_base::sync_with_stdio(false);
  // Max acc: 2^16 = 65536
  // Max size of array: 2^24 = 16777216
  // Max elem | value |: 2^64 = 18446744073709551616
  int accuracy = MAX_PRECISION; // Default accuracy.

  if ( argc > 1 ) {
    if (!strcmp(argv[1], "-h")) {
      printUsage(argv);
      return SUCCESS;
    }

    accuracy = atoi(argv[1]);
    if (accuracy < 1  && accuracy > MAX_PRECISION)
      return FAILURE;
  }

  mpf_class meanValue(0, accuracy);
  mpf_class meanValueSquare(0, accuracy);
  mpf_class sum(0, accuracy);

  // Main sequence.
  mpf_class* arr = new mpf_class[MAX_ARR_SIZE];
  size_t size = 0;

  string line;
#ifdef LOG_INFO
  cout << "Enter input in one line:" << endl;
#endif
  std::getline(cin, line);
  stringstream lineStream(line);

  mpf_class input_val;
  input_val.set_prec(accuracy);
  while (true)
  {
    if(!(lineStream >> input_val)) break;
    sum += input_val;
    arr[size] = input_val*input_val;
    size++;
  }

  meanValue = sum / size;
  meanValueSquare = meanValue * meanValue;
#ifdef LOG_INFO
  cout << "Starting prog <size of arr: " << size <<  ">" << endl;
#endif

  cout.precision(accuracy);

  cout << meanValue << endl;
  cout << varVal(arr, size, accuracy, meanValueSquare) << endl;
  // TODO: cout << periodVal << endl;

  delete[](arr);
  return 0;
}
<|endoftext|>


<commit_before>#include <iostream>

#include "boost/asio.hpp"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/service.h"

#include "vtrc-common/vtrc-pool-pair.h"

#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-call-context.h"
#include "vtrc-common/vtrc-call-keeper.h"
#include "vtrc-common/vtrc-exception.h"
#include "vtrc-common/vtrc-protocol-layer.h"

#include "vtrc-client-base/vtrc-client.h"
#include "protocol/vtrc-rpc-lowlevel.pb.h"
#include "protocol/vtrc-service.pb.h"
#include "protocol/vtrc-errors.pb.h"

#include "boost/random.hpp"
#include "boost/random/random_device.hpp"

#include "vtrc-thread.h"
#include "vtrc-ref.h"
#include "vtrc-bind.h"
#include "vtrc-condition-variable.h"
#include "vtrc-chrono.h"

using namespace vtrc;

void on_connect( const boost::system::error_code &err )
{
    std::cout << "connected "
              << err.value( ) << " "
              << err.message( ) << "\n";
}

struct work_time {
    typedef vtrc::chrono::high_resolution_clock::time_point time_point;
    time_point start_;
    work_time( )
        :start_(vtrc::chrono::high_resolution_clock::now( ))
    {}
    ~work_time( )
    {
        time_point::duration stop(
                    vtrc::chrono::high_resolution_clock::now( ) - start_);
        std::cout << "call time: " << stop << "\n";
    }
};

class ping_impl: public vtrc_service::internal {

    client::vtrc_client *c_;

public:

    ping_impl( client::vtrc_client *c )
        :c_( c )
    {}

    void ping(::google::protobuf::RpcController* controller,
                         const ::vtrc_service::ping_req* request,
                         ::vtrc_service::pong_res* response,
                         ::google::protobuf::Closure* done)
    {
        common::closure_holder chold(done);
        std::cout << "ping event rcvd "
                  << c_->connection( )
                     ->get_call_context( )
                     ->get_lowlevel_message( )->id( )
                  << " " << vtrc::this_thread::get_id( ) << " "
                  //<< vtrc::chrono::high_resolution_clock::now( )
                  << "\n";

        vtrc::this_thread::sleep_for(
                    vtrc::chrono::microseconds(50) );

        return;

        const vtrc::common::call_context *cc =
                    vtrc::common::call_context::get( c_->connection( ) );

        vtrc::shared_ptr<google::protobuf::RpcChannel>
                ch(c_->create_channel( common::rpc_channel::USE_CONTEXT_CALL ));

        vtrc_service::test_message      mi;
        vtrc_service::test_rpc::Stub s( ch.get( ) );

        s.test2( NULL, &mi, &mi, NULL );

        //if( done ) done->Run( );
    }
};

class test_ev: public vtrc_service::test_events
{
    vtrc::common::connection_iface *c_;
public:
    test_ev( vtrc::common::connection_iface *c )
        :c_( c )
    {}

    void test(::google::protobuf::RpcController* controller,
                         const ::vtrc_service::test_message* request,
                         ::vtrc_service::test_message* response,
                         ::google::protobuf::Closure* done)
    {
        common::closure_holder ch(done);
        std::cout << "test event rcvd "
                  << c_->get_call_context( )->get_lowlevel_message( )->id( )
                  << " " << vtrc::this_thread::get_id( ) << " "
                  << "\n";
    }

};

void run_client( vtrc::shared_ptr<client::vtrc_client> cl, bool wait)
{
    vtrc::shared_ptr<google::protobuf::RpcChannel>
            ch(cl->create_channel( wait ? common::rpc_channel::DISABLE_WAIT
                                        : common::rpc_channel::DEFAULT ));
    vtrc_service::test_rpc::Stub s( ch.get( ) );

    vtrc_service::test_message mi;
    vtrc_service::test_message mir;

    size_t last = 0;

    std::string ts(1024 * 800, 0);

    std::cout << "this thread: "
              << vtrc::this_thread::get_id( ) << " "
              << "\n";

    for( int i=0; i<29999999999; ++i ) {
        try {

            if( wait )
                vtrc::this_thread::sleep_for(
                            vtrc::chrono::microseconds(500) );
            work_time wt;
            //mi.set_b( ts );
            s.test( NULL, &mi, &mir, NULL );
            last = i; //mir.id( );
            std::cout << "response: " << last << "\n";
            //cl.reset( );
        } catch( const vtrc::common::exception &ex ) {
            std::cout << "call error: "
                      << " code (" << ex.code( ) << ")"
                      << " category (" << ex.category( ) << ")"
                      << " what: " << ex.what( )
                      << " (" << ex.additional( ) << ")"
                      << "\n";
            //if( i % 100 == 0 )
            std::cout << i << "\n";
            if( ex.category( ) == vtrc_errors::CATEGORY_SYSTEM ) break;
            if( ex.code( ) == vtrc_errors::ERR_COMM ) break;
        } catch( const std::exception &ex ) {
            //std::cout << "call error: " << ex.what( ) << "\n";
        }
    }
}

void on_init_error(const vtrc_errors::container &cont, const char *message )
{
    std::cout << "Client init error: " << message << "\n";
    std::cout << cont.DebugString( );
}

void on_connect( )
{
    std::cout << "on_connect\n";
}

void on_ready( vtrc::condition_variable &cond )
{
    std::cout << "on_ready\n";
    cond.notify_all( );
}

void on_disconnect( vtrc::condition_variable &cond )
{
    std::cout << "on_disconnect\n";
    cond.notify_all( );
}

int main( )
{
    common::pool_pair pp(2, 4);
    vtrc::shared_ptr<client::vtrc_client> cl(client::vtrc_client::create(pp));

    cl->set_session_key( "1234" );

    vtrc::mutex              mut;
    vtrc::condition_variable cond;

    cl->get_on_connect( ).connect( boost::bind( on_connect ) );
    cl->get_on_ready( ).connect( boost::bind( on_ready, vtrc::ref(cond) ));
    cl->get_on_disconnect( ).connect( boost::bind( on_disconnect, vtrc::ref(cond) ));
    cl->get_on_init_error( ).connect( boost::bind( on_init_error, _1, _2 ) );

    //cl->connect( "/tmp/test.socket" );
    //cl->connect( "10.3.0.40", "44667" );
    //cl->connect( "\\\\.\\pipe\\test_pipe");
    cl->connect( "127.0.0.1", "44667" );
    //cl->connect( "::1", "44668" );
    ///cl->async_connect( "127.0.0.1", "44667", on_connect );

    cl->assign_rpc_handler( vtrc::shared_ptr<test_ev>(new test_ev(cl->connection( ).get( ))) );
    cl->assign_rpc_handler( vtrc::shared_ptr<ping_impl>(new ping_impl(cl.get( ))) );

    vtrc::unique_lock<vtrc::mutex>  lck(mut);
    cond.wait( lck, vtrc::bind( &client::vtrc_client::ready, cl ) );

    std::cout << "start program\n";

    //vtrc::thread( run_client, cl, true ).detach( );
    //vtrc::thread( run_client, cl, false ).detach( );

    vtrc::thread r( run_client, cl, false );

    //cond.wait( lck );
    r.join( );

    pp.stop_all( );
    pp.join_all( );

    google::protobuf::ShutdownProtobufLibrary( );
    return 0;

}
<commit_msg>proto<commit_after>#include <iostream>

#include "boost/asio.hpp"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/service.h"

#include "vtrc-common/vtrc-pool-pair.h"

#include "vtrc-common/vtrc-connection-iface.h"
#include "vtrc-common/vtrc-call-context.h"
#include "vtrc-common/vtrc-call-keeper.h"
#include "vtrc-common/vtrc-exception.h"
#include "vtrc-common/vtrc-protocol-layer.h"

#include "vtrc-client-base/vtrc-client.h"
#include "protocol/vtrc-rpc-lowlevel.pb.h"
#include "protocol/vtrc-service.pb.h"
#include "protocol/vtrc-errors.pb.h"

#include "boost/random.hpp"
#include "boost/random/random_device.hpp"

#include "vtrc-thread.h"
#include "vtrc-ref.h"
#include "vtrc-bind.h"
#include "vtrc-condition-variable.h"
#include "vtrc-chrono.h"

using namespace vtrc;

void on_connect( const boost::system::error_code &err )
{
    std::cout << "connected "
              << err.value( ) << " "
              << err.message( ) << "\n";
}

struct work_time {
    typedef vtrc::chrono::high_resolution_clock::time_point time_point;
    time_point start_;
    work_time( )
        :start_(vtrc::chrono::high_resolution_clock::now( ))
    {}
    ~work_time( )
    {
        time_point::duration stop(
                    vtrc::chrono::high_resolution_clock::now( ) - start_);
        std::cout << "call time: " << stop << "\n";
    }
};

class ping_impl: public vtrc_service::internal {

    client::vtrc_client *c_;

public:

    ping_impl( client::vtrc_client *c )
        :c_( c )
    {}

    void ping(::google::protobuf::RpcController* controller,
                         const ::vtrc_service::ping_req* request,
                         ::vtrc_service::pong_res* response,
                         ::google::protobuf::Closure* done)
    {
        common::closure_holder chold(done);
        std::cout << "ping event rcvd "
                  << c_->connection( )
                     ->get_call_context( )
                     ->get_lowlevel_message( )->id( )
                  << " " << vtrc::this_thread::get_id( ) << " "
                  //<< vtrc::chrono::high_resolution_clock::now( )
                  << "\n";

        vtrc::this_thread::sleep_for(
                    vtrc::chrono::microseconds(50) );

        return;

        const vtrc::common::call_context *cc =
                    vtrc::common::call_context::get( c_->connection( ) );

        vtrc::shared_ptr<google::protobuf::RpcChannel>
                ch(c_->create_channel( common::rpc_channel::USE_CONTEXT_CALL ));

        vtrc_service::test_message      mi;
        vtrc_service::test_rpc::Stub s( ch.get( ) );

        s.test2( NULL, &mi, &mi, NULL );

        //if( done ) done->Run( );
    }
};

class test_ev: public vtrc_service::test_events
{
    vtrc::common::connection_iface *c_;
public:
    test_ev( vtrc::common::connection_iface *c )
        :c_( c )
    {}

    void test(::google::protobuf::RpcController* controller,
                         const ::vtrc_service::test_message* request,
                         ::vtrc_service::test_message* response,
                         ::google::protobuf::Closure* done)
    {
        common::closure_holder ch(done);
        std::cout << "test event rcvd "
                  << c_->get_call_context( )->get_lowlevel_message( )->id( )
                  << " " << vtrc::this_thread::get_id( ) << " "
                  << "\n";
    }

};

void run_client( vtrc::shared_ptr<client::vtrc_client> cl, bool wait)
{
    vtrc::shared_ptr<google::protobuf::RpcChannel>
            ch(cl->create_channel( wait ? common::rpc_channel::DISABLE_WAIT
                                        : common::rpc_channel::DEFAULT ));
    vtrc_service::test_rpc::Stub s( ch.get( ) );

    vtrc_service::test_message mi;
    vtrc_service::test_message mir;

    size_t last = 0;

    std::string ts(1024 * 800, 0);

    std::cout << "this thread: "
              << vtrc::this_thread::get_id( ) << " "
              << "\n";
    for( int i=0; i<2999999; ++i ) {
        try {

            if( wait )
                vtrc::this_thread::sleep_for(
                            vtrc::chrono::microseconds(500) );
            work_time wt;
            //mi.set_b( ts );
            s.test( NULL, &mi, &mir, NULL );
            last = i; //mir.id( );
//            if( 0 == last % 201 )
                std::cout << "response: " << last << "\n";
            //cl.reset( );
        } catch( const vtrc::common::exception &ex ) {
//            std::cout << "call error: "
//                      << " code (" << ex.code( ) << ")"
//                      << " category (" << ex.category( ) << ")"
//                      << " what: " << ex.what( )
//                      << " (" << ex.additional( ) << ")"
//                      << "\n";
            //if( i % 100 == 0 )
//            std::cout << i << "\n";
            if( ex.category( ) == vtrc_errors::CATEGORY_SYSTEM ) break;
            if( ex.code( ) == vtrc_errors::ERR_COMM ) break;
        } catch( const std::exception &ex ) {
            //std::cout << "call error: " << ex.what( ) << "\n";
        }
    }
    std::cout << "last is: " << last << "\n";
}

void on_init_error(const vtrc_errors::container &cont, const char *message )
{
    std::cout << "Client init error: " << message << "\n";
    std::cout << cont.DebugString( );
}

void on_connect( )
{
    std::cout << "on_connect\n";
}

void on_ready( vtrc::condition_variable &cond )
{
    std::cout << "on_ready\n";
    cond.notify_all( );
}

void on_disconnect( vtrc::condition_variable &cond )
{
    std::cout << "on_disconnect\n";
    cond.notify_all( );
}

int main( )
{
    common::pool_pair pp(2, 4);
    vtrc::shared_ptr<client::vtrc_client> cl(client::vtrc_client::create(pp));

    cl->set_session_key( "1234" );

    vtrc::mutex              mut;
    vtrc::condition_variable cond;

    cl->get_on_connect( ).connect( boost::bind( on_connect ) );
    cl->get_on_ready( ).connect( boost::bind( on_ready, vtrc::ref(cond) ));
    cl->get_on_disconnect( ).connect( boost::bind( on_disconnect, vtrc::ref(cond) ));
    cl->get_on_init_error( ).connect( boost::bind( on_init_error, _1, _2 ) );

    //cl->connect( "/tmp/test.socket" );
    //cl->connect( "10.3.0.40", "44667" );
    //cl->connect( "\\\\.\\pipe\\test_pipe");
    cl->connect( "127.0.0.1", "44667" );
    //cl->connect( "::1", "44668" );
    ///cl->async_connect( "127.0.0.1", "44667", on_connect );

    cl->assign_rpc_handler( vtrc::shared_ptr<test_ev>(new test_ev(cl->connection( ).get( ))) );
    cl->assign_rpc_handler( vtrc::shared_ptr<ping_impl>(new ping_impl(cl.get( ))) );

    vtrc::unique_lock<vtrc::mutex>  lck(mut);
    cond.wait( lck, vtrc::bind( &client::vtrc_client::ready, cl ) );

    std::cout << "start program\n";

    //vtrc::thread( run_client, cl, true ).detach( );
    //vtrc::thread( run_client, cl, false ).detach( );

    vtrc::thread r( run_client, cl, false );

    //cond.wait( lck );
    r.join( );

    pp.stop_all( );
    pp.join_all( );

    google::protobuf::ShutdownProtobufLibrary( );
    return 0;

}
<|endoftext|>


<commit_before>// Copyright (C) 2015, 2018 Rob Caelers <rob.caelers@gmail.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 "loopp/http/HttpClient.hpp"

#include <sstream>
#include <algorithm>
#include <cstring>
#include <iostream>

#include "boost_xtensa.hpp"
#include "boost/lexical_cast.hpp"
#include "boost/algorithm/string.hpp"

#include "esp_log.h"
#include "esp_heap_caps.h"

#include "loopp/net/TCPStream.hpp"
#include "loopp/net/TLSStream.hpp"
#include "loopp/net/StreamBuffer.hpp"
#include "loopp/http/Uri.hpp"
#include "loopp/http/Request.hpp"
#include "loopp/http/Response.hpp"
#include "loopp/http/Headers.hpp"

static const char tag[] = "HTTP";

using namespace loopp;
using namespace loopp::http;

HttpClient::HttpClient(std::shared_ptr<loopp::core::MainLoop> loop) :
  loop(loop)
{
}

void
HttpClient::set_client_certificate(const char *cert, const char *key)
{
  client_cert = cert;
  client_key = key;
}

void
HttpClient::set_ca_certificate(const char *cert)
{
  ca_cert = cert;
}

void
HttpClient::execute(Request request, request_complete_slot_t slot)
{
  this->request = std::move(request);
  this->complete_slot = std::move(slot);

  try
    {
      if (ca_cert != nullptr)
        {
          std::shared_ptr<loopp::net::TLSStream> tls_sock = std::make_shared<loopp::net::TLSStream>(loop);
          if (client_cert != nullptr && client_key != nullptr)
            {
              tls_sock->set_client_certificate(client_cert, client_key);
            }
          tls_sock->set_ca_certificate(ca_cert);
          sock = tls_sock;
        }
      else
        {
          sock = std::make_shared<loopp::net::TCPStream>(loop);
        }

      auto self = shared_from_this();
      sock->connect(this->request.uri().host(), this->request.uri().port(), [this, self] (std::error_code ec) {
          if (!ec)
            {
              send_request();
            }
          else
            {
              handle_error("connect", ec);
            }
        });
    }
  catch (std::system_error &e)
    {
      handle_error(std::string("connect: ") + e.what(), e.code());
    }
}

void
HttpClient::read_body_async(std::size_t size, body_callback_t callback)
{
  read_body_async(size, loopp::core::make_slot(loop, callback));
}

void
HttpClient::read_body_async(std::size_t size, body_slot_t slot)
{
  std::size_t bytes_to_read = std::min<std::size_t>(body_length_left, std::max<int>(0, size - response_buffer.consume_size()));

  if (bytes_to_read > 0)
    {
      auto self = shared_from_this();
      sock->read_async(response_buffer, bytes_to_read,
                       [this, self, slot] (std::error_code ec, std::size_t bytes_transferred) {
                         if (!ec)
                           {
                             this->body_length_left -= bytes_transferred;
                             slot.call(ec, &response_buffer);
                           }
                         else
                           {
                             handle_error("read response", ec);
                           }
                       });
    }
  else
    {
      slot.call(std::error_code(), &response_buffer);
    }
}

void
HttpClient::send_request()
{
  try
    {
      update_request_headers();

      std::ostream stream(&request_buffer);

      stream << request.method() << " " << request.uri().path() << " HTTP/1.1\r\n";

      for (auto header : request.headers())
        {
          stream << header.first << ": " << header.second << "\r\n";
          ESP_LOGD(tag, "header : %s -> %s ", header.first.c_str(), header.second.c_str());;
        }
      stream << "\r\n";

      bool chunked = false;
      if (request.headers().has("Transfer-Encoding"))
        {
          chunked = boost::ifind_first(request.headers()["Transfer-Encoding"], "chunked");
        }

      auto self = shared_from_this();
      sock->write_async(request_buffer, [this, self, chunked] (std::error_code ec, std::size_t bytes_transferred) {
          if (!ec)
            {
              // TODO: support sending chunked body.
              send_body();
            }
          else
            {
              handle_error("send header", ec);
            }
        });
    }
  catch (std::system_error &e)
    {
      handle_error(std::string("send publish: ") + e.what(), e.code());
    }
}

void
HttpClient::update_request_headers()
{
  loopp::http::Headers &headers = request.headers();

  headers.emplace("Host", request.uri().host());

  if (!request.headers().has("Transfer-Encoding") ||
      !boost::ifind_first(request.headers()["Transfer-Encoding"], "chunked"))
    {
      headers.emplace("Content-Length", std::to_string(request.content().size()));
    }
}

void
HttpClient::send_body()
{
  if (request.content().size() > 0)
    {
      std::ostream stream(&request_buffer);
      stream << request.content();

      auto self = shared_from_this();
      sock->write_async(request_buffer, [this, self] (std::error_code ec, std::size_t bytes_transferred) {
          if (!ec)
            {
              read_response();
            }
          else
            {
              handle_error("send body", ec);
            }
        });
    }
  else
    {
      read_response();
    }
}

void
HttpClient::read_response()
{
  auto self = shared_from_this();
  sock->read_until_async(response_buffer, "\r\n\r\n", [this, self] (std::error_code ec, std::size_t bytes_transferred) {
      if (!ec)
        {
          handle_response();
        }
      else
        {
          handle_error("read response", ec);
        }
    });
}

void
HttpClient::handle_response()
{
  std::istream response_stream(&response_buffer);
  response_stream.imbue(std::locale::classic());

  parse_status_line(response_stream);
  parse_headers(response_stream);

  complete_slot.call(std::error_code(), response);
}

void
HttpClient::parse_status_line(std::istream &response_stream)
{
  std::string http_version;
  response_stream >> http_version;

  std::string status_code;
  response_stream >> status_code;

  std::string status_message;
  std::getline(response_stream, status_message);
  boost::algorithm::trim(status_message);

  response.status_code(boost::lexical_cast<int>(status_code));
  response.status_message(status_message);
}

void
HttpClient::parse_headers(std::istream &response_stream)
{
  response.headers().parse(response_stream);

  if (response.headers().has("connection"))
    {
      // TODO: pipelining
      keep_alive = !boost::iequals(response.headers()["Connection"], "close");
    }

  bool chunked = false;
  if (response.headers().has("transfer-encoding"))
    {
      chunked = boost::ifind_first(response.headers()["transfer-encoding"], "chunked");
    }

  if (!chunked)
    {
      if (response.headers().has("Content-Length"))
        {
          body_length = boost::lexical_cast<std::size_t>(response.headers()["Content-Length"]);

          if (body_length > response_buffer.consume_size())
            {
              body_length_left = body_length - response_buffer.consume_size();
            }
          else
            {
              body_length_left = 0;
            }

          ESP_LOGD(tag, "body-size=%d left=%d in-buffer=%d", body_length, body_length_left, response_buffer.consume_size());
        }
    }
}

void
HttpClient::handle_error(std::string what, std::error_code ec)
{
  if (ec)
    {
      ESP_LOGE(tag, "HTTP Error: %s %s", what.c_str(), ec.message().c_str());
      sock->close();
      sock.reset();
      complete_slot.call(ec, response);
    }
}
<commit_msg>Fix https connections<commit_after>// Copyright (C) 2015, 2018 Rob Caelers <rob.caelers@gmail.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 "loopp/http/HttpClient.hpp"

#include <algorithm>
#include <cstring>
#include <iostream>
#include <sstream>

#include "boost_xtensa.hpp"
#include "boost/algorithm/string.hpp"
#include "boost/lexical_cast.hpp"

#include "esp_heap_caps.h"
#include "esp_log.h"

#include "loopp/http/Headers.hpp"
#include "loopp/http/Request.hpp"
#include "loopp/http/Response.hpp"
#include "loopp/http/Uri.hpp"
#include "loopp/net/StreamBuffer.hpp"
#include "loopp/net/TCPStream.hpp"
#include "loopp/net/TLSStream.hpp"

static const char tag[] = "HTTP";

using namespace loopp;
using namespace loopp::http;

HttpClient::HttpClient(std::shared_ptr<loopp::core::MainLoop> loop)
    : loop(loop)
{
}

void
HttpClient::set_client_certificate(const char *cert, const char *key)
{
  client_cert = cert;
  client_key = key;
}

void
HttpClient::set_ca_certificate(const char *cert)
{
  ca_cert = cert;
}

void
HttpClient::execute(Request request, request_complete_slot_t slot)
{
  this->request = std::move(request);
  this->complete_slot = std::move(slot);

  try
    {
      if (this->request.scheme() == "https")
        {
          std::shared_ptr<loopp::net::TLSStream> tls_sock = std::make_shared<loopp::net::TLSStream>(loop);
          if (client_cert != nullptr && client_key != nullptr)
            {
              tls_sock->set_client_certificate(client_cert, client_key);
            }
          if (ca_cert != nullptr)
            {
              tls_sock->set_ca_certificate(ca_cert);
            }
          sock = tls_sock;
        }
      else
        {
          sock = std::make_shared<loopp::net::TCPStream>(loop);
        }

      auto self = shared_from_this();
      sock->connect(this->request.uri().host(), this->request.uri().port(), [this, self](std::error_code ec) {
        if (!ec)
          {
            send_request();
          }
        else
          {
            handle_error("connect", ec);
          }
      });
    }
  catch (std::system_error &e)
    {
      handle_error(std::string("connect: ") + e.what(), e.code());
    }
}

void
HttpClient::read_body_async(std::size_t size, body_callback_t callback)
{
  read_body_async(size, loopp::core::make_slot(loop, callback));
}

void
HttpClient::read_body_async(std::size_t size, body_slot_t slot)
{
  std::size_t bytes_to_read = std::min<std::size_t>(body_length_left, std::max<int>(0, size - response_buffer.consume_size()));

  if (bytes_to_read > 0)
    {
      auto self = shared_from_this();
      sock->read_async(response_buffer, bytes_to_read,
                       [this, self, slot](std::error_code ec, std::size_t bytes_transferred) {
                         if (!ec)
                           {
                             this->body_length_left -= bytes_transferred;
                             slot.call(ec, &response_buffer);
                           }
                         else
                           {
                             handle_error("read response", ec);
                           }
                       });
    }
  else
    {
      slot.call(std::error_code(), &response_buffer);
    }
}

void
HttpClient::send_request()
{
  try
    {
      update_request_headers();

      std::ostream stream(&request_buffer);

      stream << request.method() << " " << request.uri().path() << " HTTP/1.1\r\n";

      for (auto header : request.headers())
        {
          stream << header.first << ": " << header.second << "\r\n";
        }
      stream << "\r\n";

      bool chunked = false;
      if (request.headers().has("Transfer-Encoding"))
        {
          chunked = boost::ifind_first(request.headers()["Transfer-Encoding"], "chunked");
        }

      auto self = shared_from_this();
      sock->write_async(request_buffer, [this, self, chunked](std::error_code ec, std::size_t bytes_transferred) {
        if (!ec)
          {
            // TODO: support sending chunked body.
            send_body();
          }
        else
          {
            handle_error("send header", ec);
          }
      });
    }
  catch (std::system_error &e)
    {
      handle_error(std::string("send publish: ") + e.what(), e.code());
    }
}

void
HttpClient::update_request_headers()
{
  loopp::http::Headers &headers = request.headers();

  headers.emplace("Host", request.uri().host());

  if (!request.headers().has("Transfer-Encoding")
      || !boost::ifind_first(request.headers()["Transfer-Encoding"], "chunked"))
    {
      headers.emplace("Content-Length", std::to_string(request.content().size()));
    }
}

void
HttpClient::send_body()
{
  if (request.content().size() > 0)
    {
      std::ostream stream(&request_buffer);
      stream << request.content();

      auto self = shared_from_this();
      sock->write_async(request_buffer, [this, self](std::error_code ec, std::size_t bytes_transferred) {
        if (!ec)
          {
            read_response();
          }
        else
          {
            handle_error("send body", ec);
          }
      });
    }
  else
    {
      read_response();
    }
}

void
HttpClient::read_response()
{
  auto self = shared_from_this();
  sock->read_until_async(response_buffer, "\r\n\r\n", [this, self](std::error_code ec, std::size_t bytes_transferred) {
    if (!ec)
      {
        handle_response();
      }
    else
      {
        handle_error("read response", ec);
      }
  });
}

void
HttpClient::handle_response()
{
  std::istream response_stream(&response_buffer);
  response_stream.imbue(std::locale::classic());

  parse_status_line(response_stream);
  parse_headers(response_stream);

  complete_slot.call(std::error_code(), response);
}

void
HttpClient::parse_status_line(std::istream &response_stream)
{
  std::string http_version;
  response_stream >> http_version;

  std::string status_code;
  response_stream >> status_code;

  std::string status_message;
  std::getline(response_stream, status_message);
  boost::algorithm::trim(status_message);

  response.status_code(boost::lexical_cast<int>(status_code));
  response.status_message(status_message);
}

void
HttpClient::parse_headers(std::istream &response_stream)
{
  response.headers().parse(response_stream);

  if (response.headers().has("connection"))
    {
      // TODO: pipelining
      keep_alive = !boost::iequals(response.headers()["Connection"], "close");
    }

  bool chunked = false;
  if (response.headers().has("transfer-encoding"))
    {
      chunked = boost::ifind_first(response.headers()["transfer-encoding"], "chunked");
    }

  if (!chunked)
    {
      if (response.headers().has("Content-Length"))
        {
          body_length = boost::lexical_cast<std::size_t>(response.headers()["Content-Length"]);

          if (body_length > response_buffer.consume_size())
            {
              body_length_left = body_length - response_buffer.consume_size();
            }
          else
            {
              body_length_left = 0;
            }

          ESP_LOGD(tag, "body-size=%d left=%d in-buffer=%d", body_length, body_length_left,
                   response_buffer.consume_size());
        }
    }
}

void
HttpClient::handle_error(std::string what, std::error_code ec)
{
  if (ec)
    {
      ESP_LOGE(tag, "HTTP Error: %s %s", what.c_str(), ec.message().c_str());
      sock->close();
      sock.reset();
      complete_slot.call(ec, response);
    }
}
<|endoftext|>


<commit_before>/*
Copyright(c) 2016-2019 Panos Karabelas

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.
*/

//= INCLUDES =======================
#include "Widget_Viewport.h"
#include "Rendering/Renderer.h"
#include "World/Entity.h"
#include "World/Components/Camera.h"
#include "Widget_World.h"
#include "Core/Settings.h"
#include "../DragDrop.h"
//==================================

//= NAMESPACES ==========
using namespace std;
using namespace Directus;
using namespace Math;
//=======================

namespace _Widget_Viewport
{
	static Renderer* g_renderer	= nullptr;
	static World* g_world		= nullptr;
	float g_window_padding		= 4.0f;
}

Widget_Viewport::Widget_Viewport(Context* context) : Widget(context)
{
	m_title						= "Viewport";
	m_timeSinceLastResChange	= 0.0f;

	m_windowFlags |= ImGuiWindowFlags_NoScrollbar;
	_Widget_Viewport::g_renderer	= m_context->GetSubsystem<Renderer>().get();
	_Widget_Viewport::g_world		= m_context->GetSubsystem<World>().get();
	m_xMin = 400;
	m_yMin = 250;
}

bool Widget_Viewport::Begin()
{
	ImGui::SetNextWindowSize(ImVec2(m_xMin, m_yMin), ImGuiCond_FirstUseEver);
	ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(_Widget_Viewport::g_window_padding, _Widget_Viewport::g_window_padding));
	ImGui::Begin(m_title.c_str(), &m_isVisible, m_windowFlags);

	return true;
}

void Widget_Viewport::Tick(const float delta_time)
{
	if (!_Widget_Viewport::g_renderer)
		return;

	ShowFrame(delta_time);
	ImGui::PopStyleVar();
}

void Widget_Viewport::ShowFrame(const float delta_time)
{
	// Get current frame window resolution
	auto width			= static_cast<unsigned int>(ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x);
	auto height			= static_cast<unsigned int>(ImGui::GetWindowContentRegionMax().y - ImGui::GetWindowContentRegionMin().y);
	const auto max_res	= _Widget_Viewport::g_renderer->GetMaxResolution();
	if (width > max_res || height > max_res)
		return;

	// Make pixel perfect
	width	-= (width	% 2 != 0) ? 1 : 0;
	height	-= (height	% 2 != 0) ? 1 : 0;

	ImGui::Image(
		_Widget_Viewport::g_renderer->GetFrameShaderResource(),
		ImVec2(static_cast<float>(width), static_cast<float>(height)),
		ImVec2(0, 0),
		ImVec2(1, 1),
		ImColor(255, 255, 255, 255),
		ImColor(50, 127, 166, 255)
	);

	// Update engine's viewport
	_Widget_Viewport::g_renderer->viewport_editor_offset = Vector2(ImGui::GetWindowPos()) + _Widget_Viewport::g_window_padding;
	_Widget_Viewport::g_renderer->SetViewport(RHI_Viewport(0.0f, 0.0f, static_cast<float>(width), static_cast<float>(height)));

	// Update engine's resolution
	if (m_timeSinceLastResChange >= 0.250f) // Don't stress the GPU too much
	{
		_Widget_Viewport::g_renderer->SetResolution(width, height);
		m_timeSinceLastResChange = 0;
	}
	m_timeSinceLastResChange += delta_time;

	// If this widget was clicked, make the engine pick an entity
	if (ImGui::IsMouseClicked(0) && ImGui::IsItemHovered())
	{
		EditorHelper::Get().PickEntity();
	}

	// Handle model drop
	if (auto payload = DragDrop::Get().GetPayload(DragPayload_Model))
	{
		EditorHelper::Get().LoadModel(get<const char*>(payload->data));
	}
}<commit_msg>Draw the image after a potential Renderer::SetResolution() call has been made<commit_after>/*
Copyright(c) 2016-2019 Panos Karabelas

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.
*/

//= INCLUDES =======================
#include "Widget_Viewport.h"
#include "Rendering/Renderer.h"
#include "World/Entity.h"
#include "World/Components/Camera.h"
#include "Widget_World.h"
#include "Core/Settings.h"
#include "../DragDrop.h"
//==================================

//= NAMESPACES ==========
using namespace std;
using namespace Directus;
using namespace Math;
//=======================

namespace _Widget_Viewport
{
	static Renderer* g_renderer	= nullptr;
	static World* g_world		= nullptr;
	float g_window_padding		= 4.0f;
}

Widget_Viewport::Widget_Viewport(Context* context) : Widget(context)
{
	m_title						= "Viewport";
	m_timeSinceLastResChange	= 0.0f;

	m_windowFlags |= ImGuiWindowFlags_NoScrollbar;
	_Widget_Viewport::g_renderer	= m_context->GetSubsystem<Renderer>().get();
	_Widget_Viewport::g_world		= m_context->GetSubsystem<World>().get();
	m_xMin = 400;
	m_yMin = 250;
}

bool Widget_Viewport::Begin()
{
	ImGui::SetNextWindowSize(ImVec2(m_xMin, m_yMin), ImGuiCond_FirstUseEver);
	ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(_Widget_Viewport::g_window_padding, _Widget_Viewport::g_window_padding));
	ImGui::Begin(m_title.c_str(), &m_isVisible, m_windowFlags);

	return true;
}

void Widget_Viewport::Tick(const float delta_time)
{
	if (!_Widget_Viewport::g_renderer)
		return;

	ShowFrame(delta_time);
	ImGui::PopStyleVar();
}

void Widget_Viewport::ShowFrame(const float delta_time)
{
	// Get current frame window resolution
	auto width			= static_cast<unsigned int>(ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x);
	auto height			= static_cast<unsigned int>(ImGui::GetWindowContentRegionMax().y - ImGui::GetWindowContentRegionMin().y);
	const auto max_res	= _Widget_Viewport::g_renderer->GetMaxResolution();
	if (width > max_res || height > max_res)
		return;

	// Make pixel perfect
	width	-= (width	% 2 != 0) ? 1 : 0;
	height	-= (height	% 2 != 0) ? 1 : 0;

	// Update engine's viewport
	_Widget_Viewport::g_renderer->viewport_editor_offset = Vector2(ImGui::GetWindowPos()) + _Widget_Viewport::g_window_padding;
	_Widget_Viewport::g_renderer->SetViewport(RHI_Viewport(0.0f, 0.0f, static_cast<float>(width), static_cast<float>(height)));

	// Update engine's resolution
	if (m_timeSinceLastResChange >= 0.250f) // Don't stress the GPU too much
	{
		_Widget_Viewport::g_renderer->SetResolution(width, height);
		m_timeSinceLastResChange = 0;
	}
	m_timeSinceLastResChange += delta_time;

	// Draw the image after a potential Renderer::SetResolution() call has been made
	ImGui::Image(
		_Widget_Viewport::g_renderer->GetFrameShaderResource(),
		ImVec2(static_cast<float>(width), static_cast<float>(height)),
		ImVec2(0, 0),
		ImVec2(1, 1),
		ImColor(255, 255, 255, 255),
		ImColor(50, 127, 166, 255)
	);

	// If this widget was clicked, make the engine pick an entity
	if (ImGui::IsMouseClicked(0) && ImGui::IsItemHovered())
	{
		EditorHelper::Get().PickEntity();
	}

	// Handle model drop
	if (auto payload = DragDrop::Get().GetPayload(DragPayload_Model))
	{
		EditorHelper::Get().LoadModel(get<const char*>(payload->data));
	}
}<|endoftext|>