<commit_before>/* Copyright (C) 2013 BMW Group
 * Author: Manfred Bathelt (manfred.bathelt@bmw.de)
 * Author: Juergen Gehring (juergen.gehring@bmw.de)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _GLIBCXX_USE_NANOSLEEP
#define _GLIBCXX_USE_NANOSLEEP
#endif

#include <CommonAPI/DBus/DBusInputStream.h>
#include <CommonAPI/DBus/DBusMessage.h>
#include <CommonAPI/DBus/DBusProxy.h>
#include <CommonAPI/DBus/DBusConnection.h>
#include <CommonAPI/DBus/DBusStubAdapter.h>
#include <CommonAPI/DBus/DBusUtils.h>

#include <commonapi/tests/TestInterfaceDBusProxy.h>
#include <commonapi/tests/TestInterfaceDBusStubAdapter.h>
#include <commonapi/tests/TestInterfaceStubDefault.h>

#include <gtest/gtest.h>

#include <algorithm>
#include <cstdint>
#include <iostream>
#include <string>
#include <thread>
#include <vector>

static const std::string commonApiAddress = "local:CommonAPI.DBus.tests.DBusProxyTestInterface:CommonAPI.DBus.tests.DBusProxyTestService";
static const std::string commonApiServiceName = "CommonAPI.DBus.tests.DBusProxyTest";
static const std::string interfaceName = "CommonAPI.DBus.tests.DBusProxyTestInterface";
static const std::string busName = "CommonAPI.DBus.tests.DBusProxyTestService";
static const std::string objectPath = "/CommonAPI/DBus/tests/DBusProxyTestService";

class ProxyTest: public ::testing::Test {
protected:

    virtual void TearDown() {
        proxyDBusConnection_->disconnect();

        stubAdapter_.reset();

        if (stubDBusConnection_) {
            if (stubDBusConnection_->isConnected()) {
                stubDBusConnection_->releaseServiceName(busName);
                stubDBusConnection_->disconnect();
            }
            stubDBusConnection_.reset();
        }
    }

    void SetUp() {
        proxyDBusConnection_ = CommonAPI::DBus::DBusConnection::getSessionBus();
        ASSERT_TRUE(proxyDBusConnection_->connect());

        proxy_ = std::make_shared<commonapi::tests::TestInterfaceDBusProxy>(
                        commonApiAddress,
                        interfaceName,
                        busName,
                        objectPath,
                        proxyDBusConnection_);
    }

    void registerTestStub() {
        stubDBusConnection_ = CommonAPI::DBus::DBusConnection::getSessionBus();
        ASSERT_TRUE(stubDBusConnection_->connect());

        ASSERT_TRUE(stubDBusConnection_->requestServiceNameAndBlock(busName));

        auto stubDefault = std::make_shared<commonapi::tests::TestInterfaceStubDefault>();
        stubAdapter_ = std::make_shared<commonapi::tests::TestInterfaceDBusStubAdapter>(
                        commonApiAddress,
                        interfaceName,
                        busName,
                        objectPath,
                        stubDBusConnection_,
                        stubDefault);
        stubAdapter_->init();
    }

    void proxyRegisterForAvailabilityStatus() {
        proxyAvailabilityStatus_ = CommonAPI::AvailabilityStatus::UNKNOWN;

        proxy_->getProxyStatusEvent().subscribe([&](const CommonAPI::AvailabilityStatus& availabilityStatus) {
            std::cout << "Proxy AvailabilityStatus changed to " << (int) availabilityStatus << std::endl;
            proxyAvailabilityStatus_ = availabilityStatus;
        });
    }

    bool proxyWaitForAvailabilityStatus(const CommonAPI::AvailabilityStatus& availabilityStatus) const {
        std::chrono::milliseconds loopWaitDuration(100);

        if (proxyAvailabilityStatus_ == availabilityStatus)
            return true;

        for (int i = 0; i < 10; i++) {
            std::this_thread::sleep_for(loopWaitDuration);

            if (proxyAvailabilityStatus_ == availabilityStatus)
                return true;
        }

        return false;
    }

    std::shared_ptr<CommonAPI::DBus::DBusConnection> proxyDBusConnection_;
    std::shared_ptr<commonapi::tests::TestInterfaceDBusProxy> proxy_;
    CommonAPI::AvailabilityStatus proxyAvailabilityStatus_;

    std::shared_ptr<CommonAPI::DBus::DBusConnection> stubDBusConnection_;
    std::shared_ptr<commonapi::tests::TestInterfaceDBusStubAdapter> stubAdapter_;
};

TEST_F(ProxyTest, HasCorrectConnectionName) {
  std::string actualName = proxy_->getDBusBusName();
  EXPECT_EQ(busName, actualName);
}

TEST_F(ProxyTest, HasCorrectObjectPath) {
  std::string actualPath = proxy_->getDBusObjectPath();
  EXPECT_EQ(objectPath, actualPath);
}

TEST_F(ProxyTest, HasCorrectInterfaceName) {
  std::string actualName = proxy_->getInterfaceName();
  EXPECT_EQ(interfaceName, actualName);
}

TEST_F(ProxyTest, IsNotAvailable) {
	bool isAvailable = proxy_->isAvailable();
	EXPECT_FALSE(isAvailable);
}

TEST_F(ProxyTest, ServiceRegistry) {
	std::shared_ptr<CommonAPI::DBus::DBusProxyConnection> connection = proxy_->getDBusConnection();
	auto registry = connection->getDBusServiceRegistry();
	ASSERT_FALSE(!registry);
}

TEST_F(ProxyTest, DBusProxyStatusEventBeforeServiceIsRegistered) {
    proxyRegisterForAvailabilityStatus();

    ASSERT_NE(proxyAvailabilityStatus_, CommonAPI::AvailabilityStatus::AVAILABLE);

    registerTestStub();

    ASSERT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::AVAILABLE));

    stubDBusConnection_->disconnect();

    ASSERT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::NOT_AVAILABLE));
}

TEST_F(ProxyTest, DBusProxyStatusEventAfterServiceIsRegistered) {
    proxyDBusConnection_->disconnect();

    registerTestStub();

    ASSERT_TRUE(proxyDBusConnection_->connect());

    proxyRegisterForAvailabilityStatus();

    ASSERT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::AVAILABLE));

    stubDBusConnection_->disconnect();

    ASSERT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::NOT_AVAILABLE));
}

TEST_F(ProxyTest, ServiceStatus) {
    proxyDBusConnection_->requestServiceNameAndBlock(busName);

    std::shared_ptr<commonapi::tests::TestInterfaceStubDefault> stubDefault = std::make_shared<commonapi::tests::TestInterfaceStubDefault>();
    std::shared_ptr<commonapi::tests::TestInterfaceDBusStubAdapter> stubAdapter =  std::make_shared<commonapi::tests::TestInterfaceDBusStubAdapter>(
                    commonApiAddress,
                    interfaceName,
                    busName,
                    objectPath,
                    proxyDBusConnection_,
                    stubDefault);

    stubAdapter->init();

    auto testConnection = CommonAPI::DBus::DBusConnection::getSessionBus();
    testConnection->connect();

	std::vector<std::string> actuallyAvailableServices;
	actuallyAvailableServices = testConnection->getDBusServiceRegistry()->getAvailableServiceInstances(commonApiServiceName,
			"local");

	auto found = std::find(actuallyAvailableServices.begin(), actuallyAvailableServices.end(), commonApiAddress);

	ASSERT_TRUE(actuallyAvailableServices.begin() != actuallyAvailableServices.end());
	ASSERT_TRUE(found != actuallyAvailableServices.end());

	testConnection->disconnect();
}

TEST_F(ProxyTest, IsAvailableBlocking) {
    std::shared_ptr<commonapi::tests::TestInterfaceStubDefault> stubDefault = std::make_shared<commonapi::tests::TestInterfaceStubDefault>();
    std::shared_ptr<commonapi::tests::TestInterfaceDBusStubAdapter> stubAdapter =  std::make_shared<commonapi::tests::TestInterfaceDBusStubAdapter>(
                    commonApiAddress,
                    interfaceName,
                    busName,
                    objectPath,
                    proxyDBusConnection_,
                    stubDefault);

    stubAdapter->init();

    bool registered = proxyDBusConnection_->requestServiceNameAndBlock(busName);
    bool isAvailable = proxy_->isAvailableBlocking();
    EXPECT_EQ(registered, isAvailable);
}

TEST_F(ProxyTest, HasNecessaryAttributesAndEvents) {
	CommonAPI::InterfaceVersionAttribute& versionAttribute = (proxy_->getInterfaceVersionAttribute());
	CommonAPI::ProxyStatusEvent& statusEvent = (proxy_->getProxyStatusEvent());
}

TEST_F(ProxyTest, IsConnected) {
  ASSERT_TRUE(proxy_->getDBusConnection()->isConnected());
}

TEST_F(ProxyTest, TestInterfaceVersionAttribute) {
	CommonAPI::InterfaceVersionAttribute& versionAttribute = proxy_->getInterfaceVersionAttribute();
	CommonAPI::Version version;
	CommonAPI::CallStatus status = versionAttribute.getValue(version);
	ASSERT_EQ(CommonAPI::CallStatus::NOT_AVAILABLE, status);
}

TEST_F(ProxyTest, AsyncCallbacksAreCalledIfServiceNotAvailable) {
    commonapi::tests::DerivedTypeCollection::TestEnumExtended2 testInputStruct;
    commonapi::tests::DerivedTypeCollection::TestMap testInputMap;
    bool wasCalled = false;
    proxy_->testDerivedTypeMethodAsync(testInputStruct, testInputMap, [&] (const CommonAPI::CallStatus& callStatus,
                                                                          const commonapi::tests::DerivedTypeCollection::TestEnumExtended2&,
                                                                          const commonapi::tests::DerivedTypeCollection::TestMap&) {
                    ASSERT_EQ(callStatus, CommonAPI::CallStatus::NOT_AVAILABLE);
                    wasCalled = true;
            }
    );
    sleep(1);
    ASSERT_TRUE(wasCalled);
}

int main(int argc, char** argv) {
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
<commit_msg>tests: correct bus name in DBusProxyTest<commit_after>/* Copyright (C) 2013 BMW Group
 * Author: Manfred Bathelt (manfred.bathelt@bmw.de)
 * Author: Juergen Gehring (juergen.gehring@bmw.de)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _GLIBCXX_USE_NANOSLEEP
#define _GLIBCXX_USE_NANOSLEEP
#endif

#include <CommonAPI/DBus/DBusInputStream.h>
#include <CommonAPI/DBus/DBusMessage.h>
#include <CommonAPI/DBus/DBusProxy.h>
#include <CommonAPI/DBus/DBusConnection.h>
#include <CommonAPI/DBus/DBusStubAdapter.h>
#include <CommonAPI/DBus/DBusUtils.h>

#include <commonapi/tests/TestInterfaceDBusProxy.h>
#include <commonapi/tests/TestInterfaceDBusStubAdapter.h>
#include <commonapi/tests/TestInterfaceStubDefault.h>

#include <gtest/gtest.h>

#include <algorithm>
#include <cstdint>
#include <iostream>
#include <string>
#include <thread>
#include <vector>

static const std::string commonApiAddress = "local:CommonAPI.DBus.tests.DBusProxyTestInterface:CommonAPI.DBus.tests.DBusProxyTestService";
static const std::string commonApiServiceName = "CommonAPI.DBus.tests.DBusProxyTestInterface";
static const std::string interfaceName = "CommonAPI.DBus.tests.DBusProxyTestInterface";
static const std::string busName = "CommonAPI.DBus.tests.DBusProxyTestService";
static const std::string objectPath = "/CommonAPI/DBus/tests/DBusProxyTestService";

class ProxyTest: public ::testing::Test {
protected:

    virtual void TearDown() {
        proxyDBusConnection_->disconnect();

        stubAdapter_.reset();

        if (stubDBusConnection_) {
            if (stubDBusConnection_->isConnected()) {
                stubDBusConnection_->releaseServiceName(busName);
                stubDBusConnection_->disconnect();
            }
            stubDBusConnection_.reset();
        }
    }

    void SetUp() {
        proxyDBusConnection_ = CommonAPI::DBus::DBusConnection::getSessionBus();
        ASSERT_TRUE(proxyDBusConnection_->connect());

        proxy_ = std::make_shared<commonapi::tests::TestInterfaceDBusProxy>(
                        commonApiAddress,
                        interfaceName,
                        busName,
                        objectPath,
                        proxyDBusConnection_);
    }

    void registerTestStub() {
        stubDBusConnection_ = CommonAPI::DBus::DBusConnection::getSessionBus();
        ASSERT_TRUE(stubDBusConnection_->connect());

        ASSERT_TRUE(stubDBusConnection_->requestServiceNameAndBlock(busName));

        auto stubDefault = std::make_shared<commonapi::tests::TestInterfaceStubDefault>();
        stubAdapter_ = std::make_shared<commonapi::tests::TestInterfaceDBusStubAdapter>(
                        commonApiAddress,
                        interfaceName,
                        busName,
                        objectPath,
                        stubDBusConnection_,
                        stubDefault);
        stubAdapter_->init();
    }

    void proxyRegisterForAvailabilityStatus() {
        proxyAvailabilityStatus_ = CommonAPI::AvailabilityStatus::UNKNOWN;

        proxy_->getProxyStatusEvent().subscribe([&](const CommonAPI::AvailabilityStatus& availabilityStatus) {
            std::cout << "Proxy AvailabilityStatus changed to " << (int) availabilityStatus << std::endl;
            proxyAvailabilityStatus_ = availabilityStatus;
        });
    }

    bool proxyWaitForAvailabilityStatus(const CommonAPI::AvailabilityStatus& availabilityStatus) const {
        std::chrono::milliseconds loopWaitDuration(100);

        if (proxyAvailabilityStatus_ == availabilityStatus)
            return true;

        for (int i = 0; i < 10; i++) {
            std::this_thread::sleep_for(loopWaitDuration);

            if (proxyAvailabilityStatus_ == availabilityStatus)
                return true;
        }

        return false;
    }

    std::shared_ptr<CommonAPI::DBus::DBusConnection> proxyDBusConnection_;
    std::shared_ptr<commonapi::tests::TestInterfaceDBusProxy> proxy_;
    CommonAPI::AvailabilityStatus proxyAvailabilityStatus_;

    std::shared_ptr<CommonAPI::DBus::DBusConnection> stubDBusConnection_;
    std::shared_ptr<commonapi::tests::TestInterfaceDBusStubAdapter> stubAdapter_;
};

TEST_F(ProxyTest, HasCorrectConnectionName) {
  std::string actualName = proxy_->getDBusBusName();
  EXPECT_EQ(busName, actualName);
}

TEST_F(ProxyTest, HasCorrectObjectPath) {
  std::string actualPath = proxy_->getDBusObjectPath();
  EXPECT_EQ(objectPath, actualPath);
}

TEST_F(ProxyTest, HasCorrectInterfaceName) {
  std::string actualName = proxy_->getInterfaceName();
  EXPECT_EQ(interfaceName, actualName);
}

TEST_F(ProxyTest, IsNotAvailable) {
	bool isAvailable = proxy_->isAvailable();
	EXPECT_FALSE(isAvailable);
}

TEST_F(ProxyTest, ServiceRegistry) {
	std::shared_ptr<CommonAPI::DBus::DBusProxyConnection> connection = proxy_->getDBusConnection();
	auto registry = connection->getDBusServiceRegistry();
	ASSERT_FALSE(!registry);
}

TEST_F(ProxyTest, DBusProxyStatusEventBeforeServiceIsRegistered) {
    proxyRegisterForAvailabilityStatus();

    ASSERT_NE(proxyAvailabilityStatus_, CommonAPI::AvailabilityStatus::AVAILABLE);

    registerTestStub();

    ASSERT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::AVAILABLE));

    stubDBusConnection_->disconnect();

    ASSERT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::NOT_AVAILABLE));
}

TEST_F(ProxyTest, DBusProxyStatusEventAfterServiceIsRegistered) {
    proxyDBusConnection_->disconnect();

    registerTestStub();

    ASSERT_TRUE(proxyDBusConnection_->connect());

    proxyRegisterForAvailabilityStatus();

    ASSERT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::AVAILABLE));

    stubDBusConnection_->disconnect();

    ASSERT_TRUE(proxyWaitForAvailabilityStatus(CommonAPI::AvailabilityStatus::NOT_AVAILABLE));
}

TEST_F(ProxyTest, ServiceStatus) {
    proxyDBusConnection_->requestServiceNameAndBlock(busName);

    std::shared_ptr<commonapi::tests::TestInterfaceStubDefault> stubDefault = std::make_shared<commonapi::tests::TestInterfaceStubDefault>();
    std::shared_ptr<commonapi::tests::TestInterfaceDBusStubAdapter> stubAdapter =  std::make_shared<commonapi::tests::TestInterfaceDBusStubAdapter>(
                    commonApiAddress,
                    interfaceName,
                    busName,
                    objectPath,
                    proxyDBusConnection_,
                    stubDefault);

    stubAdapter->init();

    auto testConnection = CommonAPI::DBus::DBusConnection::getSessionBus();
    testConnection->connect();

	std::vector<std::string> actuallyAvailableServices;
	actuallyAvailableServices = testConnection->getDBusServiceRegistry()->getAvailableServiceInstances(commonApiServiceName,
			"local");

	auto found = std::find(actuallyAvailableServices.begin(), actuallyAvailableServices.end(), commonApiAddress);

	ASSERT_TRUE(actuallyAvailableServices.begin() != actuallyAvailableServices.end());
	ASSERT_TRUE(found != actuallyAvailableServices.end());

	testConnection->disconnect();
}

TEST_F(ProxyTest, IsAvailableBlocking) {
    registerTestStub();

    const bool isAvailable = proxy_->isAvailableBlocking();
    EXPECT_TRUE(isAvailable);
}

TEST_F(ProxyTest, HasNecessaryAttributesAndEvents) {
	CommonAPI::InterfaceVersionAttribute& versionAttribute = (proxy_->getInterfaceVersionAttribute());
	CommonAPI::ProxyStatusEvent& statusEvent = (proxy_->getProxyStatusEvent());
}

TEST_F(ProxyTest, IsConnected) {
  ASSERT_TRUE(proxy_->getDBusConnection()->isConnected());
}

TEST_F(ProxyTest, TestInterfaceVersionAttribute) {
	CommonAPI::InterfaceVersionAttribute& versionAttribute = proxy_->getInterfaceVersionAttribute();
	CommonAPI::Version version;
	CommonAPI::CallStatus status = versionAttribute.getValue(version);
	ASSERT_EQ(CommonAPI::CallStatus::NOT_AVAILABLE, status);
}

TEST_F(ProxyTest, AsyncCallbacksAreCalledIfServiceNotAvailable) {
    commonapi::tests::DerivedTypeCollection::TestEnumExtended2 testInputStruct;
    commonapi::tests::DerivedTypeCollection::TestMap testInputMap;
    bool wasCalled = false;
    proxy_->testDerivedTypeMethodAsync(testInputStruct, testInputMap, [&] (const CommonAPI::CallStatus& callStatus,
                                                                          const commonapi::tests::DerivedTypeCollection::TestEnumExtended2&,
                                                                          const commonapi::tests::DerivedTypeCollection::TestMap&) {
                    ASSERT_EQ(callStatus, CommonAPI::CallStatus::NOT_AVAILABLE);
                    wasCalled = true;
            }
    );
    sleep(1);
    ASSERT_TRUE(wasCalled);
}

int main(int argc, char** argv) {
	::testing::InitGoogleTest(&argc, argv);
	return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>#include <unistd.h>
#include <v8.h>
#include <node.h>
#include <assert.h>
#include <errno.h>
#include "../deps/aeternum/aeternum.h"

using namespace v8;
using namespace node;

static Handle<Value> Prefork(const Arguments& args) {
  HandleScope scope;

  int i, stdio_fds[3] = { -1, -1, -1 };

  if (!args[0].IsEmpty() && args[0]->IsArray()) {
    Local<Array> custom_fds = Local<Array>::Cast(args[0]);
    for(i = 0; i < 3; i++) {
      stdio_fds[i] = custom_fds->Get(i)->Int32Value();
    }
  }

  // fork(2) and setsid()
  if (aeternum_fork() < 0) {
    return ThrowException(ErrnoException(errno, "aeternum_fork()"));
  }
  // let the event loop know it happened
  ev_default_fork();

  if (aeternum_dup(stdio_fds[0], STDIN_FILENO) == -1) {
    return ThrowException(ErrnoException(errno, "aeternum_dup()"));
  }
  if (aeternum_dup(stdio_fds[1], STDOUT_FILENO) == -1) {
    return ThrowException(ErrnoException(errno, "aeternum_dup()"));
  }
  if (aeternum_dup(stdio_fds[2], STDERR_FILENO) == -1) {
    return ThrowException(ErrnoException(errno, "aeternum_dup()"));
  }

  // return null, since any error would have made things blow up by now.
  return scope.Close(Null());
}

extern "C" void init(Handle<Object> target) {
  HandleScope scope;

  NODE_SET_METHOD(target, "prefork", Prefork);
}
<commit_msg>[fix] Workaround for caching of pid by process.pid.<commit_after>#include <unistd.h>
#include <v8.h>
#include <node.h>
#include <assert.h>
#include <errno.h>
#include "../deps/aeternum/aeternum.h"

using namespace v8;
using namespace node;

static Handle<Value> Prefork(const Arguments& args) {
  HandleScope scope;

  int i, stdio_fds[3] = { -1, -1, -1 };

  if (!args[0].IsEmpty() && args[0]->IsArray()) {
    Local<Array> custom_fds = Local<Array>::Cast(args[0]);
    for(i = 0; i < 3; i++) {
      stdio_fds[i] = custom_fds->Get(i)->Int32Value();
    }
  }

  // fork(2) and setsid()
  if (aeternum_fork() < 0) {
    return ThrowException(ErrnoException(errno, "aeternum_fork()"));
  }
  // let the event loop know it happened
  ev_default_fork();

  if (aeternum_dup(stdio_fds[0], STDIN_FILENO) == -1) {
    return ThrowException(ErrnoException(errno, "aeternum_dup()"));
  }
  if (aeternum_dup(stdio_fds[1], STDOUT_FILENO) == -1) {
    return ThrowException(ErrnoException(errno, "aeternum_dup()"));
  }
  if (aeternum_dup(stdio_fds[2], STDERR_FILENO) == -1) {
    return ThrowException(ErrnoException(errno, "aeternum_dup()"));
  }

  // return the new pid of the child process.
  return scope.Close(Integer::New(getpid()));
}

extern "C" void init(Handle<Object> target) {
  HandleScope scope;

  NODE_SET_METHOD(target, "prefork", Prefork);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, MassaRoddel, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/peer_connection.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"

#include "libtorrent/extensions/ut_pex.hpp"

namespace libtorrent { namespace
{
	const char extension_name[] = "ut_pex";

	enum
	{
		extension_index = 1,
		max_peer_entries = 100
	};

	bool send_peer(peer_connection const& p)
	{
		// don't send out peers that we haven't connected to
		// (that have connected to us)
		if (!p.is_local()) return false;
		// don't send out peers that we haven't successfully connected to
		if (p.is_connecting()) return false;
		return true;
	}

	struct ut_pex_plugin: torrent_plugin
	{
		ut_pex_plugin(torrent& t): m_torrent(t), m_1_minute(0) {}

		virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection* pc);

		std::vector<char>& get_ut_pex_msg()
		{
			return m_ut_pex_msg;
		}

		// the second tick of the torrent
		// each minute the new lists of "added" + "added.f" and "dropped"
		// are calculated here and the pex message is created
		// each peer connection will use this message
		// max_peer_entries limits the packet size
		virtual void tick()
		{
			if (++m_1_minute < 60) return;

			m_1_minute = 0;

			entry pex;
			std::string& pla = pex["added"].string();
			std::string& pld = pex["dropped"].string();
			std::string& plf = pex["added.f"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& pld6 = pex["dropped6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> pld_out(pld);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> pld6_out(pld6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			std::set<tcp::endpoint> dropped;
			m_old_peers.swap(dropped);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
				peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				tcp::endpoint const& remote = peer->remote();
				m_old_peers.insert(remote);

				std::set<tcp::endpoint>::iterator di = dropped.find(remote);
				if (di == dropped.end())
				{
					// don't write too big of a package
					if (num_added >= max_peer_entries) break;

					// only send proper bittorrent peers
					bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
					if (!p) continue;

					// no supported flags to set yet
					// 0x01 - peer supports encryption
					// 0x02 - peer is a seed
					int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
					flags |= p->supports_encryption() ? 1 : 0;
#endif
					// i->first was added since the last time
					if (remote.address().is_v4())
					{
						detail::write_endpoint(remote, pla_out);
						detail::write_uint8(flags, plf_out);
					}
					else
					{
						detail::write_endpoint(remote, pla6_out);
						detail::write_uint8(flags, plf6_out);
					}
					++num_added;
				}
				else
				{
					// this was in the previous message
					// so, it wasn't dropped
					dropped.erase(di);
				}
			}

			for (std::set<tcp::endpoint>::const_iterator i = dropped.begin()
				, end(dropped.end()); i != end; ++i)
			{
				if (i->address().is_v4())
					detail::write_endpoint(*i, pld_out);
				else
					detail::write_endpoint(*i, pld6_out);
			}

			m_ut_pex_msg.clear();
			bencode(std::back_inserter(m_ut_pex_msg), pex);
		}

	private:
		torrent& m_torrent;

		std::set<tcp::endpoint> m_old_peers;
		int m_1_minute;
		std::vector<char> m_ut_pex_msg;
	};

	struct ut_pex_peer_plugin : peer_plugin
	{
		ut_pex_peer_plugin(torrent& t, peer_connection& pc, ut_pex_plugin& tp)
			: m_torrent(t)
			, m_pc(pc)
			, m_tp(tp)
			, m_1_minute(0)
			, m_message_index(0)
			, m_first_time(true)
		{}

		virtual void add_handshake(entry& h)
		{
			entry& messages = h["m"];
			messages[extension_name] = extension_index;
		}

		virtual bool on_extension_handshake(entry const& h)
		{
			entry const& messages = h["m"];

			if (entry const* index = messages.find_key(extension_name))
			{
				m_message_index = index->integer();
				return true;
			}
			else
			{
				m_message_index = 0;
				return false;
			}
		}

		virtual bool on_extended(int length, int msg, buffer::const_interval body)
		{
			if (msg != extension_index) return false;
			if (m_message_index == 0) return false;

			if (length > 500 * 1024)
				throw protocol_error("uT peer exchange message larger than 500 kB");

			if (body.left() < length) return true;

			try
			{
				entry pex_msg = bdecode(body.begin, body.end);
				std::string const& peers = pex_msg["added"].string();
				std::string const& peer_flags = pex_msg["added.f"].string();

				int num_peers = peers.length() / 6;
				char const* in = peers.c_str();
				char const* fin = peer_flags.c_str();

				if (int(peer_flags.size()) != num_peers)
					return true;

				peer_id pid(0);
				policy& p = m_torrent.get_policy();
				for (int i = 0; i < num_peers; ++i)
				{
					tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
					char flags = detail::read_uint8(fin);
					p.peer_from_tracker(adr, pid, peer_info::pex, flags);
				}

				if (entry const* p6 = pex_msg.find_key("added6"))
				{
					std::string const& peers6 = p6->string();
					std::string const& peer6_flags = pex_msg["added6.f"].string();

					int num_peers = peers6.length() / 18;
					char const* in = peers6.c_str();
					char const* fin = peer6_flags.c_str();

					if (int(peer6_flags.size()) != num_peers)
						return true;

					peer_id pid(0);
					policy& p = m_torrent.get_policy();
					for (int i = 0; i < num_peers; ++i)
					{
						tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in);
						char flags = detail::read_uint8(fin);
						p.peer_from_tracker(adr, pid, peer_info::pex, flags);
					}
				}
			}
			catch (std::exception&)
			{
				throw protocol_error("invalid uT peer exchange message");
			}
			return true;
		}

		// the peers second tick
		// every minute we send a pex message
		virtual void tick()
		{
			if (!m_message_index) return;	// no handshake yet
			if (++m_1_minute <= 60) return;

			if (m_first_time)
			{
				send_ut_peer_list();
				m_first_time = false;
			}
			else
			{
				send_ut_peer_diff();
			}
			m_1_minute = 0;
		}

	private:

		void send_ut_peer_diff()
		{
			std::vector<char> const& pex_msg = m_tp.get_ut_pex_msg();

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		void send_ut_peer_list()
		{
			entry pex;
			// leave the dropped string empty
			pex["dropped"].string();
			std::string& pla = pex["added"].string();
			std::string& plf = pex["added.f"].string();
			pex["dropped6"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
				peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				// don't write too big of a package
				if (num_added >= max_peer_entries) break;

				// only send proper bittorrent peers
				bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
				if (!p) continue;

				// no supported flags to set yet
				// 0x01 - peer supports encryption
				// 0x02 - peer is a seed
				int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
				flags |= p->supports_encryption() ? 1 : 0;
#endif
				tcp::endpoint const& remote = peer->remote();
				// i->first was added since the last time
				if (remote.address().is_v4())
				{
					detail::write_endpoint(remote, pla_out);
					detail::write_uint8(flags, plf_out);
				}
				else
				{
					detail::write_endpoint(remote, pla6_out);
					detail::write_uint8(flags, plf6_out);
				}
				++num_added;
			}
			std::vector<char> pex_msg;
			bencode(std::back_inserter(pex_msg), pex);

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		torrent& m_torrent;
		peer_connection& m_pc;
		ut_pex_plugin& m_tp;
		int m_1_minute;
		int m_message_index;

		// this is initialized to true, and set to
		// false after the first pex message has been sent.
		// it is used to know if a diff message or a full
		// message should be sent.
		bool m_first_time;
	};

	boost::shared_ptr<peer_plugin> ut_pex_plugin::new_connection(peer_connection* pc)
	{
		bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
		if (!c) return boost::shared_ptr<peer_plugin>();
		return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
			, *pc, *this));
	}
}}

namespace libtorrent
{

	boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
	{
		if (t->torrent_file().priv())
		{
			return boost::shared_ptr<torrent_plugin>();
		}
		return boost::shared_ptr<torrent_plugin>(new ut_pex_plugin(*t));
	}

}

<commit_msg>ut_pex sends peers sooner<commit_after>/*

Copyright (c) 2006, MassaRoddel, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/shared_ptr.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/peer_connection.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"

#include "libtorrent/extensions/ut_pex.hpp"

namespace libtorrent { namespace
{
	const char extension_name[] = "ut_pex";

	enum
	{
		extension_index = 1,
		max_peer_entries = 100
	};

	bool send_peer(peer_connection const& p)
	{
		// don't send out peers that we haven't connected to
		// (that have connected to us)
		if (!p.is_local()) return false;
		// don't send out peers that we haven't successfully connected to
		if (p.is_connecting()) return false;
		return true;
	}

	struct ut_pex_plugin: torrent_plugin
	{
		ut_pex_plugin(torrent& t): m_torrent(t), m_1_minute(55) {}

		virtual boost::shared_ptr<peer_plugin> new_connection(peer_connection* pc);

		std::vector<char>& get_ut_pex_msg()
		{
			return m_ut_pex_msg;
		}

		// the second tick of the torrent
		// each minute the new lists of "added" + "added.f" and "dropped"
		// are calculated here and the pex message is created
		// each peer connection will use this message
		// max_peer_entries limits the packet size
		virtual void tick()
		{
			if (++m_1_minute < 60) return;

			m_1_minute = 0;

			entry pex;
			std::string& pla = pex["added"].string();
			std::string& pld = pex["dropped"].string();
			std::string& plf = pex["added.f"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& pld6 = pex["dropped6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> pld_out(pld);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> pld6_out(pld6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			std::set<tcp::endpoint> dropped;
			m_old_peers.swap(dropped);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
				peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				tcp::endpoint const& remote = peer->remote();
				m_old_peers.insert(remote);

				std::set<tcp::endpoint>::iterator di = dropped.find(remote);
				if (di == dropped.end())
				{
					// don't write too big of a package
					if (num_added >= max_peer_entries) break;

					// only send proper bittorrent peers
					bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
					if (!p) continue;

					// no supported flags to set yet
					// 0x01 - peer supports encryption
					// 0x02 - peer is a seed
					int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
					flags |= p->supports_encryption() ? 1 : 0;
#endif
					// i->first was added since the last time
					if (remote.address().is_v4())
					{
						detail::write_endpoint(remote, pla_out);
						detail::write_uint8(flags, plf_out);
					}
					else
					{
						detail::write_endpoint(remote, pla6_out);
						detail::write_uint8(flags, plf6_out);
					}
					++num_added;
				}
				else
				{
					// this was in the previous message
					// so, it wasn't dropped
					dropped.erase(di);
				}
			}

			for (std::set<tcp::endpoint>::const_iterator i = dropped.begin()
				, end(dropped.end()); i != end; ++i)
			{
				if (i->address().is_v4())
					detail::write_endpoint(*i, pld_out);
				else
					detail::write_endpoint(*i, pld6_out);
			}

			m_ut_pex_msg.clear();
			bencode(std::back_inserter(m_ut_pex_msg), pex);
		}

	private:
		torrent& m_torrent;

		std::set<tcp::endpoint> m_old_peers;
		int m_1_minute;
		std::vector<char> m_ut_pex_msg;
	};

	struct ut_pex_peer_plugin : peer_plugin
	{
		ut_pex_peer_plugin(torrent& t, peer_connection& pc, ut_pex_plugin& tp)
			: m_torrent(t)
			, m_pc(pc)
			, m_tp(tp)
			, m_1_minute(55)
			, m_message_index(0)
			, m_first_time(true)
		{}

		virtual void add_handshake(entry& h)
		{
			entry& messages = h["m"];
			messages[extension_name] = extension_index;
		}

		virtual bool on_extension_handshake(entry const& h)
		{
			entry const& messages = h["m"];

			if (entry const* index = messages.find_key(extension_name))
			{
				m_message_index = index->integer();
				return true;
			}
			else
			{
				m_message_index = 0;
				return false;
			}
		}

		virtual bool on_extended(int length, int msg, buffer::const_interval body)
		{
			if (msg != extension_index) return false;
			if (m_message_index == 0) return false;

			if (length > 500 * 1024)
				throw protocol_error("uT peer exchange message larger than 500 kB");

			if (body.left() < length) return true;

			try
			{
				entry pex_msg = bdecode(body.begin, body.end);
				std::string const& peers = pex_msg["added"].string();
				std::string const& peer_flags = pex_msg["added.f"].string();

				int num_peers = peers.length() / 6;
				char const* in = peers.c_str();
				char const* fin = peer_flags.c_str();

				if (int(peer_flags.size()) != num_peers)
					return true;

				peer_id pid(0);
				policy& p = m_torrent.get_policy();
				for (int i = 0; i < num_peers; ++i)
				{
					tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
					char flags = detail::read_uint8(fin);
					p.peer_from_tracker(adr, pid, peer_info::pex, flags);
				}

				if (entry const* p6 = pex_msg.find_key("added6"))
				{
					std::string const& peers6 = p6->string();
					std::string const& peer6_flags = pex_msg["added6.f"].string();

					int num_peers = peers6.length() / 18;
					char const* in = peers6.c_str();
					char const* fin = peer6_flags.c_str();

					if (int(peer6_flags.size()) != num_peers)
						return true;

					peer_id pid(0);
					policy& p = m_torrent.get_policy();
					for (int i = 0; i < num_peers; ++i)
					{
						tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in);
						char flags = detail::read_uint8(fin);
						p.peer_from_tracker(adr, pid, peer_info::pex, flags);
					}
				}
			}
			catch (std::exception&)
			{
				throw protocol_error("invalid uT peer exchange message");
			}
			return true;
		}

		// the peers second tick
		// every minute we send a pex message
		virtual void tick()
		{
			if (!m_message_index) return;	// no handshake yet
			if (++m_1_minute <= 60) return;

			if (m_first_time)
			{
				send_ut_peer_list();
				m_first_time = false;
			}
			else
			{
				send_ut_peer_diff();
			}
			m_1_minute = 0;
		}

	private:

		void send_ut_peer_diff()
		{
			std::vector<char> const& pex_msg = m_tp.get_ut_pex_msg();

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		void send_ut_peer_list()
		{
			entry pex;
			// leave the dropped string empty
			pex["dropped"].string();
			std::string& pla = pex["added"].string();
			std::string& plf = pex["added.f"].string();
			pex["dropped6"].string();
			std::string& pla6 = pex["added6"].string();
			std::string& plf6 = pex["added6.f"].string();
			std::back_insert_iterator<std::string> pla_out(pla);
			std::back_insert_iterator<std::string> plf_out(plf);
			std::back_insert_iterator<std::string> pla6_out(pla6);
			std::back_insert_iterator<std::string> plf6_out(plf6);

			int num_added = 0;
			for (torrent::peer_iterator i = m_torrent.begin()
				, end(m_torrent.end()); i != end; ++i)
			{
				peer_connection* peer = *i;
				if (!send_peer(*peer)) continue;

				// don't write too big of a package
				if (num_added >= max_peer_entries) break;

				// only send proper bittorrent peers
				bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(peer);
				if (!p) continue;

				// no supported flags to set yet
				// 0x01 - peer supports encryption
				// 0x02 - peer is a seed
				int flags = p->is_seed() ? 2 : 0;
#ifndef TORRENT_DISABLE_ENCRYPTION
				flags |= p->supports_encryption() ? 1 : 0;
#endif
				tcp::endpoint const& remote = peer->remote();
				// i->first was added since the last time
				if (remote.address().is_v4())
				{
					detail::write_endpoint(remote, pla_out);
					detail::write_uint8(flags, plf_out);
				}
				else
				{
					detail::write_endpoint(remote, pla6_out);
					detail::write_uint8(flags, plf6_out);
				}
				++num_added;
			}
			std::vector<char> pex_msg;
			bencode(std::back_inserter(pex_msg), pex);

			buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size());

			detail::write_uint32(1 + 1 + pex_msg.size(), i.begin);
			detail::write_uint8(bt_peer_connection::msg_extended, i.begin);
			detail::write_uint8(m_message_index, i.begin);
			std::copy(pex_msg.begin(), pex_msg.end(), i.begin);
			i.begin += pex_msg.size();

			TORRENT_ASSERT(i.begin == i.end);
			m_pc.setup_send();
		}

		torrent& m_torrent;
		peer_connection& m_pc;
		ut_pex_plugin& m_tp;
		int m_1_minute;
		int m_message_index;

		// this is initialized to true, and set to
		// false after the first pex message has been sent.
		// it is used to know if a diff message or a full
		// message should be sent.
		bool m_first_time;
	};

	boost::shared_ptr<peer_plugin> ut_pex_plugin::new_connection(peer_connection* pc)
	{
		bt_peer_connection* c = dynamic_cast<bt_peer_connection*>(pc);
		if (!c) return boost::shared_ptr<peer_plugin>();
		return boost::shared_ptr<peer_plugin>(new ut_pex_peer_plugin(m_torrent
			, *pc, *this));
	}
}}

namespace libtorrent
{

	boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
	{
		if (t->torrent_file().priv())
		{
			return boost::shared_ptr<torrent_plugin>();
		}
		return boost::shared_ptr<torrent_plugin>(new ut_pex_plugin(*t));
	}

}

<|endoftext|>


<commit_before>//
//  main2.cpp
//  test_SCUD
//
//  Created by Boris Vigman on 08/07/2017.
//  Copyright © 2017 Boris Vigman. All rights reserved.
//

#include "scud.h"
using namespace SCUD;

#include <iostream>
#include <thread>
#include <chrono>
#include "vector"

template<typename TSchedulable,typename Tid> class Queue1:public LinkableQueue<int,void*>{

};
template<typename TSchedulable,typename Tid> class Dropper1:public LinkableDropper<int,void*>{
public:

    void processOnPush(TSchedulable sch, long long schedulingParam){
        int x=0;
    }
    void processOnPull(TSchedulable sch, long long schedulingParam){
        int x=0;
    }
    void processOnPullPush(TSchedulable sch, long long schedulingParam){
        int x=0;
    }
};
class Source{
    char priority;
    float weight;
    int label;
    long long delay;
    Queue1<int,void*> queue0;
    LinkableQueue<int,void*> queue1;
    Dropper1<int,void*> drop0;
    LinkableDropper<int,void*> drop1;
    LinkablePass<int, void*> pass1,pass2;
    //LinkablePass<int,void*> pass;
    void run(){
        SCUD_RC r0;
        drop1.unlink(&r0);
        drop0.setPriority(7);
        drop1.setPriority(priority);
        SCUD_RC rc= queue0.setPriority(priority);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue0.setWeight(weight);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue0.setLowThreshold(1);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue0.setHighThreshold(20);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue1.setDRRQuantum(0);
        rc=queue1.setDRRQuantum(50);
        rc=queue1.setWeight(5);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue1.setLowThreshold(1);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue1.setHighThreshold(30);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc= queue1.setPriority(priority);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        int count=10;

        //while(count>0){
        SCUD_RC status=SCUD_RC_OK;
        //queue.unlink(&status);
        //std::cout<<"loop: source"<<std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(delay));
        queue1.linkSuccessor(&drop1);
        queue0.linkSuccessor(&drop0);

        drop0.linkSuccessor(&queue0);
        //status=next->linkPredecessor(&drop1);

        //}
        while(1){
            std::this_thread::sleep_for(std::chrono::milliseconds(delay));

            //buildCompound();
            auto start= std::chrono::high_resolution_clock::now() ;
            drop0.push(label, label*10);
            auto end= std::chrono::high_resolution_clock::now() ;
            auto diff = end - start;
            //std::cout<<"Push delay="<<std::chrono::duration <double, std::micro>(diff).count()<<std::endl;
            //std::cout<<"Queue1 ["<<label<<"] has "<<queue1.size()<<" objects"<<std::endl;
             start= std::chrono::high_resolution_clock::now() ;
            pass1.pullAndPush();
             end= std::chrono::high_resolution_clock::now() ;
             diff = end - start;
            //std::cout<<"Pull/Push delay="<<std::chrono::duration <double, std::micro>(diff).count()<<std::endl;
            //std::cout<<"Queue0 ["<<label<<"] has "<<queue0.size()<<" objects;"<<"Queue1 ["<<label<<"] has "<<queue1.size()<<" objects"<<std::endl;
            //breakCompound();
            /*
            count--;
            if(count<0){
                count=100;
                std::this_thread::sleep_for(std::chrono::milliseconds(delay*100));
            }
             */
        }
    }
