<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2016.  All rights reserved
 */
#include    "../../StroikaPreComp.h"

#if     qHasFeature_OpenSSL
#include    <openssl/evp.h>
#include    <openssl/err.h>
#endif

#include    "../../Containers/Common.h"
#include    "../../Debug/Assertions.h"
#include    "../../Execution/Common.h"
#include    "../../Memory/SmallStackBuffer.h"

#include    "OpenSSLCryptoStream.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Containers;
using   namespace   Stroika::Foundation::Cryptography;
using   namespace   Stroika::Foundation::Cryptography::Encoding;
using   namespace   Stroika::Foundation::Memory;
using   namespace   Stroika::Foundation::Streams;

using   Memory::BLOB;

// @todo examine/test https://github.com/saju/misc/blob/master/misc/openssl_aes.c

#if     qHasFeature_OpenSSL && defined (_MSC_VER)
// Use #pragma comment lib instead of explicit entry in the lib entry of the project file
#pragma comment (lib, "libeay32.lib")
#pragma comment (lib, "ssleay32.lib")
#endif

//// VERY ROUGH DRAFT - NOT VERY CLOSE TO CORRECT FOR ALL ALGORITHSM
//// SEE http://www.openssl.org/docs/crypto/EVP_EncryptInit.html
/// SEE https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption
//// for details on what todo

#if     qHasFeature_OpenSSL
namespace {
    struct  InOutStrmCommon_ {
        InOutStrmCommon_ (const OpenSSLCryptoParams& cryptoParams, Direction d)
            : fCTX_ ()
            , fFinalCalled_ (false)
        {
            ::EVP_CIPHER_CTX_init (&fCTX_);
            cryptoParams.fInitializer (&fCTX_, d);
        }
        InOutStrmCommon_ (const InOutStrmCommon_&) = delete;
        InOutStrmCommon_& operator= (const InOutStrmCommon_&) = delete;
        ~InOutStrmCommon_ ()
        {
            Verify (::EVP_CIPHER_CTX_cleanup (&fCTX_) == 1);
        }
        static  constexpr   size_t _GetMinOutBufSize (size_t n)
        {
            return n + EVP_MAX_BLOCK_LENGTH;
        }
        // return nBytes in outBuf, throws on error
        size_t _runOnce (const Byte* data2ProcessStart, const Byte* data2ProcessEnd, Byte* outBufStart, Byte* outBufEnd)
        {
            Require (outBufStart <= outBufEnd and static_cast<size_t> (outBufEnd - outBufStart) >= _GetMinOutBufSize (data2ProcessEnd - data2ProcessStart));  // always need out buf big enuf for inbuf
            int outLen = 0;
            Cryptography::OpenSSL::Exception::ThrowLastErrorIfFailed (::EVP_CipherUpdate (&fCTX_, outBufStart, &outLen, data2ProcessStart, static_cast<int> (data2ProcessEnd - data2ProcessStart)));
            Ensure (outLen >= 0);
            Ensure (outLen <= (outBufEnd - outBufStart));
            return size_t (outLen);
        }
        // return nBytes in outBuf, throws on error
        // Can call multiple times - it keeps track itself if finalized.
        size_t _cipherFinal (Byte* outBufStart, Byte* outBufEnd)
        {
            Require (outBufStart <= outBufEnd and static_cast<size_t> (outBufEnd - outBufStart) >= _GetMinOutBufSize (0));
            if (fFinalCalled_) {
                return 0;   // not an error - just zero more bytes
            }
            int outLen = 0;
            Cryptography::OpenSSL::Exception::ThrowLastErrorIfFailed (::EVP_CipherFinal_ex (&fCTX_, outBufStart, &outLen));
            fFinalCalled_ = true;
            Ensure (outLen >= 0);
            Ensure (outLen <= (outBufEnd - outBufStart));
            return size_t (outLen);
        }
        EVP_CIPHER_CTX  fCTX_;
        bool            fFinalCalled_;
    };
}
#endif

#if     qHasFeature_OpenSSL
class   OpenSSLInputStream::IRep_ : public InputStream<Byte>::_IRep, private InOutStrmCommon_ {
private:
    DEFINE_CONSTEXPR_CONSTANT(size_t, kInBufSize_, 10 * 1024);

public:
    IRep_ (const OpenSSLCryptoParams& cryptoParams, Direction d, const InputStream<Byte>& realIn)
        : InputStream<Byte>::_IRep ()
        , InOutStrmCommon_ (cryptoParams, d)
        , fCriticalSection_ ()
        , fOutBuf_ (_GetMinOutBufSize (kInBufSize_))
        , fOutBufStart_ (nullptr)
        , fOutBufEnd_ (nullptr)
        , fRealIn_ (realIn)
    {
    }
    virtual bool    IsSeekable () const override
    {
        return false;
    }
    virtual SeekOffsetType  GetReadOffset () const override
    {
        RequireNotReached ();
        return 0;
    }
    virtual SeekOffsetType  SeekRead (Whence whence, SignedSeekOffsetType offset) override
    {
        RequireNotReached ();
        return 0;
    }
    virtual size_t  Read (SeekOffsetType* offset, Byte* intoStart, Byte* intoEnd) override
    {
        Require (offset == nullptr);    // not seekable
        /*
         *  Keep track if unread bytes in fOutBuf_ - bounded by fOutBufStart_ and fOutBufEnd_.
         *  If none to read there - pull from fRealIn_ src, and push those through the cipher.
         *  and use that to re-populate fOutBuf_.
         */
        Require (intoStart < intoEnd);
        auto    critSec { Execution::make_unique_lock (fCriticalSection_) };
        if (fOutBufStart_ == fOutBufEnd_) {
            Byte toDecryptBuf[kInBufSize_];
            size_t n2Decrypt = fRealIn_.Read (begin (toDecryptBuf), end (toDecryptBuf));
            if (n2Decrypt == 0) {
                size_t nBytesInOutBuf = _cipherFinal (fOutBuf_.begin (), fOutBuf_.end ());
                Assert (nBytesInOutBuf <= fOutBuf_.GetSize ());
                fOutBufStart_ = fOutBuf_.begin ();
                fOutBufEnd_ = fOutBufStart_ + nBytesInOutBuf;
            }
            else {
                fOutBuf_.GrowToSize (_GetMinOutBufSize (NEltsOf (toDecryptBuf)));
                size_t nBytesInOutBuf = _runOnce (begin (toDecryptBuf), begin (toDecryptBuf) + n2Decrypt, fOutBuf_.begin (), fOutBuf_.end ());
                Assert (nBytesInOutBuf <= fOutBuf_.GetSize ());
                fOutBufStart_ = fOutBuf_.begin ();
                fOutBufEnd_ = fOutBufStart_ + nBytesInOutBuf;
            }
        }
        if (fOutBufStart_ < fOutBufEnd_) {
            size_t  n2Copy = min (fOutBufEnd_ - fOutBufStart_, intoEnd - intoStart);
            (void)::memcpy (intoStart, fOutBufStart_, n2Copy);
            fOutBufStart_ += n2Copy;
            return n2Copy;
        }
        return 0;   // EOF
    }

private:
    mutable mutex                                                           fCriticalSection_;
    Memory::SmallStackBuffer < Byte, kInBufSize_ + EVP_MAX_BLOCK_LENGTH >   fOutBuf_;
    Byte*                                                                   fOutBufStart_;
    Byte*                                                                   fOutBufEnd_;
    InputStream<Byte>                                                       fRealIn_;
};
#endif

#if     qHasFeature_OpenSSL
class   OpenSSLOutputStream::IRep_ : public OutputStream<Byte>::_IRep, private InOutStrmCommon_ {
public:
    IRep_ (const OpenSSLCryptoParams& cryptoParams, Direction d, const OutputStream<Byte>& realOut)
        : OutputStream<Byte>::_IRep ()
        , InOutStrmCommon_ (cryptoParams, d)
        , fCriticalSection_ ()
        , fRealOut_ (realOut)
    {
    }
    virtual ~IRep_ ()
    {
        // no need for critical section because at most one thread can be running DTOR at a time, and no other methods can be running
        try {
            Flush ();
        }
        catch (...) {
            // not great to do in DTOR, because we must drop exceptions on the floor!
        }
    }
    virtual bool    IsSeekable () const override
    {
        return false;
    }
    virtual SeekOffsetType  GetWriteOffset () const override
    {
        RequireNotReached ();
        return 0;
    }
    virtual SeekOffsetType  SeekWrite (Whence whence, SignedSeekOffsetType offset) override
    {
        RequireNotReached ();
        return 0;
    }
    // pointer must refer to valid memory at least bufSize long, and cannot be nullptr. BufSize must always be >= 1.
    // Writes always succeed fully or throw.
    virtual void    Write (const Byte* start, const Byte* end) override
    {
        Require (start < end);  // for OutputStream<Byte> - this funciton requires non-empty write
        Memory::SmallStackBuffer < Byte, 1000 + EVP_MAX_BLOCK_LENGTH >  outBuf (_GetMinOutBufSize (end - start));
        auto    critSec { Execution::make_unique_lock (fCriticalSection_) };
        size_t nBytesEncypted = _runOnce (start, end, outBuf.begin (), outBuf.end ());
        Assert (nBytesEncypted <= outBuf.GetSize ());
        fRealOut_.Write (outBuf.begin (), outBuf.begin () + nBytesEncypted);
    }

    virtual void    Flush () override
    {
        Byte    outBuf[EVP_MAX_BLOCK_LENGTH];
        size_t nBytesInOutBuf = _cipherFinal (begin (outBuf), end (outBuf));
        Assert (nBytesInOutBuf < sizeof (outBuf));
        fRealOut_.Write (begin (outBuf), begin (outBuf) + nBytesInOutBuf);
    }

private:
    mutable recursive_mutex     fCriticalSection_;
    OutputStream<Byte>          fRealOut_;
};
#endif

#if     qHasFeature_OpenSSL
/*
 ********************************************************************************
 ******************** Cryptography::OpenSSLInputStream **************************
 ********************************************************************************
 */
namespace {
    void    ApplySettings2CTX_ (EVP_CIPHER_CTX* ctx, const EVP_CIPHER* cipher, Direction d, bool nopad, bool useArgumentKeyLength, const Memory::BLOB& key, const Memory::BLOB& initialIV)
    {
        RequireNotNull (ctx);
        RequireNotNull (cipher);
        bool    enc = (d == Direction::eEncrypt);
        if (nopad) {
            Verify (::EVP_CIPHER_CTX_set_padding (ctx, 0) == 1);
        }
        Cryptography::OpenSSL::Exception::ThrowLastErrorIfFailed (::EVP_CipherInit_ex (ctx, cipher, NULL, nullptr, nullptr, enc));
        size_t keyLen = EVP_CIPHER_CTX_key_length (ctx);
        size_t ivLen = EVP_CIPHER_CTX_iv_length (ctx);

        if (useArgumentKeyLength) {
            keyLen = key.length ();
            Verify (::EVP_CIPHER_CTX_set_key_length (ctx, static_cast<int> (keyLen)) == 1);
        }

        Memory::SmallStackBuffer<Byte> useKey { keyLen };
        Memory::SmallStackBuffer<Byte> useIV { ivLen };

        memset (useKey.begin (), 0, keyLen);
        memset (useIV.begin (), 0, ivLen);

        memcpy (useKey.begin (), key.begin (), min(keyLen, key.size ()));
        memcpy (useIV.begin (), initialIV.begin (), min(ivLen, initialIV.size ()));

        Cryptography::OpenSSL::Exception::ThrowLastErrorIfFailed (::EVP_CipherInit_ex (ctx, nullptr, NULL, useKey.begin (), useIV.begin (), enc));
    }
}

