<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * Version: MPL 1.1 / GPLv3+ / LGPLv3+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Initial Developer of the Original Code is
 *        Caolán McNamara <caolanm@redhat.com> (Red Hat, Inc.)
 * Portions created by the Initial Developer are Copyright (C) 2011 the
 * Initial Developer. All Rights Reserved.
 *
 * Contributor(s): Caolán McNamara <caolanm@redhat.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
 * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
 * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
 * instead of those above.
 */

#include <sal/cppunit.h>

#include <cppuhelper/bootstrap.hxx>
#include <comphelper/processfactory.hxx>

#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/document/XFilter.hpp>

#include <osl/file.hxx>
#include <osl/process.h>

#include <vcl/svapp.hxx>

using namespace ::com::sun::star;

namespace
{
    class LotusWordProTest : public ::CppUnit::TestFixture
    {
    public:
        LotusWordProTest();

        virtual void setUp();
        virtual void tearDown();

        void recursiveScan(const rtl::OUString &rURL, bool bExpected);
        bool load(const rtl::OUString &rURL);
        void test();

        CPPUNIT_TEST_SUITE(LotusWordProTest);
        CPPUNIT_TEST(test);
        CPPUNIT_TEST_SUITE_END();
    private:
        uno::Reference<uno::XComponentContext> m_xContext;
        uno::Reference<lang::XMultiComponentFactory> m_xFactory;
        uno::Reference<lang::XMultiServiceFactory> m_xMSF;
        uno::Reference<document::XFilter> m_xFilter;

        ::rtl::OUString m_aPWDURL;
        int m_nLoadedDocs;
    };