public:
    Source(){weight=-1;priority=-1;label=-1;delay=100;}
    Source(int lbl, char p,float w,long long delayMilli){
        priority=p;
        weight=w;
        label=lbl;
        delay=delayMilli;
    }
    std::thread start() {
        return std::thread([=] { run(); });
    }
    void buildCompound(){
        drop0.linkSuccessor(&queue0);
        queue0.linkSuccessor(&pass1);
        pass1.linkSuccessor(&queue1);
        queue1.linkSuccessor(&pass2);
        pass2.linkSuccessor(&drop1);

    }
    void breakCompound(){
        SCUD_RC status=SCUD_RC_OK;
        Linkable<int,void*>::LinkedObjectsTuple lot1=drop1.unlink(&status);
        if(status!=SCUD_RC_OK){
            std::cout<<SCHelper::convertReturnCodeToString(status)<<std::endl;
        }
        Linkable<int,void*>::LinkedObjectsTuple lot2=queue0.unlink(&status);
        if(status!=SCUD_RC_OK){
            std::cout<<SCHelper::convertReturnCodeToString(status)<<std::endl;
        }
        Linkable<int,void*>::LinkedObjectsTuple lot3=queue1.unlink(&status);
        if(status!=SCUD_RC_OK){
            std::cout<<SCHelper::convertReturnCodeToString(status)<<std::endl;
        }
    }
    Linkable<int,void*>* compoundBegin(){
        return &drop0;
    }
    Linkable<int,void*>* compoundEnd(){
        return &drop1;
    }
};