OpenSSLCryptoParams::OpenSSLCryptoParams (CipherAlgorithm alg, Memory::BLOB key, Memory::BLOB initialIV)
    : fInitializer ()
{
    bool    nopad = false;
    switch (alg) {
        case CipherAlgorithm::eRC2_CBC: {
                fInitializer = [nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, ::EVP_rc2_cbc (), d, nopad, true, key, initialIV);
                };
            }
            break;
        case CipherAlgorithm::eRC2_ECB: {
                fInitializer = [nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, ::EVP_rc2_ecb (), d, nopad, true, key, initialIV);
                };
            }
            break;
        case CipherAlgorithm::eRC2_CFB: {
                fInitializer = [nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, ::EVP_rc2_cfb (), d, nopad, true, key, initialIV);
                };
            }
            break;
        case CipherAlgorithm::eRC2_OFB: {
                fInitializer = [nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, ::EVP_rc2_ofb (), d, nopad, true, key, initialIV);
                };
            }
            break;
        case CipherAlgorithm::eRC4: {
                fInitializer = [nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, ::EVP_rc4 (), d, nopad, true, key, initialIV);
                };
            }
            break;
        default: {
                fInitializer = [alg, nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, Convert2OpenSSL (alg), d, nopad, false, key, initialIV);
                };
                break;

            }
    }
}

OpenSSLCryptoParams::OpenSSLCryptoParams (CipherAlgorithm alg, const DerivedKey& derivedKey)
    : OpenSSLCryptoParams (alg, derivedKey.fKey, derivedKey.fIV)
{
}
#endif

#if     qHasFeature_OpenSSL
/*
 ********************************************************************************
 ******************** Cryptography::OpenSSLInputStream **************************
 ********************************************************************************
 */
OpenSSLInputStream::OpenSSLInputStream (const OpenSSLCryptoParams& cryptoParams, Direction direction, const InputStream<Byte>& realIn)
    : InputStream<Byte> (make_shared<IRep_> (cryptoParams, direction, realIn))
{
}
#endif

#if     qHasFeature_OpenSSL
/*
 ********************************************************************************
 ******************* Cryptography::OpenSSLOutputStream **************************
 ********************************************************************************
 */
OpenSSLOutputStream::OpenSSLOutputStream (const OpenSSLCryptoParams& cryptoParams, Direction direction, const OutputStream<Byte>& realOut)
    : OutputStream<Byte> (make_shared<IRep_> (cryptoParams, direction, realOut))
{
}
#endif
<commit_msg>fixed https://stroika.atlassian.net/browse/STK-193 - issue with short encrpytions failing with block ciphers - was bug in pull code in streams<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2016.  All rights reserved
 */
#include    "../../StroikaPreComp.h"

#if     qHasFeature_OpenSSL
#include    <openssl/evp.h>
#include    <openssl/err.h>
#endif

#include    "../../Containers/Common.h"
#include    "../../Debug/Assertions.h"
#include    "../../Execution/Common.h"
#include    "../../Memory/SmallStackBuffer.h"

#include    "OpenSSLCryptoStream.h"

using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Containers;
using   namespace   Stroika::Foundation::Cryptography;
using   namespace   Stroika::Foundation::Cryptography::Encoding;
using   namespace   Stroika::Foundation::Memory;
using   namespace   Stroika::Foundation::Streams;

using   Memory::BLOB;

// @todo examine/test https://github.com/saju/misc/blob/master/misc/openssl_aes.c

#if     qHasFeature_OpenSSL && defined (_MSC_VER)
// Use #pragma comment lib instead of explicit entry in the lib entry of the project file
#pragma comment (lib, "libeay32.lib")
#pragma comment (lib, "ssleay32.lib")
#endif

//// VERY ROUGH DRAFT - NOT VERY CLOSE TO CORRECT FOR ALL ALGORITHSM
//// SEE http://www.openssl.org/docs/crypto/EVP_EncryptInit.html
/// SEE https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption
//// for details on what todo

#if     qHasFeature_OpenSSL
namespace {
    struct  InOutStrmCommon_ {
        InOutStrmCommon_ (const OpenSSLCryptoParams& cryptoParams, Direction d)
            : fCTX_ ()
            , fFinalCalled_ (false)
        {
            ::EVP_CIPHER_CTX_init (&fCTX_);
            cryptoParams.fInitializer (&fCTX_, d);
        }
        InOutStrmCommon_ (const InOutStrmCommon_&) = delete;
        InOutStrmCommon_& operator= (const InOutStrmCommon_&) = delete;
        ~InOutStrmCommon_ ()
        {
            Verify (::EVP_CIPHER_CTX_cleanup (&fCTX_) == 1);
        }
        static  constexpr   size_t _GetMinOutBufSize (size_t n)
        {
            return n + EVP_MAX_BLOCK_LENGTH;
        }
        // return nBytes in outBuf, throws on error
        size_t _runOnce (const Byte* data2ProcessStart, const Byte* data2ProcessEnd, Byte* outBufStart, Byte* outBufEnd)
        {
            Require (outBufStart <= outBufEnd and static_cast<size_t> (outBufEnd - outBufStart) >= _GetMinOutBufSize (data2ProcessEnd - data2ProcessStart));  // always need out buf big enuf for inbuf
            int outLen = 0;
            Cryptography::OpenSSL::Exception::ThrowLastErrorIfFailed (::EVP_CipherUpdate (&fCTX_, outBufStart, &outLen, data2ProcessStart, static_cast<int> (data2ProcessEnd - data2ProcessStart)));
            Ensure (outLen >= 0);
            Ensure (outLen <= (outBufEnd - outBufStart));
            return size_t (outLen);
        }
        // return nBytes in outBuf, throws on error
        // Can call multiple times - it keeps track itself if finalized.
        size_t _cipherFinal (Byte* outBufStart, Byte* outBufEnd)
        {
            Require (outBufStart <= outBufEnd and static_cast<size_t> (outBufEnd - outBufStart) >= _GetMinOutBufSize (0));
            if (fFinalCalled_) {
                return 0;   // not an error - just zero more bytes
            }
            int outLen = 0;
            Cryptography::OpenSSL::Exception::ThrowLastErrorIfFailed (::EVP_CipherFinal_ex (&fCTX_, outBufStart, &outLen));
            fFinalCalled_ = true;
            Ensure (outLen >= 0);
            Ensure (outLen <= (outBufEnd - outBufStart));
            return size_t (outLen);
        }
        EVP_CIPHER_CTX  fCTX_;
        bool            fFinalCalled_;
    };
}
#endif

#if     qHasFeature_OpenSSL
class   OpenSSLInputStream::IRep_ : public InputStream<Byte>::_IRep, private InOutStrmCommon_ {
private:
    DEFINE_CONSTEXPR_CONSTANT(size_t, kInBufSize_, 10 * 1024);

public:
    IRep_ (const OpenSSLCryptoParams& cryptoParams, Direction d, const InputStream<Byte>& realIn)
        : InputStream<Byte>::_IRep ()
        , InOutStrmCommon_ (cryptoParams, d)
        , fCriticalSection_ ()
        , fOutBuf_ (_GetMinOutBufSize (kInBufSize_))
        , fOutBufStart_ (nullptr)
        , fOutBufEnd_ (nullptr)
        , fRealIn_ (realIn)
    {
    }
    virtual bool    IsSeekable () const override
    {
        return false;
    }
    virtual SeekOffsetType  GetReadOffset () const override
    {
        RequireNotReached ();
        return 0;
    }
    virtual SeekOffsetType  SeekRead (Whence whence, SignedSeekOffsetType offset) override
    {
        RequireNotReached ();
        return 0;
    }
    virtual size_t  Read (SeekOffsetType* offset, Byte* intoStart, Byte* intoEnd) override
    {
        Require (offset == nullptr);    // not seekable
        /*
         *  Keep track if unread bytes in fOutBuf_ - bounded by fOutBufStart_ and fOutBufEnd_.
         *  If none to read there - pull from fRealIn_ src, and push those through the cipher.
         *  and use that to re-populate fOutBuf_.
         */
        Require (intoStart < intoEnd);
        auto    critSec { Execution::make_unique_lock (fCriticalSection_) };
        if (fOutBufStart_ == fOutBufEnd_) {
            /*
             *  Then pull from 'real in' stream until we have reach EOF there, or until we have some bytes to output
             *  on our own.
             */
            Byte toDecryptBuf[kInBufSize_];
Again:
            size_t n2Decrypt = fRealIn_.Read (begin (toDecryptBuf), end (toDecryptBuf));
            if (n2Decrypt == 0) {
                size_t nBytesInOutBuf = _cipherFinal (fOutBuf_.begin (), fOutBuf_.end ());
                Assert (nBytesInOutBuf <= fOutBuf_.GetSize ());
                fOutBufStart_ = fOutBuf_.begin ();
                fOutBufEnd_ = fOutBufStart_ + nBytesInOutBuf;
            }
            else {
                fOutBuf_.GrowToSize (_GetMinOutBufSize (NEltsOf (toDecryptBuf)));
                size_t nBytesInOutBuf = _runOnce (begin (toDecryptBuf), begin (toDecryptBuf) + n2Decrypt, fOutBuf_.begin (), fOutBuf_.end ());
                Assert (nBytesInOutBuf <= fOutBuf_.GetSize ());
                if (nBytesInOutBuf == 0) {
                    // This can happen with block ciphers - we put stuff in, and get nothing out. But we cannot return EOF
                    // yet, so try again...
                    goto Again;
                }
                else {
                    fOutBufStart_ = fOutBuf_.begin ();
                    fOutBufEnd_ = fOutBufStart_ + nBytesInOutBuf;
                }
            }
        }
        if (fOutBufStart_ < fOutBufEnd_) {
            size_t  n2Copy = min (fOutBufEnd_ - fOutBufStart_, intoEnd - intoStart);
            (void)::memcpy (intoStart, fOutBufStart_, n2Copy);
            fOutBufStart_ += n2Copy;
            return n2Copy;
        }
        return 0;   // EOF
    }

private:
    mutable mutex                                                           fCriticalSection_;
    Memory::SmallStackBuffer < Byte, kInBufSize_ + EVP_MAX_BLOCK_LENGTH >   fOutBuf_;
    Byte*                                                                   fOutBufStart_;
    Byte*                                                                   fOutBufEnd_;
    InputStream<Byte>                                                       fRealIn_;
};
#endif

#if     qHasFeature_OpenSSL
class   OpenSSLOutputStream::IRep_ : public OutputStream<Byte>::_IRep, private InOutStrmCommon_ {
public:
    IRep_ (const OpenSSLCryptoParams& cryptoParams, Direction d, const OutputStream<Byte>& realOut)
        : OutputStream<Byte>::_IRep ()
        , InOutStrmCommon_ (cryptoParams, d)
        , fCriticalSection_ ()
        , fRealOut_ (realOut)
    {
    }
    virtual ~IRep_ ()
    {
        // no need for critical section because at most one thread can be running DTOR at a time, and no other methods can be running
        try {
            Flush ();
        }
        catch (...) {
            // not great to do in DTOR, because we must drop exceptions on the floor!
        }
    }
    virtual bool    IsSeekable () const override
    {
        return false;
    }
    virtual SeekOffsetType  GetWriteOffset () const override
    {
        RequireNotReached ();
        return 0;
    }
    virtual SeekOffsetType  SeekWrite (Whence whence, SignedSeekOffsetType offset) override
    {
        RequireNotReached ();
        return 0;
    }
    // pointer must refer to valid memory at least bufSize long, and cannot be nullptr. BufSize must always be >= 1.
    // Writes always succeed fully or throw.
    virtual void    Write (const Byte* start, const Byte* end) override
    {
        Require (start < end);  // for OutputStream<Byte> - this funciton requires non-empty write
        Memory::SmallStackBuffer < Byte, 1000 + EVP_MAX_BLOCK_LENGTH >  outBuf (_GetMinOutBufSize (end - start));
        auto    critSec { Execution::make_unique_lock (fCriticalSection_) };
        size_t nBytesEncypted = _runOnce (start, end, outBuf.begin (), outBuf.end ());
        Assert (nBytesEncypted <= outBuf.GetSize ());
        fRealOut_.Write (outBuf.begin (), outBuf.begin () + nBytesEncypted);
    }