    LotusWordProTest::LotusWordProTest() : m_nLoadedDocs(0)
    {
        m_xContext = cppu::defaultBootstrap_InitialComponentContext();
        m_xFactory = m_xContext->getServiceManager();
        m_xMSF = uno::Reference<lang::XMultiServiceFactory>(m_xFactory, uno::UNO_QUERY_THROW);
        m_xFilter = uno::Reference< document::XFilter >(m_xMSF->createInstance(
            ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.Writer.LotusWordProImportFilter"))),
            uno::UNO_QUERY_THROW);

        oslProcessError err = osl_getProcessWorkingDir(&m_aPWDURL.pData);
        CPPUNIT_ASSERT_MESSAGE("no PWD!", err == osl_Process_E_None);

        //Without this we're crashing because callees are using
        //getProcessServiceFactory.  In general those should be removed in favour
        //of retaining references to the root ServiceFactory as its passed around
        comphelper::setProcessServiceFactory(m_xMSF);

        //Lotus Import filter pokes at printers :-(
        InitVCL(m_xMSF);
    }

    void LotusWordProTest::setUp()
    {
    }

    void LotusWordProTest::tearDown()
    {
    }

    bool LotusWordProTest::load(const rtl::OUString &rURL)
    {
        uno::Sequence< beans::PropertyValue > aDescriptor(1);
        aDescriptor[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("URL"));
        aDescriptor[0].Value <<= rURL;
        sal_Bool bRet = m_xFilter->filter(aDescriptor);

        ++m_nLoadedDocs;

        return bRet;
    }

    void LotusWordProTest::recursiveScan(const rtl::OUString &rURL, bool bExpected)
    {
        osl::Directory aDir(rURL);

        CPPUNIT_ASSERT(osl::FileBase::E_None == aDir.open());
        osl::DirectoryItem aItem;
        osl::FileStatus aFileStatus(osl_FileStatus_Mask_FileURL|osl_FileStatus_Mask_Type);
        while (aDir.getNextItem(aItem) == osl::FileBase::E_None)
        {
            aItem.getFileStatus(aFileStatus);
            rtl::OUString sURL = aFileStatus.getFileURL();
            if (aFileStatus.getFileType() == osl::FileStatus::Directory)
                recursiveScan(sURL, bExpected);
            else
            {
                bool bRes = load(sURL);
                rtl::OString aRes(rtl::OUStringToOString(sURL, osl_getThreadTextEncoding()));
                CPPUNIT_ASSERT_MESSAGE(aRes.getStr(), bRes == bExpected);
            }
        }
        CPPUNIT_ASSERT(osl::FileBase::E_None == aDir.close());
    }

    void LotusWordProTest::test()
    {
        recursiveScan(m_aPWDURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/qa/cppunit/data/pass")), true);
        recursiveScan(m_aPWDURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/qa/cppunit/data/fail/")), false);

        printf("LotusWordPro: tested %d files\n", m_nLoadedDocs);
    }

    CPPUNIT_TEST_SUITE_REGISTRATION(LotusWordProTest);
}

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>clean up<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * Version: MPL 1.1 / GPLv3+ / LGPLv3+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Initial Developer of the Original Code is
 *        Caolán McNamara <caolanm@redhat.com> (Red Hat, Inc.)
 * Portions created by the Initial Developer are Copyright (C) 2011 the
 * Initial Developer. All Rights Reserved.
 *
 * Contributor(s): Caolán McNamara <caolanm@redhat.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 3 or later (the "GPLv3+"), or
 * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
 * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
 * instead of those above.
 */

#include <sal/cppunit.h>

#include <cppuhelper/bootstrap.hxx>
#include <comphelper/processfactory.hxx>

#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/document/XFilter.hpp>

#include <osl/file.hxx>
#include <osl/process.h>

#include <vcl/svapp.hxx>

using namespace ::com::sun::star;

namespace
{
    class LotusWordProTest : public ::CppUnit::TestFixture
    {
    public:
        LotusWordProTest();
        ~LotusWordProTest();

        virtual void setUp();
        virtual void tearDown();

        void recursiveScan(const rtl::OUString &rURL, bool bExpected);
        bool load(const rtl::OUString &rURL);
        void test();

        CPPUNIT_TEST_SUITE(LotusWordProTest);
        CPPUNIT_TEST(test);
        CPPUNIT_TEST_SUITE_END();
    private:
        uno::Reference<uno::XComponentContext> m_xContext;
        uno::Reference<lang::XMultiComponentFactory> m_xFactory;
        uno::Reference<lang::XMultiServiceFactory> m_xMSF;
        uno::Reference<document::XFilter> m_xFilter;

        ::rtl::OUString m_aPWDURL;
        int m_nLoadedDocs;
    };

    LotusWordProTest::LotusWordProTest() : m_nLoadedDocs(0)
    {
        m_xContext = cppu::defaultBootstrap_InitialComponentContext();
        m_xFactory = m_xContext->getServiceManager();
        m_xMSF = uno::Reference<lang::XMultiServiceFactory>(m_xFactory, uno::UNO_QUERY_THROW);
        m_xFilter = uno::Reference< document::XFilter >(m_xMSF->createInstance(
            ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.Writer.LotusWordProImportFilter"))),
            uno::UNO_QUERY_THROW);

        oslProcessError err = osl_getProcessWorkingDir(&m_aPWDURL.pData);
        CPPUNIT_ASSERT_MESSAGE("no PWD!", err == osl_Process_E_None);

        //Without this we're crashing because callees are using
        //getProcessServiceFactory.  In general those should be removed in favour
        //of retaining references to the root ServiceFactory as its passed around
        comphelper::setProcessServiceFactory(m_xMSF);

        //Lotus Import filter pokes at printers :-(
        InitVCL(m_xMSF);
    }

    LotusWordProTest::~LotusWordProTest()
    {
        DeInitVCL();
    }

    void LotusWordProTest::setUp()
    {
    }

    void LotusWordProTest::tearDown()
    {
    }

    bool LotusWordProTest::load(const rtl::OUString &rURL)
    {
        uno::Sequence< beans::PropertyValue > aDescriptor(1);
        aDescriptor[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("URL"));
        aDescriptor[0].Value <<= rURL;
        sal_Bool bRet = m_xFilter->filter(aDescriptor);

        ++m_nLoadedDocs;

        return bRet;
    }

    void LotusWordProTest::recursiveScan(const rtl::OUString &rURL, bool bExpected)
    {
        osl::Directory aDir(rURL);

        CPPUNIT_ASSERT(osl::FileBase::E_None == aDir.open());
        osl::DirectoryItem aItem;
        osl::FileStatus aFileStatus(osl_FileStatus_Mask_FileURL|osl_FileStatus_Mask_Type);
        while (aDir.getNextItem(aItem) == osl::FileBase::E_None)
        {
            aItem.getFileStatus(aFileStatus);
            rtl::OUString sURL = aFileStatus.getFileURL();
            if (aFileStatus.getFileType() == osl::FileStatus::Directory)
                recursiveScan(sURL, bExpected);
            else
            {
                bool bRes = load(sURL);
                rtl::OString aRes(rtl::OUStringToOString(sURL, osl_getThreadTextEncoding()));
                CPPUNIT_ASSERT_MESSAGE(aRes.getStr(), bRes == bExpected);
            }
        }
        CPPUNIT_ASSERT(osl::FileBase::E_None == aDir.close());
    }

    void LotusWordProTest::test()
    {
        recursiveScan(m_aPWDURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/qa/cppunit/data/pass")), true);
        recursiveScan(m_aPWDURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/qa/cppunit/data/fail/")), false);

        printf("LotusWordPro: tested %d files\n", m_nLoadedDocs);
    }

    CPPUNIT_TEST_SUITE_REGISTRATION(LotusWordProTest);
}

CPPUNIT_PLUGIN_IMPLEMENT();

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


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

#include "PKCS11Path.h"
#include "BinaryUtils.h"
#include "Logger.h"

#ifdef _WIN32
#undef UNICODE
#include <Shlobj.h>
#include <Shlwapi.h>
#include <Knownfolders.h>
#include <winscard.h>
#elif defined __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#include <unistd.h>
#else
#include <winscard.h>
#include <unistd.h>
#endif

#include <cstring>
#include <map>

std::vector<std::string> PKCS11Path::atrList() {
	SCARDCONTEXT hContext = 0;
	std::vector<std::string> result;
	LONG err = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &hContext);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardEstablishContext ERROR: %x", err);
		return result;
	}

	DWORD size = 0;
	err = SCardListReaders(hContext, nullptr, nullptr, &size);
	if (err != SCARD_S_SUCCESS || !size) {
		_log("SCardListReaders || !size ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

	std::string readers(size, 0);
	err = SCardListReaders(hContext, nullptr, &readers[0], &size);
	readers.resize(size);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardListReaders ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

    std::vector<SCARD_READERSTATE> list;
    for (const char *name = readers.c_str(); *name; name += strlen(name) + 1) {
        _log("found reader: %s", name);
        list.push_back({name, 0, 0, 0, 0, 0});
    }

    err = SCardGetStatusChange(hContext, 0, list.data(), DWORD(list.size()));
    if (err != SCARD_S_SUCCESS)
        _log("SCardGetStatusChange ERROR: %x", err);
    for(const SCARD_READERSTATE &state: list)
    {
        if (state.dwEventState & SCARD_STATE_PRESENT)
        {
            std::string atr = BinaryUtils::bin2hex(state.rgbAtr, state.cbAtr);
            result.push_back(atr);
            _log("Set ATR = %s for reader %s", atr.c_str(), state.szReader);
        }
    }

    SCardReleaseContext(hContext);
    return result;
}

PKCS11Path::Params PKCS11Path::getPkcs11ModulePath() {
#ifdef _WIN32
    // Use PKCS11 driver on windows to avoid PIN buffering
    static const std::string litPath = [] {
        PWSTR programFilesX86 = 0;
        SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, 0, NULL, &programFilesX86);
        std::wstring path = programFilesX86;
        CoTaskMemFree(programFilesX86);
        if (PathFileExistsW((path + L"\\PWPW\\pwpw-card-pkcs11.dll").c_str()))
            path += L"\\PWPW\\pwpw-card-pkcs11.dll";
        else
            path += L"\\CryptoTech\\CryptoCard\\CCPkiP11.dll";
        int size = WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), nullptr, 0, nullptr, nullptr);
        std::string result(size, 0);
        WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), &result[0], size, nullptr, nullptr);
        return result;
    }();
#elif defined __APPLE__
    static const std::string openscPath("/Library/OpenSC/lib/opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("/Library/latvia-eid/lib/otlv-pkcs11.so");
    static const std::string finPath("/Library/mPolluxDigiSign/libcryptoki.dylib");
    static const std::string lit1Path("/Library/Security/tokend/CCSuite.tokend/Contents/Frameworks/libccpkip11.dylib");
    static const std::string lit2Path("/Library/PWPW-Card/pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string belPath("/usr/local/lib/beid-pkcs11.bundle/Contents/MacOS/libbeidpkcs11.dylib");
    static const std::string eTokenPath("/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib");
    static const std::string ocsPath("/Library/AWP/lib/libOcsCryptoki.dylib");
#else
    static const std::string openscPath("opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("otlv-pkcs11.so");
    static const std::string finPath("libcryptoki.so");
    static const std::string lit1Path("/usr/lib/ccs/libccpkip11.so");
    static const std::string lit2Path("pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string belPath("libbeidpkcs11.so.0");
    static const std::string eTokenPath("/usr/local/lib/libeTPkcs11.dylib");
    static const std::string ocsPath("/usr/local/AWP/lib/libOcsCryptoki.so");
#endif
    static const std::map<std::string, Params> m = {
#ifdef _WIN32
        {"3BFD1800008031FE4553434536302D43443134352D46CD", {"C:\\Windows\\System32\\aetpkss1.dll", "PIN", "PIN"}},
#else
        {"3BFE1800008031FE454573744549442076657220312E30A8", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_COLD_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4561B168301900086", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4162A0083019000E1", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV2_ATR
        {"3BFE1800008031FE45803180664090A4162A00830F9000EF", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV3_ATR
        {"3BFA1800008031FE45FE654944202F20504B4903", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3.5_COLD_ATR

        {"3BDD18008131FE45904C41545649412D65494490008C", {latPath, "PIN1", "PIN2"}},

        {"3B7B940000806212515646696E454944", {finPath, "PIN1", "PIN2"}},
        {"3B7F9600008031B865B0850300EF1200F6829000", {finPath, "PIN1", "PIN2"}},

        {"3B9813400AA503010101AD1311", {belPath, "PIN", "PIN"}},

        {"3BD5180081313A7D8073C8211030", {eTokenPath, "PIN", "PIN"}},
        {"3BD518008131FE7D8073C82110F4", {eTokenPath, "PIN", "PIN"}},

        {"3BDB960080B1FE451F830012233F536549440F9000F1", {ocsPath, "PIN1", "PIN2"}},
#endif
        {"3BF81300008131FE45536D617274417070F8", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B08311C0A983009000", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B0831100C883009000", {litPath, "PIN", "PIN"}},
        {"3B9F9681B1FE451F070064051EB20031B0739621DB00900050", {litPath, "PIN", "PIN"}},
        {"3B9F90801FC30068104405014649534531C800000000", {litPath, "PIN", "PIN"}},
    };

    const std::vector<std::string> list = atrList();
    for (const std::string &atr : list) {
        auto it = m.find(atr);
        if (it != m.end())
            return it->second;
    }
#ifdef _WIN32
    return Params();
#else
    if (!list.empty())
        _log("Unknown ATR '%s' using default module '%s'", list[0].c_str(), openscPath.c_str());
    return {openscPath, "PIN", "PIN"};
#endif
}
<commit_msg>Fix linux module extension (#84)<commit_after>/*
 * Chrome Token Signing Native Host
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "PKCS11Path.h"
#include "BinaryUtils.h"
#include "Logger.h"

#ifdef _WIN32
#undef UNICODE
#include <Shlobj.h>
#include <Shlwapi.h>
#include <Knownfolders.h>
#include <winscard.h>
#elif defined __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#include <unistd.h>
#else
#include <winscard.h>
#include <unistd.h>
#endif

#include <cstring>
#include <map>

std::vector<std::string> PKCS11Path::atrList() {
	SCARDCONTEXT hContext = 0;
	std::vector<std::string> result;
	LONG err = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &hContext);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardEstablishContext ERROR: %x", err);
		return result;
	}

	DWORD size = 0;
	err = SCardListReaders(hContext, nullptr, nullptr, &size);
	if (err != SCARD_S_SUCCESS || !size) {
		_log("SCardListReaders || !size ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

	std::string readers(size, 0);
	err = SCardListReaders(hContext, nullptr, &readers[0], &size);
	readers.resize(size);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardListReaders ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

    std::vector<SCARD_READERSTATE> list;
    for (const char *name = readers.c_str(); *name; name += strlen(name) + 1) {
        _log("found reader: %s", name);
        list.push_back({ name, nullptr, 0, 0, 0, {} });
    }

    err = SCardGetStatusChange(hContext, 0, list.data(), DWORD(list.size()));
    if (err != SCARD_S_SUCCESS)
        _log("SCardGetStatusChange ERROR: %x", err);
    for(const SCARD_READERSTATE &state: list)
    {
        if (state.dwEventState & SCARD_STATE_PRESENT)
        {
            std::string atr = BinaryUtils::bin2hex(state.rgbAtr, state.cbAtr);
            result.push_back(atr);
            _log("Set ATR = %s for reader %s", atr.c_str(), state.szReader);
        }
    }

    SCardReleaseContext(hContext);
    return result;
}

PKCS11Path::Params PKCS11Path::getPkcs11ModulePath() {
#ifdef _WIN32
    // Use PKCS11 driver on windows to avoid PIN buffering
    static const std::string litPath = [] {
        PWSTR programFilesX86 = 0;
        SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, 0, nullptr, &programFilesX86);
        std::wstring path = programFilesX86;
        CoTaskMemFree(programFilesX86);
        if (PathFileExistsW((path + L"\\PWPW\\pwpw-card-pkcs11.dll").c_str()))
            path += L"\\PWPW\\pwpw-card-pkcs11.dll";
        else
            path += L"\\CryptoTech\\CryptoCard\\CCPkiP11.dll";
        int size = WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), nullptr, 0, nullptr, nullptr);
        std::string result(size, 0);
        WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), &result[0], size, nullptr, nullptr);
        return result;
    }();
#elif defined __APPLE__
    static const std::string openscPath("/Library/OpenSC/lib/opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("/Library/latvia-eid/lib/otlv-pkcs11.so");
    static const std::string finPath("/Library/mPolluxDigiSign/libcryptoki.dylib");
    static const std::string lit1Path("/Library/Security/tokend/CCSuite.tokend/Contents/Frameworks/libccpkip11.dylib");
    static const std::string lit2Path("/Library/PWPW-Card/pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string belPath("/usr/local/lib/beid-pkcs11.bundle/Contents/MacOS/libbeidpkcs11.dylib");
    static const std::string eTokenPath("/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib");
    static const std::string ocsPath("/Library/AWP/lib/libOcsCryptoki.dylib");
#else
    static const std::string openscPath("opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("otlv-pkcs11.so");
    static const std::string finPath("libcryptoki.so");
    static const std::string lit1Path("/usr/lib/ccs/libccpkip11.so");
    static const std::string lit2Path("pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string belPath("libbeidpkcs11.so.0");
    static const std::string eTokenPath("/usr/local/lib/libeTPkcs11.so");
    static const std::string ocsPath("/usr/local/AWP/lib/libOcsCryptoki.so");
#endif
    static const std::map<std::string, Params> m = {
#ifdef _WIN32
        {"3BFD1800008031FE4553434536302D43443134352D46CD", {"C:\\Windows\\System32\\aetpkss1.dll", "PIN", "PIN"}},
#else
        {"3BFE1800008031FE454573744549442076657220312E30A8", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_COLD_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4561B168301900086", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4162A0083019000E1", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV2_ATR
        {"3BFE1800008031FE45803180664090A4162A00830F9000EF", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV3_ATR
        {"3BFA1800008031FE45FE654944202F20504B4903", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3.5_COLD_ATR

        {"3BDD18008131FE45904C41545649412D65494490008C", {latPath, "PIN1", "PIN2"}},

        {"3B7B940000806212515646696E454944", {finPath, "PIN1", "PIN2"}},
        {"3B7F9600008031B865B0850300EF1200F6829000", {finPath, "PIN1", "PIN2"}},

        {"3B9813400AA503010101AD1311", {belPath, "PIN", "PIN"}},

        {"3BD5180081313A7D8073C8211030", {eTokenPath, "PIN", "PIN"}},
        {"3BD518008131FE7D8073C82110F4", {eTokenPath, "PIN", "PIN"}},

        {"3BDB960080B1FE451F830012233F536549440F9000F1", {ocsPath, "PIN1", "PIN2"}},
#endif
        {"3BF81300008131FE45536D617274417070F8", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B08311C0A983009000", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B0831100C883009000", {litPath, "PIN", "PIN"}},
        {"3B9F9681B1FE451F070064051EB20031B0739621DB00900050", {litPath, "PIN", "PIN"}},
        {"3B9F90801FC30068104405014649534531C800000000", {litPath, "PIN", "PIN"}},
    };

    const std::vector<std::string> list = atrList();
    for (const std::string &atr : list) {
        auto it = m.find(atr);
        if (it != m.end())
            return it->second;
    }
#ifdef _WIN32
    return Params();
#else
    if (!list.empty())
        _log("Unknown ATR '%s' using default module '%s'", list[0].c_str(), openscPath.c_str());
    return {openscPath, "PIN", "PIN"};
#endif
}
<|endoftext|>


<commit_before>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/render/Rect.hpp
 *
 * Copyright 2017 Patrik Huber
 *
 * 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.
 */
#pragma once

#ifndef RECT_HPP_
#define RECT_HPP_

namespace eos {
namespace render {

/**
 * @brief A simple type representing a rectangle.
 */
template<typename T>
struct Rect
{
	T x, y; // these are the top-left corner x and y
	T width, height;
};

} /* namespace render */
} /* namespace eos */

#endif /* RECT_HPP_ */
<commit_msg>Added EOS_ prefix to RECT header-guard<commit_after>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/render/Rect.hpp
 *
 * Copyright 2017 Patrik Huber
 *
 * 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.
 */
#pragma once

#ifndef EOS_RECT_HPP_
#define EOS_RECT_HPP_

namespace eos {
namespace render {

/**
 * @brief A simple type representing a rectangle.
 */
template<typename T>
struct Rect
{
	T x, y; // these are the top-left corner x and y
	T width, height;
};

} /* namespace render */
} /* namespace eos */

#endif /* EOS_RECT_HPP_ */
<|endoftext|>


<commit_before>#pragma once
/**
 * \file	exemodel/pollee.hpp
 * \author	Yi Qingliang <niqingliang2003@tom.com>
 */
#include <unistd.h>
#include <sys/epoll.h>

#include <cstdint>
#include <cstddef>

namespace exemodel {

class poller;
/**
 * \class pollee
 * \brief \em poller can wait on it for any events it cared about.
 */
class pollee {
public:
	/**
	 * \brief the ctor of pollee
	 * \param fd	the file descriptor representing this pollee.
	 * \param evts	the events it cared about.
	 */
	explicit pollee(int fd, uint32_t evts);
	virtual ~pollee();
public:
	ssize_t read(void *buf, size_t nbyte)
	{
		return ::read(m_fd, buf, nbyte);
	}

	ssize_t wrire(const void *buf, size_t nbyte)
	{
		return ::write(m_fd, buf, nbyte);
	}
public:
	/**
	 * \brief used for disposing the event caught by the \em poller attached.
	 * \note all subclasses of \em pollee must implement it.
	 */
	virtual void dispose(poller & mgr, uint32_t evts) = 0;
public:
	int _fd_(void) const { return m_fd; }
	uint32_t _evts_(void) const { return m_evts; }
private:
	pollee(const pollee & rhs) = delete;
	pollee & operator = (const pollee & rhs) = delete;
protected:
	uint32_t	m_evts;		// the events *this* object caring about.
private:
	const int	m_fd;		// the fd reprented by *this* object.
};

}
<commit_msg>fix type error<commit_after>#pragma once
/**
 * \file	exemodel/pollee.hpp
 * \author	Yi Qingliang <niqingliang2003@tom.com>
 */
#include <unistd.h>
#include <sys/epoll.h>

#include <cstdint>
#include <cstddef>

namespace exemodel {

class poller;
/**
 * \class pollee
 * \brief \em poller can wait on it for any events it cared about.
 */
class pollee {
public:
	/**
	 * \brief the ctor of pollee
	 * \param fd	the file descriptor representing this pollee.
	 * \param evts	the events it cared about.
	 */
	explicit pollee(int fd, uint32_t evts);
	virtual ~pollee();
public:
	ssize_t read(void *buf, size_t nbyte)
	{
		return ::read(m_fd, buf, nbyte);
	}

	ssize_t write(const void *buf, size_t nbyte)
	{
		return ::write(m_fd, buf, nbyte);
	}
public:
	/**
	 * \brief used for disposing the event caught by the \em poller attached.
	 * \note all subclasses of \em pollee must implement it.
	 */
	virtual void dispose(poller & mgr, uint32_t evts) = 0;
public:
	int _fd_(void) const { return m_fd; }
	uint32_t _evts_(void) const { return m_evts; }
private:
	pollee(const pollee & rhs) = delete;
	pollee & operator = (const pollee & rhs) = delete;
protected:
	uint32_t	m_evts;		// the events *this* object caring about.
private:
	const int	m_fd;		// the fd reprented by *this* object.
};

}
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

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.
*/
#ifndef FLUSSPFERD_BLOB_HPP
#define FLUSSPFERD_BLOB_HPP

#include "native_object_base.hpp"
#include "class.hpp"
#include <vector>

namespace flusspferd {

class blob : public native_object_base {
public:
  blob(object const &obj, call_context &x);
  blob(object const &obj, unsigned char const *data, std::size_t length);
  ~blob();

  struct class_info : flusspferd::class_info {
    static char const *full_name() { return "Blob"; }

    static char const *constructor_name() { return "Blob"; }
    typedef boost::mpl::size_t<1> constructor_arity;

    static object create_prototype();
    static void augment_constructor(object &);
  };

  unsigned char *get_data() { return &data[0]; }
  std::size_t size() { return data.size(); }

  std::vector<unsigned char> &get() { return data; }

protected:
  void property_op(property_mode mode, value const &id, value &data);
  bool property_resolve(value const &id, unsigned access);

private: // JS methos
  void append(blob const &o);
  object slice(int from, boost::optional<int> to);
  object to_array();
  object clone();
  string as_utf8();
  string as_utf16();

  value set_index(int index, value x);
  value get_index(int index);
private: // JS properties
  void prop_length(property_mode mode, value &data);

private: // JS constructor methods
  static object from_utf8(string const &);
  static object from_utf16(string const &);

private:
  std::vector<unsigned char> data;

  static unsigned char el_from_value(value const &);

  void init();
};

}

#endif
<commit_msg>core: typo<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

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.
*/
#ifndef FLUSSPFERD_BLOB_HPP
#define FLUSSPFERD_BLOB_HPP

#include "native_object_base.hpp"
#include "class.hpp"
#include <vector>

namespace flusspferd {

class blob : public native_object_base {
public:
  blob(object const &obj, call_context &x);
  blob(object const &obj, unsigned char const *data, std::size_t length);
  ~blob();

  struct class_info : flusspferd::class_info {
    static char const *full_name() { return "Blob"; }

    static char const *constructor_name() { return "Blob"; }
    typedef boost::mpl::size_t<1> constructor_arity;

    static object create_prototype();
    static void augment_constructor(object &);
  };

  unsigned char *get_data() { return &data[0]; }
  std::size_t size() { return data.size(); }

  std::vector<unsigned char> &get() { return data; }

protected:
  void property_op(property_mode mode, value const &id, value &data);
  bool property_resolve(value const &id, unsigned access);

private: // JS methods
  void append(blob const &o);
  object slice(int from, boost::optional<int> to);
  object to_array();
  object clone();
  string as_utf8();
  string as_utf16();

  value set_index(int index, value x);
  value get_index(int index);
private: // JS properties
  void prop_length(property_mode mode, value &data);

private: // JS constructor methods
  static object from_utf8(string const &);
  static object from_utf16(string const &);

private:
  std::vector<unsigned char> data;

  static unsigned char el_from_value(value const &);

  void init();
};

}

#endif
<|endoftext|>


<commit_before>#include <Poco/String.h>
#include <Poco/StreamCopier.h>

#include "util/Template.h"

using namespace std;
using namespace Poco;
using namespace BeeeOn;

Template::Template(const string &text):
	m_content(text)
{
}

Template::Template(istream &in)
{
	StreamCopier::copyToString(in, m_content);
}

void Template::subst(string &s, const string &key, const string &value)
{
	if (key.empty())
		return;

	replaceInPlace(s, key, value, 0);
}

string Template::apply(const map<string, string> &context)
{
	std::string text(m_content);

	for (auto pair : context)
		subst(text, "${" + pair.first + "}", pair.second);

	return text;
}
<commit_msg>Template: debug log substitution context<commit_after>#include <Poco/String.h>
#include <Poco/StreamCopier.h>

#include "util/Template.h"
#include "Debug.h"

using namespace std;
using namespace Poco;
using namespace BeeeOn;

Template::Template(const string &text):
	m_content(text)
{
}

Template::Template(istream &in)
{
	StreamCopier::copyToString(in, m_content);
}

void Template::subst(string &s, const string &key, const string &value)
{
	if (key.empty())
		return;

	replaceInPlace(s, key, value, 0);
}

string Template::apply(const map<string, string> &context)
{
	Logger &logger = LOGGER_CLASS(this);
	std::string text(m_content);

	for (auto pair : context) {
		if (logger.debug()) {
			logger.debug(pair.first + " => " + pair.second,
					__FILE__, __LINE__);
		}

		subst(text, "${" + pair.first + "}", pair.second);
	}

	return text;
}
<|endoftext|>


<commit_before><commit_msg>Add missing initialization of fStreamerFunc<commit_after><|endoftext|>


<commit_before>/**
 * @file Cosa/Time.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2013-2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/Time.hh"

IOStream& operator<<(IOStream& outs, const time_t& t)
{
  outs << time_t::full_year( t.year ) << '-';
  if (t.month < 10) outs << '0';
  outs << t.month << '-';
  if (t.date < 10) outs << '0';
  outs << t.date << ' ';
  if (t.hours < 10) outs << '0';
  outs << t.hours << ':';
  if (t.minutes < 10) outs << '0';
  outs << t.minutes << ':';
  if (t.seconds < 10) outs << '0';
  outs << t.seconds;
  return (outs);
}

bool
time_t::parse(str_P s)
{
  static size_t BUF_MAX = 32;
  char buf[BUF_MAX];
  strcpy_P(buf, s);
  char* sp = &buf[0];
  uint16_t value = strtoul(sp, &sp, 10);

  if (UNLIKELY(*sp != '-')) return false;
  year = value % 100;
  if (UNLIKELY(full_year() != value)) return false;

  value = strtoul(sp + 1, &sp, 10);
  if (UNLIKELY(*sp != '-')) return false;
  month = value;

  value = strtoul(sp + 1, &sp, 10);
  if (UNLIKELY(*sp != ' ')) return false;
  date = value;

  value = strtoul(sp + 1, &sp, 10);
  if (UNLIKELY(*sp != ':')) return false;
  hours = value;

  value = strtoul(sp + 1, &sp, 10);
  if (UNLIKELY(*sp != ':')) return false;
  minutes = value;

  value = strtoul(sp + 1, &sp, 10);
  if (UNLIKELY(*sp != 0)) return false;
  seconds = value;

  set_day();
  return (is_valid());
}

uint16_t time_t::s_epoch_year = Y2K_EPOCH_YEAR;
uint8_t time_t::epoch_offset = 0;
uint8_t time_t::epoch_weekday = Y2K_EPOCH_WEEKDAY;
uint8_t time_t::pivot_year = 0;

const uint8_t time_t::days_in[] __PROGMEM = {
  0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

time_t::time_t(clock_t c, int8_t zone)
{
  c += zone * (int32_t) SECONDS_PER_HOUR;
  uint16_t dayno = c / SECONDS_PER_DAY;
  c -= dayno * (uint32_t) SECONDS_PER_DAY;
  day = weekday_for(dayno);

  uint16_t y = epoch_year();
  for (;;) {
    uint16_t days = days_per( y );
    if (dayno < days) break;
    dayno -= days;
    y++;
  }
  bool leap_year = is_leap(y);
  y -= epoch_year();
  y += epoch_offset;
  while (y > 100)
    y -= 100;
  year = y;

  month = 1;
  for (;;) {
    uint8_t days = pgm_read_byte(&days_in[month]);
    if (leap_year && (month == 2)) days++;
    if (dayno < days) break;
    dayno -= days;
    month++;
  }
  date = dayno + 1;

  hours = c / SECONDS_PER_HOUR;

  uint16_t c_ms;
  if (hours < 18) // save 16uS
    c_ms = (uint16_t) c - (hours * (uint16_t) SECONDS_PER_HOUR);
  else
    c_ms = c - (hours * (uint32_t) SECONDS_PER_HOUR);
  minutes = c_ms / SECONDS_PER_MINUTE;
  seconds = c_ms - (minutes * SECONDS_PER_MINUTE);
}

time_t::operator clock_t() const
{
  clock_t c = days() * SECONDS_PER_DAY;
  if (hours < 18)
    c += hours * (uint16_t) SECONDS_PER_HOUR;
  else
    c += hours * (uint32_t) SECONDS_PER_HOUR;
  c += minutes * (uint16_t) SECONDS_PER_MINUTE;
  c += seconds;

  return (c);
}

uint16_t time_t::days() const
{
  uint16_t day_count = day_of_year();

  uint16_t y = full_year();
  while (y-- > epoch_year())
    day_count += days_per(y);

  return (day_count);
}

uint16_t time_t::day_of_year() const
{
  uint16_t dayno = date - 1;
  bool leap_year = is_leap();

  for (uint8_t m = 1; m < month; m++) {
    dayno += pgm_read_byte(&days_in[m]);
    if (leap_year && (m == 2)) dayno++;
  }

  return (dayno);
}

void time_t::use_fastest_epoch()
{
  // Figure out when we were compiled and use the year for a really
  // fast epoch_year. Format "MMM DD YYYY"
  const char* compile_date = (const char *) PSTR(__DATE__);
  uint16_t compile_year = 0;
  for (uint8_t i = 7; i < 11; i++)
    compile_year = compile_year*10 + (pgm_read_byte(&compile_date[i]) - '0');

  // Temporarily set a Y2K epoch so we can figure out the day for
  // January 1 of this year
  epoch_year( Y2K_EPOCH_YEAR );
  epoch_weekday = Y2K_EPOCH_WEEKDAY;
  time_t this_year(0);
  this_year.year = compile_year % 100;
  this_year.set_day();
  uint8_t compile_weekday = this_year.day;

  time_t::epoch_year( compile_year );
  time_t::epoch_weekday = compile_weekday;
  time_t::pivot_year = this_year.year;
}
<commit_msg>Cleanup.<commit_after>/**
 * @file Cosa/Time.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2013-2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/Time.hh"

IOStream& operator<<(IOStream& outs, const time_t& t)
{
  outs << time_t::full_year( t.year ) << '-';
  if (t.month < 10) outs << '0';
  outs << t.month << '-';
  if (t.date < 10) outs << '0';
  outs << t.date << ' ';
  if (t.hours < 10) outs << '0';
  outs << t.hours << ':';
  if (t.minutes < 10) outs << '0';
  outs << t.minutes << ':';
  if (t.seconds < 10) outs << '0';
  outs << t.seconds;
  return (outs);
}

bool
time_t::parse(str_P s)
{
  static size_t BUF_MAX = 32;
  char buf[BUF_MAX];
  strcpy_P(buf, s);
  char* sp = &buf[0];
  uint16_t value = strtoul(sp, &sp, 10);

  if (UNLIKELY(*sp != '-')) return false;
  year = value % 100;
  if (UNLIKELY(full_year() != value)) return false;

  value = strtoul(sp + 1, &sp, 10);
  if (UNLIKELY(*sp != '-')) return false;
  month = value;

  value = strtoul(sp + 1, &sp, 10);
  if (UNLIKELY(*sp != ' ')) return false;
  date = value;

  value = strtoul(sp + 1, &sp, 10);
  if (UNLIKELY(*sp != ':')) return false;
  hours = value;

  value = strtoul(sp + 1, &sp, 10);
  if (UNLIKELY(*sp != ':')) return false;
  minutes = value;

  value = strtoul(sp + 1, &sp, 10);
  if (UNLIKELY(*sp != 0)) return false;
  seconds = value;

  set_day();
  return (is_valid());
}

uint16_t time_t::s_epoch_year = Y2K_EPOCH_YEAR;
uint8_t time_t::epoch_offset = 0;
uint8_t time_t::epoch_weekday = Y2K_EPOCH_WEEKDAY;
uint8_t time_t::pivot_year = 0;

const uint8_t time_t::days_in[] __PROGMEM = {
  0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

time_t::time_t(clock_t c, int8_t zone)
{
  c += zone * (int32_t) SECONDS_PER_HOUR;
  uint16_t dayno = c / SECONDS_PER_DAY;
  c -= dayno * (uint32_t) SECONDS_PER_DAY;
  day = weekday_for(dayno);

  uint16_t y = epoch_year();
  for (;;) {
    uint16_t days = days_per(y);
    if (dayno < days) break;
    dayno -= days;
    y++;
  }
  bool leap_year = is_leap(y);
  y -= epoch_year();
  y += epoch_offset;
  while (y > 100)
    y -= 100;
  year = y;

  month = 1;
  for (;;) {
    uint8_t days = pgm_read_byte(&days_in[month]);
    if (leap_year && (month == 2)) days++;
    if (dayno < days) break;
    dayno -= days;
    month++;
  }
  date = dayno + 1;

  hours = c / SECONDS_PER_HOUR;

  uint16_t c_ms;
  if (hours < 18) // save 16uS
    c_ms = (uint16_t) c - (hours * (uint16_t) SECONDS_PER_HOUR);
  else
    c_ms = c - (hours * (uint32_t) SECONDS_PER_HOUR);
  minutes = c_ms / SECONDS_PER_MINUTE;
  seconds = c_ms - (minutes * SECONDS_PER_MINUTE);
}

time_t::operator clock_t() const
{
  clock_t c = days() * SECONDS_PER_DAY;
  if (hours < 18)
    c += hours * (uint16_t) SECONDS_PER_HOUR;
  else
    c += hours * (uint32_t) SECONDS_PER_HOUR;
  c += minutes * (uint16_t) SECONDS_PER_MINUTE;
  c += seconds;

  return (c);
}

uint16_t time_t::days() const
{
  uint16_t day_count = day_of_year();

  uint16_t y = full_year();
  while (y-- > epoch_year())
    day_count += days_per(y);

  return (day_count);
}

uint16_t time_t::day_of_year() const
{
  uint16_t dayno = date - 1;
  bool leap_year = is_leap();

  for (uint8_t m = 1; m < month; m++) {
    dayno += pgm_read_byte(&days_in[m]);
    if (leap_year && (m == 2)) dayno++;
  }

  return (dayno);
}

void time_t::use_fastest_epoch()
{
  // Figure out when we were compiled and use the year for a really
  // fast epoch_year. Format "MMM DD YYYY"
  const char* compile_date = (const char *) PSTR(__DATE__);
  uint16_t compile_year = 0;
  for (uint8_t i = 7; i < 11; i++)
    compile_year = compile_year*10 + (pgm_read_byte(&compile_date[i]) - '0');

  // Temporarily set a Y2K epoch so we can figure out the day for
  // January 1 of this year
  epoch_year(Y2K_EPOCH_YEAR);
  epoch_weekday = Y2K_EPOCH_WEEKDAY;
  time_t this_year(0);
  this_year.year = compile_year % 100;
  this_year.set_day();
  uint8_t compile_weekday = this_year.day;

  time_t::epoch_year(compile_year);
  time_t::epoch_weekday = compile_weekday;
  time_t::pivot_year = this_year.year;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, 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.

*/

#ifndef TORRENT_FILE_HPP_INCLUDED
#define TORRENT_FILE_HPP_INCLUDED

#include <memory>

#include <boost/noncopyable.hpp>
#include <boost/filesystem/path.hpp>

namespace libtorrent
{

	struct file_error: std::runtime_error
	{
		file_error(std::string const& msg): std::runtime_error(msg) {}
	};

	class file: public boost::noncopyable
	{
	public:

#ifdef _MSC_VER
		typedef _int64 size_type;
#else
		typedef long long int size_type;
#endif

		class seek_mode
		{
		friend file;
		seek_mode(int v): m_val(v) {}
		int m_val;
		};

		static seek_mode begin;
		static seek_mode end;

		class open_mode
		{
		friend file;
		public:

			open_mode(): m_mask(0) {}

			open_mode operator|(open_mode m) const
			{ return open_mode(m.m_mask | m_mask); }

			open_mode operator|=(open_mode m)
			{
				m_mask |= m.m_mask;
				return *this;
			}

		private:

			open_mode(int val): m_mask(val) {}
			int m_mask;
		};

		static open_mode in;
		static open_mode out;

		file();
		file(boost::filesystem::path const& p, open_mode m);
		~file();

		void open(boost::filesystem::path const& p, open_mode m);
		void close();

		size_type write(const char*, size_type num_bytes);
		size_type read(char*, size_type num_bytes);

		void seek(size_type pos, seek_mode m);
		size_type tell();

	private:

		struct impl;
		const std::auto_ptr<impl> m_impl;

	};

}

#endif // TORRENT_FILE_HPP_INCLUDED

<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, 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.

*/

#ifndef TORRENT_FILE_HPP_INCLUDED
#define TORRENT_FILE_HPP_INCLUDED

#include <memory>

#include <boost/noncopyable.hpp>
#include <boost/filesystem/path.hpp>

namespace libtorrent
{

	struct file_error: std::runtime_error
	{
		file_error(std::string const& msg): std::runtime_error(msg) {}
	};

	class file: public boost::noncopyable
	{
	public:

#ifdef _MSC_VER
		typedef _int64 size_type;
#else
		typedef long long int size_type;
#endif

		class seek_mode
		{
		friend file;
		seek_mode(int v): m_val(v) {}
		int m_val;
		};

		const static seek_mode begin;
		const static seek_mode end;

		class open_mode
		{
		friend file;
		public:

			open_mode(): m_mask(0) {}

			open_mode operator|(open_mode m) const
			{ return open_mode(m.m_mask | m_mask); }

			open_mode operator|=(open_mode m)
			{
				m_mask |= m.m_mask;
				return *this;
			}

		private:

			open_mode(int val): m_mask(val) {}
			int m_mask;
		};

		const static open_mode in;
		const static open_mode out;

		file();
		file(boost::filesystem::path const& p, open_mode m);
		~file();

		void open(boost::filesystem::path const& p, open_mode m);
		void close();

		size_type write(const char*, size_type num_bytes);
		size_type read(char*, size_type num_bytes);

		void seek(size_type pos, seek_mode m);
		size_type tell();

	private:

		struct impl;
		const std::auto_ptr<impl> m_impl;

	};

}

#endif // TORRENT_FILE_HPP_INCLUDED

<|endoftext|>


<commit_before>/*

Copyright (c) 2003, 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.

*/

#ifndef TORRENT_STAT_HPP_INCLUDED
#define TORRENT_STAT_HPP_INCLUDED

#include <algorithm>
#include <vector>
#include <assert.h>
#include <cstring>

#include "libtorrent/size_type.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	class TORRENT_EXPORT stat_channel
	{
	friend class invariant_access;
	public:
		enum { history = 10 };

		stat_channel()
			: m_counter(0)
			, m_total_counter(0)
			, m_rate_sum(0)
		{
			std::memset(m_rate_history, 0, sizeof(m_rate_history));
		}

		void operator+=(stat_channel const& s)
		{
			m_counter += s.m_counter;
			m_total_counter += s.m_counter;
		}

		void add(int count)
		{
			TORRENT_ASSERT(count >= 0);

			m_counter += count;
			m_total_counter += count;
		}

		// should be called once every second
		void second_tick(float tick_interval);
		float rate() const { return m_rate_sum / float(history); }
		size_type rate_sum() const { return m_rate_sum; }
		size_type total() const { return m_total_counter; }

		void offset(size_type counter)
		{
			TORRENT_ASSERT(counter >= 0);
			m_total_counter += counter;
		}

		size_type counter() const { return m_counter; }

	private:

#ifndef NDEBUG
		void check_invariant() const
		{
			int sum = 0;
			for (int i = 0; i < history; ++i) sum += m_rate_history[i];
			TORRENT_ASSERT(m_rate_sum == sum);
			TORRENT_ASSERT(m_total_counter >= 0);
		}
#endif

		// history of rates a few seconds back
		int m_rate_history[history];

		// the accumulator for this second.
		int m_counter;

		// total counters
		size_type m_total_counter;

		// sum of all elements in m_rate_history
		size_type m_rate_sum;
	};

	class TORRENT_EXPORT stat
	{
	friend class invariant_access;
	public:
		void operator+=(const stat& s)
		{
			for (int i = 0; i < num_channels; ++i)
				m_stat[i] += s.m_stat[i];
		}

		void received_bytes(int bytes_payload, int bytes_protocol)
		{
			TORRENT_ASSERT(bytes_payload >= 0);
			TORRENT_ASSERT(bytes_protocol >= 0);

			m_stat[download_payload].add(bytes_payload);
			m_stat[download_protocol].add(bytes_protocol);
		}

		void sent_bytes(int bytes_payload, int bytes_protocol)
		{
			TORRENT_ASSERT(bytes_payload >= 0);
			TORRENT_ASSERT(bytes_protocol >= 0);

			m_stat[upload_payload].add(bytes_payload);
			m_stat[upload_protocol].add(bytes_protocol);
		}

		// calculate ip protocol overhead
		void calc_ip_overhead()
		{
			int uploaded = m_stat[upload_protocol].counter()
				+ m_stat[upload_payload].counter();
			int downloaded = m_stat[download_protocol].counter()
				+ m_stat[download_payload].counter();

			// IP + TCP headers are 40 bytes per MTU (1460)
			// bytes of payload, but at least 40 bytes
			m_stat[upload_ip_protocol].add((std::max)(uploaded / 1460, 40));
			m_stat[download_ip_protocol].add((std::max)(downloaded / 1460, 40));

			// also account for ACK traffic. That adds to the transfers
			// in the opposite direction. Even on connections with symmetric
			// transfer rates, it seems to add a penalty.
			m_stat[upload_ip_protocol].add((std::max)(downloaded / 20, 40));
			m_stat[download_ip_protocol].add((std::max)(uploaded / 20, 40));
		}

		int upload_ip_overhead() const { return m_stat[upload_ip_protocol].counter(); }
		int download_ip_overhead() const { return m_stat[download_ip_protocol].counter(); }

		// should be called once every second
		void second_tick(float tick_interval)
		{
			for (int i = 0; i < num_channels; ++i)
				m_stat[i].second_tick(tick_interval);
		}

		float upload_rate() const
		{
			return (m_stat[upload_payload].rate_sum()
				+ m_stat[upload_protocol].rate_sum()
				+ m_stat[upload_ip_protocol].rate_sum())
				/ float(stat_channel::history);
		}

		float download_rate() const
		{
			return (m_stat[download_payload].rate_sum()
				+ m_stat[download_protocol].rate_sum()
				+ m_stat[download_ip_protocol].rate_sum())
				/ float(stat_channel::history);
		}

		float upload_payload_rate() const
		{ return m_stat[upload_payload].rate(); }

		float download_payload_rate() const
		{ return m_stat[download_payload].rate(); }

		size_type total_payload_upload() const
		{ return m_stat[upload_payload].total(); }
		size_type total_payload_download() const
		{ return m_stat[download_payload].total(); }

		size_type total_protocol_upload() const
		{ return m_stat[upload_protocol].total(); }
		size_type total_protocol_download() const
		{ return m_stat[download_protocol].total(); }

		// this is used to offset the statistics when a
		// peer_connection is opened and have some previous
		// transfers from earlier connections.
		void add_stat(size_type downloaded, size_type uploaded)
		{
			TORRENT_ASSERT(downloaded >= 0);
			TORRENT_ASSERT(uploaded >= 0);
			m_stat[download_payload].offset(downloaded);
			m_stat[upload_payload].offset(uploaded);
		}

		size_type last_payload_downloaded() const
		{ return m_stat[download_payload].counter(); }
		size_type last_payload_uploaded() const
		{ return m_stat[upload_payload].counter(); }

	private:

		// these are the channels we keep stats for
		enum
		{
			upload_payload,
			upload_protocol,
			upload_ip_protocol,
			download_payload,
			download_protocol,
			download_ip_protocol,
			num_channels
		};

		stat_channel m_stat[num_channels];
	};

}

#endif // TORRENT_STAT_HPP_INCLUDED

<commit_msg>updated IP overhead calculation<commit_after>/*

Copyright (c) 2003, 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.

*/

#ifndef TORRENT_STAT_HPP_INCLUDED
#define TORRENT_STAT_HPP_INCLUDED

#include <algorithm>
#include <vector>
#include <assert.h>
#include <cstring>

#include "libtorrent/size_type.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	class TORRENT_EXPORT stat_channel
	{
	friend class invariant_access;
	public:
		enum { history = 10 };

		stat_channel()
			: m_counter(0)
			, m_total_counter(0)
			, m_rate_sum(0)
		{
			std::memset(m_rate_history, 0, sizeof(m_rate_history));
		}

		void operator+=(stat_channel const& s)
		{
			m_counter += s.m_counter;
			m_total_counter += s.m_counter;
		}

		void add(int count)
		{
			TORRENT_ASSERT(count >= 0);

			m_counter += count;
			m_total_counter += count;
		}

		// should be called once every second
		void second_tick(float tick_interval);
		float rate() const { return m_rate_sum / float(history); }
		size_type rate_sum() const { return m_rate_sum; }
		size_type total() const { return m_total_counter; }

		void offset(size_type counter)
		{
			TORRENT_ASSERT(counter >= 0);
			m_total_counter += counter;
		}

		size_type counter() const { return m_counter; }

	private:

#ifndef NDEBUG
		void check_invariant() const
		{
			int sum = 0;
			for (int i = 0; i < history; ++i) sum += m_rate_history[i];
			TORRENT_ASSERT(m_rate_sum == sum);
			TORRENT_ASSERT(m_total_counter >= 0);
		}
#endif

		// history of rates a few seconds back
		int m_rate_history[history];

		// the accumulator for this second.
		int m_counter;

		// total counters
		size_type m_total_counter;

		// sum of all elements in m_rate_history
		size_type m_rate_sum;
	};

	class TORRENT_EXPORT stat
	{
	friend class invariant_access;
	public:
		void operator+=(const stat& s)
		{
			for (int i = 0; i < num_channels; ++i)
				m_stat[i] += s.m_stat[i];
		}

		void received_bytes(int bytes_payload, int bytes_protocol)
		{
			TORRENT_ASSERT(bytes_payload >= 0);
			TORRENT_ASSERT(bytes_protocol >= 0);

			m_stat[download_payload].add(bytes_payload);
			m_stat[download_protocol].add(bytes_protocol);
		}

		void sent_bytes(int bytes_payload, int bytes_protocol)
		{
			TORRENT_ASSERT(bytes_payload >= 0);
			TORRENT_ASSERT(bytes_protocol >= 0);

			m_stat[upload_payload].add(bytes_payload);
			m_stat[upload_protocol].add(bytes_protocol);
		}

		// calculate ip protocol overhead
		void calc_ip_overhead()
		{
			int uploaded = m_stat[upload_protocol].counter()
				+ m_stat[upload_payload].counter();
			int downloaded = m_stat[download_protocol].counter()
				+ m_stat[download_payload].counter();

			// IP + TCP headers are 40 bytes per MTU (1460)
			// bytes of payload, but at least 40 bytes
			m_stat[upload_ip_protocol].add((std::max)(uploaded / 1460, uploaded>0?40:0));
			m_stat[download_ip_protocol].add((std::max)(downloaded / 1460, downloaded>0?40:0));

			// also account for ACK traffic. That adds to the transfers
			// in the opposite direction. Even on connections with symmetric
			// transfer rates, it seems to add a penalty.
			m_stat[upload_ip_protocol].add((std::max)(downloaded * 40 / 1460, downloaded>0?40:0));
			m_stat[download_ip_protocol].add((std::max)(uploaded * 40 / 1460, uploaded>0?40:0));
		}

		int upload_ip_overhead() const { return m_stat[upload_ip_protocol].counter(); }
		int download_ip_overhead() const { return m_stat[download_ip_protocol].counter(); }

		// should be called once every second
		void second_tick(float tick_interval)
		{
			for (int i = 0; i < num_channels; ++i)
				m_stat[i].second_tick(tick_interval);
		}

		float upload_rate() const
		{
			return (m_stat[upload_payload].rate_sum()
				+ m_stat[upload_protocol].rate_sum()
				+ m_stat[upload_ip_protocol].rate_sum())
				/ float(stat_channel::history);
		}

		float download_rate() const
		{
			return (m_stat[download_payload].rate_sum()
				+ m_stat[download_protocol].rate_sum()
				+ m_stat[download_ip_protocol].rate_sum())
				/ float(stat_channel::history);
		}

		float upload_payload_rate() const
		{ return m_stat[upload_payload].rate(); }

		float download_payload_rate() const
		{ return m_stat[download_payload].rate(); }

		size_type total_payload_upload() const
		{ return m_stat[upload_payload].total(); }
		size_type total_payload_download() const
		{ return m_stat[download_payload].total(); }

		size_type total_protocol_upload() const
		{ return m_stat[upload_protocol].total(); }
		size_type total_protocol_download() const
		{ return m_stat[download_protocol].total(); }

		// this is used to offset the statistics when a
		// peer_connection is opened and have some previous
		// transfers from earlier connections.
		void add_stat(size_type downloaded, size_type uploaded)
		{
			TORRENT_ASSERT(downloaded >= 0);
			TORRENT_ASSERT(uploaded >= 0);
			m_stat[download_payload].offset(downloaded);
			m_stat[upload_payload].offset(uploaded);
		}

		size_type last_payload_downloaded() const
		{ return m_stat[download_payload].counter(); }
		size_type last_payload_uploaded() const
		{ return m_stat[upload_payload].counter(); }

	private:

		// these are the channels we keep stats for
		enum
		{
			upload_payload,
			upload_protocol,
			upload_ip_protocol,
			download_payload,
			download_protocol,
			download_ip_protocol,
			num_channels
		};

		stat_channel m_stat[num_channels];
	};

}

#endif // TORRENT_STAT_HPP_INCLUDED

<|endoftext|>


<commit_before>/*

Copyright (c) 2003, 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.

*/

#ifndef TORRENT_STAT_HPP_INCLUDED
#define TORRENT_STAT_HPP_INCLUDED

#include <algorithm>
#include <vector>
#include <assert.h>
#include <math.h>

#include "libtorrent/size_type.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	class TORRENT_EXPORT stat_channel
	{
	friend class invariant_access;
	public:
		enum { history = 10 };

		stat_channel()
			: m_counter(0)
			, m_total_counter(0)
			, m_rate_sum(0)
		{
			std::fill(m_rate_history
				, m_rate_history + history, 0.f);
		}

		void operator+=(stat_channel const& s)
		{
			m_counter += s.m_counter;
			m_total_counter += s.m_counter;
		}

		void add(int count)
		{
			TORRENT_ASSERT(count >= 0);

			m_counter += count;
			m_total_counter += count;
		}

		// should be called once every second
		void second_tick(float tick_interval);
		float rate() const { return m_rate_sum / history; }
		size_type total() const { return m_total_counter; }

		void offset(size_type counter)
		{
			TORRENT_ASSERT(counter >= 0);
			m_total_counter += counter;
		}

		size_type counter() const { return m_counter; }

	private:

#ifndef NDEBUG
		void check_invariant() const
		{
			float sum = 0.f;
			for (int i = 0; i < history; ++i) sum += m_rate_history[i];
			TORRENT_ASSERT(fabs(m_rate_sum - sum) < 0.1);
			TORRENT_ASSERT(m_total_counter >= 0);
		}
#endif

		// history of rates a few seconds back
		float m_rate_history[history];

		// the accumulator for this second.
		int m_counter;

		// total counters
		size_type m_total_counter;

		// sum of all elements in m_rate_history
		float m_rate_sum;
	};

	class TORRENT_EXPORT stat
	{
	friend class invariant_access;
	public:
		void operator+=(const stat& s)
		{
			for (int i = 0; i < num_channels; ++i)
				m_stat[i] += s.m_stat[i];
		}

		void received_bytes(int bytes_payload, int bytes_protocol)
		{
			TORRENT_ASSERT(bytes_payload >= 0);
			TORRENT_ASSERT(bytes_protocol >= 0);

			m_stat[download_payload].add(bytes_payload);
			m_stat[download_protocol].add(bytes_protocol);
		}

		void sent_bytes(int bytes_payload, int bytes_protocol)
		{
			TORRENT_ASSERT(bytes_payload >= 0);
			TORRENT_ASSERT(bytes_protocol >= 0);

			m_stat[upload_payload].add(bytes_payload);
			m_stat[upload_protocol].add(bytes_protocol);
		}

		// calculate ip protocol overhead
		void calc_ip_overhead()
		{
			int uploaded = m_stat[upload_protocol].counter()
				+ m_stat[upload_payload].counter();
			int downloaded = m_stat[download_protocol].counter()
				+ m_stat[download_payload].counter();

			// IP + TCP headers are 40 bytes per MTU (1460)
			// bytes of payload, but at least 40 bytes
			m_stat[upload_ip_protocol].add((std::max)(uploaded / 1460, 40));
			m_stat[download_ip_protocol].add((std::max)(downloaded / 1460, 40));

			// also account for ACK traffic. That adds to the transfers
			// in the opposite direction. Even on connections with symmetric
			// transfer rates, it seems to add a penalty.
			m_stat[upload_ip_protocol].add((std::max)(downloaded / 20, 40));
			m_stat[download_ip_protocol].add((std::max)(uploaded / 20, 40));
		}

		int upload_ip_overhead() const { return m_stat[upload_ip_protocol].counter(); }
		int download_ip_overhead() const { return m_stat[download_ip_protocol].counter(); }

		// should be called once every second
		void second_tick(float tick_interval)
		{
			for (int i = 0; i < num_channels; ++i)
				m_stat[i].second_tick(tick_interval);
		}

		float upload_rate() const
		{
			return m_stat[upload_payload].rate()
				+ m_stat[upload_protocol].rate()
				+ m_stat[upload_ip_protocol].rate();
		}

		float download_rate() const
		{
			return m_stat[download_payload].rate()
				+ m_stat[download_protocol].rate()
				+ m_stat[download_ip_protocol].rate();
		}

		float upload_payload_rate() const
		{ return m_stat[upload_payload].rate(); }

		float download_payload_rate() const
		{ return m_stat[download_payload].rate(); }

		size_type total_payload_upload() const
		{ return m_stat[upload_payload].total(); }
		size_type total_payload_download() const
		{ return m_stat[download_payload].total(); }

		size_type total_protocol_upload() const
		{ return m_stat[upload_protocol].total(); }
		size_type total_protocol_download() const
		{ return m_stat[download_protocol].total(); }

		// this is used to offset the statistics when a
		// peer_connection is opened and have some previous
		// transfers from earlier connections.
		void add_stat(size_type downloaded, size_type uploaded)
		{
			TORRENT_ASSERT(downloaded >= 0);
			TORRENT_ASSERT(uploaded >= 0);
			m_stat[download_payload].offset(downloaded);
			m_stat[upload_payload].offset(uploaded);
		}

		size_type last_payload_downloaded() const
		{ return m_stat[download_payload].counter(); }
		size_type last_payload_uploaded() const
		{ return m_stat[upload_payload].counter(); }

	private:

		// these are the channels we keep stats for
		enum
		{
			upload_payload,
			upload_protocol,
			upload_ip_protocol,
			download_payload,
			download_protocol,
			download_ip_protocol,
			num_channels
		};

		stat_channel m_stat[num_channels];
	};

}

#endif // TORRENT_STAT_HPP_INCLUDED

<commit_msg>switched from floats to integers in stat_channel history, to avoid rounding errors<commit_after>/*

Copyright (c) 2003, 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.

*/

#ifndef TORRENT_STAT_HPP_INCLUDED
#define TORRENT_STAT_HPP_INCLUDED

#include <algorithm>
#include <vector>
#include <assert.h>

#include "libtorrent/size_type.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{
	class TORRENT_EXPORT stat_channel
	{
	friend class invariant_access;
	public:
		enum { history = 10 };

		stat_channel()
			: m_counter(0)
			, m_total_counter(0)
			, m_rate_sum(0)
		{
			std::memset(m_rate_history, 0, sizeof(m_rate_history));
		}

		void operator+=(stat_channel const& s)
		{
			m_counter += s.m_counter;
			m_total_counter += s.m_counter;
		}

		void add(int count)
		{
			TORRENT_ASSERT(count >= 0);

			m_counter += count;
			m_total_counter += count;
		}

		// should be called once every second
		void second_tick(float tick_interval);
		float rate() const { return m_rate_sum / float(history); }
		size_type rate_sum() const { return m_rate_sum; }
		size_type total() const { return m_total_counter; }

		void offset(size_type counter)
		{
			TORRENT_ASSERT(counter >= 0);
			m_total_counter += counter;
		}

		size_type counter() const { return m_counter; }

	private:

#ifndef NDEBUG
		void check_invariant() const
		{
			int sum = 0;
			for (int i = 0; i < history; ++i) sum += m_rate_history[i];
			TORRENT_ASSERT(m_rate_sum == sum);
			TORRENT_ASSERT(m_total_counter >= 0);
		}
#endif

		// history of rates a few seconds back
		int m_rate_history[history];

		// the accumulator for this second.
		int m_counter;

		// total counters
		size_type m_total_counter;

		// sum of all elements in m_rate_history
		size_type m_rate_sum;
	};

	class TORRENT_EXPORT stat
	{
	friend class invariant_access;
	public:
		void operator+=(const stat& s)
		{
			for (int i = 0; i < num_channels; ++i)
				m_stat[i] += s.m_stat[i];
		}

		void received_bytes(int bytes_payload, int bytes_protocol)
		{
			TORRENT_ASSERT(bytes_payload >= 0);
			TORRENT_ASSERT(bytes_protocol >= 0);

			m_stat[download_payload].add(bytes_payload);
			m_stat[download_protocol].add(bytes_protocol);
		}

		void sent_bytes(int bytes_payload, int bytes_protocol)
		{
			TORRENT_ASSERT(bytes_payload >= 0);
			TORRENT_ASSERT(bytes_protocol >= 0);

			m_stat[upload_payload].add(bytes_payload);
			m_stat[upload_protocol].add(bytes_protocol);
		}

		// calculate ip protocol overhead
		void calc_ip_overhead()
		{
			int uploaded = m_stat[upload_protocol].counter()
				+ m_stat[upload_payload].counter();
			int downloaded = m_stat[download_protocol].counter()
				+ m_stat[download_payload].counter();

			// IP + TCP headers are 40 bytes per MTU (1460)
			// bytes of payload, but at least 40 bytes
			m_stat[upload_ip_protocol].add((std::max)(uploaded / 1460, 40));
			m_stat[download_ip_protocol].add((std::max)(downloaded / 1460, 40));

			// also account for ACK traffic. That adds to the transfers
			// in the opposite direction. Even on connections with symmetric
			// transfer rates, it seems to add a penalty.
			m_stat[upload_ip_protocol].add((std::max)(downloaded / 20, 40));
			m_stat[download_ip_protocol].add((std::max)(uploaded / 20, 40));
		}

		int upload_ip_overhead() const { return m_stat[upload_ip_protocol].counter(); }
		int download_ip_overhead() const { return m_stat[download_ip_protocol].counter(); }

		// should be called once every second
		void second_tick(float tick_interval)
		{
			for (int i = 0; i < num_channels; ++i)
				m_stat[i].second_tick(tick_interval);
		}

		float upload_rate() const
		{
			return (m_stat[upload_payload].rate_sum()
				+ m_stat[upload_protocol].rate_sum()
				+ m_stat[upload_ip_protocol].rate_sum())
				/ float(stat_channel::history);
		}

		float download_rate() const
		{
			return (m_stat[download_payload].rate_sum()
				+ m_stat[download_protocol].rate_sum()
				+ m_stat[download_ip_protocol].rate_sum())
				/ float(stat_channel::history);
		}

		float upload_payload_rate() const
		{ return m_stat[upload_payload].rate(); }

		float download_payload_rate() const
		{ return m_stat[download_payload].rate(); }

		size_type total_payload_upload() const
		{ return m_stat[upload_payload].total(); }
		size_type total_payload_download() const
		{ return m_stat[download_payload].total(); }

		size_type total_protocol_upload() const
		{ return m_stat[upload_protocol].total(); }
		size_type total_protocol_download() const
		{ return m_stat[download_protocol].total(); }

		// this is used to offset the statistics when a
		// peer_connection is opened and have some previous
		// transfers from earlier connections.
		void add_stat(size_type downloaded, size_type uploaded)
		{
			TORRENT_ASSERT(downloaded >= 0);
			TORRENT_ASSERT(uploaded >= 0);
			m_stat[download_payload].offset(downloaded);
			m_stat[upload_payload].offset(uploaded);
		}

		size_type last_payload_downloaded() const
		{ return m_stat[download_payload].counter(); }
		size_type last_payload_uploaded() const
		{ return m_stat[upload_payload].counter(); }

	private:

		// these are the channels we keep stats for
		enum
		{
			upload_payload,
			upload_protocol,
			upload_ip_protocol,
			download_payload,
			download_protocol,
			download_ip_protocol,
			num_channels
		};

		stat_channel m_stat[num_channels];
	};

}

#endif // TORRENT_STAT_HPP_INCLUDED

<|endoftext|>


<commit_before>#include <silicium/process.hpp>
#include <silicium/to_unique.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/system/system_error.hpp>
#include <algorithm>
#include <memory>

#ifdef __linux__
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#endif

namespace Si
{
	process_parameters::process_parameters()
		: stdout(nullptr)
		, stderr(nullptr)
		, stdin(nullptr)
	{
	}

	namespace
	{
		namespace detail
		{
			void terminating_close(int file) noexcept
			{
				if (close(file) < 0)
				{
					//it is intended that this will terminate the process because of noexcept
					throw boost::system::system_error(errno, boost::system::system_category());
				}
			}

			struct file_closer
			{
				void operator()(int *file) const noexcept
				{
					assert(file);
					terminating_close(*file);
				}
			};

			void copy_all(int source, sink<char> &destination)
			{
				for (;;)
				{
					buffering_sink<char> buffer_helper(destination);
					auto const buffer = buffer_helper.make_append_space(std::numeric_limits<std::size_t>::max());
					assert(!buffer.empty());
					auto const rc = read(source, buffer.begin(), buffer.size());
					if (rc == 0)
					{
						break;
					}
					if (rc < 0)
					{
						throw boost::system::system_error(errno, boost::system::system_category());
					}
					commit(buffer_helper, static_cast<std::size_t>(rc));
				}
			}

			void set_close_on_exec(int file)
			{
				fcntl(file, F_SETFD, fcntl(file, F_GETFD) | FD_CLOEXEC);
			}

			struct file_descriptor : private boost::noncopyable
			{
				int handle;

				file_descriptor() BOOST_NOEXCEPT
					: handle(-1)
				{
				}

				file_descriptor(file_descriptor &&other) BOOST_NOEXCEPT
					: handle(-1)
				{
					swap(other);
				}

				explicit file_descriptor(int handle) BOOST_NOEXCEPT
					: handle(handle)
				{
				}

				file_descriptor &operator = (file_descriptor &&other) BOOST_NOEXCEPT
				{
					swap(other);
					return *this;
				}

				void swap(file_descriptor &other) BOOST_NOEXCEPT
				{
					using std::swap;
					swap(handle, other.handle);
				}

				void close() BOOST_NOEXCEPT
				{
					file_descriptor().swap(*this);
				}

				~file_descriptor() BOOST_NOEXCEPT
				{
					if (handle >= 0)
					{
						terminating_close(handle);
					}
				}
			};

			struct pipe
			{
				file_descriptor write, read;

				void close() BOOST_NOEXCEPT
				{
					pipe().swap(*this);
				}

				void swap(pipe &other) BOOST_NOEXCEPT
				{
					write.swap(other.write);
					read.swap(other.read);
				}
			};

			pipe make_pipe()
			{
				std::array<int, 2> fds;
				if (::pipe(fds.data()) < 0)
				{
					throw boost::system::system_error(errno, boost::system::system_category());
				}
				pipe result;
				result.read  = file_descriptor(fds[0]);
				result.write = file_descriptor(fds[1]);
				return result;
			}
		}
	}

	int run_process(process_parameters const &parameters)
	{
		auto executable = parameters.executable.string();
		auto arguments = parameters.arguments;
		std::vector<char *> argument_pointers;
		argument_pointers.emplace_back(&executable[0]);
		std::transform(begin(arguments), end(arguments), std::back_inserter(argument_pointers), [](std::string &arg)
		{
			return &arg[0];
		});
		argument_pointers.emplace_back(nullptr);

		detail::pipe stdout;
		if (parameters.stdout)
		{
			stdout = detail::make_pipe();
		}

		auto stdin = detail::make_pipe();

		std::array<int, 2> child_error;
		std::unique_ptr<int, detail::file_closer> child_error_reading;
		std::unique_ptr<int, detail::file_closer> child_error_writing;
		if (pipe(child_error.data()) < 0)
		{
			throw boost::system::system_error(errno, boost::system::system_category());
		}
		child_error_reading.reset(child_error.data() + 0);
		child_error_writing.reset(child_error.data() + 1);

		pid_t const forked = fork();
		if (forked < 0)
		{
			throw boost::system::system_error(errno, boost::system::system_category());
		}

		//child
		if (forked == 0)
		{
			if (parameters.stdout)
			{
				if (dup2(stdout.write.handle, STDOUT_FILENO) < 0)
				{
					std::abort();
				}
				if (dup2(stdout.write.handle, STDERR_FILENO) < 0)
				{
					std::abort();
				}
				stdout.close();
			}

			if (dup2(stdin.read.handle, STDIN_FILENO) < 0)
			{
				std::abort();
			}
			stdin.close();

			child_error_reading.reset();
			detail::set_close_on_exec(*child_error_writing);

			boost::filesystem::current_path(parameters.current_path);

			execvp(parameters.executable.c_str(), argument_pointers.data());

			int error = errno;
			ssize_t written = write(*child_error_writing, &error, sizeof(error));
			if (written != sizeof(error))
			{
				_exit(1);
			}
			child_error_writing.reset();

			//kill the process in case execv fails
			_exit(0);
		}

		//parent
		else
		{
			child_error_writing.reset();

			if (parameters.stdout)
			{
				stdout.write.close();
				detail::copy_all(stdout.read.handle, *parameters.stdout);
			}
			stdin.read.close();

			int status = 0;
			if (waitpid(forked, &status, 0) < 0)
			{
				throw boost::system::system_error(errno, boost::system::system_category());
			}

			int error = 0;
			ssize_t read_error = read(*child_error_reading, &error, sizeof(error));
			if (read_error < 0)
			{
				throw boost::system::system_error(errno, boost::system::system_category());
			}
			if (read_error != 0)
			{
				assert(read_error == sizeof(error));
				throw boost::system::system_error(error, boost::system::system_category());
			}

			int const exit_status = WEXITSTATUS(status);
			return exit_status;
		}
	}

	int run_process(
			boost::filesystem::path executable,
			std::vector<std::string> arguments,
			boost::filesystem::path current_path,
			Si::sink<char> &output)
	{
		Si::process_parameters parameters;
		parameters.executable = std::move(executable);
		parameters.arguments = std::move(arguments);
		parameters.current_path = std::move(current_path);
		parameters.stdout = &output;
		return Si::run_process(parameters);
	}
}
<commit_msg>use pipe wrapper for error propagation<commit_after>#include <silicium/process.hpp>
#include <silicium/to_unique.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/system/system_error.hpp>
#include <algorithm>
#include <memory>

#ifdef __linux__
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#endif

namespace Si
{
	process_parameters::process_parameters()
		: stdout(nullptr)
		, stderr(nullptr)
		, stdin(nullptr)
	{
	}

	namespace
	{
		namespace detail
		{
			void terminating_close(int file) noexcept
			{
				if (close(file) < 0)
				{
					//it is intended that this will terminate the process because of noexcept
					throw boost::system::system_error(errno, boost::system::system_category());
				}
			}

			struct file_closer
			{
				void operator()(int *file) const noexcept
				{
					assert(file);
					terminating_close(*file);
				}
			};

			void copy_all(int source, sink<char> &destination)
			{
				for (;;)
				{
					buffering_sink<char> buffer_helper(destination);
					auto const buffer = buffer_helper.make_append_space(std::numeric_limits<std::size_t>::max());
					assert(!buffer.empty());
					auto const rc = read(source, buffer.begin(), buffer.size());
					if (rc == 0)
					{
						break;
					}
					if (rc < 0)
					{
						throw boost::system::system_error(errno, boost::system::system_category());
					}
					commit(buffer_helper, static_cast<std::size_t>(rc));
				}
			}

			void set_close_on_exec(int file)
			{
				fcntl(file, F_SETFD, fcntl(file, F_GETFD) | FD_CLOEXEC);
			}

			struct file_descriptor : private boost::noncopyable
			{
				int handle;

				file_descriptor() BOOST_NOEXCEPT
					: handle(-1)
				{
				}

				file_descriptor(file_descriptor &&other) BOOST_NOEXCEPT
					: handle(-1)
				{
					swap(other);
				}

				explicit file_descriptor(int handle) BOOST_NOEXCEPT
					: handle(handle)
				{
				}

				file_descriptor &operator = (file_descriptor &&other) BOOST_NOEXCEPT
				{
					swap(other);
					return *this;
				}

				void swap(file_descriptor &other) BOOST_NOEXCEPT
				{
					using std::swap;
					swap(handle, other.handle);
				}

				void close() BOOST_NOEXCEPT
				{
					file_descriptor().swap(*this);
				}

				~file_descriptor() BOOST_NOEXCEPT
				{
					if (handle >= 0)
					{
						terminating_close(handle);
					}
				}
			};

			struct pipe
			{
				file_descriptor write, read;

				void close() BOOST_NOEXCEPT
				{
					pipe().swap(*this);
				}

				void swap(pipe &other) BOOST_NOEXCEPT
				{
					write.swap(other.write);
					read.swap(other.read);
				}
			};

			pipe make_pipe()
			{
				std::array<int, 2> fds;
				if (::pipe(fds.data()) < 0)
				{
					throw boost::system::system_error(errno, boost::system::system_category());
				}
				pipe result;
				result.read  = file_descriptor(fds[0]);
				result.write = file_descriptor(fds[1]);
				return result;
			}
		}
	}

	int run_process(process_parameters const &parameters)
	{
		auto executable = parameters.executable.string();
		auto arguments = parameters.arguments;
		std::vector<char *> argument_pointers;
		argument_pointers.emplace_back(&executable[0]);
		std::transform(begin(arguments), end(arguments), std::back_inserter(argument_pointers), [](std::string &arg)
		{
			return &arg[0];
		});
		argument_pointers.emplace_back(nullptr);

		detail::pipe stdout;
		if (parameters.stdout)
		{
			stdout = detail::make_pipe();
		}

		auto stdin = detail::make_pipe();
		auto child_error = detail::make_pipe();

		pid_t const forked = fork();
		if (forked < 0)
		{
			throw boost::system::system_error(errno, boost::system::system_category());
		}

		//child
		if (forked == 0)
		{
			if (parameters.stdout)
			{
				if (dup2(stdout.write.handle, STDOUT_FILENO) < 0)
				{
					std::abort();
				}
				if (dup2(stdout.write.handle, STDERR_FILENO) < 0)
				{
					std::abort();
				}
				stdout.close();
			}

			if (dup2(stdin.read.handle, STDIN_FILENO) < 0)
			{
				std::abort();
			}
			stdin.close();

			child_error.read.close();
			detail::set_close_on_exec(child_error.write.handle);

			boost::filesystem::current_path(parameters.current_path);

			execvp(parameters.executable.c_str(), argument_pointers.data());

			int error = errno;
			ssize_t written = write(child_error.write.handle, &error, sizeof(error));
			if (written != sizeof(error))
			{
				_exit(1);
			}
			child_error.write.close();

			//kill the process in case execv fails
			_exit(0);
		}

		//parent
		else
		{
			child_error.write.close();

			if (parameters.stdout)
			{
				stdout.write.close();
				detail::copy_all(stdout.read.handle, *parameters.stdout);
			}
			stdin.read.close();

			int status = 0;
			if (waitpid(forked, &status, 0) < 0)
			{
				throw boost::system::system_error(errno, boost::system::system_category());
			}

			int error = 0;
			ssize_t read_error = read(child_error.read.handle, &error, sizeof(error));
			if (read_error < 0)
			{
				throw boost::system::system_error(errno, boost::system::system_category());
			}
			if (read_error != 0)
			{
				assert(read_error == sizeof(error));
				throw boost::system::system_error(error, boost::system::system_category());
			}

			int const exit_status = WEXITSTATUS(status);
			return exit_status;
		}
	}

	int run_process(
			boost::filesystem::path executable,
			std::vector<std::string> arguments,
			boost::filesystem::path current_path,
			Si::sink<char> &output)
	{
		Si::process_parameters parameters;
		parameters.executable = std::move(executable);
		parameters.arguments = std::move(arguments);
		parameters.current_path = std::move(current_path);
		parameters.stdout = &output;
		return Si::run_process(parameters);
	}
}
<|endoftext|>