class Sink{
    //LinkableSchedulerPriority<int, void*> scheduler;
    //LinkableSchedulerNaiveRR<int, void*> scheduler;
    LinkableSchedulerDRR<int, void*> scheduler;
    LinkableNull<int, void*> null;
    void run(){
        scheduler.setPriority(9);
        scheduler.setWeight(1);

//        while(1){
//            //std::cout<<"loop: sink"<<std::endl;
//            std::this_thread::sleep_for(std::chrono::milliseconds(100));
//            SCUD_RC rc=SCUD_RC_OK;
//            struct Linkable<int,void*>::Queueable res;
////            rc=next->pull(res);
////            if(rc==SCUD_RC_OK){
////                std::cout<<"Sink: Pulled object "<<res.scheduled<<" "<<std::endl;
////            }else{
////                std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
////            }
////            if(res.scheduled>100000){
////                int x=0;
////            }
//        }
    }
public:
    Sink(Linkable<int, void*>* l){

    }
    std::thread start() {
        return std::thread([=] { run(); });
    }
    void buildCompound(){
        scheduler.linkSuccessor(&null);
    };
    void breakCompound(){
        SCUD_RC status=SCUD_RC_OK;
        null.unlink(&status);
    };
    Linkable<int,void*>* compoundBegin(){
        return &scheduler;
    }
    Linkable<int,void*>* compoundEnd(){
        return &null;
    }

};
class Mixer{
    std::vector<Source*> v;
    Sink* sink;
    void run()
    {
        SCUD_RC rc=SCUD_RC_OK;
        sink->breakCompound();
        //std::cout<<"loop: mixer"<<std::endl;
        int s=v.size();
        //std::cout<<"loop: mixer 1"<<std::endl;
        for(int i=0;i<s;i++){
            v[i]->breakCompound();
            pull();
        }
        sink->buildCompound();
        for(int i=0;i<s;i++){
            v[i]->buildCompound();
            sink->compoundBegin()->linkPredecessor(v[i]->compoundEnd());
        }

        while (1) {
            //std::cout<<"loop: mixer 0"<<std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            std::cout<<"** ROUND **"<<std::endl;
            for(int j=0;j<100;++j)
            {

                pull();

            }
        }
    }

public:
    void addSource(Source* s){
        v.push_back(s);
    }
    void addSink(Sink* s){
        sink=s;
    }
    void addNull(){

    };
    void pull(){
        SCUD_RC rc=SCUD_RC_OK;
        struct Linkable<int,void*>::Queueable res;
        res.scheduled=-1;
        auto start= std::chrono::high_resolution_clock::now() ;
        rc=sink->compoundEnd()->pull(res);
        auto end= std::chrono::high_resolution_clock::now() ;
        auto diff = end - start;
        //std::cout<<"Pull delay="<<std::chrono::duration <double, std::micro>(diff).count()<<std::endl;

        if(rc==SCUD_RC_OK){
            std::cout<<"---Mixer: Pulled object "<<res.scheduled<<" "<<std::endl;
        }else if(rc==SCUD_RC_FAIL_LINK_NO_PACKET_AVAILABLE){
            std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        }
    }
    std::thread start() {
        return std::thread([=] { run(); });
    }
};
int main()
{
    Source s1(1,10,1,100);
    //Source s2(2,20,1,100);
    //Source s3(3,30,1,100);
    //Source s4(5,50,1,1000);

    Mixer m;
    m.addSource(&s1);
    //m.addSource(&s2);
    //m.addSource(&s3);
    //m.addSource(&s4);

    std::cout<<"SW version is: "<<SCHelper::version()<<std::endl;
    LinkableNull<int, void*> null;
    Sink si0(0);

    m.addSink(&si0);

    std::thread t1=s1.start();
    //std::thread t2=s2.start();
    //std::thread t3=s3.start();
    //std::thread t4=s4.start();
    std::thread ti0=si0.start();
    std::thread m0=m.start();

    t1.join();
    //t2.join();
    //t3.join();
    //t4.join();
    ti0.join();
    m0.join();
    std::cout << "done!\n";
}