    virtual void    Flush () override
    {
        Byte    outBuf[EVP_MAX_BLOCK_LENGTH];
        size_t nBytesInOutBuf = _cipherFinal (begin (outBuf), end (outBuf));
        Assert (nBytesInOutBuf < sizeof (outBuf));
        fRealOut_.Write (begin (outBuf), begin (outBuf) + nBytesInOutBuf);
    }

private:
    mutable recursive_mutex     fCriticalSection_;
    OutputStream<Byte>          fRealOut_;
};
#endif

#if     qHasFeature_OpenSSL
/*
 ********************************************************************************
 ******************** Cryptography::OpenSSLInputStream **************************
 ********************************************************************************
 */
namespace {
    void    ApplySettings2CTX_ (EVP_CIPHER_CTX* ctx, const EVP_CIPHER* cipher, Direction d, bool nopad, bool useArgumentKeyLength, const Memory::BLOB& key, const Memory::BLOB& initialIV)
    {
        RequireNotNull (ctx);
        RequireNotNull (cipher);
        bool    enc = (d == Direction::eEncrypt);
        if (nopad) {
            Verify (::EVP_CIPHER_CTX_set_padding (ctx, 0) == 1);
        }
        Cryptography::OpenSSL::Exception::ThrowLastErrorIfFailed (::EVP_CipherInit_ex (ctx, cipher, NULL, nullptr, nullptr, enc));
        size_t keyLen = EVP_CIPHER_CTX_key_length (ctx);
        size_t ivLen = EVP_CIPHER_CTX_iv_length (ctx);

        if (useArgumentKeyLength) {
            keyLen = key.length ();
            Verify (::EVP_CIPHER_CTX_set_key_length (ctx, static_cast<int> (keyLen)) == 1);
        }

        Memory::SmallStackBuffer<Byte> useKey { keyLen };
        Memory::SmallStackBuffer<Byte> useIV { ivLen };

        memset (useKey.begin (), 0, keyLen);
        memset (useIV.begin (), 0, ivLen);

        memcpy (useKey.begin (), key.begin (), min(keyLen, key.size ()));
        memcpy (useIV.begin (), initialIV.begin (), min(ivLen, initialIV.size ()));

        Cryptography::OpenSSL::Exception::ThrowLastErrorIfFailed (::EVP_CipherInit_ex (ctx, nullptr, NULL, useKey.begin (), useIV.begin (), enc));
    }
}

OpenSSLCryptoParams::OpenSSLCryptoParams (CipherAlgorithm alg, Memory::BLOB key, Memory::BLOB initialIV)
    : fInitializer ()
{
    bool    nopad = false;
    switch (alg) {
        case CipherAlgorithm::eRC2_CBC: {
                fInitializer = [nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, ::EVP_rc2_cbc (), d, nopad, true, key, initialIV);
                };
            }
            break;
        case CipherAlgorithm::eRC2_ECB: {
                fInitializer = [nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, ::EVP_rc2_ecb (), d, nopad, true, key, initialIV);
                };
            }
            break;
        case CipherAlgorithm::eRC2_CFB: {
                fInitializer = [nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, ::EVP_rc2_cfb (), d, nopad, true, key, initialIV);
                };
            }
            break;
        case CipherAlgorithm::eRC2_OFB: {
                fInitializer = [nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, ::EVP_rc2_ofb (), d, nopad, true, key, initialIV);
                };
            }
            break;
        case CipherAlgorithm::eRC4: {
                fInitializer = [nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, ::EVP_rc4 (), d, nopad, true, key, initialIV);
                };
            }
            break;
        default: {
                fInitializer = [alg, nopad, key, initialIV] (EVP_CIPHER_CTX * ctx, Direction d) {
                    ApplySettings2CTX_ (ctx, Convert2OpenSSL (alg), d, nopad, false, key, initialIV);
                };
                break;

            }
    }
}

OpenSSLCryptoParams::OpenSSLCryptoParams (CipherAlgorithm alg, const DerivedKey& derivedKey)
    : OpenSSLCryptoParams (alg, derivedKey.fKey, derivedKey.fIV)
{
}
#endif

#if     qHasFeature_OpenSSL
/*
 ********************************************************************************
 ******************** Cryptography::OpenSSLInputStream **************************
 ********************************************************************************
 */
OpenSSLInputStream::OpenSSLInputStream (const OpenSSLCryptoParams& cryptoParams, Direction direction, const InputStream<Byte>& realIn)
    : InputStream<Byte> (make_shared<IRep_> (cryptoParams, direction, realIn))
{
}
#endif

#if     qHasFeature_OpenSSL
/*
 ********************************************************************************
 ******************* Cryptography::OpenSSLOutputStream **************************
 ********************************************************************************
 */
OpenSSLOutputStream::OpenSSLOutputStream (const OpenSSLCryptoParams& cryptoParams, Direction direction, const OutputStream<Byte>& realOut)
    : OutputStream<Byte> (make_shared<IRep_> (cryptoParams, direction, realOut))
{
}
#endif
<|endoftext|>


<commit_before>#include "instantiationconstraint.h"

#include <model/devisertypes.h>

InstantiationConstraint::InstantiationConstraint(DeviserValidator *validator)
  : DeviserConstraint(validator)
{

}

int InstantiationConstraint::analyzePackage(DeviserPackage *package)
{
  int errors = 0;

  foreach (DeviserVersion* version, package->getVersions())
  {
    foreach(DeviserClass* pClass, version ->getElements())
    {
      foreach(DeviserConcrete* instantiation, pClass->getConcretes())
      {
        if (instantiation->getElement().isEmpty())
        {
          ADD_MESSAGE_WITH_SEVERITY(DEVISER_ERROR, "The instantiation '"
                                    << instantiation->getName()
                                    << "' has no element defined, this is a required attribute.");
          ++errors;
        }
      }
    }

  }

  return errors;
}
<commit_msg>- issue #111045570: also validate that there is a name specified<commit_after>#include "instantiationconstraint.h"

#include <model/devisertypes.h>

InstantiationConstraint::InstantiationConstraint(DeviserValidator *validator)
  : DeviserConstraint(validator)
{

}

int InstantiationConstraint::analyzePackage(DeviserPackage *package)
{
  int errors = 0;

  foreach (DeviserVersion* version, package->getVersions())
  {
    foreach(DeviserClass* pClass, version ->getElements())
    {
      foreach(DeviserConcrete* instantiation, pClass->getConcretes())
      {
        if (instantiation->getName().isEmpty())
        {
          ADD_MESSAGE_WITH_SEVERITY(DEVISER_ERROR, "In class '"
                                    << pClass->getName()
                                    << "' an instantiation has no XML name, this is a required attribute.");
          ++errors;
        }
        if (instantiation->getElement().isEmpty())
        {
          ADD_MESSAGE_WITH_SEVERITY(DEVISER_ERROR, "The instantiation '"
                                    << instantiation->getName()
                                    << "' has no element defined, this is a required attribute.");
          ++errors;
        }
      }
    }

  }

  return errors;
}
<|endoftext|>


<commit_before>#include "precomp.h"
#include "game_object_types.h"
#include "game_object_manager.h"
#include "game_object.h"
#include "player.h"
#include "../tile_chunk.h"
#include "throwable_object.h"
#include "../net/message.h"

clan::Sprite Player::s_rw,
			 Player::s_lw,
			 Player::s_uw,
			 Player::s_dw,
			 Player::s_h;

static clan::Font title;

Player::Player(uint32_t guid): GameObject(type(),guid)
{
	keys=add_property<uint32_t>("keys",0);
	life=add_property<uint32_t>("life",100);
	kills=add_property<uint32_t>("kills",0);
	killer=add_property<uint32_t>("killer");
	name=add_property<std::string>("name","Sir. Waitfor Servereply");

	clan::Contour contour;
	contour.get_points().push_back(clan::Pointf(16,13));
	contour.get_points().push_back(clan::Pointf(16,63));
	contour.get_points().push_back(clan::Pointf(47,63));
	contour.get_points().push_back(clan::Pointf(47,13));

	m_outline.get_contours().push_back(contour);
	m_outline.calculate_radius();
	m_outline.calculate_smallest_enclosing_discs();

	m_next_attack_time = 0;
}

Player::~Player()
{

}

uint32_t Player::get_next_attack_time()
{
	return m_next_attack_time;
}

void Player::set_next_attack_time(uint32_t time)
{
	m_next_attack_time = time;
}

clan::Colorf Player::get_hp_bar_color()
{
	float r,g;
	r = 1.0f - (float)life/100;
	g = (float)life/100;
	return clan::Colorf(r,g,0.0f,1.0f);
}

bool Player::preload(clan::Canvas & canvas, clan::ResourceManager & resources)
{
	title = clan::Font(canvas,"Arial",12); ///DON'T CHANGE EVEN AGAIN
	s_rw = clan::Sprite::resource(canvas, "champ_rw", resources );
	s_lw = clan::Sprite::resource(canvas, "champ_lw", resources );
	s_uw = clan::Sprite::resource(canvas, "champ_uw", resources );
	s_dw = clan::Sprite::resource(canvas, "champ_dw", resources );

	s_h = clan::Sprite::resource(canvas, "hp_bar", resources );

	return true;
}

void Player::free()
{
	s_rw = clan::Sprite();
	s_lw = clan::Sprite();
	s_uw = clan::Sprite();
	s_dw = clan::Sprite();

	s_h = clan::Sprite();

	title = clan::Font();
}

void Player::load(clan::Canvas & canvas, clan::ResourceManager & resources)
{
	m_rw = s_rw.clone();
	m_lw = s_lw.clone();
	m_uw = s_uw.clone();
	m_dw = s_dw.clone();

	m_h = s_h.clone();

	m_sprite=m_dw;
	clan::Console::write_line("is null: %1",m_sprite.is_null());
}

void Player::update(const clan::GameTime & time)
{
	if(!m_sprite.is_null())
		m_sprite.update(time.get_time_elapsed_ms());
	//m_pos.data().x += 16.0f * (float)time.get_time_elapsed_ms()/1000.0f;

	last_pos = m_pos.get();
	if(keys&EUIKT_MOVE_LEFT && m_pos.get().x>-20.0f)
	{
		m_sprite=m_lw;
		clan::vec2f v=m_pos;
		v.x-= 32.0f * (float)time.get_time_elapsed_ms()/900.0f;
		m_pos.set(v);
	}
	if(keys&EUIKT_MOVE_RIGHT && m_pos.get().x<980.0f)
	{
		m_sprite=m_rw;
		clan::vec2f v=m_pos;
		v.x+= 32.0f * (float)time.get_time_elapsed_ms()/900.0f;
		m_pos.set(v);
	}
	if(keys&EUIKT_MOVE_UP && m_pos.get().y>0.0f)
	{
		m_sprite=m_uw;
		clan::vec2f v=m_pos;
		v.y-= 32.0f * (float)time.get_time_elapsed_ms()/900.0f;
		m_pos.set(v);
	}
	if(keys&EUIKT_MOVE_DOWN && m_pos.get().y<660.0f)
	{
		m_sprite=m_dw;
		clan::vec2f v=m_pos;
		v.y+= 32.0f * (float)time.get_time_elapsed_ms()/900.0f;
		m_pos.set(v);
	}

	m_outline.set_translation(m_pos.get().x,m_pos.get().y);
}

void Player::render(clan::Canvas & c, const clan::vec2 & offset)
{
#if defined GAME_CLIENT
	if(!m_sprite.is_null())
	{
		m_sprite.draw(c, m_pos.get().x+offset.x, m_pos.get().y+offset.y);
		c.fill_rect(m_pos.get().x+offset.x+10, m_pos.get().y+offset.y-1,  m_pos.get().x+offset.x+10+(44*life/100), m_pos.get().y+offset.y+8,  get_hp_bar_color());
		m_h.draw(c,m_pos.get().x+offset.x, m_pos.get().y+offset.y-5);
		m_outline.draw(offset.x,offset.y,clan::Colorf(1,0,0,1),c);

		title.draw_text(c, m_pos.get().x+offset.x+6,m_pos.get().y+offset.y-8, name.get()+": "+clan::StringHelp::uint_to_text(kills.get()), get_hp_bar_color());
	}
#endif
}

void Player::on_message(const Message & msg)
{
	if(msg.get_type()==MSGC_INPUT)
	{
		const MSGC_Input & input = static_cast<const MSGC_Input &>(msg);
		keys = input.keys;
	}
}

void Player::on_collide(GameObject * obj)
{
	if(obj->is_alive() && obj->get_type()==EGOT_THROWABLE_OBJECT)
	{
		if(static_cast<ThrowableObject*>(obj)->get_owner_guid()==this->get_guid())
			return;

		obj->set_is_alive(false);

		if(this->life>10)
		{
			this->life = this->life - 10;
		}
		else
		{
			this->killer=static_cast<ThrowableObject*>(obj)->get_owner_guid();
			this->life=0;
		}
	}
}

void Player::on_tile_collide(const Tile & tile)
{
	m_pos = last_pos;
}

clan::CollisionOutline & Player::get_outline()
{
	return m_outline;
}<commit_msg>Signed-off-by: serengeor <serengeor@gmail.com><commit_after>#include "precomp.h"
#include "game_object_types.h"
#include "game_object_manager.h"
#include "game_object.h"
#include "player.h"
#include "../tile_chunk.h"
#include "throwable_object.h"
#include "../net/message.h"

clan::Sprite Player::s_rw,
			 Player::s_lw,
			 Player::s_uw,
			 Player::s_dw,
			 Player::s_h;

static clan::Font title;

Player::Player(uint32_t guid): GameObject(type(),guid)
{
	keys=add_property<uint32_t>("keys",0);
	life=add_property<uint32_t>("life",100);
	kills=add_property<uint32_t>("kills",0);
	killer=add_property<uint32_t>("killer");
	name=add_property<std::string>("name","Sir. Waitfor Servereply");

	clan::Contour contour;
	contour.get_points().push_back(clan::Pointf(16,13));
	contour.get_points().push_back(clan::Pointf(16,63));
	contour.get_points().push_back(clan::Pointf(47,63));
	contour.get_points().push_back(clan::Pointf(47,13));

	m_outline.get_contours().push_back(contour);
	m_outline.calculate_radius();
	m_outline.calculate_smallest_enclosing_discs();

	m_next_attack_time = 0;
}

Player::~Player()
{

}

uint32_t Player::get_next_attack_time()
{
	return m_next_attack_time;
}

void Player::set_next_attack_time(uint32_t time)
{
	m_next_attack_time = time;
}

clan::Colorf Player::get_hp_bar_color()
{
	float r,g;
	r = 1.0f - (float)life/100;
	g = (float)life/100;
	return clan::Colorf(r,g,0.0f,1.0f);
}

bool Player::preload(clan::Canvas & canvas, clan::ResourceManager & resources)
{
	title = clan::Font(canvas,"Arial",12); ///DON'T CHANGE EVEN AGAIN
	s_rw = clan::Sprite::resource(canvas, "champ_rw", resources );
	s_lw = clan::Sprite::resource(canvas, "champ_lw", resources );
	s_uw = clan::Sprite::resource(canvas, "champ_uw", resources );
	s_dw = clan::Sprite::resource(canvas, "champ_dw", resources );

	s_h = clan::Sprite::resource(canvas, "hp_bar", resources );

	return true;
}

void Player::free()
{
	s_rw = clan::Sprite();
	s_lw = clan::Sprite();
	s_uw = clan::Sprite();
	s_dw = clan::Sprite();

	s_h = clan::Sprite();

	title = clan::Font();
}

void Player::load(clan::Canvas & canvas, clan::ResourceManager & resources)
{
	m_rw = s_rw.clone();
	m_lw = s_lw.clone();
	m_uw = s_uw.clone();
	m_dw = s_dw.clone();

	m_h = s_h.clone();

	m_sprite=m_dw;
}

void Player::update(const clan::GameTime & time)
{
	if(!m_sprite.is_null())
		m_sprite.update(time.get_time_elapsed_ms());
	//m_pos.data().x += 16.0f * (float)time.get_time_elapsed_ms()/1000.0f;

	last_pos = m_pos.get();
	if(keys&EUIKT_MOVE_LEFT && m_pos.get().x>-20.0f)
	{
		m_sprite=m_lw;
		clan::vec2f v=m_pos;
		v.x-= 32.0f * (float)time.get_time_elapsed_ms()/900.0f;
		m_pos.set(v);
	}
	if(keys&EUIKT_MOVE_RIGHT && m_pos.get().x<980.0f)
	{
		m_sprite=m_rw;
		clan::vec2f v=m_pos;
		v.x+= 32.0f * (float)time.get_time_elapsed_ms()/900.0f;
		m_pos.set(v);
	}
	if(keys&EUIKT_MOVE_UP && m_pos.get().y>0.0f)
	{
		m_sprite=m_uw;
		clan::vec2f v=m_pos;
		v.y-= 32.0f * (float)time.get_time_elapsed_ms()/900.0f;
		m_pos.set(v);
	}
	if(keys&EUIKT_MOVE_DOWN && m_pos.get().y<660.0f)
	{
		m_sprite=m_dw;
		clan::vec2f v=m_pos;
		v.y+= 32.0f * (float)time.get_time_elapsed_ms()/900.0f;
		m_pos.set(v);
	}

	m_outline.set_translation(m_pos.get().x,m_pos.get().y);
}

void Player::render(clan::Canvas & c, const clan::vec2 & offset)
{
#if defined GAME_CLIENT
	if(!m_sprite.is_null())
	{
		m_sprite.draw(c, m_pos.get().x+offset.x, m_pos.get().y+offset.y);
		c.fill_rect(m_pos.get().x+offset.x+10, m_pos.get().y+offset.y-1,  m_pos.get().x+offset.x+10+(44*life/100), m_pos.get().y+offset.y+8,  get_hp_bar_color());
		m_h.draw(c,m_pos.get().x+offset.x, m_pos.get().y+offset.y-5);
		m_outline.draw(offset.x,offset.y,clan::Colorf(1,0,0,1),c);

		title.draw_text(c, m_pos.get().x+offset.x+6,m_pos.get().y+offset.y-8, name.get()+": "+clan::StringHelp::uint_to_text(kills.get()), get_hp_bar_color());
	}
#endif
}

void Player::on_message(const Message & msg)
{
	if(msg.get_type()==MSGC_INPUT)
	{
		const MSGC_Input & input = static_cast<const MSGC_Input &>(msg);
		keys = input.keys;
	}
}

void Player::on_collide(GameObject * obj)
{
	if(obj->is_alive() && obj->get_type()==EGOT_THROWABLE_OBJECT)
	{
		if(static_cast<ThrowableObject*>(obj)->get_owner_guid()==this->get_guid())
			return;

		obj->set_is_alive(false);

		if(this->life>10)
		{
			this->life = this->life - 10;
		}
		else
		{
			this->killer=static_cast<ThrowableObject*>(obj)->get_owner_guid();
			this->life=0;
		}
	}
}

void Player::on_tile_collide(const Tile & tile)
{
	m_pos = last_pos;
}

clan::CollisionOutline & Player::get_outline()
{
	return m_outline;
}<|endoftext|>


<commit_before>// General tests that the header search paths detected by the driver and passed
// to CC1 are sane.
//
// Test a very broken version of multiarch that shipped in Ubuntu 11.04.
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN:     -ccc-host-triple i386-unknown-linux \
// RUN:     --sysroot=%S/Inputs/ubuntu_11.04_multiarch_tree \
// RUN:   | FileCheck --check-prefix=CHECK-UBUNTU-11-04 %s
// CHECK-UBUNTU-11-04: "{{.*}}clang{{.*}}" "-cc1"
// CHECK-UBUNTU-11-04: "-isysroot" "[[SYSROOT:[^"]+]]"
// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5"
// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5/i686-linux-gnu"
// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5/backward"
// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
// CHECK-UBUNTU-11-04: "-internal-isystem" "{{.*}}/lib/clang/{{[0-9]\.[0-9]}}/include"
// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/include"
// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
<commit_msg>Try to fix an issue on some hosts where the 'lib' in the builtin include path is actually a multilib.<commit_after>// General tests that the header search paths detected by the driver and passed
// to CC1 are sane.
//
// Test a very broken version of multiarch that shipped in Ubuntu 11.04.
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN:     -ccc-host-triple i386-unknown-linux \
// RUN:     --sysroot=%S/Inputs/ubuntu_11.04_multiarch_tree \
// RUN:   | FileCheck --check-prefix=CHECK-UBUNTU-11-04 %s
// CHECK-UBUNTU-11-04: "{{.*}}clang{{.*}}" "-cc1"
// CHECK-UBUNTU-11-04: "-isysroot" "[[SYSROOT:[^"]+]]"
// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5"
// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5/i686-linux-gnu"
// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/i386-linux-gnu/gcc/i686-linux-gnu/4.5/../../../../../include/c++/4.5/backward"
// CHECK-UBUNTU-11-04: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
// CHECK-UBUNTU-11-04: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/include"
// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
<|endoftext|>


<commit_before>#include "./../../../Common/verbose-output/rule.hpp"

#include <boost/static_assert.hpp>

namespace utils { namespace verbose_output {
    /// @brief rule for events from integrals state changing
    /// @detailed 1. let x be monotonous increasing integral under observation
    ///           2. let we want to track x every time if it goes through 100
    ///           3. so integrals_rule will raise event if we observe x + y, where y >= 100
    template<typename T>
    class integrals_rule
        :    public rule
    {
        BOOST_STATIC_ASSERT((boost::is_arithmetic<T>::value));

        typedef integrals_rule<T> this_class;
        typedef rule base_class;

    public:
        /// @brief default constructor
        /// @param state observable
        /// @param stride stride we want to log observable through
        integrals_rule(T state, T stride)
            :    m_state(state), m_stride(stride){ };

        /// @brief inherited from rule interface
        /// @see rule
        result_type operator()(args<0>::type);

    private:
        // logics: we could not adaptively change rule behavior.
        //         Correctly, it should be done by changing rule
        // private setter and getter for observable state
        T state() const{ return m_state; }
        this_class& state(T val){ m_state = val; return *this; }

        // just getter for observations stride
        T stride() const{ return m_stride; }

        T m_state;
        T m_stride;
    };
}}

#define _tmpl_head_T_ template<typename T>
#define _cls_name_ integrals_rule<T>

#include "./../../../Common/verbose-output/rules/details/integrals_rule.inl"
<commit_msg>numerals_rule.hpp: add #def protection for multiple object translating during compilation<commit_after>#ifndef INC_NUMERALS_RULE_HPP_
#define INC_NUMERALS_RULE_HPP_

#include "./../../../Common/verbose-output/rule.hpp"

#include <boost/static_assert.hpp>

namespace utils { namespace verbose_output {
    /// @brief rule for events from integrals state changing
    /// @detailed 1. let x be monotonous increasing integral under observation
    ///           2. let we want to track x every time if it goes through 100
    ///           3. so integrals_rule will raise event if we observe x + y, where y >= 100
    template<typename T>
    class integrals_rule
        :    public rule
    {
        BOOST_STATIC_ASSERT((boost::is_arithmetic<T>::value));

        typedef integrals_rule<T> this_class;
        typedef rule base_class;

    public:
        /// @brief default constructor
        /// @param state observable
        /// @param stride stride we want to log observable through
        integrals_rule(T state, T stride)
            :    m_state(state), m_stride(stride){ };

        /// @brief inherited from rule interface
        /// @see rule
        result_type operator()(args<0>::type);

    private:
        // logics: we could not adaptively change rule behavior.
        //         Correctly, it should be done by changing rule
        // private setter and getter for observable state
        T state() const{ return m_state; }
        this_class& state(T val){ m_state = val; return *this; }

        // just getter for observations stride
        T stride() const{ return m_stride; }

        T m_state;
        T m_stride;
    };
}}

#define _tmpl_head_T_ template<typename T>
#define _cls_name_ integrals_rule<T>

#include "./../../../Common/verbose-output/rules/details/integrals_rule.inl"

#endif
<|endoftext|>