<commit_msg>Update main.cpp<commit_after>//
//  main2.cpp
//  test_SCUD
//
//  Created by Boris Vigman on 08/07/2017.
//  Copyright © 2017-2019 Boris Vigman. All rights reserved.
//

#include "scud.h"
using namespace SCUD;

#include <iostream>
#include <thread>
#include <chrono>
#include "vector"

template<typename TSchedulable,typename Tid> class Queue1:public LinkableQueue<int,void*>{

};
template<typename TSchedulable,typename Tid> class Dropper1:public LinkableDropper<int,void*>{
public:

    void processOnPush(TSchedulable sch, long long schedulingParam){
        int x=0;
    }
    void processOnPull(TSchedulable sch, long long schedulingParam){
        int x=0;
    }
    void processOnPullPush(TSchedulable sch, long long schedulingParam){
        int x=0;
    }
};
class Source{
    char priority;
    float weight;
    int label;
    long long delay;
    Queue1<int,void*> queue0;
    LinkableQueue<int,void*> queue1;
    Dropper1<int,void*> drop0;
    LinkableDropper<int,void*> drop1;
    LinkablePass<int, void*> pass1,pass2;
    //LinkablePass<int,void*> pass;
    void run(){
        SCUD_RC r0;
        drop1.unlink(&r0);
        drop0.setPriority(7);
        drop1.setPriority(priority);
        SCUD_RC rc= queue0.setPriority(priority);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue0.setWeight(weight);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue0.setLowThreshold(1);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue0.setHighThreshold(20);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue1.setDRRQuantum(0);
        rc=queue1.setDRRQuantum(50);
        rc=queue1.setWeight(5);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue1.setLowThreshold(1);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc=queue1.setHighThreshold(30);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        rc= queue1.setPriority(priority);std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        int count=10;

        //while(count>0){
        SCUD_RC status=SCUD_RC_OK;
        //queue.unlink(&status);
        //std::cout<<"loop: source"<<std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(delay));
        queue1.linkSuccessor(&drop1);
        queue0.linkSuccessor(&drop0);

        drop0.linkSuccessor(&queue0);
        //status=next->linkPredecessor(&drop1);

        //}
        while(1){
            std::this_thread::sleep_for(std::chrono::milliseconds(delay));

            //buildCompound();
            auto start= std::chrono::high_resolution_clock::now() ;
            drop0.push(label, label*10);
            auto end= std::chrono::high_resolution_clock::now() ;
            auto diff = end - start;
            //std::cout<<"Push delay="<<std::chrono::duration <double, std::micro>(diff).count()<<std::endl;
            //std::cout<<"Queue1 ["<<label<<"] has "<<queue1.size()<<" objects"<<std::endl;
             start= std::chrono::high_resolution_clock::now() ;
            pass1.pullAndPush();
             end= std::chrono::high_resolution_clock::now() ;
             diff = end - start;
            //std::cout<<"Pull/Push delay="<<std::chrono::duration <double, std::micro>(diff).count()<<std::endl;
            //std::cout<<"Queue0 ["<<label<<"] has "<<queue0.size()<<" objects;"<<"Queue1 ["<<label<<"] has "<<queue1.size()<<" objects"<<std::endl;
            //breakCompound();
            /*
            count--;
            if(count<0){
                count=100;
                std::this_thread::sleep_for(std::chrono::milliseconds(delay*100));
            }
             */
        }
    }
public:
    Source(){weight=-1;priority=-1;label=-1;delay=100;}
    Source(int lbl, char p,float w,long long delayMilli){
        priority=p;
        weight=w;
        label=lbl;
        delay=delayMilli;
    }
    std::thread start() {
        return std::thread([=] { run(); });
    }
    void buildCompound(){
        drop0.linkSuccessor(&queue0);
        queue0.linkSuccessor(&pass1);
        pass1.linkSuccessor(&queue1);
        queue1.linkSuccessor(&pass2);
        pass2.linkSuccessor(&drop1);

    }
    void breakCompound(){
        SCUD_RC status=SCUD_RC_OK;
        Linkable<int,void*>::LinkedObjectsTuple lot1=drop1.unlink(&status);
        if(status!=SCUD_RC_OK){
            std::cout<<SCHelper::convertReturnCodeToString(status)<<std::endl;
        }
        Linkable<int,void*>::LinkedObjectsTuple lot2=queue0.unlink(&status);
        if(status!=SCUD_RC_OK){
            std::cout<<SCHelper::convertReturnCodeToString(status)<<std::endl;
        }
        Linkable<int,void*>::LinkedObjectsTuple lot3=queue1.unlink(&status);
        if(status!=SCUD_RC_OK){
            std::cout<<SCHelper::convertReturnCodeToString(status)<<std::endl;
        }
    }
    Linkable<int,void*>* compoundBegin(){
        return &drop0;
    }
    Linkable<int,void*>* compoundEnd(){
        return &drop1;
    }
};