<commit_before>#include <cassert>
#include <iostream>
#include <climits>
#include "solvers/equality_assistant.h"
#include "config.h"

using namespace theorysolver;

#define VERBOSE_ASSISTANT true

#define EF satsolver::ExtendedFormula
#define SPEF std::shared_ptr<EF>
#define EA EqualityAtom
#define SPEA std::shared_ptr<EA>

// Return a formula that uses only atoms in the canonical “xi-xj<=n” form.
// Note that it may use literal #0; for instance, xi >= n is converted to
// x0 - xi <= -n, so we will have to make sure x0 is always equal to 0.
SPEF canonize_atom(SPEA atom, std::vector<SPEA> &literal_to_EA, std::string literal) {
    unsigned long int id1;
    assert(atom);
    if(atom->left==atom->right) {
        switch (atom->op) {
            case EA::EQUAL: // t1 = t1
                atom->canonical = SPEF(new EF(EF::TRUE));
                break;
            case EA::UNEQUAL: // t1 != t1
                atom->canonical = SPEF(new EF(EF::FALSE));
                break;
        }
    }
    else {
        switch (atom->op) {
            case EA::EQUAL: // t1 = t2   --> t1 = t2
                atom->canonical = SPEF(new EF(EF::LITERAL, literal));
                break;
            case EA::UNEQUAL: // t2 != t2   -->   ~(t1 = t2)
                id1 = EqualityAtom::add_EA(literal_to_EA, atom->left, EA::EQUAL, atom->right);
                atom->canonical = SPEF(new EF(EF::NOT,
                            SPEF(new EF(EF::LITERAL, EqualityAtom::variable_name_from_atom_id(id1)))
                       ));
                break;
        }
    }
    return atom->canonical;
}

SPEF EqualityAssistant::canonize_formula(SPEF formula, std::vector<SPEA> &literal_to_EA) {
    SPEA atom;
    switch (formula->get_type()) {
        case EF::XOR:
        case EF::OR:
        case EF::AND:
        case EF::IMPLIES:
            return std::make_shared<EF>(formula->get_type(), EqualityAssistant::canonize_formula(formula->get_f1(), literal_to_EA), EqualityAssistant::canonize_formula(formula->get_f2(), literal_to_EA));
        case EF::NOT:
            return std::make_shared<EF>(formula->get_type(), EqualityAssistant::canonize_formula(formula->get_f1(), literal_to_EA));
        case EF::LITERAL:
            atom = EqualityAtom::SPEA_from_variable(literal_to_EA, formula->get_literal());
            if (!EqualityAtom::is_atom_variable(formula->get_literal()))
                return std::make_shared<EF>(formula->get_type(), formula->get_literal());
            atom = EqualityAtom::SPEA_from_variable(literal_to_EA, formula->get_literal());
            return canonize_atom(atom, literal_to_EA, formula->get_literal());
        case EF::TRUE:
        case EF::FALSE:
            return std::make_shared<EF>(formula->get_type());
    }
    assert(false);
}

EqualityAssistant::EqualityAssistant(std::vector<SPEA> &literal_to_EA, std::shared_ptr<std::map<std::string, int>> name_to_variable, std::shared_ptr<satsolver::Formula> formula) :
    formula(formula), literal_to_EA(literal_to_EA), name_to_variable(*name_to_variable), variable_to_name(), union_find(), unequal(), consistent_state(true), depth_back(-1), old_polarity(formula->get_nb_variables()+1, 0) {
    for (auto it : *name_to_variable)
        this->variable_to_name.insert(make_pair(it.second, it.first));
}

int EqualityAssistant::on_flip(unsigned int variable) {
    unsigned int atom_id;
    SPEA atom;
    int clause_id=-1;
    if (VERBOSE_ASSISTANT && VERBOSE)
        std::cout << "flip variable: " << variable;
    if (!EqualityAtom::is_atom_literal(this->variable_to_name, variable)) {
        if (VERBOSE_ASSISTANT && VERBOSE)
            std::cout << ", which is not an atom." << std::endl;
        return -1; // We care only about variables matching atoms.
    }
    assert(variable <= static_cast<unsigned int>(this->formula->get_nb_variables()));
    atom_id = EqualityAtom::atom_id_from_literal(this->variable_to_name, variable);
    atom = EqualityAtom::SPEA_from_literal(this->literal_to_EA, this->variable_to_name, variable);
    if (VERBOSE_ASSISTANT && VERBOSE)
        std::cout << ", whose atom is: " << atom_id << ", and whose new state is: ";
    if (this->formula->get_aff()->is_true(variable)) {
        if (VERBOSE_ASSISTANT && VERBOSE)
            std::cout << "true" << std::endl;
        assert(this->consistent_state);
        if (this->old_polarity[variable] == 1)
            return -1;
        clause_id = this->insert_atom(atom->left, atom->right, atom->op == EA::EQUAL, atom_id, variable);
        this->old_polarity[variable] = 1;
    }
    else if (this->formula->get_aff()->is_false(variable)) {
        if (VERBOSE_ASSISTANT && VERBOSE)
            std::cout << "false" << std::endl;
        assert(this->consistent_state);
        if (this->old_polarity[variable] == -1)
            return -1;
        clause_id = this->insert_atom(atom->left, atom->right, atom->op == EA::UNEQUAL, atom_id, variable);
        this->old_polarity[variable] = -1;
    }
    else {
        if (VERBOSE_ASSISTANT && VERBOSE)
            std::cout << "unknown" << std::endl;
        if (this->old_polarity[variable] == 0)
            return -1;
        if (this->old_polarity[variable] == 1) {
            this->union_find.unmerge();
        }
        else {
            assert(this->unequal.size());
            assert(this->unequal.back().first == atom_id);
            this->unequal.pop_back();
        }
        this->consistent_state = true;

        this->old_polarity[variable] = 0;
    }
    return clause_id;
}

int EqualityAssistant::insert_atom(unsigned int i, unsigned int j, bool equal, unsigned int atom_id, int lit_conf) {
    if (equal) {
        this->union_find.merge(atom_id, i, j);
        for (auto it : this->unequal) {
            if (this->union_find.find(it.second.first) == this->union_find.find(it.second.second)) {
                this->consistent_state = false;
                return this->learn_clause(it.first, i, j, lit_conf);
            }
        }
    }
    else {
        this->consistent_state = (this->union_find.find(i) != this->union_find.find(j));
        this->unequal.push_back(std::make_pair(atom_id, std::make_pair(i, j)));
        if (!this->consistent_state)
            return this->learn_clause(atom_id, i, j, lit_conf);
    }
    return -1;
}

int EqualityAssistant::literal_from_atom_id(int atom_id) const {
    if (atom_id > 0)
        return EqualityAtom::literal_from_atom_id(this->name_to_variable, static_cast<unsigned int>(atom_id));
    else
        return -EqualityAtom::literal_from_atom_id(this->name_to_variable, static_cast<unsigned int>(-atom_id));
}

#define invert_polarity(lit) this->formula->get_aff()->is_true(lit) ? -lit : lit

int EqualityAssistant::learn_clause(int unequal_atomid, int i, int j, int lit_conf) {
    std::unordered_set<int> clause;
    int max_depth=-1, max_depth_l=0 ;
    int lit;
    int tmp;
    lit_conf = invert_polarity(lit_conf) ;
    clause.insert(lit_conf);
    clause.insert(lit=invert_polarity(this->literal_from_atom_id(unequal_atomid)));
    if(lit!=lit_conf) {
        max_depth = this->formula->get_ded()->get_deduction_depth(lit) ;
        max_depth_l = lit ;
    }
    for (auto it : this->union_find.get_path(i)) {
        lit = invert_polarity(this->literal_from_atom_id(it));
        clause.insert(lit);
        if(lit!=lit_conf && this->formula->get_ded()->get_deduction_depth(lit) > max_depth) {
            max_depth = this->formula->get_ded()->get_deduction_depth(lit) ;
            max_depth_l = lit ;
        }
    }
    for (auto it : this->union_find.get_path(j)) {
        lit = invert_polarity(this->literal_from_atom_id(it));
        clause.insert(lit);
        if(lit!=lit_conf && this->formula->get_ded()->get_deduction_depth(lit) > max_depth) {
            max_depth = this->formula->get_ded()->get_deduction_depth(lit) ;
            max_depth_l = lit ;
        }
    }
    assert(max_depth >= 0);
    this->depth_back = max_depth ;
    assert(clause.size()>=2) ;
    assert(this->formula->get_aff());
    tmp = static_cast<int>(this->formula->add_clause(std::make_shared<satsolver::Clause>(this->formula->get_nb_variables(), clause, this->formula->get_aff())));
    std::cout << "Learn : " << this->formula->to_clauses_vector()[tmp]->to_string() << " with " << lit_conf << " " << max_depth_l << std::endl ;
    if(WITH_WL) this->formula->to_clauses_vector()[tmp]->init_WL_CL(lit_conf,max_depth_l) ;
    return tmp ;
}

bool EqualityAssistant::is_state_consistent() {
    return this->consistent_state;
}

bool EqualityAssistant::detect_isolated_literals() {
    return false;
}

unsigned int EqualityAssistant::get_depth_back() {
    return -1;
}
<commit_msg>Add EqualityAssistant::get_depth_back.<commit_after>#include <cassert>
#include <iostream>
#include <climits>
#include "solvers/equality_assistant.h"
#include "config.h"

using namespace theorysolver;

#define VERBOSE_ASSISTANT true

#define EF satsolver::ExtendedFormula
#define SPEF std::shared_ptr<EF>
#define EA EqualityAtom
#define SPEA std::shared_ptr<EA>

// Return a formula that uses only atoms in the canonical “xi-xj<=n” form.
// Note that it may use literal #0; for instance, xi >= n is converted to
// x0 - xi <= -n, so we will have to make sure x0 is always equal to 0.
SPEF canonize_atom(SPEA atom, std::vector<SPEA> &literal_to_EA, std::string literal) {
    unsigned long int id1;
    assert(atom);
    if(atom->left==atom->right) {
        switch (atom->op) {
            case EA::EQUAL: // t1 = t1
                atom->canonical = SPEF(new EF(EF::TRUE));
                break;
            case EA::UNEQUAL: // t1 != t1
                atom->canonical = SPEF(new EF(EF::FALSE));
                break;
        }
    }
    else {
        switch (atom->op) {
            case EA::EQUAL: // t1 = t2   --> t1 = t2
                atom->canonical = SPEF(new EF(EF::LITERAL, literal));
                break;
            case EA::UNEQUAL: // t2 != t2   -->   ~(t1 = t2)
                id1 = EqualityAtom::add_EA(literal_to_EA, atom->left, EA::EQUAL, atom->right);
                atom->canonical = SPEF(new EF(EF::NOT,
                            SPEF(new EF(EF::LITERAL, EqualityAtom::variable_name_from_atom_id(id1)))
                       ));
                break;
        }
    }
    return atom->canonical;
}

SPEF EqualityAssistant::canonize_formula(SPEF formula, std::vector<SPEA> &literal_to_EA) {
    SPEA atom;
    switch (formula->get_type()) {
        case EF::XOR:
        case EF::OR:
        case EF::AND:
        case EF::IMPLIES:
            return std::make_shared<EF>(formula->get_type(), EqualityAssistant::canonize_formula(formula->get_f1(), literal_to_EA), EqualityAssistant::canonize_formula(formula->get_f2(), literal_to_EA));
        case EF::NOT:
            return std::make_shared<EF>(formula->get_type(), EqualityAssistant::canonize_formula(formula->get_f1(), literal_to_EA));
        case EF::LITERAL:
            atom = EqualityAtom::SPEA_from_variable(literal_to_EA, formula->get_literal());
            if (!EqualityAtom::is_atom_variable(formula->get_literal()))
                return std::make_shared<EF>(formula->get_type(), formula->get_literal());
            atom = EqualityAtom::SPEA_from_variable(literal_to_EA, formula->get_literal());
            return canonize_atom(atom, literal_to_EA, formula->get_literal());
        case EF::TRUE:
        case EF::FALSE:
            return std::make_shared<EF>(formula->get_type());
    }
    assert(false);
}