class Sink{
    //LinkableSchedulerPriority<int, void*> scheduler;
    //LinkableSchedulerNaiveRR<int, void*> scheduler;
    LinkableSchedulerDRR<int, void*> scheduler;
    LinkableNull<int, void*> null;
    void run(){
        scheduler.setPriority(9);
        scheduler.setWeight(1);

//        while(1){
//            //std::cout<<"loop: sink"<<std::endl;
//            std::this_thread::sleep_for(std::chrono::milliseconds(100));
//            SCUD_RC rc=SCUD_RC_OK;
//            struct Linkable<int,void*>::Queueable res;
////            rc=next->pull(res);
////            if(rc==SCUD_RC_OK){
////                std::cout<<"Sink: Pulled object "<<res.scheduled<<" "<<std::endl;
////            }else{
////                std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
////            }
////            if(res.scheduled>100000){
////                int x=0;
////            }
//        }
    }
public:
    Sink(Linkable<int, void*>* l){

    }
    std::thread start() {
        return std::thread([=] { run(); });
    }
    void buildCompound(){
        scheduler.linkSuccessor(&null);
    };
    void breakCompound(){
        SCUD_RC status=SCUD_RC_OK;
        null.unlink(&status);
    };
    Linkable<int,void*>* compoundBegin(){
        return &scheduler;
    }
    Linkable<int,void*>* compoundEnd(){
        return &null;
    }

};
class Mixer{
    std::vector<Source*> v;
    Sink* sink;
    void run()
    {
        SCUD_RC rc=SCUD_RC_OK;
        sink->breakCompound();
        //std::cout<<"loop: mixer"<<std::endl;
        int s=v.size();
        //std::cout<<"loop: mixer 1"<<std::endl;
        for(int i=0;i<s;i++){
            v[i]->breakCompound();
            pull();
        }
        sink->buildCompound();
        for(int i=0;i<s;i++){
            v[i]->buildCompound();
            sink->compoundBegin()->linkPredecessor(v[i]->compoundEnd());
        }

        while (1) {
            //std::cout<<"loop: mixer 0"<<std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            std::cout<<"** ROUND **"<<std::endl;
            for(int j=0;j<100;++j)
            {

                pull();

            }
        }
    }

public:
    void addSource(Source* s){
        v.push_back(s);
    }
    void addSink(Sink* s){
        sink=s;
    }
    void addNull(){

    };
    void pull(){
        SCUD_RC rc=SCUD_RC_OK;
        struct Linkable<int,void*>::Queueable res;
        res.scheduled=-1;
        auto start= std::chrono::high_resolution_clock::now() ;
        rc=sink->compoundEnd()->pull(res);
        auto end= std::chrono::high_resolution_clock::now() ;
        auto diff = end - start;
        //std::cout<<"Pull delay="<<std::chrono::duration <double, std::micro>(diff).count()<<std::endl;

        if(rc==SCUD_RC_OK){
            std::cout<<"---Mixer: Pulled object "<<res.scheduled<<" "<<std::endl;
        }else if(rc==SCUD_RC_FAIL_LINK_NO_PACKET_AVAILABLE){
            std::cout<<SCHelper::convertReturnCodeToString(rc)<<std::endl;
        }
    }
    std::thread start() {
        return std::thread([=] { run(); });
    }
};
int main()
{
    Source s1(1,10,1,100);
    //Source s2(2,20,1,100);
    //Source s3(3,30,1,100);
    //Source s4(5,50,1,1000);

    Mixer m;
    m.addSource(&s1);
    //m.addSource(&s2);
    //m.addSource(&s3);
    //m.addSource(&s4);

    std::cout<<"SW version is: "<<SCHelper::version()<<std::endl;
    LinkableNull<int, void*> null;
    Sink si0(0);

    m.addSink(&si0);

    std::thread t1=s1.start();
    //std::thread t2=s2.start();
    //std::thread t3=s3.start();
    //std::thread t4=s4.start();
    std::thread ti0=si0.start();
    std::thread m0=m.start();

    t1.join();
    //t2.join();
    //t3.join();
    //t4.join();
    ti0.join();
    m0.join();
    std::cout << "done!\n";
}

<|endoftext|>


<commit_before>#include "internal.hpp"

#include "file.hpp"
#include "report.hpp"
#include "util.hpp"

#include <cstring>

namespace CaDiCaL {

void Report::print_header (char * line) {
  int len = strlen (header);
  for (int i = -1, j = pos - (len + 1)/2 - 1; i < len; i++, j++)
    line[j] = i < 0 ? ' ' : header[i];
}

Report::Report (const char * h, int precision, int min, double value) :
  header (h)
{
  char fmt[10];
  sprintf (fmt, "%%.%df", abs (precision));
  if (precision < 0) strcat (fmt, "%%");
  sprintf (buffer, fmt, value);
  const int min_width = min;
  if (strlen (buffer) >= (size_t) min_width) return;
  sprintf (fmt, "%%%d.%df", min_width, abs (precision));
  if (precision < 0) strcat (fmt, "%%");
  sprintf (buffer, fmt, value);
}

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

// The following statistics are printed in columns, whenever 'report' is
// called.  For instance 'reduce' with prefix '-' will call it.  The other
// more interesting report is due to learning a unit, called iteration, with
// prefix 'i'.  To add another statistics column, add a corresponding line
// here.  If you want to report something else add 'report (..)' functions.

#define REPORTS \
/*     HEADER, PRECISION, MIN, VALUE */ \
REPORT("seconds",      2, 5, seconds ()) \
REPORT("MB",           0, 2, current_bytes () / (double)(1l<<20)) \
REPORT("level",        1, 4, jump_avg) \
REPORT("reductions",   0, 2, stats.reductions) \
REPORT("restarts",     0, 4, stats.restarts) \
REPORT("conflicts",    0, 5, stats.conflicts) \
REPORT("redundant",    0, 5, stats.redundant) \
REPORT("glue",         1, 4, slow_glue_avg) \
REPORT("size",         1, 4, size_avg) \
REPORT("irredundant",  0, 4, stats.irredundant) \
REPORT("variables",    0, 4, active_variables ()) \
REPORT("remaining",   -1, 5, percent (active_variables (), max_var)) \
REPORT("restarteff",   2, 4, restarteff) \
REPORT("restartint",   1, 4, restartint) \

#if 0

REPORT("prop/dec",     0, 2, relative (stats.propagations, stats.decisions)) \
REPORT("glue-fast",    1, 4, fast_glue_avg) \
REPORT("level-fast",   1, 4, fast_jump_avg) \
REPORT("bump-high",   -1, 5, percent (stats.bumphi, stats.bumped)) \

#endif

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

void Internal::report (char type, bool verbose) {
#ifndef LOGGING
  if (opts.quiet || (verbose && !opts.verbose)) return;
#endif
  const int max_reports = 32;
  Report reports[max_reports];
  int n = 0;
#define REPORT(HEAD,PREC,MIN,EXPR) \
  assert (n < max_reports); \
  reports[n++] = Report (HEAD, PREC, MIN, (double)(EXPR));
  REPORTS
#undef REPORT
  if (!(stats.reports++ % 20)) {
    File::print ("c\n");
    int pos = 4;
    for (int i = 0; i < n; i++) {
      int len = strlen (reports[i].buffer);
      reports[i].pos = pos + (len + 1)/2;
      pos += len + 1;
    }
    const int max_line = pos + 20, nrows = 3;
    char line[max_line];
    for (int start = 0; start < nrows; start++) {
      int i;
      for (i = 0; i < max_line; i++) line[i] = ' ';
      line[0] = 'c';
      for (i = start; i < n; i += nrows) reports[i].print_header (line);
      for (i = max_line-1; line[i-1] == ' '; i--) ;
      line[i] = 0;
      File::print (line);
      File::print ('\n');
    }
    File::print ("c\n");
  }
  File::print ("c "), File::print (type);
  for (int i = 0; i < n; i++)
    File::print (' '), File::print (reports[i].buffer);
  File::print ('\n');
  fflush (stdout);
}

};

<commit_msg>better report<commit_after>#include "internal.hpp"

#include "file.hpp"
#include "report.hpp"
#include "util.hpp"

#include <cstring>