EqualityAssistant::EqualityAssistant(std::vector<SPEA> &literal_to_EA, std::shared_ptr<std::map<std::string, int>> name_to_variable, std::shared_ptr<satsolver::Formula> formula) :
    formula(formula), literal_to_EA(literal_to_EA), name_to_variable(*name_to_variable), variable_to_name(), union_find(), unequal(), consistent_state(true), depth_back(-1), old_polarity(formula->get_nb_variables()+1, 0) {
    for (auto it : *name_to_variable)
        this->variable_to_name.insert(make_pair(it.second, it.first));
}

int EqualityAssistant::on_flip(unsigned int variable) {
    unsigned int atom_id;
    SPEA atom;
    int clause_id=-1;
    if (VERBOSE_ASSISTANT && VERBOSE)
        std::cout << "flip variable: " << variable;
    if (!EqualityAtom::is_atom_literal(this->variable_to_name, variable)) {
        if (VERBOSE_ASSISTANT && VERBOSE)
            std::cout << ", which is not an atom." << std::endl;
        return -1; // We care only about variables matching atoms.
    }
    assert(variable <= static_cast<unsigned int>(this->formula->get_nb_variables()));
    atom_id = EqualityAtom::atom_id_from_literal(this->variable_to_name, variable);
    atom = EqualityAtom::SPEA_from_literal(this->literal_to_EA, this->variable_to_name, variable);
    if (VERBOSE_ASSISTANT && VERBOSE)
        std::cout << ", whose atom is: " << atom_id << ", and whose new state is: ";
    if (this->formula->get_aff()->is_true(variable)) {
        if (VERBOSE_ASSISTANT && VERBOSE)
            std::cout << "true" << std::endl;
        assert(this->consistent_state);
        if (this->old_polarity[variable] == 1)
            return -1;
        clause_id = this->insert_atom(atom->left, atom->right, atom->op == EA::EQUAL, atom_id, variable);
        this->old_polarity[variable] = 1;
    }
    else if (this->formula->get_aff()->is_false(variable)) {
        if (VERBOSE_ASSISTANT && VERBOSE)
            std::cout << "false" << std::endl;
        assert(this->consistent_state);
        if (this->old_polarity[variable] == -1)
            return -1;
        clause_id = this->insert_atom(atom->left, atom->right, atom->op == EA::UNEQUAL, atom_id, variable);
        this->old_polarity[variable] = -1;
    }
    else {
        if (VERBOSE_ASSISTANT && VERBOSE)
            std::cout << "unknown" << std::endl;
        if (this->old_polarity[variable] == 0)
            return -1;
        if (this->old_polarity[variable] == 1) {
            this->union_find.unmerge();
        }
        else {
            assert(this->unequal.size());
            assert(this->unequal.back().first == atom_id);
            this->unequal.pop_back();
        }
        this->consistent_state = true;

        this->old_polarity[variable] = 0;
    }
    return clause_id;
}

int EqualityAssistant::insert_atom(unsigned int i, unsigned int j, bool equal, unsigned int atom_id, int lit_conf) {
    if (equal) {
        this->union_find.merge(atom_id, i, j);
        for (auto it : this->unequal) {
            if (this->union_find.find(it.second.first) == this->union_find.find(it.second.second)) {
                this->consistent_state = false;
                return this->learn_clause(it.first, i, j, lit_conf);
            }
        }
    }
    else {
        this->consistent_state = (this->union_find.find(i) != this->union_find.find(j));
        this->unequal.push_back(std::make_pair(atom_id, std::make_pair(i, j)));
        if (!this->consistent_state)
            return this->learn_clause(atom_id, i, j, lit_conf);
    }
    return -1;
}

int EqualityAssistant::literal_from_atom_id(int atom_id) const {
    if (atom_id > 0)
        return EqualityAtom::literal_from_atom_id(this->name_to_variable, static_cast<unsigned int>(atom_id));
    else
        return -EqualityAtom::literal_from_atom_id(this->name_to_variable, static_cast<unsigned int>(-atom_id));
}

#define invert_polarity(lit) this->formula->get_aff()->is_true(lit) ? -lit : lit

int EqualityAssistant::learn_clause(int unequal_atomid, int i, int j, int lit_conf) {
    std::unordered_set<int> clause;
    int max_depth=-1, max_depth_l=0 ;
    int lit;
    int tmp;
    lit_conf = invert_polarity(lit_conf) ;
    clause.insert(lit_conf);
    clause.insert(lit=invert_polarity(this->literal_from_atom_id(unequal_atomid)));
    if(lit!=lit_conf) {
        max_depth = this->formula->get_ded()->get_deduction_depth(lit) ;
        max_depth_l = lit ;
    }
    for (auto it : this->union_find.get_path(i)) {
        lit = invert_polarity(this->literal_from_atom_id(it));
        clause.insert(lit);
        if(lit!=lit_conf && this->formula->get_ded()->get_deduction_depth(lit) > max_depth) {
            max_depth = this->formula->get_ded()->get_deduction_depth(lit) ;
            max_depth_l = lit ;
        }
    }
    for (auto it : this->union_find.get_path(j)) {
        lit = invert_polarity(this->literal_from_atom_id(it));
        clause.insert(lit);
        if(lit!=lit_conf && this->formula->get_ded()->get_deduction_depth(lit) > max_depth) {
            max_depth = this->formula->get_ded()->get_deduction_depth(lit) ;
            max_depth_l = lit ;
        }
    }
    assert(max_depth >= 0);
    this->depth_back = max_depth ;
    assert(clause.size()>=2) ;
    assert(this->formula->get_aff());
    tmp = static_cast<int>(this->formula->add_clause(std::make_shared<satsolver::Clause>(this->formula->get_nb_variables(), clause, this->formula->get_aff())));
    std::cout << "Learn : " << this->formula->to_clauses_vector()[tmp]->to_string() << " with " << lit_conf << " " << max_depth_l << std::endl ;
    if(WITH_WL) this->formula->to_clauses_vector()[tmp]->init_WL_CL(lit_conf,max_depth_l) ;
    return tmp ;
}

bool EqualityAssistant::is_state_consistent() {
    return this->consistent_state;
}

bool EqualityAssistant::detect_isolated_literals() {
    return false;
}

unsigned int EqualityAssistant::get_depth_back() {
    assert(this->depth_back>=0) ;
    unsigned int tmp = static_cast<unsigned int>(this->depth_back) ; // cette fonction ne doit être appelée qu'une fois par clause apprise
    this->depth_back = -1 ;
    return tmp ;
}
<|endoftext|>


<commit_before>/*
 *  Copyright 2017 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <vector>

#include "test/gmock.h"
#include "test/gtest.h"

#include "api/video_codecs/video_decoder.h"
#include "call/rtp_stream_receiver_controller.h"
#include "media/base/fakevideorenderer.h"
#include "modules/pacing/packet_router.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "modules/utility/include/process_thread.h"
#include "rtc_base/criticalsection.h"
#include "rtc_base/event.h"
#include "system_wrappers/include/clock.h"
#include "test/field_trial.h"
#include "video/call_stats.h"
#include "video/video_receive_stream.h"

namespace webrtc {
namespace {

using testing::_;
using testing::Invoke;

constexpr int kDefaultTimeOutMs = 50;

const char kNewJitterBufferFieldTrialEnabled[] =
    "WebRTC-NewVideoJitterBuffer/Enabled/";

class MockTransport : public Transport {
 public:
  MOCK_METHOD3(SendRtp,
               bool(const uint8_t* packet,
                    size_t length,
                    const PacketOptions& options));
  MOCK_METHOD2(SendRtcp, bool(const uint8_t* packet, size_t length));
};

class MockVideoDecoder : public VideoDecoder {
 public:
  MOCK_METHOD2(InitDecode,
               int32_t(const VideoCodec* config, int32_t number_of_cores));
  MOCK_METHOD4(Decode,
               int32_t(const EncodedImage& input,
                       bool missing_frames,
                       const CodecSpecificInfo* codec_specific_info,
                       int64_t render_time_ms));
  MOCK_METHOD1(RegisterDecodeCompleteCallback,
               int32_t(DecodedImageCallback* callback));
  MOCK_METHOD0(Release, int32_t(void));
  const char* ImplementationName() const { return "MockVideoDecoder"; }
};

}  // namespace

class VideoReceiveStreamTest : public testing::Test {
 public:
  VideoReceiveStreamTest()
      : process_thread_(ProcessThread::Create("TestThread")),
        override_field_trials_(kNewJitterBufferFieldTrialEnabled),
        config_(&mock_transport_),
        call_stats_(Clock::GetRealTimeClock(), process_thread_.get()) {}

  void SetUp() {
    constexpr int kDefaultNumCpuCores = 2;
    config_.rtp.remote_ssrc = 1111;
    config_.rtp.local_ssrc = 2222;
    config_.renderer = &fake_renderer_;
    VideoReceiveStream::Decoder h264_decoder;
    h264_decoder.payload_type = 99;
    h264_decoder.payload_name = "H264";
    h264_decoder.codec_params.insert(
        {"sprop-parameter-sets", "Z0IACpZTBYmI,aMljiA=="});
    h264_decoder.decoder = &mock_h264_video_decoder_;
    config_.decoders.push_back(h264_decoder);
    VideoReceiveStream::Decoder null_decoder;
    null_decoder.payload_type = 98;
    null_decoder.payload_name = "null";
    null_decoder.decoder = &mock_null_video_decoder_;
    config_.decoders.push_back(null_decoder);

    video_receive_stream_.reset(new webrtc::internal::VideoReceiveStream(
        &rtp_stream_receiver_controller_, kDefaultNumCpuCores, &packet_router_,
        config_.Copy(), process_thread_.get(), &call_stats_));
  }

 protected:
  std::unique_ptr<ProcessThread> process_thread_;
  webrtc::test::ScopedFieldTrials override_field_trials_;
  VideoReceiveStream::Config config_;
  CallStats call_stats_;
  MockVideoDecoder mock_h264_video_decoder_;
  MockVideoDecoder mock_null_video_decoder_;
  cricket::FakeVideoRenderer fake_renderer_;
  MockTransport mock_transport_;
  PacketRouter packet_router_;
  RtpStreamReceiverController rtp_stream_receiver_controller_;
  std::unique_ptr<webrtc::internal::VideoReceiveStream> video_receive_stream_;
};

TEST_F(VideoReceiveStreamTest, CreateFrameFromH264FmtpSpropAndIdr) {
  constexpr uint8_t idr_nalu[] = {0x05, 0xFF, 0xFF, 0xFF};
  RtpPacketToSend rtppacket(nullptr);
  uint8_t* payload = rtppacket.AllocatePayload(sizeof(idr_nalu));
  memcpy(payload, idr_nalu, sizeof(idr_nalu));
  rtppacket.SetMarker(true);
  rtppacket.SetSsrc(1111);
  rtppacket.SetPayloadType(99);
  rtppacket.SetSequenceNumber(1);
  rtppacket.SetTimestamp(0);
  rtc::Event init_decode_event_(false, false);
  EXPECT_CALL(mock_h264_video_decoder_, InitDecode(_, _))
      .WillOnce(Invoke([&init_decode_event_](const VideoCodec* config,
                                             int32_t number_of_cores) {
        init_decode_event_.Set();
        return 0;
      }));
  EXPECT_CALL(mock_h264_video_decoder_, RegisterDecodeCompleteCallback(_));
  video_receive_stream_->Start();
  EXPECT_CALL(mock_h264_video_decoder_, Decode(_, false, _, _));
  RtpPacketReceived parsed_packet;
  ASSERT_TRUE(parsed_packet.Parse(rtppacket.data(), rtppacket.size()));
  rtp_stream_receiver_controller_.OnRtpPacket(parsed_packet);
  EXPECT_CALL(mock_h264_video_decoder_, Release());
  // Make sure the decoder thread had a chance to run.
  init_decode_event_.Wait(kDefaultTimeOutMs);
}

}  // namespace webrtc
<commit_msg>Removed old and unused WebRTC-NewVideoJitterBuffer field trial from VideoReceiveStreamTest.<commit_after>/*
 *  Copyright 2017 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <vector>

#include "test/gmock.h"
#include "test/gtest.h"

#include "api/video_codecs/video_decoder.h"
#include "call/rtp_stream_receiver_controller.h"
#include "media/base/fakevideorenderer.h"
#include "modules/pacing/packet_router.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "modules/utility/include/process_thread.h"
#include "rtc_base/criticalsection.h"
#include "rtc_base/event.h"
#include "system_wrappers/include/clock.h"
#include "test/field_trial.h"
#include "video/call_stats.h"
#include "video/video_receive_stream.h"

namespace webrtc {
namespace {

using testing::_;
using testing::Invoke;

constexpr int kDefaultTimeOutMs = 50;

class MockTransport : public Transport {
 public:
  MOCK_METHOD3(SendRtp,
               bool(const uint8_t* packet,
                    size_t length,
                    const PacketOptions& options));
  MOCK_METHOD2(SendRtcp, bool(const uint8_t* packet, size_t length));
};

class MockVideoDecoder : public VideoDecoder {
 public:
  MOCK_METHOD2(InitDecode,
               int32_t(const VideoCodec* config, int32_t number_of_cores));
  MOCK_METHOD4(Decode,
               int32_t(const EncodedImage& input,
                       bool missing_frames,
                       const CodecSpecificInfo* codec_specific_info,
                       int64_t render_time_ms));
  MOCK_METHOD1(RegisterDecodeCompleteCallback,
               int32_t(DecodedImageCallback* callback));
  MOCK_METHOD0(Release, int32_t(void));
  const char* ImplementationName() const { return "MockVideoDecoder"; }
};

}  // namespace

class VideoReceiveStreamTest : public testing::Test {
 public:
  VideoReceiveStreamTest()
      : process_thread_(ProcessThread::Create("TestThread")),
        config_(&mock_transport_),
        call_stats_(Clock::GetRealTimeClock(), process_thread_.get()) {}

  void SetUp() {
    constexpr int kDefaultNumCpuCores = 2;
    config_.rtp.remote_ssrc = 1111;
    config_.rtp.local_ssrc = 2222;
    config_.renderer = &fake_renderer_;
    VideoReceiveStream::Decoder h264_decoder;
    h264_decoder.payload_type = 99;
    h264_decoder.payload_name = "H264";
    h264_decoder.codec_params.insert(
        {"sprop-parameter-sets", "Z0IACpZTBYmI,aMljiA=="});
    h264_decoder.decoder = &mock_h264_video_decoder_;
    config_.decoders.push_back(h264_decoder);
    VideoReceiveStream::Decoder null_decoder;
    null_decoder.payload_type = 98;
    null_decoder.payload_name = "null";
    null_decoder.decoder = &mock_null_video_decoder_;
    config_.decoders.push_back(null_decoder);

    video_receive_stream_.reset(new webrtc::internal::VideoReceiveStream(
        &rtp_stream_receiver_controller_, kDefaultNumCpuCores, &packet_router_,
        config_.Copy(), process_thread_.get(), &call_stats_));
  }

 protected:
  std::unique_ptr<ProcessThread> process_thread_;
  VideoReceiveStream::Config config_;
  CallStats call_stats_;
  MockVideoDecoder mock_h264_video_decoder_;
  MockVideoDecoder mock_null_video_decoder_;
  cricket::FakeVideoRenderer fake_renderer_;
  MockTransport mock_transport_;
  PacketRouter packet_router_;
  RtpStreamReceiverController rtp_stream_receiver_controller_;
  std::unique_ptr<webrtc::internal::VideoReceiveStream> video_receive_stream_;
};

TEST_F(VideoReceiveStreamTest, CreateFrameFromH264FmtpSpropAndIdr) {
  constexpr uint8_t idr_nalu[] = {0x05, 0xFF, 0xFF, 0xFF};
  RtpPacketToSend rtppacket(nullptr);
  uint8_t* payload = rtppacket.AllocatePayload(sizeof(idr_nalu));
  memcpy(payload, idr_nalu, sizeof(idr_nalu));
  rtppacket.SetMarker(true);
  rtppacket.SetSsrc(1111);
  rtppacket.SetPayloadType(99);
  rtppacket.SetSequenceNumber(1);
  rtppacket.SetTimestamp(0);
  rtc::Event init_decode_event_(false, false);
  EXPECT_CALL(mock_h264_video_decoder_, InitDecode(_, _))
      .WillOnce(Invoke([&init_decode_event_](const VideoCodec* config,
                                             int32_t number_of_cores) {
        init_decode_event_.Set();
        return 0;
      }));
  EXPECT_CALL(mock_h264_video_decoder_, RegisterDecodeCompleteCallback(_));
  video_receive_stream_->Start();
  EXPECT_CALL(mock_h264_video_decoder_, Decode(_, false, _, _));
  RtpPacketReceived parsed_packet;
  ASSERT_TRUE(parsed_packet.Parse(rtppacket.data(), rtppacket.size()));
  rtp_stream_receiver_controller_.OnRtpPacket(parsed_packet);
  EXPECT_CALL(mock_h264_video_decoder_, Release());
  // Make sure the decoder thread had a chance to run.
  init_decode_event_.Wait(kDefaultTimeOutMs);
}

}  // namespace webrtc
<|endoftext|>


<commit_before>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* 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 any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "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 AUTHORS BE HELD 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 "splashcore.h"

using namespace std;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

GNUCPPToolchain::GNUCPPToolchain(string basepath, string triplet)
	: CPPToolchain(basepath, TOOLCHAIN_GNU)
	, GNUToolchain(triplet)
{
	//Get the full compiler version
	m_stringVersion = string("GNU C++") + ShellCommand(basepath + " --version | head -n 1 | cut -d \")\" -f 2");

	//Parse it
	if(3 != sscanf(m_stringVersion.c_str(), "GNU C++ %4d.%4d.%4d",
		&m_majorVersion, &m_minorVersion, &m_patchVersion))
	{
		//TODO: handle this better, don't abort :P
		LogFatal("bad G++ version\n");
	}

	//Some compilers can target other arches if you feed them the right flags.
	//Thanks to @GyrosGeier for this
	string cmd =
		string("/bin/bash -c \"") +
		basepath + " -print-multi-lib | sed -e 's/.*;//' -e 's/@/ -/g' | while read line; do " +
		basepath + " \\$line -print-multiarch; done" +
		string("\"");
	string extra_arches = ShellCommand(cmd);
	vector<string> triplets;
	ParseLines(extra_arches, triplets);
	for(auto t : triplets)
		m_triplets.emplace(t);

	//If no arches found in the last step, fall back to the triplet in the file name
	if(m_triplets.empty())
		m_triplets.emplace(triplet);

	//Look up where this toolchain gets its include files from
	for(auto t : m_triplets)
	{
		vector<string> paths;
		FindDefaultIncludePaths(paths, basepath, false, t);
		m_defaultIncludePaths[t] = paths;
		m_virtualSystemIncludePath[t] =
			"__sysinclude__/" + str_replace(" ", "_", m_stringVersion) + "_" + t;
	}

	//Set suffixes for WINDOWS
	if(triplet.find("mingw") != string::npos)
	{
		m_exeSuffix = ".exe";
		m_shlibSuffix = ".dll";
		m_stlibSuffix = ".lib";
		m_objSuffix = ".obj";
		m_shlibPrefix = "";
	}

	//Set suffixes for POSIX
	else
	{
		m_exeSuffix = "";
		m_shlibSuffix = ".so";
		m_stlibSuffix = ".a";
		m_objSuffix = ".o";
		m_shlibPrefix = "lib";
	}

	//Generate the hash
	//TODO: Anything else to add here?
	m_hash = sha256(m_stringVersion + triplet);
}

GNUCPPToolchain::~GNUCPPToolchain()
{
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Toolchain properties

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Actual operations

bool GNUCPPToolchain::ScanDependencies(
	string arch,
	string path,
	string root,
	set<BuildFlag> flags,
	set<string>& deps,
	map<string, string>& dephashes,
	string& output,
	set<string>& missingFiles)
{
	return GNUToolchain::ScanDependencies(
		m_basepath, arch, path, root, flags, m_defaultIncludePaths[arch], deps, dephashes, output, missingFiles);
}

/**
	@brief Compile stuff
 */
bool GNUCPPToolchain::Build(
	string triplet,
	set<string> sources,
	string fname,
	set<BuildFlag> flags,
	map<string, string>& outputs,
	string& output)
{
	return GNUToolchain::Compile(m_basepath, triplet, sources, fname, flags, outputs, output);
}
<commit_msg>BUGFIX: C++ compler should use C++ include paths<commit_after>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* 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 any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "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 AUTHORS BE HELD 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 "splashcore.h"

using namespace std;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

GNUCPPToolchain::GNUCPPToolchain(string basepath, string triplet)
	: CPPToolchain(basepath, TOOLCHAIN_GNU)
	, GNUToolchain(triplet)
{
	//Get the full compiler version
	m_stringVersion = string("GNU C++") + ShellCommand(basepath + " --version | head -n 1 | cut -d \")\" -f 2");

	//Parse it
	if(3 != sscanf(m_stringVersion.c_str(), "GNU C++ %4d.%4d.%4d",
		&m_majorVersion, &m_minorVersion, &m_patchVersion))
	{
		//TODO: handle this better, don't abort :P
		LogFatal("bad G++ version\n");
	}

	//Some compilers can target other arches if you feed them the right flags.
	//Thanks to @GyrosGeier for this
	string cmd =
		string("/bin/bash -c \"") +
		basepath + " -print-multi-lib | sed -e 's/.*;//' -e 's/@/ -/g' | while read line; do " +
		basepath + " \\$line -print-multiarch; done" +
		string("\"");
	string extra_arches = ShellCommand(cmd);
	vector<string> triplets;
	ParseLines(extra_arches, triplets);
	for(auto t : triplets)
		m_triplets.emplace(t);

	//If no arches found in the last step, fall back to the triplet in the file name
	if(m_triplets.empty())
		m_triplets.emplace(triplet);

	//Look up where this toolchain gets its include files from
	for(auto t : m_triplets)
	{
		vector<string> paths;
		FindDefaultIncludePaths(paths, basepath, true, t);
		m_defaultIncludePaths[t] = paths;
		m_virtualSystemIncludePath[t] =
			"__sysinclude__/" + str_replace(" ", "_", m_stringVersion) + "_" + t;
	}

	//Set suffixes for WINDOWS
	if(triplet.find("mingw") != string::npos)
	{
		m_exeSuffix = ".exe";
		m_shlibSuffix = ".dll";
		m_stlibSuffix = ".lib";
		m_objSuffix = ".obj";
		m_shlibPrefix = "";
	}

	//Set suffixes for POSIX
	else
	{
		m_exeSuffix = "";
		m_shlibSuffix = ".so";
		m_stlibSuffix = ".a";
		m_objSuffix = ".o";
		m_shlibPrefix = "lib";
	}

	//Generate the hash
	//TODO: Anything else to add here?
	m_hash = sha256(m_stringVersion + triplet);
}