namespace CaDiCaL {

void Report::print_header (char * line) {
  int len = strlen (header);
  for (int i = -1, j = pos - (len + 1)/2 - 1; i < len; i++, j++)
    line[j] = i < 0 ? ' ' : header[i];
}

Report::Report (const char * h, int precision, int min, double value) :
  header (h)
{
  char fmt[10];
  sprintf (fmt, "%%.%df", abs (precision));
  if (precision < 0) strcat (fmt, "%%");
  sprintf (buffer, fmt, value);
  const int min_width = min;
  if (strlen (buffer) >= (size_t) min_width) return;
  sprintf (fmt, "%%%d.%df", min_width, abs (precision));
  if (precision < 0) strcat (fmt, "%%");
  sprintf (buffer, fmt, value);
}

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

// The following statistics are printed in columns, whenever 'report' is
// called.  For instance 'reduce' with prefix '-' will call it.  The other
// more interesting report is due to learning a unit, called iteration, with
// prefix 'i'.  To add another statistics column, add a corresponding line
// here.  If you want to report something else add 'report (..)' functions.

#define REPORTS \
/*     HEADER, PRECISION, MIN, VALUE */ \
REPORT("seconds",      2, 5, seconds ()) \
REPORT("MB",           0, 2, current_bytes () / (double)(1l<<20)) \
REPORT("level",        1, 4, jump_avg) \
REPORT("reductions",   0, 2, stats.reductions) \
REPORT("restarts",     0, 4, stats.restarts) \
REPORT("conflicts",    0, 5, stats.conflicts) \
REPORT("redundant",    0, 5, stats.redundant) \
REPORT("glue",         1, 3, slow_glue_avg) \
REPORT("size",         1, 4, size_avg) \
REPORT("irredundant",  0, 4, stats.irredundant) \
REPORT("variables",    0, 4, active_variables ()) \
REPORT("remaining",   -1, 5, percent (active_variables (), max_var)) \
REPORT("restarteff",   2, 4, restarteff) \
REPORT("restartint",   1, 4, restartint) \

#if 0

REPORT("prop/dec",     0, 2, relative (stats.propagations, stats.decisions)) \
REPORT("glue-fast",    1, 4, fast_glue_avg) \
REPORT("level-fast",   1, 4, fast_jump_avg) \
REPORT("bump-high",   -1, 5, percent (stats.bumphi, stats.bumped)) \

#endif

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

void Internal::report (char type, bool verbose) {
#ifndef LOGGING
  if (opts.quiet || (verbose && !opts.verbose)) return;
#endif
  const int max_reports = 32;
  Report reports[max_reports];
  int n = 0;
#define REPORT(HEAD,PREC,MIN,EXPR) \
  assert (n < max_reports); \
  reports[n++] = Report (HEAD, PREC, MIN, (double)(EXPR));
  REPORTS
#undef REPORT
  if (!(stats.reports++ % 20)) {
    File::print ("c\n");
    int pos = 4;
    for (int i = 0; i < n; i++) {
      int len = strlen (reports[i].buffer);
      reports[i].pos = pos + (len + 1)/2;
      pos += len + 1;
    }
    const int max_line = pos + 20, nrows = 3;
    char line[max_line];
    for (int start = 0; start < nrows; start++) {
      int i;
      for (i = 0; i < max_line; i++) line[i] = ' ';
      line[0] = 'c';
      for (i = start; i < n; i += nrows) reports[i].print_header (line);
      for (i = max_line-1; line[i-1] == ' '; i--) ;
      line[i] = 0;
      File::print (line);
      File::print ('\n');
    }
    File::print ("c\n");
  }
  File::print ("c "), File::print (type);
  for (int i = 0; i < n; i++)
    File::print (' '), File::print (reports[i].buffer);
  File::print ('\n');
  fflush (stdout);
}

};

<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013-2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef SEMAPHORE_H
#define SEMAPHORE_H

#include "stl/vector.hpp"
#include "stl/lock_guard.hpp"

#include "spinlock.hpp"
#include "scheduler.hpp"

//TODO Implement a queue and use it for more fairness

struct semaphore {
private:
    spinlock lock;
    size_t value;
    std::vector<scheduler::pid_t> queue;

public:
    void init(size_t v){
        value = v;
    }

    void wait(){
        std::lock_guard<spinlock> l(lock);

        if(value > 0){
            --value;
        } else {
            queue.push_back(scheduler::get_pid());
            scheduler::block_process(scheduler::get_pid());
        }
    }

    void signal(){
        std::lock_guard<spinlock> l(lock);

        if(queue.empty()){
            ++value;
        } else {
            auto pid = queue.back();
            scheduler::unblock_process(pid);

            queue.pop_back();

            //No need to increment value, the process won't
            //decrement it
        }
    }
};

#endif
<commit_msg>Use std::list instead of std::vector<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013-2014.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#ifndef SEMAPHORE_H
#define SEMAPHORE_H

#include "stl/vector.hpp"
#include "stl/list.hpp"
#include "stl/lock_guard.hpp"

#include "spinlock.hpp"
#include "scheduler.hpp"

struct semaphore {
private:
    spinlock lock;
    size_t value;
    std::list<scheduler::pid_t> queue;

public:
    void init(size_t v){
        value = v;
    }

    void wait(){
        std::lock_guard<spinlock> l(lock);

        if(value > 0){
            --value;
        } else {
            queue.push_back(scheduler::get_pid());
            scheduler::block_process(scheduler::get_pid());
        }
    }

    void signal(){
        std::lock_guard<spinlock> l(lock);

        if(queue.empty()){
            ++value;
        } else {
            auto pid = queue.front();
            scheduler::unblock_process(pid);

            queue.pop_front();

            //No need to increment value, the process won't
            //decrement it
        }
    }
};

#endif
<|endoftext|>


<commit_before><commit_msg>PoHeader constructure problem with boost<commit_after><|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <iostream>
#include <fstream>
#include <dirent.h>
#include <string>
#include <vector>
#include <map>

#include <osl/file.hxx>
#include <rtl/string.hxx>

#include "po.hxx"

using namespace std;

bool isInSameFile( const OString& rFirstLine, const OString& rSecondLine)
{
    const OString rFirstSource =
        rFirstLine.getToken(PoEntry::SOURCEFILE,'\t');
    const OString rSecondSource =
        rSecondLine.getToken(PoEntry::SOURCEFILE,'\t');
    return
        rFirstSource.copy(0,rFirstSource.lastIndexOf("\\")) ==
        rSecondSource.copy(0,rSecondSource.lastIndexOf("\\"));
}

//Get path of po file
OString GetPath(const OString& rPath, const OString& rLine)
{
    OString sSourceFile = rLine.getToken(PoEntry::SOURCEFILE,'\t');
    OString sSourcePath = rPath + "/" +
                          rLine.getToken(PoEntry::PROJECT,'\t') + "/" +
                          sSourceFile.copy(0,sSourceFile.lastIndexOf("\\")).
                                      replaceAll("\\","/");
    return sSourcePath;
}

OString DelLocalId(const OString& rLine)
{
    unsigned nTabIndex = 0;
    for(unsigned nComponent=0; nComponent<PoEntry::LOCALID; ++nComponent)
    {
        nTabIndex = rLine.indexOf('\t',nTabIndex);
        ++nTabIndex;
    }
    return rLine.replaceAt(nTabIndex,
                           rLine.indexOf('\t',nTabIndex)-nTabIndex,
                           "");
}

//Renew po files of the actual language
void HandleLanguage(struct dirent* pLangEntry, const OString& rOldPath,
    const OString& rNewPath, const OString& rpo2loPath,
    const OString& rSDFPath)
{
    const OString LangEntryName = pLangEntry->d_name;

    //Generate and open sdf
    cout << "Process start with language: " <<  LangEntryName.getStr() << endl;
    OUString aTempUrl;
    if (osl::FileBase::createTempFile(0, 0, &aTempUrl)
        != osl::FileBase::E_None)
    {
        cerr << "osl::FileBase::createTempFile() failed\n";
        return;
    }
    OUString aTempPath;
    if (osl::FileBase::getSystemPathFromFileURL(aTempUrl, aTempPath)
        != osl::FileBase::E_None)
    {
        cerr
            << "osl::FileBase::getSystemPathFromFileURL(" << aTempUrl
            << ") failed\n";
        return;
    }
    const OString SDFFileName =
        OUStringToOString(aTempPath, RTL_TEXTENCODING_UTF8);
    system( (rpo2loPath +
            " -i " + rOldPath + "/" + LangEntryName +
            " -o " + SDFFileName +
            " -l " + LangEntryName +
            " -t " + rSDFPath).getStr());
    cout << "Language sdf is ready!" << endl;

    //Store info for po entries
    ifstream aSDFInput(SDFFileName.getStr());
    map<sal_Int32,pair<OString,OString> > aPoInfos;
    string s;
    getline(aSDFInput,s);
    while(!aSDFInput.eof())
    {
        //Get strings belong to one po entry and store
        const OString sActUnTrans = OString(s.data(),s.length());
        if( sActUnTrans.getToken(PoEntry::LANGUAGEID,'\t')=="ast" ) throw;
        getline(aSDFInput,s);
        const OString sActTrans = OString(s.data(),s.length());

        if(!(aPoInfos.insert( pair<sal_Int32,pair<OString,OString> >(
            sActTrans.getToken(PoEntry::WIDTH,'\t').toInt32(),
            pair<OString,OString>(sActUnTrans,sActTrans))).second))
        {
            cerr << "Error: faild to insert into map!" << '\n';
            throw;
        }
        getline(aSDFInput,s);
    }

    //Close and remove sdf file
    aSDFInput.close();
    if (osl::File::remove(aTempUrl) != osl::FileBase::E_None)
    {
        cerr << "Warning: failure removing temporary " << aTempUrl << '\n';
    }

    //Construct and write out po entries
    PoOfstream aNewPo;
    for( map<sal_Int32,pair<OString,OString> >::iterator
        pActInfo=aPoInfos.begin(); pActInfo!=aPoInfos.end(); ++pActInfo )
    {
        //Make new po file and add header
        if ( pActInfo==aPoInfos.begin() ||
            !isInSameFile(((--pActInfo)++)->second.first,pActInfo->second.first) )
        {
            if( pActInfo!=aPoInfos.begin() )
                aNewPo.close();

            const OString sNewPoFileName =
                GetPath(rNewPath + "/" +LangEntryName,pActInfo->second.first) +
                ".po";
            system(("mkdir -p " + sNewPoFileName.copy(0,sNewPoFileName.lastIndexOf("/"))).getStr());
            aNewPo.open(sNewPoFileName);
            if (!aNewPo.isOpen())
            {
                cerr
                    << "Cannot open new po file: "
                    << sNewPoFileName.getStr() << endl;
                return;
            }
            const OString sOldPoFileName =
                GetPath(rOldPath + "/" +LangEntryName,pActInfo->second.first) +
                ".po";
            ifstream aOldPo(sOldPoFileName.getStr());
            if (!aOldPo.is_open())
            {
                cerr
                    << "Cannot open old po file: "
                    << sOldPoFileName.getStr() << endl;
                return;
            }
            aNewPo.writeHeader(PoHeader(aOldPo));
            aOldPo.close();
        }

        //Write out po entries
        const PoEntry::TYPE vInitializer[] =
            { PoEntry::TTEXT, PoEntry::TQUICKHELPTEXT, PoEntry::TTITLE };
        const vector<PoEntry::TYPE> vTypes( vInitializer,
            vInitializer + sizeof(vInitializer) / sizeof(vInitializer[0]) );
        unsigned short nDummyBit = 0;
        for( unsigned short nIndex=0; nIndex<vTypes.size(); ++nIndex )
        {
            if (!pActInfo->second.first.getToken(vTypes[nIndex],'\t').isEmpty())
            {
                /**Because of xrmex there are duplicated id's,
                only use this if xrmex have already fixed*/
                const OString sSource =
                    pActInfo->second.first.getToken(PoEntry::SOURCEFILE,'\t');
                const OString sEnding =
                    sSource.copy(sSource.getLength()-4, 4);
                if (pActInfo->second.first.getToken(PoEntry::GROUPID,'\t')==
                    pActInfo->second.first.getToken(PoEntry::LOCALID,'\t') &&
                    ( sEnding == ".xrm" || sEnding == ".xml" ))
                {
                    pActInfo->second.first = DelLocalId(pActInfo->second.first);
                }
                try
                {
                    PoEntry aPE(pActInfo->second.first, vTypes[nIndex]);
                    const OString sActStr =
                        pActInfo->second.second.getToken(vTypes[nIndex],'\t');
                    aPE.setMsgStr(sActStr);
                    aPE.setFuzzy( sActStr.isEmpty() ? false :
                        static_cast<bool>(pActInfo->second.second.getToken(PoEntry::DUMMY,'\t').
                            copy(nDummyBit++,1).toBoolean()));
                    aNewPo.writeEntry(aPE);
                }
                catch( PoEntry::Exception& )
                {
                    cerr
                        << "Invalid sdf line "
                        << pActInfo->second.first.replaceAll("\t","\\t").getStr() << '\n';
                }
            }
        }
    }
    aNewPo.close();
    aPoInfos.clear();
}