GNUCPPToolchain::~GNUCPPToolchain()
{
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Toolchain properties

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Actual operations

bool GNUCPPToolchain::ScanDependencies(
	string arch,
	string path,
	string root,
	set<BuildFlag> flags,
	set<string>& deps,
	map<string, string>& dephashes,
	string& output,
	set<string>& missingFiles)
{
	return GNUToolchain::ScanDependencies(
		m_basepath, arch, path, root, flags, m_defaultIncludePaths[arch], deps, dephashes, output, missingFiles);
}

/**
	@brief Compile stuff
 */
bool GNUCPPToolchain::Build(
	string triplet,
	set<string> sources,
	string fname,
	set<BuildFlag> flags,
	map<string, string>& outputs,
	string& output)
{
	return GNUToolchain::Compile(m_basepath, triplet, sources, fname, flags, outputs, output);
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/video_engine/test/common/fake_encoder.h"
#include "webrtc/video_engine/test/common/frame_generator.h"
#include "webrtc/video_engine/test/common/frame_generator_capturer.h"
#include "webrtc/video_engine/test/common/null_transport.h"
#include "webrtc/video_engine/new_include/call.h"
#include "webrtc/video_engine/new_include/video_send_stream.h"

namespace webrtc {

class SendTransportObserver : public test::NullTransport {
 public:
  explicit SendTransportObserver(unsigned long timeout_ms)
      : rtp_header_parser_(RtpHeaderParser::Create()),
        send_test_complete_(EventWrapper::Create()),
        timeout_ms_(timeout_ms) {}

  EventTypeWrapper Wait() { return send_test_complete_->Wait(timeout_ms_); }

 protected:
  scoped_ptr<RtpHeaderParser> rtp_header_parser_;
  scoped_ptr<EventWrapper> send_test_complete_;

 private:
  unsigned long timeout_ms_;
};

class VideoSendStreamTest : public ::testing::Test {
 public:
  VideoSendStreamTest() : fake_encoder_(Clock::GetRealTimeClock()) {}

 protected:
  static const uint32_t kSendSsrc;
  void RunSendTest(Call* call,
                   const VideoSendStream::Config& config,
                   SendTransportObserver* observer) {
    VideoSendStream* send_stream = call->CreateSendStream(config);
    scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer(
        test::FrameGeneratorCapturer::Create(
            send_stream->Input(),
            test::FrameGenerator::Create(320, 240, Clock::GetRealTimeClock()),
            30));
    send_stream->StartSend();
    frame_generator_capturer->Start();

    EXPECT_EQ(kEventSignaled, observer->Wait());

    frame_generator_capturer->Stop();
    send_stream->StopSend();
    call->DestroySendStream(send_stream);
  }

  VideoSendStream::Config GetSendTestConfig(Call* call) {
    VideoSendStream::Config config = call->GetDefaultSendConfig();
    config.encoder = &fake_encoder_;
    config.internal_source = false;
    test::FakeEncoder::SetCodecSettings(&config.codec, 1);
    return config;
  }

  test::FakeEncoder fake_encoder_;
};

const uint32_t VideoSendStreamTest::kSendSsrc = 0xC0FFEE;

TEST_F(VideoSendStreamTest, SendsSetSsrc) {
  class SendSsrcObserver : public SendTransportObserver {
   public:
    SendSsrcObserver() : SendTransportObserver(30 * 1000) {}

    virtual bool SendRTP(const uint8_t* packet, size_t length) OVERRIDE {
      RTPHeader header;
      EXPECT_TRUE(
          rtp_header_parser_->Parse(packet, static_cast<int>(length), &header));

      if (header.ssrc == kSendSsrc)
        send_test_complete_->Set();

      return true;
    }
  } observer;

  Call::Config call_config(&observer);
  scoped_ptr<Call> call(Call::Create(call_config));

  VideoSendStream::Config send_config = GetSendTestConfig(call.get());
  send_config.rtp.ssrcs.push_back(kSendSsrc);

  RunSendTest(call.get(), send_config, &observer);
}

TEST_F(VideoSendStreamTest, SupportsCName) {
  static std::string kCName = "PjQatC14dGfbVwGPUOA9IH7RlsFDbWl4AhXEiDsBizo=";
  class CNameObserver : public SendTransportObserver {
   public:
    CNameObserver() : SendTransportObserver(30 * 1000) {}

    virtual bool SendRTCP(const uint8_t* packet, size_t length) OVERRIDE {
      RTCPUtility::RTCPParserV2 parser(packet, length, true);
      EXPECT_TRUE(parser.IsValid());

      RTCPUtility::RTCPPacketTypes packet_type = parser.Begin();
      while (packet_type != RTCPUtility::kRtcpNotValidCode) {
        if (packet_type == RTCPUtility::kRtcpSdesChunkCode) {
          EXPECT_EQ(parser.Packet().CName.CName, kCName);
          send_test_complete_->Set();
        }

        packet_type = parser.Iterate();
      }

      return true;
    }
  } observer;

  Call::Config call_config(&observer);
  scoped_ptr<Call> call(Call::Create(call_config));

  VideoSendStream::Config send_config = GetSendTestConfig(call.get());
  send_config.rtp.ssrcs.push_back(kSendSsrc);
  send_config.rtp.c_name = kCName;

  RunSendTest(call.get(), send_config, &observer);
}

}  // namespace webrtc
<commit_msg>Test that VideoSendStream responds to NACK.<commit_after>/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/video_engine/test/common/fake_encoder.h"
#include "webrtc/video_engine/test/common/frame_generator.h"
#include "webrtc/video_engine/test/common/frame_generator_capturer.h"
#include "webrtc/video_engine/test/common/null_transport.h"
#include "webrtc/video_engine/new_include/call.h"
#include "webrtc/video_engine/new_include/video_send_stream.h"

namespace webrtc {

class SendTransportObserver : public test::NullTransport {
 public:
  explicit SendTransportObserver(unsigned long timeout_ms)
      : rtp_header_parser_(RtpHeaderParser::Create()),
        send_test_complete_(EventWrapper::Create()),
        timeout_ms_(timeout_ms) {}

  EventTypeWrapper Wait() { return send_test_complete_->Wait(timeout_ms_); }

 protected:
  scoped_ptr<RtpHeaderParser> rtp_header_parser_;
  scoped_ptr<EventWrapper> send_test_complete_;

 private:
  unsigned long timeout_ms_;
};

class VideoSendStreamTest : public ::testing::Test {
 public:
  VideoSendStreamTest() : fake_encoder_(Clock::GetRealTimeClock()) {}

 protected:
  static const uint32_t kSendSsrc;
  void RunSendTest(Call* call,
                   const VideoSendStream::Config& config,
                   SendTransportObserver* observer) {
    VideoSendStream* send_stream = call->CreateSendStream(config);
    scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer(
        test::FrameGeneratorCapturer::Create(
            send_stream->Input(),
            test::FrameGenerator::Create(320, 240, Clock::GetRealTimeClock()),
            30));
    send_stream->StartSend();
    frame_generator_capturer->Start();

    EXPECT_EQ(kEventSignaled, observer->Wait());

    frame_generator_capturer->Stop();
    send_stream->StopSend();
    call->DestroySendStream(send_stream);
  }

  VideoSendStream::Config GetSendTestConfig(Call* call) {
    VideoSendStream::Config config = call->GetDefaultSendConfig();
    config.encoder = &fake_encoder_;
    config.internal_source = false;
    config.rtp.ssrcs.push_back(kSendSsrc);
    test::FakeEncoder::SetCodecSettings(&config.codec, 1);
    return config;
  }

  test::FakeEncoder fake_encoder_;
};

const uint32_t VideoSendStreamTest::kSendSsrc = 0xC0FFEE;

TEST_F(VideoSendStreamTest, SendsSetSsrc) {
  class SendSsrcObserver : public SendTransportObserver {
   public:
    SendSsrcObserver() : SendTransportObserver(30 * 1000) {}

    virtual bool SendRTP(const uint8_t* packet, size_t length) OVERRIDE {
      RTPHeader header;
      EXPECT_TRUE(
          rtp_header_parser_->Parse(packet, static_cast<int>(length), &header));

      if (header.ssrc == kSendSsrc)
        send_test_complete_->Set();

      return true;
    }
  } observer;

  Call::Config call_config(&observer);
  scoped_ptr<Call> call(Call::Create(call_config));

  VideoSendStream::Config send_config = GetSendTestConfig(call.get());

  RunSendTest(call.get(), send_config, &observer);
}

TEST_F(VideoSendStreamTest, SupportsCName) {
  static std::string kCName = "PjQatC14dGfbVwGPUOA9IH7RlsFDbWl4AhXEiDsBizo=";
  class CNameObserver : public SendTransportObserver {
   public:
    CNameObserver() : SendTransportObserver(30 * 1000) {}

    virtual bool SendRTCP(const uint8_t* packet, size_t length) OVERRIDE {
      RTCPUtility::RTCPParserV2 parser(packet, length, true);
      EXPECT_TRUE(parser.IsValid());

      RTCPUtility::RTCPPacketTypes packet_type = parser.Begin();
      while (packet_type != RTCPUtility::kRtcpNotValidCode) {
        if (packet_type == RTCPUtility::kRtcpSdesChunkCode) {
          EXPECT_EQ(parser.Packet().CName.CName, kCName);
          send_test_complete_->Set();
        }

        packet_type = parser.Iterate();
      }

      return true;
    }
  } observer;

  Call::Config call_config(&observer);
  scoped_ptr<Call> call(Call::Create(call_config));

  VideoSendStream::Config send_config = GetSendTestConfig(call.get());
  send_config.rtp.c_name = kCName;

  RunSendTest(call.get(), send_config, &observer);
}

TEST_F(VideoSendStreamTest, RespondsToNack) {
  class NackObserver : public SendTransportObserver, webrtc::Transport {
   public:
    NackObserver()
        : SendTransportObserver(30 * 1000),
          thread_(ThreadWrapper::CreateThread(NackProcess, this)),
          send_call_receiver_(NULL),
          send_count_(0),
          ssrc_(0),
          nacked_sequence_number_(0) {}

    ~NackObserver() {
      EXPECT_TRUE(thread_->Stop());
    }

    void SetReceiver(PacketReceiver* send_call_receiver) {
      send_call_receiver_ = send_call_receiver;
    }

    // Sending NACKs must be done from a different "network" thread to prevent
    // violating locking orders. With this no locks are held prior to inserting
    // packets back into the sender.
    static bool NackProcess(void* observer) {
      return static_cast<NackObserver*>(observer)->SendNack();
    }

    bool SendNack() {
      NullReceiveStatistics null_stats;
      RTCPSender rtcp_sender(0, false, Clock::GetRealTimeClock(), &null_stats);
      EXPECT_EQ(0, rtcp_sender.RegisterSendTransport(this));

      rtcp_sender.SetRTCPStatus(kRtcpNonCompound);
      rtcp_sender.SetRemoteSSRC(ssrc_);

      RTCPSender::FeedbackState feedback_state;
      EXPECT_EQ(0, rtcp_sender.SendRTCP(
          feedback_state, kRtcpNack, 1, &nacked_sequence_number_));
      return false;
    }

    virtual int SendPacket(int channel, const void* data, int len) OVERRIDE {
      ADD_FAILURE()
          << "This should never be reached. Only a NACK should be sent.";
      return -1;
    }

    virtual int SendRTCPPacket(int channel,
                               const void* data,
                               int len) OVERRIDE {
      EXPECT_TRUE(send_call_receiver_->DeliverPacket(
          static_cast<const uint8_t*>(data), static_cast<size_t>(len)));
      return len;
    }

    virtual bool SendRTP(const uint8_t* packet, size_t length) OVERRIDE {
      EXPECT_TRUE(send_call_receiver_ != NULL);
      RTPHeader header;
      EXPECT_TRUE(
          rtp_header_parser_->Parse(packet, static_cast<int>(length), &header));

      // Nack second packet after receiving the third one.
      if (++send_count_ == 3) {
        ssrc_ = header.ssrc;
        nacked_sequence_number_ = header.sequenceNumber - 1;
        unsigned int id;
        EXPECT_TRUE(thread_->Start(id));
      }

      if (header.sequenceNumber == nacked_sequence_number_)
        send_test_complete_->Set();

      return true;
    }
   private:
    scoped_ptr<ThreadWrapper> thread_;
    PacketReceiver* send_call_receiver_;
    int send_count_;
    uint32_t ssrc_;
    uint16_t nacked_sequence_number_;
  } observer;

  Call::Config call_config(&observer);
  scoped_ptr<Call> call(Call::Create(call_config));
  observer.SetReceiver(call->Receiver());

  VideoSendStream::Config send_config = GetSendTestConfig(call.get());
  send_config.rtp.nack.rtp_history_ms = 1000;

  RunSendTest(call.get(), send_config, &observer);
}

}  // namespace webrtc
<|endoftext|>