int main(int argc, char* argv[])
{
    //Usage
    if (argc < 4)
    {
        cout << "Use: renewpot oldpots newpots po2lo en-US.sdf" << endl;
        return 1;
    }

    //Call processing function with all language directories
    DIR* pTranslations = opendir(argv[1]);
    while ( struct dirent* pActEntry = readdir(pTranslations) )
    {
        if ( OString(pActEntry->d_name).indexOf('.')==-1 )
            HandleLanguage(pActEntry,OString(argv[1]),
                           OString(argv[2]),OString(argv[3]),
                           OString(argv[4]));
    }
    closedir(pTranslations);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>WaE ignoring return value<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <iostream>
#include <fstream>
#include <dirent.h>
#include <string>
#include <vector>
#include <map>

#include <osl/file.hxx>
#include <rtl/string.hxx>

#include "po.hxx"

using namespace std;

bool isInSameFile( const OString& rFirstLine, const OString& rSecondLine)
{
    const OString rFirstSource =
        rFirstLine.getToken(PoEntry::SOURCEFILE,'\t');
    const OString rSecondSource =
        rSecondLine.getToken(PoEntry::SOURCEFILE,'\t');
    return
        rFirstSource.copy(0,rFirstSource.lastIndexOf("\\")) ==
        rSecondSource.copy(0,rSecondSource.lastIndexOf("\\"));
}

//Get path of po file
OString GetPath(const OString& rPath, const OString& rLine)
{
    OString sSourceFile = rLine.getToken(PoEntry::SOURCEFILE,'\t');
    OString sSourcePath = rPath + "/" +
                          rLine.getToken(PoEntry::PROJECT,'\t') + "/" +
                          sSourceFile.copy(0,sSourceFile.lastIndexOf("\\")).
                                      replaceAll("\\","/");
    return sSourcePath;
}

OString DelLocalId(const OString& rLine)
{
    unsigned nTabIndex = 0;
    for(unsigned nComponent=0; nComponent<PoEntry::LOCALID; ++nComponent)
    {
        nTabIndex = rLine.indexOf('\t',nTabIndex);
        ++nTabIndex;
    }
    return rLine.replaceAt(nTabIndex,
                           rLine.indexOf('\t',nTabIndex)-nTabIndex,
                           "");
}

//Renew po files of the actual language
void HandleLanguage(struct dirent* pLangEntry, const OString& rOldPath,
    const OString& rNewPath, const OString& rpo2loPath,
    const OString& rSDFPath)
{
    const OString LangEntryName = pLangEntry->d_name;

    //Generate and open sdf
    cout << "Process start with language: " <<  LangEntryName.getStr() << endl;
    OUString aTempUrl;
    if (osl::FileBase::createTempFile(0, 0, &aTempUrl)
        != osl::FileBase::E_None)
    {
        cerr << "osl::FileBase::createTempFile() failed\n";
        return;
    }
    OUString aTempPath;
    if (osl::FileBase::getSystemPathFromFileURL(aTempUrl, aTempPath)
        != osl::FileBase::E_None)
    {
        cerr
            << "osl::FileBase::getSystemPathFromFileURL(" << aTempUrl
            << ") failed\n";
        return;
    }
    const OString SDFFileName =
        OUStringToOString(aTempPath, RTL_TEXTENCODING_UTF8);
    const char* cmd = (rpo2loPath +
            " -i " + rOldPath + "/" + LangEntryName +
            " -o " + SDFFileName +
            " -l " + LangEntryName +
                       " -t " + rSDFPath).getStr();
    if (system(cmd) != 0)
    {
        std::cerr << "Error: Failed to execute " << cmd << '\n';
        throw false;
    }
    cout << "Language sdf is ready!" << endl;

    //Store info for po entries
    ifstream aSDFInput(SDFFileName.getStr());
    map<sal_Int32,pair<OString,OString> > aPoInfos;
    string s;
    getline(aSDFInput,s);
    while(!aSDFInput.eof())
    {
        //Get strings belong to one po entry and store
        const OString sActUnTrans = OString(s.data(),s.length());
        if( sActUnTrans.getToken(PoEntry::LANGUAGEID,'\t')=="ast" ) throw;
        getline(aSDFInput,s);
        const OString sActTrans = OString(s.data(),s.length());

        if(!(aPoInfos.insert( pair<sal_Int32,pair<OString,OString> >(
            sActTrans.getToken(PoEntry::WIDTH,'\t').toInt32(),
            pair<OString,OString>(sActUnTrans,sActTrans))).second))
        {
            cerr << "Error: faild to insert into map!" << '\n';
            throw;
        }
        getline(aSDFInput,s);
    }

    //Close and remove sdf file
    aSDFInput.close();
    if (osl::File::remove(aTempUrl) != osl::FileBase::E_None)
    {
        cerr << "Warning: failure removing temporary " << aTempUrl << '\n';
    }

    //Construct and write out po entries
    PoOfstream aNewPo;
    for( map<sal_Int32,pair<OString,OString> >::iterator
        pActInfo=aPoInfos.begin(); pActInfo!=aPoInfos.end(); ++pActInfo )
    {
        //Make new po file and add header
        if ( pActInfo==aPoInfos.begin() ||
            !isInSameFile(((--pActInfo)++)->second.first,pActInfo->second.first) )
        {
            if( pActInfo!=aPoInfos.begin() )
                aNewPo.close();

            const OString sNewPoFileName =
                GetPath(rNewPath + "/" +LangEntryName,pActInfo->second.first) +
                ".po";
            const char* cmd2 = ("mkdir -p " + sNewPoFileName.copy(0,sNewPoFileName.lastIndexOf("/"))).getStr();
            if (system(cmd2) != 0)
            {
                std::cerr << "Error: Failed to execute " << cmd2 << '\n';
                throw false;
            }

            aNewPo.open(sNewPoFileName);
            if (!aNewPo.isOpen())
            {
                cerr
                    << "Cannot open new po file: "
                    << sNewPoFileName.getStr() << endl;
                return;
            }
            const OString sOldPoFileName =
                GetPath(rOldPath + "/" +LangEntryName,pActInfo->second.first) +
                ".po";
            ifstream aOldPo(sOldPoFileName.getStr());
            if (!aOldPo.is_open())
            {
                cerr
                    << "Cannot open old po file: "
                    << sOldPoFileName.getStr() << endl;
                return;
            }
            aNewPo.writeHeader(PoHeader(aOldPo));
            aOldPo.close();
        }

        //Write out po entries
        const PoEntry::TYPE vInitializer[] =
            { PoEntry::TTEXT, PoEntry::TQUICKHELPTEXT, PoEntry::TTITLE };
        const vector<PoEntry::TYPE> vTypes( vInitializer,
            vInitializer + sizeof(vInitializer) / sizeof(vInitializer[0]) );
        unsigned short nDummyBit = 0;
        for( unsigned short nIndex=0; nIndex<vTypes.size(); ++nIndex )
        {
            if (!pActInfo->second.first.getToken(vTypes[nIndex],'\t').isEmpty())
            {
                /**Because of xrmex there are duplicated id's,
                only use this if xrmex have already fixed*/
                const OString sSource =
                    pActInfo->second.first.getToken(PoEntry::SOURCEFILE,'\t');
                const OString sEnding =
                    sSource.copy(sSource.getLength()-4, 4);
                if (pActInfo->second.first.getToken(PoEntry::GROUPID,'\t')==
                    pActInfo->second.first.getToken(PoEntry::LOCALID,'\t') &&
                    ( sEnding == ".xrm" || sEnding == ".xml" ))
                {
                    pActInfo->second.first = DelLocalId(pActInfo->second.first);
                }
                try
                {
                    PoEntry aPE(pActInfo->second.first, vTypes[nIndex]);
                    const OString sActStr =
                        pActInfo->second.second.getToken(vTypes[nIndex],'\t');
                    aPE.setMsgStr(sActStr);
                    aPE.setFuzzy( sActStr.isEmpty() ? false :
                        static_cast<bool>(pActInfo->second.second.getToken(PoEntry::DUMMY,'\t').
                            copy(nDummyBit++,1).toBoolean()));
                    aNewPo.writeEntry(aPE);
                }
                catch( PoEntry::Exception& )
                {
                    cerr
                        << "Invalid sdf line "
                        << pActInfo->second.first.replaceAll("\t","\\t").getStr() << '\n';
                }
            }
        }
    }
    aNewPo.close();
    aPoInfos.clear();
}

int main(int argc, char* argv[])
{
    //Usage
    if (argc < 4)
    {
        cout << "Use: renewpot oldpots newpots po2lo en-US.sdf" << endl;
        return 1;
    }

    //Call processing function with all language directories
    DIR* pTranslations = opendir(argv[1]);
    while ( struct dirent* pActEntry = readdir(pTranslations) )
    {
        if ( OString(pActEntry->d_name).indexOf('.')==-1 )
            HandleLanguage(pActEntry,OString(argv[1]),
                           OString(argv[2]),OString(argv[3]),
                           OString(argv[4]));
    }
    closedir(pTranslations);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>