Revert 6107 "Adds a modified copy of talk/base to webrtc/base. I..."
This breaks Chromium FYI builds and prevent roll of webrtc/libjingle to Chrome. http://chromegw.corp.google.com/i/chromium.webrtc.fyi/builders/Win%20Builder/builds/457 > Adds a modified copy of talk/base to webrtc/base. It is the first step in migrating talk/base to webrtc/base. > > BUG=N/A > R=andrew@webrtc.org, wu@webrtc.org > > Review URL: https://webrtc-codereview.appspot.com/12199004 TBR=henrike@webrtc.org Review URL: https://webrtc-codereview.appspot.com/14479004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@6116 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
3a5825909d
commit
e9a604accd
@ -180,174 +180,6 @@ name=https://code.google.com/p/webrtc/issues/detail?id=3158 (3)
|
|||||||
KERNEL32.dll!BaseThreadInitThunk
|
KERNEL32.dll!BaseThreadInitThunk
|
||||||
|
|
||||||
# libjingle_unittest, fails on Win DrMemory Full
|
# libjingle_unittest, fails on Win DrMemory Full
|
||||||
UNINITIALIZED READ
|
|
||||||
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (4)
|
|
||||||
*!_towlower_l
|
|
||||||
*!towlower
|
|
||||||
*!tolowercase
|
|
||||||
*!rtc::IsDefaultBrowserFirefox
|
|
||||||
*!rtc::GetProxySettingsForUrl
|
|
||||||
*!rtc::AutoDetectProxy::GetProxyForUrl
|
|
||||||
*!rtc::AutoDetectProxy::DoWork
|
|
||||||
*!rtc::SignalThread::Run
|
|
||||||
*!rtc::SignalThread::Worker::Run
|
|
||||||
*!rtc::Thread::PreRun
|
|
||||||
KERNEL32.dll!BaseThreadInitThunk
|
|
||||||
|
|
||||||
UNADDRESSABLE ACCESS
|
|
||||||
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (12)
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
libjingle_peerconnection_unittes!rtc::CriticalSection::Enter
|
|
||||||
libjingle_peerconnection_unittes!rtc::CritScope::CritScope
|
|
||||||
libjingle_peerconnection_unittes!rtc::LogMessage::~LogMessage
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcVideoEngine::Print
|
|
||||||
libjingle_peerconnection_unittes!webrtc::TraceImpl::WriteToFile
|
|
||||||
libjingle_peerconnection_unittes!webrtc::TraceImpl::Process
|
|
||||||
libjingle_peerconnection_unittes!webrtc::TraceImpl::Run
|
|
||||||
libjingle_peerconnection_unittes!webrtc::ThreadWindows::Run
|
|
||||||
libjingle_peerconnection_unittes!webrtc::ThreadWindows::StartThread
|
|
||||||
libjingle_peerconnection_unittes!_callthreadstartex
|
|
||||||
libjingle_peerconnection_unittes!_threadstartex
|
|
||||||
KERNEL32.dll!BaseThreadInitThunk
|
|
||||||
|
|
||||||
UNADDRESSABLE ACCESS
|
|
||||||
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (14)
|
|
||||||
libjingle_peerconnection_unittes!std::list<>::begin
|
|
||||||
libjingle_peerconnection_unittes!rtc::LogMessage::~LogMessage
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcVideoEngine::Construct
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcVideoEngine::WebRtcVideoEngine
|
|
||||||
libjingle_peerconnection_unittes!cricket::CompositeMediaEngine<>::CompositeMediaEngine<>
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcMediaEngine::WebRtcMediaEngine
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::Initialize_s
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::OnMessage
|
|
||||||
libjingle_peerconnection_unittes!rtc::Thread::Send
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::Initialize
|
|
||||||
libjingle_peerconnection_unittes!webrtc::CreatePeerConnectionFactory
|
|
||||||
libjingle_peerconnection_unittes!PeerConnectionInterfaceTest::SetUp
|
|
||||||
libjingle_peerconnection_unittes!testing::internal::HandleSehExceptionsInMethodIfSupported<>
|
|
||||||
|
|
||||||
UNADDRESSABLE ACCESS
|
|
||||||
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (15)
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
libjingle_peerconnection_unittes!rtc::CriticalSection::Enter
|
|
||||||
libjingle_peerconnection_unittes!rtc::CritScope::CritScope
|
|
||||||
libjingle_peerconnection_unittes!rtc::LogMessage::~LogMessage
|
|
||||||
libjingle_peerconnection_unittes!TestInvalidParameterHandler
|
|
||||||
libjingle_peerconnection_unittes!_invalid_parameter
|
|
||||||
...
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcVideoEngine::Construct
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcVideoEngine::WebRtcVideoEngine
|
|
||||||
libjingle_peerconnection_unittes!cricket::CompositeMediaEngine<>::CompositeMediaEngine<>
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcMediaEngine::WebRtcMediaEngine
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::Initialize_s
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::OnMessage
|
|
||||||
libjingle_peerconnection_unittes!rtc::Thread::Send
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::Initialize
|
|
||||||
libjingle_peerconnection_unittes!webrtc::CreatePeerConnectionFactory
|
|
||||||
libjingle_peerconnection_unittes!PeerConnectionInterfaceTest::SetUp
|
|
||||||
libjingle_peerconnection_unittes!testing::internal::HandleSehExceptionsInMethodIfSupported<>
|
|
||||||
|
|
||||||
UNADDRESSABLE ACCESS
|
|
||||||
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (16)
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
libjingle_peerconnection_unittes!rtc::CriticalSection::Enter
|
|
||||||
libjingle_peerconnection_unittes!rtc::CritScope::CritScope
|
|
||||||
libjingle_peerconnection_unittes!rtc::LogMessage::~LogMessage
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcVoiceEngine::ConstructCodecs
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcVoiceEngine::Construct
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcVoiceEngine::WebRtcVoiceEngine
|
|
||||||
libjingle_peerconnection_unittes!cricket::CompositeMediaEngine<>::CompositeMediaEngine<>
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcMediaEngine::WebRtcMediaEngine
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::Initialize_s
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::OnMessage
|
|
||||||
libjingle_peerconnection_unittes!rtc::Thread::Send
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::Initialize
|
|
||||||
libjingle_peerconnection_unittes!webrtc::CreatePeerConnectionFactory
|
|
||||||
libjingle_peerconnection_unittes!PeerConnectionInterfaceTest::SetUp
|
|
||||||
libjingle_peerconnection_unittes!testing::internal::HandleSehExceptionsInMethodIfSupported<>
|
|
||||||
|
|
||||||
UNADDRESSABLE ACCESS
|
|
||||||
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (32)
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
libjingle_peerconnection_unittes!rtc::CriticalSection::Enter
|
|
||||||
libjingle_peerconnection_unittes!rtc::CritScope::CritScope
|
|
||||||
...
|
|
||||||
libjingle_peerconnection_unittes!testing::internal::CountIf<>
|
|
||||||
libjingle_peerconnection_unittes!testing::TestResult::HasFatalFailure
|
|
||||||
libjingle_peerconnection_unittes!testing::Test::HasFatalFailure
|
|
||||||
libjingle_peerconnection_unittes!testing::Test::Run
|
|
||||||
|
|
||||||
UNADDRESSABLE ACCESS
|
|
||||||
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (34)
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
libjingle_peerconnection_unittes!rtc::CriticalSection::Enter
|
|
||||||
libjingle_peerconnection_unittes!rtc::CritScope::CritScope
|
|
||||||
...
|
|
||||||
libjingle_peerconnection_unittes!TestPureCallHandler
|
|
||||||
libjingle_peerconnection_unittes!_purecall
|
|
||||||
libjingle_peerconnection_unittes!testing::internal::DefaultGlobalTestPartResultReporter::ReportTestPartResult
|
|
||||||
libjingle_peerconnection_unittes!testing::internal::DefaultPerThreadTestPartResultReporter::ReportTestPartResult
|
|
||||||
libjingle_peerconnection_unittes!testing::UnitTest::AddTestPartResult
|
|
||||||
libjingle_peerconnection_unittes!testing::internal::ReportFailureInUnknownLocation
|
|
||||||
libjingle_peerconnection_unittes!testing::internal::HandleSehExceptionsInMethodIfSupported<>
|
|
||||||
|
|
||||||
HANDLE LEAK
|
|
||||||
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (35)
|
|
||||||
system call NtCreateEvent
|
|
||||||
KERNELBASE.dll!CreateEventExW
|
|
||||||
KERNELBASE.dll!CreateEventW
|
|
||||||
libjingle_peerconnection_unittes!webrtc::EventWindows::EventWindows
|
|
||||||
libjingle_peerconnection_unittes!webrtc::EventWrapper::Create
|
|
||||||
libjingle_peerconnection_unittes!webrtc::ProcessThreadImpl::ProcessThreadImpl
|
|
||||||
libjingle_peerconnection_unittes!webrtc::ProcessThread::CreateProcessThread
|
|
||||||
libjingle_peerconnection_unittes!webrtc::voe::SharedData::SharedData
|
|
||||||
libjingle_peerconnection_unittes!webrtc::VoiceEngineImpl::VoiceEngineImpl
|
|
||||||
libjingle_peerconnection_unittes!webrtc::GetVoiceEngine
|
|
||||||
libjingle_peerconnection_unittes!webrtc::VoiceEngine::Create
|
|
||||||
libjingle_peerconnection_unittes!cricket::VoEWrapper::VoEWrapper
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcVoiceEngine::WebRtcVoiceEngine
|
|
||||||
libjingle_peerconnection_unittes!cricket::CompositeMediaEngine<>::CompositeMediaEngine<>
|
|
||||||
libjingle_peerconnection_unittes!cricket::WebRtcMediaEngine::WebRtcMediaEngine
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::Initialize_s
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::OnMessage
|
|
||||||
libjingle_peerconnection_unittes!rtc::Thread::Send
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionFactory::Initialize
|
|
||||||
libjingle_peerconnection_unittes!webrtc::CreatePeerConnectionFactory
|
|
||||||
libjingle_peerconnection_unittes!PeerConnectionInterfaceTest::SetUp
|
|
||||||
libjingle_peerconnection_unittes!testing::internal::HandleSehExceptionsInMethodIfSupported<>
|
|
||||||
|
|
||||||
UNINITIALIZED READ
|
|
||||||
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (36)
|
|
||||||
libjingle_peerconnection_unittes!webrtc::WebRtcSessionDescriptionFactory::InternalCreateAnswer
|
|
||||||
libjingle_peerconnection_unittes!webrtc::WebRtcSessionDescriptionFactory::CreateAnswer
|
|
||||||
libjingle_peerconnection_unittes!webrtc::WebRtcSession::CreateAnswer
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnection::CreateAnswer
|
|
||||||
libjingle_peerconnection_unittes!webrtc::ReturnType<>::Invoke<>
|
|
||||||
libjingle_peerconnection_unittes!webrtc::MethodCall2<>::OnMessage
|
|
||||||
libjingle_peerconnection_unittes!rtc::Thread::Send
|
|
||||||
libjingle_peerconnection_unittes!webrtc::MethodCall2<>::Marshal
|
|
||||||
libjingle_peerconnection_unittes!webrtc::PeerConnectionProxy::CreateAnswer
|
|
||||||
libjingle_peerconnection_unittes!PeerConnectionInterfaceTest::DoCreateOfferAnswer
|
|
||||||
libjingle_peerconnection_unittes!PeerConnectionInterfaceTest::DoCreateAnswer
|
|
||||||
libjingle_peerconnection_unittes!PeerConnectionInterfaceTest::CreateAnswerAsLocalDescription
|
|
||||||
libjingle_peerconnection_unittes!PeerConnectionInterfaceTest_ReceiveOfferCreatePrAnswerAndAnswer_Test::TestBody
|
|
||||||
libjingle_peerconnection_unittes!testing::internal::HandleSehExceptionsInMethodIfSupported<>
|
|
||||||
|
|
||||||
UNADDRESSABLE ACCESS
|
|
||||||
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (37)
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
ntdll.dll!RtlIntegerToUnicodeString
|
|
||||||
libjingle_peerconnection_unittes!rtc::CriticalSection::Enter
|
|
||||||
libjingle_peerconnection_unittes!rtc::CritScope::CritScope
|
|
||||||
libjingle_peerconnection_unittes!rtc::LogMessage::GetLogToStream
|
|
||||||
libjingle_peerconnection_unittes!rtc::LogMessage::ConfigureLogging
|
|
||||||
libjingle_peerconnection_unittes!main
|
|
||||||
|
|
||||||
UNINITIALIZED READ
|
UNINITIALIZED READ
|
||||||
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (4)
|
name=https://code.google.com/p/webrtc/issues/detail?id=3158 (4)
|
||||||
*!_towlower_l
|
*!_towlower_l
|
||||||
|
@ -9,102 +9,6 @@
|
|||||||
#-----------------------------------------------------------------------
|
#-----------------------------------------------------------------------
|
||||||
|
|
||||||
# 1. webrtc stuff
|
# 1. webrtc stuff
|
||||||
{
|
|
||||||
bug_1976_1
|
|
||||||
Memcheck:Unaddressable
|
|
||||||
fun:pthread_mutex_unlock
|
|
||||||
fun:_ZN9rtc15CriticalSection5LeaveEv
|
|
||||||
fun:_ZN9rtc9CritScopeD1Ev
|
|
||||||
...
|
|
||||||
fun:_ZN9rtc6Thread15ProcessMessagesEi
|
|
||||||
fun:_ZN9rtc6Thread3RunEv
|
|
||||||
fun:_ZN9rtc6Thread6PreRunEPv
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_1976_2
|
|
||||||
Memcheck:Leak
|
|
||||||
fun:calloc
|
|
||||||
obj:/usr/lib/x86_64-linux-gnu/libnss3.so
|
|
||||||
...
|
|
||||||
fun:NSS_NoDB_Init
|
|
||||||
fun:_ZN9rtc10NSSContext13InitializeSSLEPFbPvE
|
|
||||||
fun:_ZN9rtc13InitializeSSLEPFbPvE
|
|
||||||
fun:_ZN9rtc10RandomTest13SetUpTestCaseEv
|
|
||||||
fun:_ZN7testing8TestCase16RunSetUpTestCaseEv
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2100_3
|
|
||||||
Memcheck:Uninitialized
|
|
||||||
fun:tls1_enc
|
|
||||||
fun:ssl3_get_record
|
|
||||||
fun:ssl3_read_bytes
|
|
||||||
fun:ssl3_read_internal
|
|
||||||
fun:ssl3_read
|
|
||||||
fun:SSL_read
|
|
||||||
fun:_ZN9rtc20OpenSSLStreamAdapter4ReadEPvmPmPi
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2100_4
|
|
||||||
Memcheck:Uninitialized
|
|
||||||
fun:_ZN7testing8internal11CmpHelperEQIjhEENS_15AssertionResultEPKcS4_RKT_RKT0_
|
|
||||||
fun:_ZN7testing8internal8EqHelperILb0EE7CompareIjhEENS_15AssertionResultEPKcS6_RKT_RKT0_
|
|
||||||
fun:_ZN24SSLStreamAdapterTestDTLS8ReadDataEPN9rtc15StreamInterfaceE
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2100_5
|
|
||||||
Memcheck:Uninitialized
|
|
||||||
fun:dtls1_process_record
|
|
||||||
fun:dtls1_get_record
|
|
||||||
fun:dtls1_read_bytes
|
|
||||||
fun:ssl3_read_internal
|
|
||||||
fun:ssl3_read
|
|
||||||
fun:SSL_read
|
|
||||||
fun:_ZN9rtc20OpenSSLStreamAdapter4ReadEPvmPmPi
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
BIO_new_mem_buf_1
|
|
||||||
Memcheck:Leak
|
|
||||||
fun:malloc
|
|
||||||
fun:default_malloc_ex
|
|
||||||
fun:CRYPTO_malloc
|
|
||||||
fun:BUF_MEM_new
|
|
||||||
fun:mem_new
|
|
||||||
fun:BIO_set
|
|
||||||
fun:BIO_new
|
|
||||||
fun:BIO_new_mem_buf
|
|
||||||
fun:_ZN9rtc18OpenSSLCertificate13FromPEMStringERKSs
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
BIO_new_mem_buf_2
|
|
||||||
Memcheck:Leak
|
|
||||||
fun:malloc
|
|
||||||
fun:default_malloc_ex
|
|
||||||
fun:CRYPTO_malloc
|
|
||||||
fun:BUF_MEM_new
|
|
||||||
fun:mem_new
|
|
||||||
fun:BIO_set
|
|
||||||
fun:BIO_new
|
|
||||||
fun:BIO_new_mem_buf
|
|
||||||
fun:_ZN9rtc15OpenSSLIdentity14FromPEMStringsERKSsS2_
|
|
||||||
}
|
|
||||||
{
|
|
||||||
SignalsCloseAfterForcedCloseAll
|
|
||||||
Memcheck:Leak
|
|
||||||
fun:_Znw*
|
|
||||||
fun:_ZN9rtc10HttpServer10Connection12BeginProcessEPNS_15StreamInterfaceE
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
DoNotDeleteTask2
|
|
||||||
Memcheck:Leak
|
|
||||||
fun:_Znw*
|
|
||||||
...
|
|
||||||
fun:_ZN9rtc41unstarted_task_test_DoNotDeleteTask2_Test8TestBodyEv
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
bug_716
|
bug_716
|
||||||
Memcheck:Leak
|
Memcheck:Leak
|
||||||
|
@ -9,473 +9,6 @@
|
|||||||
#-----------------------------------------------------------------------
|
#-----------------------------------------------------------------------
|
||||||
|
|
||||||
# 1. webrtc stuff
|
# 1. webrtc stuff
|
||||||
{
|
|
||||||
bug_1205_33
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:webrtc::PeerConnectionProxy::~PeerConnectionProxy
|
|
||||||
fun:rtc::RefCountedObject::~RefCountedObject
|
|
||||||
fun:rtc::RefCountedObject::~RefCountedObject
|
|
||||||
fun:rtc::RefCountedObject::Release
|
|
||||||
fun:rtc::scoped_refptr::~scoped_refptr
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_1205_34
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::AtomicOps::Increment
|
|
||||||
fun:rtc::RefCountedObject::AddRef
|
|
||||||
fun:rtc::scoped_refptr::scoped_refptr
|
|
||||||
fun:webrtc::PeerConnectionFactory::CreatePeerConnection
|
|
||||||
fun:webrtc::PeerConnectionFactory::CreatePeerConnection
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_1205_35
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::scoped_refptr::scoped_refptr
|
|
||||||
fun:webrtc::PeerConnectionFactory::CreatePeerConnection
|
|
||||||
fun:webrtc::PeerConnectionFactory::CreatePeerConnection
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_1205_36
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::MessageHandler::~MessageHandler
|
|
||||||
fun:FakeAudioCaptureModule::~FakeAudioCaptureModule
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_1205_39
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::Thread::Send
|
|
||||||
fun:FakeAudioCaptureModule::UpdateProcessing
|
|
||||||
fun:FakeAudioCaptureModule::StopRecording
|
|
||||||
fun:webrtc::VoEBaseImpl::StopSend
|
|
||||||
fun:webrtc::VoEBaseImpl::DeleteChannel
|
|
||||||
fun:cricket::WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_1205_41
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::Thread::Send
|
|
||||||
fun:FakeAudioCaptureModule::~FakeAudioCaptureModule
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_2
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
...
|
|
||||||
fun:rtc::MemoryStreamBase::Read
|
|
||||||
...
|
|
||||||
fun:cricket::RtpDumpReader::ReadPacket
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_3
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:cricket::RtpSenderReceiver::OnMessage
|
|
||||||
fun:rtc::MessageQueue::Dispatch
|
|
||||||
fun:rtc::Thread::ProcessMessages
|
|
||||||
fun:rtc::Thread::Run
|
|
||||||
fun:rtc::Thread::PreRun
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_4
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:cricket::FileNetworkInterface::SendPacket
|
|
||||||
fun:cricket::RtpSenderReceiver::SendRtpPacket
|
|
||||||
fun:cricket::RtpSenderReceiver::OnMessage
|
|
||||||
fun:rtc::MessageQueue::Dispatch
|
|
||||||
fun:rtc::Thread::ProcessMessages
|
|
||||||
fun:rtc::Thread::Run
|
|
||||||
fun:rtc::Thread::PreRun
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_7
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::MemoryStreamBase::~MemoryStreamBase
|
|
||||||
fun:rtc::MemoryStream::~MemoryStream
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_8
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::MemoryStreamBase::SetPosition
|
|
||||||
fun:rtc::StreamInterface::Rewind
|
|
||||||
fun:cricket::RtpTestUtility::VerifyTestPacketsFromStream
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_13
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:std::_Vector_base::~_Vector_base
|
|
||||||
fun:std::vector::~vector
|
|
||||||
fun:cricket::RtpDumpPacket::~RtpDumpPacket
|
|
||||||
fun:cricket::RtpSenderReceiver::~RtpSenderReceiver
|
|
||||||
fun:cricket::RtpSenderReceiver::~RtpSenderReceiver
|
|
||||||
fun:rtc::scoped_ptr::~scoped_ptr
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_14
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:cricket::RtpDumpReader::~RtpDumpReader
|
|
||||||
fun:cricket::RtpDumpLoopReader::~RtpDumpLoopReader
|
|
||||||
fun:cricket::RtpDumpLoopReader::~RtpDumpLoopReader
|
|
||||||
fun:rtc::scoped_ptr::~scoped_ptr
|
|
||||||
fun:cricket::RtpSenderReceiver::~RtpSenderReceiver
|
|
||||||
fun:cricket::RtpSenderReceiver::~RtpSenderReceiver
|
|
||||||
fun:rtc::scoped_ptr::~scoped_ptr
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_15
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::FileStream::Close
|
|
||||||
fun:rtc::FileStream::~FileStream
|
|
||||||
fun:rtc::FileStream::~FileStream
|
|
||||||
fun:rtc::scoped_ptr::~scoped_ptr
|
|
||||||
fun:cricket::RtpSenderReceiver::~RtpSenderReceiver
|
|
||||||
fun:cricket::RtpSenderReceiver::~RtpSenderReceiver
|
|
||||||
fun:rtc::scoped_ptr::~scoped_ptr
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_16
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::StreamInterface::~StreamInterface
|
|
||||||
fun:rtc::FileStream::~FileStream
|
|
||||||
fun:rtc::FileStream::~FileStream
|
|
||||||
fun:rtc::scoped_ptr::~scoped_ptr
|
|
||||||
fun:cricket::RtpSenderReceiver::~RtpSenderReceiver
|
|
||||||
fun:cricket::RtpSenderReceiver::~RtpSenderReceiver
|
|
||||||
fun:rtc::scoped_ptr::~scoped_ptr
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_18
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::MemoryStream::~MemoryStream
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_22
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::MessageQueue::Quit
|
|
||||||
fun:rtc::Thread::Stop
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_23
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:::FileVideoCapturerTest::VideoCapturerListener::OnFrameCaptured
|
|
||||||
fun:sigslot::_connection2::emit
|
|
||||||
...
|
|
||||||
fun:cricket::FileVideoCapturer::ReadFrame
|
|
||||||
fun:cricket::FileVideoCapturer::FileReadThread::OnMessage
|
|
||||||
fun:rtc::MessageQueue::Dispatch
|
|
||||||
fun:rtc::Thread::ProcessMessages
|
|
||||||
fun:rtc::Thread::Run
|
|
||||||
fun:cricket::FileVideoCapturer::FileReadThread::Run
|
|
||||||
fun:rtc::Thread::PreRun
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_24
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::MemoryStreamBase::SetPosition
|
|
||||||
fun:rtc::StreamInterface::Rewind
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2078_25
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:cricket::FileNetworkInterface::SendPacket
|
|
||||||
fun:cricket::MediaChannel::DoSendPacket
|
|
||||||
fun:cricket::MediaChannel::SendPacket
|
|
||||||
fun:cricket::RtpSenderReceiver::SendRtpPacket
|
|
||||||
fun:cricket::RtpSenderReceiver::OnMessage
|
|
||||||
fun:rtc::MessageQueue::Dispatch
|
|
||||||
fun:rtc::Thread::ProcessMessages
|
|
||||||
fun:rtc::Thread::Run
|
|
||||||
fun:rtc::Thread::PreRun
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2079_1
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::VirtualSocketServer::AddPacketToNetwork
|
|
||||||
fun:rtc::VirtualSocketServer::SendUdp
|
|
||||||
fun:rtc::VirtualSocket::SendUdp
|
|
||||||
fun:rtc::VirtualSocket::SendTo
|
|
||||||
fun:rtc::AsyncUDPSocket::SendTo
|
|
||||||
fun:cricket::StunServer::SendResponse
|
|
||||||
fun:cricket::StunServer::OnBindingRequest
|
|
||||||
fun:cricket::StunServer::OnPacket
|
|
||||||
fun:sigslot::_connection4::emit
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2079_5
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::Thread::Send
|
|
||||||
fun:cricket::Transport::SetRole
|
|
||||||
fun:cricket::BaseSession::GetOrCreateTransportProxy
|
|
||||||
fun:cricket::BaseSession::CreateChannel
|
|
||||||
fun:cricket::FakeSession::CreateChannel
|
|
||||||
fun:cricket::VoiceChannel::Init
|
|
||||||
fun:cricket::ChannelManager::CreateVoiceChannel_w
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2079_6
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::Thread::ReceiveSends
|
|
||||||
fun:rtc::Thread::Send
|
|
||||||
fun:rtc::Thread::Invoke
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2079_8
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::Thread::Invoke
|
|
||||||
fun:cricket::ChannelManager::SetCaptureDevice
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2079_9
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::Thread::Send
|
|
||||||
fun:cricket::Transport::SetIceRole
|
|
||||||
fun:cricket::BaseSession::GetOrCreateTransportProxy
|
|
||||||
fun:cricket::BaseSession::CreateChannel
|
|
||||||
fun:cricket::FakeSession::CreateChannel
|
|
||||||
fun:cricket::VoiceChannel::Init
|
|
||||||
fun:cricket::ChannelManager::CreateVoiceChannel_w
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_1
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::MessageQueue::Quit
|
|
||||||
fun:rtc::SignalThread::Destroy
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_2
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::MessageQueue::Quit
|
|
||||||
fun:rtc::AsyncHttpRequest::OnComplete
|
|
||||||
fun:sigslot::_connection2::emit
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_3
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::LogMessage::UpdateMinLogSeverity
|
|
||||||
fun:rtc::LogMessage::AddLogToStream
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_8
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
...
|
|
||||||
fun:rtc::AsyncUDPSocket::OnReadEvent
|
|
||||||
fun:sigslot::_connection1::emit
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_9
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
...
|
|
||||||
fun:rtc::AsyncUDPSocket::OnWriteEvent
|
|
||||||
fun:sigslot::_connection1::emit
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_14
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::IPAddress::IPAddress
|
|
||||||
fun:rtc::SocketAddress::ToSockAddrStorage
|
|
||||||
fun:rtc::PhysicalSocket::SendTo
|
|
||||||
fun:rtc::AsyncUDPSocket::SendTo
|
|
||||||
fun:rtc::NATServer::OnExternalPacket
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_16
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
...
|
|
||||||
fun:rtc::IPAddress::operator<
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_18
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::SocketAddress::port
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_19
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:std::vector::_M_insert_aux
|
|
||||||
fun:std::vector::push_back
|
|
||||||
fun:rtc::TestClient::OnPacket
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_20
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::VirtualSocketServer::AddPacketToNetwork
|
|
||||||
fun:rtc::VirtualSocketServer::SendUdp
|
|
||||||
fun:rtc::VirtualSocket::SendUdp
|
|
||||||
fun:rtc::VirtualSocket::SendTo
|
|
||||||
fun:rtc::AsyncUDPSocket::SendTo
|
|
||||||
fun:rtc::TestClient::SendTo
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_21
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::SharedExclusiveTask::waiting_time_in_ms
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_22
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::SharedExclusiveTask::~SharedExclusiveTask
|
|
||||||
fun:rtc::ReadTask::~ReadTask
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_24
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
...
|
|
||||||
fun:OwnerThread::Run
|
|
||||||
fun:rtc::Thread::PreRun
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_25
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:sigslot::has_slots::~has_slots
|
|
||||||
fun:OwnerThread::~OwnerThread
|
|
||||||
fun:OwnerThread::~OwnerThread
|
|
||||||
fun:rtc::scoped_ptr::~scoped_ptr
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_27
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
...
|
|
||||||
fun:std::_Rb_tree::clear
|
|
||||||
fun:std::_Rb_tree::_M_erase_aux
|
|
||||||
fun:std::_Rb_tree::erase
|
|
||||||
fun:std::set::erase
|
|
||||||
fun:sigslot::has_slots::disconnect_all
|
|
||||||
fun:sigslot::has_slots::~has_slots
|
|
||||||
fun:OwnerThread::~OwnerThread
|
|
||||||
fun:OwnerThread::~OwnerThread
|
|
||||||
fun:rtc::scoped_ptr::~scoped_ptr
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_29
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::Thread::Release
|
|
||||||
fun:ThreadTest_Release_Test::TestBody
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_30
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::Thread::Invoke
|
|
||||||
fun:MessageQueueTest::IsLocked
|
|
||||||
fun:DeletedLockChecker::~DeletedLockChecker
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_31
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::MessageHandler::~MessageHandler
|
|
||||||
fun:rtc::Thread::FunctorMessageHandler::~FunctorMessageHandler
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_32
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::ReadTask::OnMessage
|
|
||||||
fun:rtc::MessageQueue::Dispatch
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_33
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::SharedExclusiveLockTest_TestSharedShared_Test::TestBody
|
|
||||||
fun:testing::internal::HandleSehExceptionsInMethodIfSupported
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_34
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
fun:rtc::WriteTask::OnMessage
|
|
||||||
fun:rtc::MessageQueue::Dispatch
|
|
||||||
fun:rtc::Thread::ProcessMessages
|
|
||||||
fun:rtc::Thread::Run
|
|
||||||
fun:rtc::Thread::PreRun
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_35
|
|
||||||
ThreadSanitizer:UnlockNonLocked
|
|
||||||
fun:pthread_mutex_unlock
|
|
||||||
fun:rtc::CriticalSection::Leave
|
|
||||||
fun:rtc::CritScope::~CritScope
|
|
||||||
...
|
|
||||||
fun:rtc::AsyncFunctorMessageHandler::OnMessage
|
|
||||||
fun:rtc::MessageQueue::Dispatch
|
|
||||||
fun:rtc::Thread::ProcessMessages
|
|
||||||
fun:rtc::Thread::Run
|
|
||||||
fun:rtc::Thread::PreRun
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2080_36
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
...
|
|
||||||
fun:rtc::FunctorMessageHandler::OnMessage
|
|
||||||
fun:rtc::MessageQueue::Dispatch
|
|
||||||
fun:rtc::Thread::ProcessMessages
|
|
||||||
fun:rtc::Thread::Run
|
|
||||||
fun:rtc::Thread::PreRun
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2931_1
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
...
|
|
||||||
fun:rtc::FireAndForgetAsyncClosure::Execute
|
|
||||||
fun:rtc::AsyncInvoker::OnMessage
|
|
||||||
fun:rtc::MessageQueue::Dispatch
|
|
||||||
fun:rtc::Thread::ProcessMessages
|
|
||||||
fun:rtc::Thread::Run
|
|
||||||
fun:rtc::Thread::PreRun
|
|
||||||
}
|
|
||||||
{
|
|
||||||
bug_2931_2
|
|
||||||
ThreadSanitizer:Race
|
|
||||||
...
|
|
||||||
fun:rtc::Callback0::HelperImpl::~HelperImpl
|
|
||||||
fun:rtc::RefCountedObject::~RefCountedObject
|
|
||||||
fun:rtc::RefCountedObject::~RefCountedObject
|
|
||||||
fun:rtc::RefCountedObject::Release
|
|
||||||
fun:rtc::scoped_refptr::~scoped_refptr
|
|
||||||
fun:rtc::Callback0::~Callback0
|
|
||||||
fun:rtc::FireAndForgetAsyncClosure::~FireAndForgetAsyncClosure
|
|
||||||
fun:rtc::RefCountedObject::~RefCountedObject
|
|
||||||
fun:rtc::RefCountedObject::~RefCountedObject
|
|
||||||
fun:rtc::RefCountedObject::Release
|
|
||||||
fun:rtc::scoped_refptr::~scoped_refptr
|
|
||||||
fun:rtc::AsyncInvoker::OnMessage
|
|
||||||
fun:rtc::MessageQueue::Dispatch
|
|
||||||
fun:rtc::Thread::ProcessMessages
|
|
||||||
fun:AsyncInvokeTest_WithCallback_Test::TestBody
|
|
||||||
...
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
bug_300
|
bug_300
|
||||||
ThreadSanitizer:Race
|
ThreadSanitizer:Race
|
||||||
|
@ -13,9 +13,6 @@ race:webrtc/modules/audio_processing/aec/aec_rdft.c
|
|||||||
|
|
||||||
# libjingle_p2p_unittest
|
# libjingle_p2p_unittest
|
||||||
# See https://code.google.com/p/webrtc/issues/detail?id=2079
|
# See https://code.google.com/p/webrtc/issues/detail?id=2079
|
||||||
race:webrtc/base/messagequeue.cc
|
|
||||||
race:webrtc/base/testclient.cc
|
|
||||||
race:webrtc/base/virtualsocketserver.cc
|
|
||||||
race:talk/base/messagequeue.cc
|
race:talk/base/messagequeue.cc
|
||||||
race:talk/base/testclient.cc
|
race:talk/base/testclient.cc
|
||||||
race:talk/base/virtualsocketserver.cc
|
race:talk/base/virtualsocketserver.cc
|
||||||
@ -23,10 +20,6 @@ race:talk/p2p/base/stunserver_unittest.cc
|
|||||||
|
|
||||||
# libjingle_unittest
|
# libjingle_unittest
|
||||||
# See https://code.google.com/p/webrtc/issues/detail?id=2080
|
# See https://code.google.com/p/webrtc/issues/detail?id=2080
|
||||||
race:webrtc/base/logging.cc
|
|
||||||
race:webrtc/base/sharedexclusivelock_unittest.cc
|
|
||||||
race:webrtc/base/signalthread_unittest.cc
|
|
||||||
race:webrtc/base/thread.cc
|
|
||||||
race:talk/base/logging.cc
|
race:talk/base/logging.cc
|
||||||
race:talk/base/sharedexclusivelock_unittest.cc
|
race:talk/base/sharedexclusivelock_unittest.cc
|
||||||
race:talk/base/signalthread_unittest.cc
|
race:talk/base/signalthread_unittest.cc
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 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 "webrtc/base/asyncfile.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
AsyncFile::AsyncFile() {
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncFile::~AsyncFile() {
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_ASYNCFILE_H__
|
|
||||||
#define WEBRTC_BASE_ASYNCFILE_H__
|
|
||||||
|
|
||||||
#include "webrtc/base/sigslot.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Provides the ability to perform file I/O asynchronously.
|
|
||||||
// TODO: Create a common base class with AsyncSocket.
|
|
||||||
class AsyncFile {
|
|
||||||
public:
|
|
||||||
AsyncFile();
|
|
||||||
virtual ~AsyncFile();
|
|
||||||
|
|
||||||
// Determines whether the file will receive read events.
|
|
||||||
virtual bool readable() = 0;
|
|
||||||
virtual void set_readable(bool value) = 0;
|
|
||||||
|
|
||||||
// Determines whether the file will receive write events.
|
|
||||||
virtual bool writable() = 0;
|
|
||||||
virtual void set_writable(bool value) = 0;
|
|
||||||
|
|
||||||
sigslot::signal1<AsyncFile*> SignalReadEvent;
|
|
||||||
sigslot::signal1<AsyncFile*> SignalWriteEvent;
|
|
||||||
sigslot::signal2<AsyncFile*, int> SignalCloseEvent;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_ASYNCFILE_H__
|
|
@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/asynchttprequest.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
enum {
|
|
||||||
MSG_TIMEOUT = SignalThread::ST_MSG_FIRST_AVAILABLE,
|
|
||||||
MSG_LAUNCH_REQUEST
|
|
||||||
};
|
|
||||||
static const int kDefaultHTTPTimeout = 30 * 1000; // 30 sec
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// AsyncHttpRequest
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
AsyncHttpRequest::AsyncHttpRequest(const std::string &user_agent)
|
|
||||||
: start_delay_(0),
|
|
||||||
firewall_(NULL),
|
|
||||||
port_(80),
|
|
||||||
secure_(false),
|
|
||||||
timeout_(kDefaultHTTPTimeout),
|
|
||||||
fail_redirect_(false),
|
|
||||||
factory_(Thread::Current()->socketserver(), user_agent),
|
|
||||||
pool_(&factory_),
|
|
||||||
client_(user_agent.c_str(), &pool_),
|
|
||||||
error_(HE_NONE) {
|
|
||||||
client_.SignalHttpClientComplete.connect(this,
|
|
||||||
&AsyncHttpRequest::OnComplete);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncHttpRequest::~AsyncHttpRequest() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncHttpRequest::OnWorkStart() {
|
|
||||||
if (start_delay_ <= 0) {
|
|
||||||
LaunchRequest();
|
|
||||||
} else {
|
|
||||||
Thread::Current()->PostDelayed(start_delay_, this, MSG_LAUNCH_REQUEST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncHttpRequest::OnWorkStop() {
|
|
||||||
// worker is already quitting, no need to explicitly quit
|
|
||||||
LOG(LS_INFO) << "HttpRequest cancelled";
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncHttpRequest::OnComplete(HttpClient* client, HttpErrorType error) {
|
|
||||||
Thread::Current()->Clear(this, MSG_TIMEOUT);
|
|
||||||
|
|
||||||
set_error(error);
|
|
||||||
if (!error) {
|
|
||||||
LOG(LS_INFO) << "HttpRequest completed successfully";
|
|
||||||
|
|
||||||
std::string value;
|
|
||||||
if (client_.response().hasHeader(HH_LOCATION, &value)) {
|
|
||||||
response_redirect_ = value.c_str();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(LS_INFO) << "HttpRequest completed with error: " << error;
|
|
||||||
}
|
|
||||||
|
|
||||||
worker()->Quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncHttpRequest::OnMessage(Message* message) {
|
|
||||||
switch (message->message_id) {
|
|
||||||
case MSG_TIMEOUT:
|
|
||||||
LOG(LS_INFO) << "HttpRequest timed out";
|
|
||||||
client_.reset();
|
|
||||||
worker()->Quit();
|
|
||||||
break;
|
|
||||||
case MSG_LAUNCH_REQUEST:
|
|
||||||
LaunchRequest();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SignalThread::OnMessage(message);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncHttpRequest::DoWork() {
|
|
||||||
// Do nothing while we wait for the request to finish. We only do this so
|
|
||||||
// that we can be a SignalThread; in the future this class should not be
|
|
||||||
// a SignalThread, since it does not need to spawn a new thread.
|
|
||||||
Thread::Current()->ProcessMessages(kForever);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncHttpRequest::LaunchRequest() {
|
|
||||||
factory_.SetProxy(proxy_);
|
|
||||||
if (secure_)
|
|
||||||
factory_.UseSSL(host_.c_str());
|
|
||||||
|
|
||||||
bool transparent_proxy = (port_ == 80) &&
|
|
||||||
((proxy_.type == PROXY_HTTPS) || (proxy_.type == PROXY_UNKNOWN));
|
|
||||||
if (transparent_proxy) {
|
|
||||||
client_.set_proxy(proxy_);
|
|
||||||
}
|
|
||||||
client_.set_fail_redirect(fail_redirect_);
|
|
||||||
client_.set_server(SocketAddress(host_, port_));
|
|
||||||
|
|
||||||
LOG(LS_INFO) << "HttpRequest start: " << host_ + client_.request().path;
|
|
||||||
|
|
||||||
Thread::Current()->PostDelayed(timeout_, this, MSG_TIMEOUT);
|
|
||||||
client_.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_ASYNCHTTPREQUEST_H_
|
|
||||||
#define WEBRTC_BASE_ASYNCHTTPREQUEST_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "webrtc/base/event.h"
|
|
||||||
#include "webrtc/base/httpclient.h"
|
|
||||||
#include "webrtc/base/signalthread.h"
|
|
||||||
#include "webrtc/base/socketpool.h"
|
|
||||||
#include "webrtc/base/sslsocketfactory.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class FirewallManager;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// AsyncHttpRequest
|
|
||||||
// Performs an HTTP request on a background thread. Notifies on the foreground
|
|
||||||
// thread once the request is done (successfully or unsuccessfully).
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class AsyncHttpRequest : public SignalThread {
|
|
||||||
public:
|
|
||||||
explicit AsyncHttpRequest(const std::string &user_agent);
|
|
||||||
~AsyncHttpRequest();
|
|
||||||
|
|
||||||
// If start_delay is less than or equal to zero, this starts immediately.
|
|
||||||
// Start_delay defaults to zero.
|
|
||||||
int start_delay() const { return start_delay_; }
|
|
||||||
void set_start_delay(int delay) { start_delay_ = delay; }
|
|
||||||
|
|
||||||
const ProxyInfo& proxy() const { return proxy_; }
|
|
||||||
void set_proxy(const ProxyInfo& proxy) {
|
|
||||||
proxy_ = proxy;
|
|
||||||
}
|
|
||||||
void set_firewall(FirewallManager * firewall) {
|
|
||||||
firewall_ = firewall;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The DNS name of the host to connect to.
|
|
||||||
const std::string& host() { return host_; }
|
|
||||||
void set_host(const std::string& host) { host_ = host; }
|
|
||||||
|
|
||||||
// The port to connect to on the target host.
|
|
||||||
int port() { return port_; }
|
|
||||||
void set_port(int port) { port_ = port; }
|
|
||||||
|
|
||||||
// Whether the request should use SSL.
|
|
||||||
bool secure() { return secure_; }
|
|
||||||
void set_secure(bool secure) { secure_ = secure; }
|
|
||||||
|
|
||||||
// Time to wait on the download, in ms.
|
|
||||||
int timeout() { return timeout_; }
|
|
||||||
void set_timeout(int timeout) { timeout_ = timeout; }
|
|
||||||
|
|
||||||
// Fail redirects to allow analysis of redirect urls, etc.
|
|
||||||
bool fail_redirect() const { return fail_redirect_; }
|
|
||||||
void set_fail_redirect(bool redirect) { fail_redirect_ = redirect; }
|
|
||||||
|
|
||||||
// Returns the redirect when redirection occurs
|
|
||||||
const std::string& response_redirect() { return response_redirect_; }
|
|
||||||
|
|
||||||
HttpRequestData& request() { return client_.request(); }
|
|
||||||
HttpResponseData& response() { return client_.response(); }
|
|
||||||
HttpErrorType error() { return error_; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void set_error(HttpErrorType error) { error_ = error; }
|
|
||||||
virtual void OnWorkStart();
|
|
||||||
virtual void OnWorkStop();
|
|
||||||
void OnComplete(HttpClient* client, HttpErrorType error);
|
|
||||||
virtual void OnMessage(Message* message);
|
|
||||||
virtual void DoWork();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void LaunchRequest();
|
|
||||||
|
|
||||||
int start_delay_;
|
|
||||||
ProxyInfo proxy_;
|
|
||||||
FirewallManager* firewall_;
|
|
||||||
std::string host_;
|
|
||||||
int port_;
|
|
||||||
bool secure_;
|
|
||||||
int timeout_;
|
|
||||||
bool fail_redirect_;
|
|
||||||
SslSocketFactory factory_;
|
|
||||||
ReuseSocketPool pool_;
|
|
||||||
HttpClient client_;
|
|
||||||
HttpErrorType error_;
|
|
||||||
std::string response_redirect_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_ASYNCHTTPREQUEST_H_
|
|
@ -1,233 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 <string>
|
|
||||||
#include "webrtc/base/asynchttprequest.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/httpserver.h"
|
|
||||||
#include "webrtc/base/socketstream.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
static const SocketAddress kServerAddr("127.0.0.1", 0);
|
|
||||||
static const SocketAddress kServerHostnameAddr("localhost", 0);
|
|
||||||
static const char kServerGetPath[] = "/get";
|
|
||||||
static const char kServerPostPath[] = "/post";
|
|
||||||
static const char kServerResponse[] = "This is a test";
|
|
||||||
|
|
||||||
class TestHttpServer : public HttpServer, public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
TestHttpServer(Thread* thread, const SocketAddress& addr) :
|
|
||||||
socket_(thread->socketserver()->CreateAsyncSocket(addr.family(),
|
|
||||||
SOCK_STREAM)) {
|
|
||||||
socket_->Bind(addr);
|
|
||||||
socket_->Listen(5);
|
|
||||||
socket_->SignalReadEvent.connect(this, &TestHttpServer::OnAccept);
|
|
||||||
}
|
|
||||||
|
|
||||||
SocketAddress address() const { return socket_->GetLocalAddress(); }
|
|
||||||
void Close() const { socket_->Close(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnAccept(AsyncSocket* socket) {
|
|
||||||
AsyncSocket* new_socket = socket_->Accept(NULL);
|
|
||||||
if (new_socket) {
|
|
||||||
HandleConnection(new SocketStream(new_socket));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rtc::scoped_ptr<AsyncSocket> socket_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncHttpRequestTest : public testing::Test,
|
|
||||||
public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
AsyncHttpRequestTest()
|
|
||||||
: started_(false),
|
|
||||||
done_(false),
|
|
||||||
server_(Thread::Current(), kServerAddr) {
|
|
||||||
server_.SignalHttpRequest.connect(this, &AsyncHttpRequestTest::OnRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool started() const { return started_; }
|
|
||||||
bool done() const { return done_; }
|
|
||||||
|
|
||||||
AsyncHttpRequest* CreateGetRequest(const std::string& host, int port,
|
|
||||||
const std::string& path) {
|
|
||||||
rtc::AsyncHttpRequest* request =
|
|
||||||
new rtc::AsyncHttpRequest("unittest");
|
|
||||||
request->SignalWorkDone.connect(this,
|
|
||||||
&AsyncHttpRequestTest::OnRequestDone);
|
|
||||||
request->request().verb = rtc::HV_GET;
|
|
||||||
request->set_host(host);
|
|
||||||
request->set_port(port);
|
|
||||||
request->request().path = path;
|
|
||||||
request->response().document.reset(new MemoryStream());
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
AsyncHttpRequest* CreatePostRequest(const std::string& host, int port,
|
|
||||||
const std::string& path,
|
|
||||||
const std::string content_type,
|
|
||||||
StreamInterface* content) {
|
|
||||||
rtc::AsyncHttpRequest* request =
|
|
||||||
new rtc::AsyncHttpRequest("unittest");
|
|
||||||
request->SignalWorkDone.connect(this,
|
|
||||||
&AsyncHttpRequestTest::OnRequestDone);
|
|
||||||
request->request().verb = rtc::HV_POST;
|
|
||||||
request->set_host(host);
|
|
||||||
request->set_port(port);
|
|
||||||
request->request().path = path;
|
|
||||||
request->request().setContent(content_type, content);
|
|
||||||
request->response().document.reset(new MemoryStream());
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TestHttpServer& server() const { return server_; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void OnRequest(HttpServer* server, HttpServerTransaction* t) {
|
|
||||||
started_ = true;
|
|
||||||
|
|
||||||
if (t->request.path == kServerGetPath) {
|
|
||||||
t->response.set_success("text/plain", new MemoryStream(kServerResponse));
|
|
||||||
} else if (t->request.path == kServerPostPath) {
|
|
||||||
// reverse the data and reply
|
|
||||||
size_t size;
|
|
||||||
StreamInterface* in = t->request.document.get();
|
|
||||||
StreamInterface* out = new MemoryStream();
|
|
||||||
in->GetSize(&size);
|
|
||||||
for (size_t i = 0; i < size; ++i) {
|
|
||||||
char ch;
|
|
||||||
in->SetPosition(size - i - 1);
|
|
||||||
in->Read(&ch, 1, NULL, NULL);
|
|
||||||
out->Write(&ch, 1, NULL, NULL);
|
|
||||||
}
|
|
||||||
out->Rewind();
|
|
||||||
t->response.set_success("text/plain", out);
|
|
||||||
} else {
|
|
||||||
t->response.set_error(404);
|
|
||||||
}
|
|
||||||
server_.Respond(t);
|
|
||||||
}
|
|
||||||
void OnRequestDone(SignalThread* thread) {
|
|
||||||
done_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool started_;
|
|
||||||
bool done_;
|
|
||||||
TestHttpServer server_;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(AsyncHttpRequestTest, TestGetSuccess) {
|
|
||||||
AsyncHttpRequest* req = CreateGetRequest(
|
|
||||||
kServerHostnameAddr.hostname(), server().address().port(),
|
|
||||||
kServerGetPath);
|
|
||||||
EXPECT_FALSE(started());
|
|
||||||
req->Start();
|
|
||||||
EXPECT_TRUE_WAIT(started(), 5000); // Should have started by now.
|
|
||||||
EXPECT_TRUE_WAIT(done(), 5000);
|
|
||||||
std::string response;
|
|
||||||
EXPECT_EQ(200U, req->response().scode);
|
|
||||||
ASSERT_TRUE(req->response().document);
|
|
||||||
req->response().document->Rewind();
|
|
||||||
req->response().document->ReadLine(&response);
|
|
||||||
EXPECT_EQ(kServerResponse, response);
|
|
||||||
req->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AsyncHttpRequestTest, TestGetNotFound) {
|
|
||||||
AsyncHttpRequest* req = CreateGetRequest(
|
|
||||||
kServerHostnameAddr.hostname(), server().address().port(),
|
|
||||||
"/bad");
|
|
||||||
req->Start();
|
|
||||||
EXPECT_TRUE_WAIT(done(), 5000);
|
|
||||||
size_t size;
|
|
||||||
EXPECT_EQ(404U, req->response().scode);
|
|
||||||
ASSERT_TRUE(req->response().document);
|
|
||||||
req->response().document->GetSize(&size);
|
|
||||||
EXPECT_EQ(0U, size);
|
|
||||||
req->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AsyncHttpRequestTest, TestGetToNonServer) {
|
|
||||||
AsyncHttpRequest* req = CreateGetRequest(
|
|
||||||
"127.0.0.1", server().address().port(),
|
|
||||||
kServerGetPath);
|
|
||||||
// Stop the server before we send the request.
|
|
||||||
server().Close();
|
|
||||||
req->Start();
|
|
||||||
EXPECT_TRUE_WAIT(done(), 10000);
|
|
||||||
size_t size;
|
|
||||||
EXPECT_EQ(500U, req->response().scode);
|
|
||||||
ASSERT_TRUE(req->response().document);
|
|
||||||
req->response().document->GetSize(&size);
|
|
||||||
EXPECT_EQ(0U, size);
|
|
||||||
req->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AsyncHttpRequestTest, DISABLED_TestGetToInvalidHostname) {
|
|
||||||
AsyncHttpRequest* req = CreateGetRequest(
|
|
||||||
"invalid", server().address().port(),
|
|
||||||
kServerGetPath);
|
|
||||||
req->Start();
|
|
||||||
EXPECT_TRUE_WAIT(done(), 5000);
|
|
||||||
size_t size;
|
|
||||||
EXPECT_EQ(500U, req->response().scode);
|
|
||||||
ASSERT_TRUE(req->response().document);
|
|
||||||
req->response().document->GetSize(&size);
|
|
||||||
EXPECT_EQ(0U, size);
|
|
||||||
req->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AsyncHttpRequestTest, TestPostSuccess) {
|
|
||||||
AsyncHttpRequest* req = CreatePostRequest(
|
|
||||||
kServerHostnameAddr.hostname(), server().address().port(),
|
|
||||||
kServerPostPath, "text/plain", new MemoryStream("abcd1234"));
|
|
||||||
req->Start();
|
|
||||||
EXPECT_TRUE_WAIT(done(), 5000);
|
|
||||||
std::string response;
|
|
||||||
EXPECT_EQ(200U, req->response().scode);
|
|
||||||
ASSERT_TRUE(req->response().document);
|
|
||||||
req->response().document->Rewind();
|
|
||||||
req->response().document->ReadLine(&response);
|
|
||||||
EXPECT_EQ("4321dcba", response);
|
|
||||||
req->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that we shut down properly even if work is outstanding.
|
|
||||||
TEST_F(AsyncHttpRequestTest, TestCancel) {
|
|
||||||
AsyncHttpRequest* req = CreateGetRequest(
|
|
||||||
kServerHostnameAddr.hostname(), server().address().port(),
|
|
||||||
kServerGetPath);
|
|
||||||
req->Start();
|
|
||||||
req->Destroy(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AsyncHttpRequestTest, TestGetSuccessDelay) {
|
|
||||||
AsyncHttpRequest* req = CreateGetRequest(
|
|
||||||
kServerHostnameAddr.hostname(), server().address().port(),
|
|
||||||
kServerGetPath);
|
|
||||||
req->set_start_delay(10); // Delay 10ms.
|
|
||||||
req->Start();
|
|
||||||
Thread::SleepMs(5);
|
|
||||||
EXPECT_FALSE(started()); // Should not have started immediately.
|
|
||||||
EXPECT_TRUE_WAIT(started(), 5000); // Should have started by now.
|
|
||||||
EXPECT_TRUE_WAIT(done(), 5000);
|
|
||||||
std::string response;
|
|
||||||
EXPECT_EQ(200U, req->response().scode);
|
|
||||||
ASSERT_TRUE(req->response().document);
|
|
||||||
req->response().document->Rewind();
|
|
||||||
req->response().document->ReadLine(&response);
|
|
||||||
EXPECT_EQ(kServerResponse, response);
|
|
||||||
req->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,129 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_ASYNCINVOKER_INL_H_
|
|
||||||
#define WEBRTC_BASE_ASYNCINVOKER_INL_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/bind.h"
|
|
||||||
#include "webrtc/base/callback.h"
|
|
||||||
#include "webrtc/base/criticalsection.h"
|
|
||||||
#include "webrtc/base/messagehandler.h"
|
|
||||||
#include "webrtc/base/refcount.h"
|
|
||||||
#include "webrtc/base/scoped_ref_ptr.h"
|
|
||||||
#include "webrtc/base/sigslot.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class AsyncInvoker;
|
|
||||||
|
|
||||||
// Helper class for AsyncInvoker. Runs a task and triggers a callback
|
|
||||||
// on the calling thread if necessary. Instances are ref-counted so their
|
|
||||||
// lifetime can be independent of AsyncInvoker.
|
|
||||||
class AsyncClosure : public RefCountInterface {
|
|
||||||
public:
|
|
||||||
virtual ~AsyncClosure() {}
|
|
||||||
// Runs the asynchronous task, and triggers a callback to the calling
|
|
||||||
// thread if needed. Should be called from the target thread.
|
|
||||||
virtual void Execute() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Simple closure that doesn't trigger a callback for the calling thread.
|
|
||||||
template <class FunctorT>
|
|
||||||
class FireAndForgetAsyncClosure : public AsyncClosure {
|
|
||||||
public:
|
|
||||||
explicit FireAndForgetAsyncClosure(const FunctorT& functor)
|
|
||||||
: functor_(functor) {}
|
|
||||||
virtual void Execute() {
|
|
||||||
functor_();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
FunctorT functor_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Base class for closures that may trigger a callback for the calling thread.
|
|
||||||
// Listens for the "destroyed" signals from the calling thread and the invoker,
|
|
||||||
// and cancels the callback to the calling thread if either is destroyed.
|
|
||||||
class NotifyingAsyncClosureBase : public AsyncClosure,
|
|
||||||
public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
virtual ~NotifyingAsyncClosureBase() { disconnect_all(); }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
NotifyingAsyncClosureBase(AsyncInvoker* invoker, Thread* calling_thread);
|
|
||||||
void TriggerCallback();
|
|
||||||
void SetCallback(const Callback0<void>& callback) {
|
|
||||||
CritScope cs(&crit_);
|
|
||||||
callback_ = callback;
|
|
||||||
}
|
|
||||||
bool CallbackCanceled() const { return calling_thread_ == NULL; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Callback0<void> callback_;
|
|
||||||
CriticalSection crit_;
|
|
||||||
AsyncInvoker* invoker_;
|
|
||||||
Thread* calling_thread_;
|
|
||||||
|
|
||||||
void CancelCallback();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Closures that have a non-void return value and require a callback.
|
|
||||||
template <class ReturnT, class FunctorT, class HostT>
|
|
||||||
class NotifyingAsyncClosure : public NotifyingAsyncClosureBase {
|
|
||||||
public:
|
|
||||||
NotifyingAsyncClosure(AsyncInvoker* invoker,
|
|
||||||
Thread* calling_thread,
|
|
||||||
const FunctorT& functor,
|
|
||||||
void (HostT::*callback)(ReturnT),
|
|
||||||
HostT* callback_host)
|
|
||||||
: NotifyingAsyncClosureBase(invoker, calling_thread),
|
|
||||||
functor_(functor),
|
|
||||||
callback_(callback),
|
|
||||||
callback_host_(callback_host) {}
|
|
||||||
virtual void Execute() {
|
|
||||||
ReturnT result = functor_();
|
|
||||||
if (!CallbackCanceled()) {
|
|
||||||
SetCallback(Callback0<void>(Bind(callback_, callback_host_, result)));
|
|
||||||
TriggerCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
FunctorT functor_;
|
|
||||||
void (HostT::*callback_)(ReturnT);
|
|
||||||
HostT* callback_host_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Closures that have a void return value and require a callback.
|
|
||||||
template <class FunctorT, class HostT>
|
|
||||||
class NotifyingAsyncClosure<void, FunctorT, HostT>
|
|
||||||
: public NotifyingAsyncClosureBase {
|
|
||||||
public:
|
|
||||||
NotifyingAsyncClosure(AsyncInvoker* invoker,
|
|
||||||
Thread* calling_thread,
|
|
||||||
const FunctorT& functor,
|
|
||||||
void (HostT::*callback)(),
|
|
||||||
HostT* callback_host)
|
|
||||||
: NotifyingAsyncClosureBase(invoker, calling_thread),
|
|
||||||
functor_(functor) {
|
|
||||||
SetCallback(Callback0<void>(Bind(callback, callback_host)));
|
|
||||||
}
|
|
||||||
virtual void Execute() {
|
|
||||||
functor_();
|
|
||||||
TriggerCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
FunctorT functor_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_ASYNCINVOKER_INL_H_
|
|
@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 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 "webrtc/base/asyncinvoker.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
AsyncInvoker::AsyncInvoker() : destroying_(false) {}
|
|
||||||
|
|
||||||
AsyncInvoker::~AsyncInvoker() {
|
|
||||||
destroying_ = true;
|
|
||||||
SignalInvokerDestroyed();
|
|
||||||
// Messages for this need to be cleared *before* our destructor is complete.
|
|
||||||
MessageQueueManager::Clear(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncInvoker::OnMessage(Message* msg) {
|
|
||||||
// Get the AsyncClosure shared ptr from this message's data.
|
|
||||||
ScopedRefMessageData<AsyncClosure>* data =
|
|
||||||
static_cast<ScopedRefMessageData<AsyncClosure>*>(msg->pdata);
|
|
||||||
scoped_refptr<AsyncClosure> closure = data->data();
|
|
||||||
delete msg->pdata;
|
|
||||||
msg->pdata = NULL;
|
|
||||||
|
|
||||||
// Execute the closure and trigger the return message if needed.
|
|
||||||
closure->Execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncInvoker::Flush(Thread* thread, uint32 id /*= MQID_ANY*/) {
|
|
||||||
if (destroying_) return;
|
|
||||||
|
|
||||||
// Run this on |thread| to reduce the number of context switches.
|
|
||||||
if (Thread::Current() != thread) {
|
|
||||||
thread->Invoke<void>(Bind(&AsyncInvoker::Flush, this, thread, id));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageList removed;
|
|
||||||
thread->Clear(this, id, &removed);
|
|
||||||
for (MessageList::iterator it = removed.begin(); it != removed.end(); ++it) {
|
|
||||||
// This message was pending on this thread, so run it now.
|
|
||||||
thread->Send(it->phandler,
|
|
||||||
it->message_id,
|
|
||||||
it->pdata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncInvoker::DoInvoke(Thread* thread, AsyncClosure* closure,
|
|
||||||
uint32 id) {
|
|
||||||
if (destroying_) {
|
|
||||||
LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
|
|
||||||
// Since this call transwers ownership of |closure|, we clean it up here.
|
|
||||||
delete closure;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
thread->Post(this, id, new ScopedRefMessageData<AsyncClosure>(closure));
|
|
||||||
}
|
|
||||||
|
|
||||||
NotifyingAsyncClosureBase::NotifyingAsyncClosureBase(AsyncInvoker* invoker,
|
|
||||||
Thread* calling_thread)
|
|
||||||
: invoker_(invoker), calling_thread_(calling_thread) {
|
|
||||||
calling_thread->SignalQueueDestroyed.connect(
|
|
||||||
this, &NotifyingAsyncClosureBase::CancelCallback);
|
|
||||||
invoker->SignalInvokerDestroyed.connect(
|
|
||||||
this, &NotifyingAsyncClosureBase::CancelCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NotifyingAsyncClosureBase::TriggerCallback() {
|
|
||||||
CritScope cs(&crit_);
|
|
||||||
if (!CallbackCanceled() && !callback_.empty()) {
|
|
||||||
invoker_->AsyncInvoke<void>(calling_thread_, callback_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NotifyingAsyncClosureBase::CancelCallback() {
|
|
||||||
// If the callback is triggering when this is called, block the
|
|
||||||
// destructor of the dying object here by waiting until the callback
|
|
||||||
// is done triggering.
|
|
||||||
CritScope cs(&crit_);
|
|
||||||
// calling_thread_ == NULL means do not trigger the callback.
|
|
||||||
calling_thread_ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_ASYNCINVOKER_H_
|
|
||||||
#define WEBRTC_BASE_ASYNCINVOKER_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/asyncinvoker-inl.h"
|
|
||||||
#include "webrtc/base/bind.h"
|
|
||||||
#include "webrtc/base/sigslot.h"
|
|
||||||
#include "webrtc/base/scopedptrcollection.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Invokes function objects (aka functors) asynchronously on a Thread, and
|
|
||||||
// owns the lifetime of calls (ie, when this object is destroyed, calls in
|
|
||||||
// flight are cancelled). AsyncInvoker can optionally execute a user-specified
|
|
||||||
// function when the asynchronous call is complete, or operates in
|
|
||||||
// fire-and-forget mode otherwise.
|
|
||||||
//
|
|
||||||
// AsyncInvoker does not own the thread it calls functors on.
|
|
||||||
//
|
|
||||||
// A note about async calls and object lifetimes: users should
|
|
||||||
// be mindful of object lifetimes when calling functions asynchronously and
|
|
||||||
// ensure objects used by the function _cannot_ be deleted between the
|
|
||||||
// invocation and execution of the functor. AsyncInvoker is designed to
|
|
||||||
// help: any calls in flight will be cancelled when the AsyncInvoker used to
|
|
||||||
// make the call is destructed, and any calls executing will be allowed to
|
|
||||||
// complete before AsyncInvoker destructs.
|
|
||||||
//
|
|
||||||
// The easiest way to ensure lifetimes are handled correctly is to create a
|
|
||||||
// class that owns the Thread and AsyncInvoker objects, and then call its
|
|
||||||
// methods asynchronously as needed.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// class MyClass {
|
|
||||||
// public:
|
|
||||||
// void FireAsyncTaskWithResult(Thread* thread, int x) {
|
|
||||||
// // Specify a callback to get the result upon completion.
|
|
||||||
// invoker_.AsyncInvoke<int>(
|
|
||||||
// thread, Bind(&MyClass::AsyncTaskWithResult, this, x),
|
|
||||||
// &MyClass::OnTaskComplete, this);
|
|
||||||
// }
|
|
||||||
// void FireAnotherAsyncTask(Thread* thread) {
|
|
||||||
// // No callback specified means fire-and-forget.
|
|
||||||
// invoker_.AsyncInvoke<void>(
|
|
||||||
// thread, Bind(&MyClass::AnotherAsyncTask, this));
|
|
||||||
//
|
|
||||||
// private:
|
|
||||||
// int AsyncTaskWithResult(int x) {
|
|
||||||
// // Some long running process...
|
|
||||||
// return x * x;
|
|
||||||
// }
|
|
||||||
// void AnotherAsyncTask() {
|
|
||||||
// // Some other long running process...
|
|
||||||
// }
|
|
||||||
// void OnTaskComplete(int result) { result_ = result; }
|
|
||||||
//
|
|
||||||
// AsyncInvoker invoker_;
|
|
||||||
// int result_;
|
|
||||||
// };
|
|
||||||
class AsyncInvoker : public MessageHandler {
|
|
||||||
public:
|
|
||||||
AsyncInvoker();
|
|
||||||
virtual ~AsyncInvoker();
|
|
||||||
|
|
||||||
// Call |functor| asynchronously on |thread|, with no callback upon
|
|
||||||
// completion. Returns immediately.
|
|
||||||
template <class ReturnT, class FunctorT>
|
|
||||||
void AsyncInvoke(Thread* thread,
|
|
||||||
const FunctorT& functor,
|
|
||||||
uint32 id = 0) {
|
|
||||||
AsyncClosure* closure =
|
|
||||||
new RefCountedObject<FireAndForgetAsyncClosure<FunctorT> >(functor);
|
|
||||||
DoInvoke(thread, closure, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call |functor| asynchronously on |thread|, calling |callback| when done.
|
|
||||||
template <class ReturnT, class FunctorT, class HostT>
|
|
||||||
void AsyncInvoke(Thread* thread,
|
|
||||||
const FunctorT& functor,
|
|
||||||
void (HostT::*callback)(ReturnT),
|
|
||||||
HostT* callback_host,
|
|
||||||
uint32 id = 0) {
|
|
||||||
AsyncClosure* closure =
|
|
||||||
new RefCountedObject<NotifyingAsyncClosure<ReturnT, FunctorT, HostT> >(
|
|
||||||
this, Thread::Current(), functor, callback, callback_host);
|
|
||||||
DoInvoke(thread, closure, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call |functor| asynchronously on |thread|, calling |callback| when done.
|
|
||||||
// Overloaded for void return.
|
|
||||||
template <class ReturnT, class FunctorT, class HostT>
|
|
||||||
void AsyncInvoke(Thread* thread,
|
|
||||||
const FunctorT& functor,
|
|
||||||
void (HostT::*callback)(),
|
|
||||||
HostT* callback_host,
|
|
||||||
uint32 id = 0) {
|
|
||||||
AsyncClosure* closure =
|
|
||||||
new RefCountedObject<NotifyingAsyncClosure<void, FunctorT, HostT> >(
|
|
||||||
this, Thread::Current(), functor, callback, callback_host);
|
|
||||||
DoInvoke(thread, closure, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Synchronously execute on |thread| all outstanding calls we own
|
|
||||||
// that are pending on |thread|, and wait for calls to complete
|
|
||||||
// before returning. Optionally filter by message id.
|
|
||||||
// The destructor will not wait for outstanding calls, so if that
|
|
||||||
// behavior is desired, call Flush() before destroying this object.
|
|
||||||
void Flush(Thread* thread, uint32 id = MQID_ANY);
|
|
||||||
|
|
||||||
// Signaled when this object is destructed.
|
|
||||||
sigslot::signal0<> SignalInvokerDestroyed;
|
|
||||||
|
|
||||||
private:
|
|
||||||
virtual void OnMessage(Message* msg);
|
|
||||||
void DoInvoke(Thread* thread, AsyncClosure* closure, uint32 id);
|
|
||||||
|
|
||||||
bool destroying_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AsyncInvoker);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_ASYNCINVOKER_H_
|
|
@ -1,140 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_ASYNCPACKETSOCKET_H_
|
|
||||||
#define WEBRTC_BASE_ASYNCPACKETSOCKET_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/dscp.h"
|
|
||||||
#include "webrtc/base/sigslot.h"
|
|
||||||
#include "webrtc/base/socket.h"
|
|
||||||
#include "webrtc/base/timeutils.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// This structure holds the info needed to update the packet send time header
|
|
||||||
// extension, including the information needed to update the authentication tag
|
|
||||||
// after changing the value.
|
|
||||||
struct PacketTimeUpdateParams {
|
|
||||||
PacketTimeUpdateParams()
|
|
||||||
: rtp_sendtime_extension_id(-1), srtp_auth_tag_len(-1),
|
|
||||||
srtp_packet_index(-1) {
|
|
||||||
}
|
|
||||||
|
|
||||||
int rtp_sendtime_extension_id; // extension header id present in packet.
|
|
||||||
std::vector<char> srtp_auth_key; // Authentication key.
|
|
||||||
int srtp_auth_tag_len; // Authentication tag length.
|
|
||||||
int64 srtp_packet_index; // Required for Rtp Packet authentication.
|
|
||||||
};
|
|
||||||
|
|
||||||
// This structure holds meta information for the packet which is about to send
|
|
||||||
// over network.
|
|
||||||
struct PacketOptions {
|
|
||||||
PacketOptions() : dscp(DSCP_NO_CHANGE) {}
|
|
||||||
explicit PacketOptions(DiffServCodePoint dscp) : dscp(dscp) {}
|
|
||||||
|
|
||||||
DiffServCodePoint dscp;
|
|
||||||
PacketTimeUpdateParams packet_time_params;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This structure will have the information about when packet is actually
|
|
||||||
// received by socket.
|
|
||||||
struct PacketTime {
|
|
||||||
PacketTime() : timestamp(-1), not_before(-1) {}
|
|
||||||
PacketTime(int64 timestamp, int64 not_before)
|
|
||||||
: timestamp(timestamp), not_before(not_before) {
|
|
||||||
}
|
|
||||||
|
|
||||||
int64 timestamp; // Receive time after socket delivers the data.
|
|
||||||
int64 not_before; // Earliest possible time the data could have arrived,
|
|
||||||
// indicating the potential error in the |timestamp| value,
|
|
||||||
// in case the system, is busy. For example, the time of
|
|
||||||
// the last select() call.
|
|
||||||
// If unknown, this value will be set to zero.
|
|
||||||
};
|
|
||||||
|
|
||||||
inline PacketTime CreatePacketTime(int64 not_before) {
|
|
||||||
return PacketTime(TimeMicros(), not_before);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provides the ability to receive packets asynchronously. Sends are not
|
|
||||||
// buffered since it is acceptable to drop packets under high load.
|
|
||||||
class AsyncPacketSocket : public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
enum State {
|
|
||||||
STATE_CLOSED,
|
|
||||||
STATE_BINDING,
|
|
||||||
STATE_BOUND,
|
|
||||||
STATE_CONNECTING,
|
|
||||||
STATE_CONNECTED
|
|
||||||
};
|
|
||||||
|
|
||||||
AsyncPacketSocket() { }
|
|
||||||
virtual ~AsyncPacketSocket() { }
|
|
||||||
|
|
||||||
// Returns current local address. Address may be set to NULL if the
|
|
||||||
// socket is not bound yet (GetState() returns STATE_BINDING).
|
|
||||||
virtual SocketAddress GetLocalAddress() const = 0;
|
|
||||||
|
|
||||||
// Returns remote address. Returns zeroes if this is not a client TCP socket.
|
|
||||||
virtual SocketAddress GetRemoteAddress() const = 0;
|
|
||||||
|
|
||||||
// Send a packet.
|
|
||||||
virtual int Send(const void *pv, size_t cb, const PacketOptions& options) = 0;
|
|
||||||
virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr,
|
|
||||||
const PacketOptions& options) = 0;
|
|
||||||
|
|
||||||
// Close the socket.
|
|
||||||
virtual int Close() = 0;
|
|
||||||
|
|
||||||
// Returns current state of the socket.
|
|
||||||
virtual State GetState() const = 0;
|
|
||||||
|
|
||||||
// Get/set options.
|
|
||||||
virtual int GetOption(Socket::Option opt, int* value) = 0;
|
|
||||||
virtual int SetOption(Socket::Option opt, int value) = 0;
|
|
||||||
|
|
||||||
// Get/Set current error.
|
|
||||||
// TODO: Remove SetError().
|
|
||||||
virtual int GetError() const = 0;
|
|
||||||
virtual void SetError(int error) = 0;
|
|
||||||
|
|
||||||
// Emitted each time a packet is read. Used only for UDP and
|
|
||||||
// connected TCP sockets.
|
|
||||||
sigslot::signal5<AsyncPacketSocket*, const char*, size_t,
|
|
||||||
const SocketAddress&,
|
|
||||||
const PacketTime&> SignalReadPacket;
|
|
||||||
|
|
||||||
// Emitted when the socket is currently able to send.
|
|
||||||
sigslot::signal1<AsyncPacketSocket*> SignalReadyToSend;
|
|
||||||
|
|
||||||
// Emitted after address for the socket is allocated, i.e. binding
|
|
||||||
// is finished. State of the socket is changed from BINDING to BOUND
|
|
||||||
// (for UDP and server TCP sockets) or CONNECTING (for client TCP
|
|
||||||
// sockets).
|
|
||||||
sigslot::signal2<AsyncPacketSocket*, const SocketAddress&> SignalAddressReady;
|
|
||||||
|
|
||||||
// Emitted for client TCP sockets when state is changed from
|
|
||||||
// CONNECTING to CONNECTED.
|
|
||||||
sigslot::signal1<AsyncPacketSocket*> SignalConnect;
|
|
||||||
|
|
||||||
// Emitted for client TCP sockets when state is changed from
|
|
||||||
// CONNECTED to CLOSED.
|
|
||||||
sigslot::signal2<AsyncPacketSocket*, int> SignalClose;
|
|
||||||
|
|
||||||
// Used only for listening TCP sockets.
|
|
||||||
sigslot::signal2<AsyncPacketSocket*, AsyncPacketSocket*> SignalNewConnection;
|
|
||||||
|
|
||||||
private:
|
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(AsyncPacketSocket);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_ASYNCPACKETSOCKET_H_
|
|
@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_ASYNCRESOLVERINTERFACE_H_
|
|
||||||
#define WEBRTC_BASE_ASYNCRESOLVERINTERFACE_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/sigslot.h"
|
|
||||||
#include "webrtc/base/socketaddress.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// This interface defines the methods to resolve the address asynchronously.
|
|
||||||
class AsyncResolverInterface {
|
|
||||||
public:
|
|
||||||
AsyncResolverInterface() {}
|
|
||||||
virtual ~AsyncResolverInterface() {}
|
|
||||||
|
|
||||||
// Start address resolve process.
|
|
||||||
virtual void Start(const SocketAddress& addr) = 0;
|
|
||||||
// Returns top most resolved address of |family|
|
|
||||||
virtual bool GetResolvedAddress(int family, SocketAddress* addr) const = 0;
|
|
||||||
// Returns error from resolver.
|
|
||||||
virtual int GetError() const = 0;
|
|
||||||
// Delete the resolver.
|
|
||||||
virtual void Destroy(bool wait) = 0;
|
|
||||||
// Returns top most resolved IPv4 address if address is resolved successfully.
|
|
||||||
// Otherwise returns address set in SetAddress.
|
|
||||||
SocketAddress address() const {
|
|
||||||
SocketAddress addr;
|
|
||||||
GetResolvedAddress(AF_INET, &addr);
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This signal is fired when address resolve process is completed.
|
|
||||||
sigslot::signal1<AsyncResolverInterface*> SignalDone;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 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 "webrtc/base/asyncsocket.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
AsyncSocket::AsyncSocket() {
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncSocket::~AsyncSocket() {
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncSocketAdapter::AsyncSocketAdapter(AsyncSocket* socket) : socket_(NULL) {
|
|
||||||
Attach(socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncSocketAdapter::~AsyncSocketAdapter() {
|
|
||||||
delete socket_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncSocketAdapter::Attach(AsyncSocket* socket) {
|
|
||||||
ASSERT(!socket_);
|
|
||||||
socket_ = socket;
|
|
||||||
if (socket_) {
|
|
||||||
socket_->SignalConnectEvent.connect(this,
|
|
||||||
&AsyncSocketAdapter::OnConnectEvent);
|
|
||||||
socket_->SignalReadEvent.connect(this,
|
|
||||||
&AsyncSocketAdapter::OnReadEvent);
|
|
||||||
socket_->SignalWriteEvent.connect(this,
|
|
||||||
&AsyncSocketAdapter::OnWriteEvent);
|
|
||||||
socket_->SignalCloseEvent.connect(this,
|
|
||||||
&AsyncSocketAdapter::OnCloseEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_ASYNCSOCKET_H_
|
|
||||||
#define WEBRTC_BASE_ASYNCSOCKET_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
#include "webrtc/base/sigslot.h"
|
|
||||||
#include "webrtc/base/socket.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// TODO: Remove Socket and rename AsyncSocket to Socket.
|
|
||||||
|
|
||||||
// Provides the ability to perform socket I/O asynchronously.
|
|
||||||
class AsyncSocket : public Socket {
|
|
||||||
public:
|
|
||||||
AsyncSocket();
|
|
||||||
virtual ~AsyncSocket();
|
|
||||||
|
|
||||||
virtual AsyncSocket* Accept(SocketAddress* paddr) = 0;
|
|
||||||
|
|
||||||
// SignalReadEvent and SignalWriteEvent use multi_threaded_local to allow
|
|
||||||
// access concurrently from different thread.
|
|
||||||
// For example SignalReadEvent::connect will be called in AsyncUDPSocket ctor
|
|
||||||
// but at the same time the SocketDispatcher maybe signaling the read event.
|
|
||||||
// ready to read
|
|
||||||
sigslot::signal1<AsyncSocket*,
|
|
||||||
sigslot::multi_threaded_local> SignalReadEvent;
|
|
||||||
// ready to write
|
|
||||||
sigslot::signal1<AsyncSocket*,
|
|
||||||
sigslot::multi_threaded_local> SignalWriteEvent;
|
|
||||||
sigslot::signal1<AsyncSocket*> SignalConnectEvent; // connected
|
|
||||||
sigslot::signal2<AsyncSocket*, int> SignalCloseEvent; // closed
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncSocketAdapter : public AsyncSocket, public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
// The adapted socket may explicitly be NULL, and later assigned using Attach.
|
|
||||||
// However, subclasses which support detached mode must override any methods
|
|
||||||
// that will be called during the detached period (usually GetState()), to
|
|
||||||
// avoid dereferencing a null pointer.
|
|
||||||
explicit AsyncSocketAdapter(AsyncSocket* socket);
|
|
||||||
virtual ~AsyncSocketAdapter();
|
|
||||||
void Attach(AsyncSocket* socket);
|
|
||||||
virtual SocketAddress GetLocalAddress() const {
|
|
||||||
return socket_->GetLocalAddress();
|
|
||||||
}
|
|
||||||
virtual SocketAddress GetRemoteAddress() const {
|
|
||||||
return socket_->GetRemoteAddress();
|
|
||||||
}
|
|
||||||
virtual int Bind(const SocketAddress& addr) {
|
|
||||||
return socket_->Bind(addr);
|
|
||||||
}
|
|
||||||
virtual int Connect(const SocketAddress& addr) {
|
|
||||||
return socket_->Connect(addr);
|
|
||||||
}
|
|
||||||
virtual int Send(const void* pv, size_t cb) {
|
|
||||||
return socket_->Send(pv, cb);
|
|
||||||
}
|
|
||||||
virtual int SendTo(const void* pv, size_t cb, const SocketAddress& addr) {
|
|
||||||
return socket_->SendTo(pv, cb, addr);
|
|
||||||
}
|
|
||||||
virtual int Recv(void* pv, size_t cb) {
|
|
||||||
return socket_->Recv(pv, cb);
|
|
||||||
}
|
|
||||||
virtual int RecvFrom(void* pv, size_t cb, SocketAddress* paddr) {
|
|
||||||
return socket_->RecvFrom(pv, cb, paddr);
|
|
||||||
}
|
|
||||||
virtual int Listen(int backlog) {
|
|
||||||
return socket_->Listen(backlog);
|
|
||||||
}
|
|
||||||
virtual AsyncSocket* Accept(SocketAddress* paddr) {
|
|
||||||
return socket_->Accept(paddr);
|
|
||||||
}
|
|
||||||
virtual int Close() {
|
|
||||||
return socket_->Close();
|
|
||||||
}
|
|
||||||
virtual int GetError() const {
|
|
||||||
return socket_->GetError();
|
|
||||||
}
|
|
||||||
virtual void SetError(int error) {
|
|
||||||
return socket_->SetError(error);
|
|
||||||
}
|
|
||||||
virtual ConnState GetState() const {
|
|
||||||
return socket_->GetState();
|
|
||||||
}
|
|
||||||
virtual int EstimateMTU(uint16* mtu) {
|
|
||||||
return socket_->EstimateMTU(mtu);
|
|
||||||
}
|
|
||||||
virtual int GetOption(Option opt, int* value) {
|
|
||||||
return socket_->GetOption(opt, value);
|
|
||||||
}
|
|
||||||
virtual int SetOption(Option opt, int value) {
|
|
||||||
return socket_->SetOption(opt, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void OnConnectEvent(AsyncSocket* socket) {
|
|
||||||
SignalConnectEvent(this);
|
|
||||||
}
|
|
||||||
virtual void OnReadEvent(AsyncSocket* socket) {
|
|
||||||
SignalReadEvent(this);
|
|
||||||
}
|
|
||||||
virtual void OnWriteEvent(AsyncSocket* socket) {
|
|
||||||
SignalWriteEvent(this);
|
|
||||||
}
|
|
||||||
virtual void OnCloseEvent(AsyncSocket* socket, int err) {
|
|
||||||
SignalCloseEvent(this, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncSocket* socket_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_ASYNCSOCKET_H_
|
|
@ -1,299 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/asynctcpsocket.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "webrtc/base/byteorder.h"
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
|
|
||||||
#if defined(WEBRTC_POSIX)
|
|
||||||
#include <errno.h>
|
|
||||||
#endif // WEBRTC_POSIX
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
static const size_t kMaxPacketSize = 64 * 1024;
|
|
||||||
|
|
||||||
typedef uint16 PacketLength;
|
|
||||||
static const size_t kPacketLenSize = sizeof(PacketLength);
|
|
||||||
|
|
||||||
static const size_t kBufSize = kMaxPacketSize + kPacketLenSize;
|
|
||||||
|
|
||||||
static const int kListenBacklog = 5;
|
|
||||||
|
|
||||||
// Binds and connects |socket|
|
|
||||||
AsyncSocket* AsyncTCPSocketBase::ConnectSocket(
|
|
||||||
rtc::AsyncSocket* socket,
|
|
||||||
const rtc::SocketAddress& bind_address,
|
|
||||||
const rtc::SocketAddress& remote_address) {
|
|
||||||
rtc::scoped_ptr<rtc::AsyncSocket> owned_socket(socket);
|
|
||||||
if (socket->Bind(bind_address) < 0) {
|
|
||||||
LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (socket->Connect(remote_address) < 0) {
|
|
||||||
LOG(LS_ERROR) << "Connect() failed with error " << socket->GetError();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return owned_socket.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncTCPSocketBase::AsyncTCPSocketBase(AsyncSocket* socket, bool listen,
|
|
||||||
size_t max_packet_size)
|
|
||||||
: socket_(socket),
|
|
||||||
listen_(listen),
|
|
||||||
insize_(max_packet_size),
|
|
||||||
inpos_(0),
|
|
||||||
outsize_(max_packet_size),
|
|
||||||
outpos_(0) {
|
|
||||||
inbuf_ = new char[insize_];
|
|
||||||
outbuf_ = new char[outsize_];
|
|
||||||
|
|
||||||
ASSERT(socket_.get() != NULL);
|
|
||||||
socket_->SignalConnectEvent.connect(
|
|
||||||
this, &AsyncTCPSocketBase::OnConnectEvent);
|
|
||||||
socket_->SignalReadEvent.connect(this, &AsyncTCPSocketBase::OnReadEvent);
|
|
||||||
socket_->SignalWriteEvent.connect(this, &AsyncTCPSocketBase::OnWriteEvent);
|
|
||||||
socket_->SignalCloseEvent.connect(this, &AsyncTCPSocketBase::OnCloseEvent);
|
|
||||||
|
|
||||||
if (listen_) {
|
|
||||||
if (socket_->Listen(kListenBacklog) < 0) {
|
|
||||||
LOG(LS_ERROR) << "Listen() failed with error " << socket_->GetError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncTCPSocketBase::~AsyncTCPSocketBase() {
|
|
||||||
delete [] inbuf_;
|
|
||||||
delete [] outbuf_;
|
|
||||||
}
|
|
||||||
|
|
||||||
SocketAddress AsyncTCPSocketBase::GetLocalAddress() const {
|
|
||||||
return socket_->GetLocalAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
SocketAddress AsyncTCPSocketBase::GetRemoteAddress() const {
|
|
||||||
return socket_->GetRemoteAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncTCPSocketBase::Close() {
|
|
||||||
return socket_->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncTCPSocket::State AsyncTCPSocketBase::GetState() const {
|
|
||||||
switch (socket_->GetState()) {
|
|
||||||
case Socket::CS_CLOSED:
|
|
||||||
return STATE_CLOSED;
|
|
||||||
case Socket::CS_CONNECTING:
|
|
||||||
if (listen_) {
|
|
||||||
return STATE_BOUND;
|
|
||||||
} else {
|
|
||||||
return STATE_CONNECTING;
|
|
||||||
}
|
|
||||||
case Socket::CS_CONNECTED:
|
|
||||||
return STATE_CONNECTED;
|
|
||||||
default:
|
|
||||||
ASSERT(false);
|
|
||||||
return STATE_CLOSED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncTCPSocketBase::GetOption(Socket::Option opt, int* value) {
|
|
||||||
return socket_->GetOption(opt, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncTCPSocketBase::SetOption(Socket::Option opt, int value) {
|
|
||||||
return socket_->SetOption(opt, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncTCPSocketBase::GetError() const {
|
|
||||||
return socket_->GetError();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncTCPSocketBase::SetError(int error) {
|
|
||||||
return socket_->SetError(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncTCPSocketBase::SendTo(const void *pv, size_t cb,
|
|
||||||
const SocketAddress& addr,
|
|
||||||
const rtc::PacketOptions& options) {
|
|
||||||
if (addr == GetRemoteAddress())
|
|
||||||
return Send(pv, cb, options);
|
|
||||||
|
|
||||||
ASSERT(false);
|
|
||||||
socket_->SetError(ENOTCONN);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncTCPSocketBase::SendRaw(const void * pv, size_t cb) {
|
|
||||||
if (outpos_ + cb > outsize_) {
|
|
||||||
socket_->SetError(EMSGSIZE);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(outbuf_ + outpos_, pv, cb);
|
|
||||||
outpos_ += cb;
|
|
||||||
|
|
||||||
return FlushOutBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncTCPSocketBase::FlushOutBuffer() {
|
|
||||||
int res = socket_->Send(outbuf_, outpos_);
|
|
||||||
if (res <= 0) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
if (static_cast<size_t>(res) <= outpos_) {
|
|
||||||
outpos_ -= res;
|
|
||||||
} else {
|
|
||||||
ASSERT(false);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (outpos_ > 0) {
|
|
||||||
memmove(outbuf_, outbuf_ + res, outpos_);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncTCPSocketBase::AppendToOutBuffer(const void* pv, size_t cb) {
|
|
||||||
ASSERT(outpos_ + cb < outsize_);
|
|
||||||
memcpy(outbuf_ + outpos_, pv, cb);
|
|
||||||
outpos_ += cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncTCPSocketBase::OnConnectEvent(AsyncSocket* socket) {
|
|
||||||
SignalConnect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncTCPSocketBase::OnReadEvent(AsyncSocket* socket) {
|
|
||||||
ASSERT(socket_.get() == socket);
|
|
||||||
|
|
||||||
if (listen_) {
|
|
||||||
rtc::SocketAddress address;
|
|
||||||
rtc::AsyncSocket* new_socket = socket->Accept(&address);
|
|
||||||
if (!new_socket) {
|
|
||||||
// TODO: Do something better like forwarding the error
|
|
||||||
// to the user.
|
|
||||||
LOG(LS_ERROR) << "TCP accept failed with error " << socket_->GetError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleIncomingConnection(new_socket);
|
|
||||||
|
|
||||||
// Prime a read event in case data is waiting.
|
|
||||||
new_socket->SignalReadEvent(new_socket);
|
|
||||||
} else {
|
|
||||||
int len = socket_->Recv(inbuf_ + inpos_, insize_ - inpos_);
|
|
||||||
if (len < 0) {
|
|
||||||
// TODO: Do something better like forwarding the error to the user.
|
|
||||||
if (!socket_->IsBlocking()) {
|
|
||||||
LOG(LS_ERROR) << "Recv() returned error: " << socket_->GetError();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inpos_ += len;
|
|
||||||
|
|
||||||
ProcessInput(inbuf_, &inpos_);
|
|
||||||
|
|
||||||
if (inpos_ >= insize_) {
|
|
||||||
LOG(LS_ERROR) << "input buffer overflow";
|
|
||||||
ASSERT(false);
|
|
||||||
inpos_ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncTCPSocketBase::OnWriteEvent(AsyncSocket* socket) {
|
|
||||||
ASSERT(socket_.get() == socket);
|
|
||||||
|
|
||||||
if (outpos_ > 0) {
|
|
||||||
FlushOutBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outpos_ == 0) {
|
|
||||||
SignalReadyToSend(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncTCPSocketBase::OnCloseEvent(AsyncSocket* socket, int error) {
|
|
||||||
SignalClose(this, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// AsyncTCPSocket
|
|
||||||
// Binds and connects |socket| and creates AsyncTCPSocket for
|
|
||||||
// it. Takes ownership of |socket|. Returns NULL if bind() or
|
|
||||||
// connect() fail (|socket| is destroyed in that case).
|
|
||||||
AsyncTCPSocket* AsyncTCPSocket::Create(
|
|
||||||
AsyncSocket* socket,
|
|
||||||
const SocketAddress& bind_address,
|
|
||||||
const SocketAddress& remote_address) {
|
|
||||||
return new AsyncTCPSocket(AsyncTCPSocketBase::ConnectSocket(
|
|
||||||
socket, bind_address, remote_address), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncTCPSocket::AsyncTCPSocket(AsyncSocket* socket, bool listen)
|
|
||||||
: AsyncTCPSocketBase(socket, listen, kBufSize) {
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncTCPSocket::Send(const void *pv, size_t cb,
|
|
||||||
const rtc::PacketOptions& options) {
|
|
||||||
if (cb > kBufSize) {
|
|
||||||
SetError(EMSGSIZE);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are blocking on send, then silently drop this packet
|
|
||||||
if (!IsOutBufferEmpty())
|
|
||||||
return static_cast<int>(cb);
|
|
||||||
|
|
||||||
PacketLength pkt_len = HostToNetwork16(static_cast<PacketLength>(cb));
|
|
||||||
AppendToOutBuffer(&pkt_len, kPacketLenSize);
|
|
||||||
AppendToOutBuffer(pv, cb);
|
|
||||||
|
|
||||||
int res = FlushOutBuffer();
|
|
||||||
if (res <= 0) {
|
|
||||||
// drop packet if we made no progress
|
|
||||||
ClearOutBuffer();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We claim to have sent the whole thing, even if we only sent partial
|
|
||||||
return static_cast<int>(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncTCPSocket::ProcessInput(char * data, size_t* len) {
|
|
||||||
SocketAddress remote_addr(GetRemoteAddress());
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (*len < kPacketLenSize)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PacketLength pkt_len = rtc::GetBE16(data);
|
|
||||||
if (*len < kPacketLenSize + pkt_len)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SignalReadPacket(this, data + kPacketLenSize, pkt_len, remote_addr,
|
|
||||||
CreatePacketTime(0));
|
|
||||||
|
|
||||||
*len -= kPacketLenSize + pkt_len;
|
|
||||||
if (*len > 0) {
|
|
||||||
memmove(data, data + kPacketLenSize + pkt_len, *len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncTCPSocket::HandleIncomingConnection(AsyncSocket* socket) {
|
|
||||||
SignalNewConnection(this, new AsyncTCPSocket(socket, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_ASYNCTCPSOCKET_H_
|
|
||||||
#define WEBRTC_BASE_ASYNCTCPSOCKET_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/asyncpacketsocket.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
#include "webrtc/base/socketfactory.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Simulates UDP semantics over TCP. Send and Recv packet sizes
|
|
||||||
// are preserved, and drops packets silently on Send, rather than
|
|
||||||
// buffer them in user space.
|
|
||||||
class AsyncTCPSocketBase : public AsyncPacketSocket {
|
|
||||||
public:
|
|
||||||
AsyncTCPSocketBase(AsyncSocket* socket, bool listen, size_t max_packet_size);
|
|
||||||
virtual ~AsyncTCPSocketBase();
|
|
||||||
|
|
||||||
// Pure virtual methods to send and recv data.
|
|
||||||
virtual int Send(const void *pv, size_t cb,
|
|
||||||
const rtc::PacketOptions& options) = 0;
|
|
||||||
virtual void ProcessInput(char* data, size_t* len) = 0;
|
|
||||||
// Signals incoming connection.
|
|
||||||
virtual void HandleIncomingConnection(AsyncSocket* socket) = 0;
|
|
||||||
|
|
||||||
virtual SocketAddress GetLocalAddress() const;
|
|
||||||
virtual SocketAddress GetRemoteAddress() const;
|
|
||||||
virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr,
|
|
||||||
const rtc::PacketOptions& options);
|
|
||||||
virtual int Close();
|
|
||||||
|
|
||||||
virtual State GetState() const;
|
|
||||||
virtual int GetOption(Socket::Option opt, int* value);
|
|
||||||
virtual int SetOption(Socket::Option opt, int value);
|
|
||||||
virtual int GetError() const;
|
|
||||||
virtual void SetError(int error);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Binds and connects |socket| and creates AsyncTCPSocket for
|
|
||||||
// it. Takes ownership of |socket|. Returns NULL if bind() or
|
|
||||||
// connect() fail (|socket| is destroyed in that case).
|
|
||||||
static AsyncSocket* ConnectSocket(AsyncSocket* socket,
|
|
||||||
const SocketAddress& bind_address,
|
|
||||||
const SocketAddress& remote_address);
|
|
||||||
virtual int SendRaw(const void* pv, size_t cb);
|
|
||||||
int FlushOutBuffer();
|
|
||||||
// Add data to |outbuf_|.
|
|
||||||
void AppendToOutBuffer(const void* pv, size_t cb);
|
|
||||||
|
|
||||||
// Helper methods for |outpos_|.
|
|
||||||
bool IsOutBufferEmpty() const { return outpos_ == 0; }
|
|
||||||
void ClearOutBuffer() { outpos_ = 0; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Called by the underlying socket
|
|
||||||
void OnConnectEvent(AsyncSocket* socket);
|
|
||||||
void OnReadEvent(AsyncSocket* socket);
|
|
||||||
void OnWriteEvent(AsyncSocket* socket);
|
|
||||||
void OnCloseEvent(AsyncSocket* socket, int error);
|
|
||||||
|
|
||||||
scoped_ptr<AsyncSocket> socket_;
|
|
||||||
bool listen_;
|
|
||||||
char* inbuf_, * outbuf_;
|
|
||||||
size_t insize_, inpos_, outsize_, outpos_;
|
|
||||||
|
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(AsyncTCPSocketBase);
|
|
||||||
};
|
|
||||||
|
|
||||||
class AsyncTCPSocket : public AsyncTCPSocketBase {
|
|
||||||
public:
|
|
||||||
// Binds and connects |socket| and creates AsyncTCPSocket for
|
|
||||||
// it. Takes ownership of |socket|. Returns NULL if bind() or
|
|
||||||
// connect() fail (|socket| is destroyed in that case).
|
|
||||||
static AsyncTCPSocket* Create(AsyncSocket* socket,
|
|
||||||
const SocketAddress& bind_address,
|
|
||||||
const SocketAddress& remote_address);
|
|
||||||
AsyncTCPSocket(AsyncSocket* socket, bool listen);
|
|
||||||
virtual ~AsyncTCPSocket() {}
|
|
||||||
|
|
||||||
virtual int Send(const void* pv, size_t cb,
|
|
||||||
const rtc::PacketOptions& options);
|
|
||||||
virtual void ProcessInput(char* data, size_t* len);
|
|
||||||
virtual void HandleIncomingConnection(AsyncSocket* socket);
|
|
||||||
|
|
||||||
private:
|
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(AsyncTCPSocket);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_ASYNCTCPSOCKET_H_
|
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 <string>
|
|
||||||
|
|
||||||
#include "webrtc/base/asynctcpsocket.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/physicalsocketserver.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
#include "webrtc/base/virtualsocketserver.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class AsyncTCPSocketTest
|
|
||||||
: public testing::Test,
|
|
||||||
public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
AsyncTCPSocketTest()
|
|
||||||
: pss_(new rtc::PhysicalSocketServer),
|
|
||||||
vss_(new rtc::VirtualSocketServer(pss_.get())),
|
|
||||||
socket_(vss_->CreateAsyncSocket(SOCK_STREAM)),
|
|
||||||
tcp_socket_(new AsyncTCPSocket(socket_, true)),
|
|
||||||
ready_to_send_(false) {
|
|
||||||
tcp_socket_->SignalReadyToSend.connect(this,
|
|
||||||
&AsyncTCPSocketTest::OnReadyToSend);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnReadyToSend(rtc::AsyncPacketSocket* socket) {
|
|
||||||
ready_to_send_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
scoped_ptr<PhysicalSocketServer> pss_;
|
|
||||||
scoped_ptr<VirtualSocketServer> vss_;
|
|
||||||
AsyncSocket* socket_;
|
|
||||||
scoped_ptr<AsyncTCPSocket> tcp_socket_;
|
|
||||||
bool ready_to_send_;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(AsyncTCPSocketTest, OnWriteEvent) {
|
|
||||||
EXPECT_FALSE(ready_to_send_);
|
|
||||||
socket_->SignalWriteEvent(socket_);
|
|
||||||
EXPECT_TRUE(ready_to_send_);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,122 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/asyncudpsocket.h"
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
static const int BUF_SIZE = 64 * 1024;
|
|
||||||
|
|
||||||
AsyncUDPSocket* AsyncUDPSocket::Create(
|
|
||||||
AsyncSocket* socket,
|
|
||||||
const SocketAddress& bind_address) {
|
|
||||||
scoped_ptr<AsyncSocket> owned_socket(socket);
|
|
||||||
if (socket->Bind(bind_address) < 0) {
|
|
||||||
LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return new AsyncUDPSocket(owned_socket.release());
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncUDPSocket* AsyncUDPSocket::Create(SocketFactory* factory,
|
|
||||||
const SocketAddress& bind_address) {
|
|
||||||
AsyncSocket* socket =
|
|
||||||
factory->CreateAsyncSocket(bind_address.family(), SOCK_DGRAM);
|
|
||||||
if (!socket)
|
|
||||||
return NULL;
|
|
||||||
return Create(socket, bind_address);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncUDPSocket::AsyncUDPSocket(AsyncSocket* socket)
|
|
||||||
: socket_(socket) {
|
|
||||||
ASSERT(socket_);
|
|
||||||
size_ = BUF_SIZE;
|
|
||||||
buf_ = new char[size_];
|
|
||||||
|
|
||||||
// The socket should start out readable but not writable.
|
|
||||||
socket_->SignalReadEvent.connect(this, &AsyncUDPSocket::OnReadEvent);
|
|
||||||
socket_->SignalWriteEvent.connect(this, &AsyncUDPSocket::OnWriteEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncUDPSocket::~AsyncUDPSocket() {
|
|
||||||
delete [] buf_;
|
|
||||||
}
|
|
||||||
|
|
||||||
SocketAddress AsyncUDPSocket::GetLocalAddress() const {
|
|
||||||
return socket_->GetLocalAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
SocketAddress AsyncUDPSocket::GetRemoteAddress() const {
|
|
||||||
return socket_->GetRemoteAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncUDPSocket::Send(const void *pv, size_t cb,
|
|
||||||
const rtc::PacketOptions& options) {
|
|
||||||
return socket_->Send(pv, cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncUDPSocket::SendTo(const void *pv, size_t cb,
|
|
||||||
const SocketAddress& addr,
|
|
||||||
const rtc::PacketOptions& options) {
|
|
||||||
return socket_->SendTo(pv, cb, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncUDPSocket::Close() {
|
|
||||||
return socket_->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncUDPSocket::State AsyncUDPSocket::GetState() const {
|
|
||||||
return STATE_BOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncUDPSocket::GetOption(Socket::Option opt, int* value) {
|
|
||||||
return socket_->GetOption(opt, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncUDPSocket::SetOption(Socket::Option opt, int value) {
|
|
||||||
return socket_->SetOption(opt, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int AsyncUDPSocket::GetError() const {
|
|
||||||
return socket_->GetError();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncUDPSocket::SetError(int error) {
|
|
||||||
return socket_->SetError(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncUDPSocket::OnReadEvent(AsyncSocket* socket) {
|
|
||||||
ASSERT(socket_.get() == socket);
|
|
||||||
|
|
||||||
SocketAddress remote_addr;
|
|
||||||
int len = socket_->RecvFrom(buf_, size_, &remote_addr);
|
|
||||||
if (len < 0) {
|
|
||||||
// An error here typically means we got an ICMP error in response to our
|
|
||||||
// send datagram, indicating the remote address was unreachable.
|
|
||||||
// When doing ICE, this kind of thing will often happen.
|
|
||||||
// TODO: Do something better like forwarding the error to the user.
|
|
||||||
SocketAddress local_addr = socket_->GetLocalAddress();
|
|
||||||
LOG(LS_INFO) << "AsyncUDPSocket[" << local_addr.ToSensitiveString() << "] "
|
|
||||||
<< "receive failed with error " << socket_->GetError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Make sure that we got all of the packet.
|
|
||||||
// If we did not, then we should resize our buffer to be large enough.
|
|
||||||
SignalReadPacket(this, buf_, static_cast<size_t>(len), remote_addr,
|
|
||||||
CreatePacketTime(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncUDPSocket::OnWriteEvent(AsyncSocket* socket) {
|
|
||||||
SignalReadyToSend(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_ASYNCUDPSOCKET_H_
|
|
||||||
#define WEBRTC_BASE_ASYNCUDPSOCKET_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/asyncpacketsocket.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
#include "webrtc/base/socketfactory.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Provides the ability to receive packets asynchronously. Sends are not
|
|
||||||
// buffered since it is acceptable to drop packets under high load.
|
|
||||||
class AsyncUDPSocket : public AsyncPacketSocket {
|
|
||||||
public:
|
|
||||||
// Binds |socket| and creates AsyncUDPSocket for it. Takes ownership
|
|
||||||
// of |socket|. Returns NULL if bind() fails (|socket| is destroyed
|
|
||||||
// in that case).
|
|
||||||
static AsyncUDPSocket* Create(AsyncSocket* socket,
|
|
||||||
const SocketAddress& bind_address);
|
|
||||||
// Creates a new socket for sending asynchronous UDP packets using an
|
|
||||||
// asynchronous socket from the given factory.
|
|
||||||
static AsyncUDPSocket* Create(SocketFactory* factory,
|
|
||||||
const SocketAddress& bind_address);
|
|
||||||
explicit AsyncUDPSocket(AsyncSocket* socket);
|
|
||||||
virtual ~AsyncUDPSocket();
|
|
||||||
|
|
||||||
virtual SocketAddress GetLocalAddress() const;
|
|
||||||
virtual SocketAddress GetRemoteAddress() const;
|
|
||||||
virtual int Send(const void *pv, size_t cb,
|
|
||||||
const rtc::PacketOptions& options);
|
|
||||||
virtual int SendTo(const void *pv, size_t cb, const SocketAddress& addr,
|
|
||||||
const rtc::PacketOptions& options);
|
|
||||||
virtual int Close();
|
|
||||||
|
|
||||||
virtual State GetState() const;
|
|
||||||
virtual int GetOption(Socket::Option opt, int* value);
|
|
||||||
virtual int SetOption(Socket::Option opt, int value);
|
|
||||||
virtual int GetError() const;
|
|
||||||
virtual void SetError(int error);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Called when the underlying socket is ready to be read from.
|
|
||||||
void OnReadEvent(AsyncSocket* socket);
|
|
||||||
// Called when the underlying socket is ready to send.
|
|
||||||
void OnWriteEvent(AsyncSocket* socket);
|
|
||||||
|
|
||||||
scoped_ptr<AsyncSocket> socket_;
|
|
||||||
char* buf_;
|
|
||||||
size_t size_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_ASYNCUDPSOCKET_H_
|
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 <string>
|
|
||||||
|
|
||||||
#include "webrtc/base/asyncudpsocket.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/physicalsocketserver.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
#include "webrtc/base/virtualsocketserver.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class AsyncUdpSocketTest
|
|
||||||
: public testing::Test,
|
|
||||||
public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
AsyncUdpSocketTest()
|
|
||||||
: pss_(new rtc::PhysicalSocketServer),
|
|
||||||
vss_(new rtc::VirtualSocketServer(pss_.get())),
|
|
||||||
socket_(vss_->CreateAsyncSocket(SOCK_DGRAM)),
|
|
||||||
udp_socket_(new AsyncUDPSocket(socket_)),
|
|
||||||
ready_to_send_(false) {
|
|
||||||
udp_socket_->SignalReadyToSend.connect(this,
|
|
||||||
&AsyncUdpSocketTest::OnReadyToSend);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnReadyToSend(rtc::AsyncPacketSocket* socket) {
|
|
||||||
ready_to_send_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
scoped_ptr<PhysicalSocketServer> pss_;
|
|
||||||
scoped_ptr<VirtualSocketServer> vss_;
|
|
||||||
AsyncSocket* socket_;
|
|
||||||
scoped_ptr<AsyncUDPSocket> udp_socket_;
|
|
||||||
bool ready_to_send_;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(AsyncUdpSocketTest, OnWriteEvent) {
|
|
||||||
EXPECT_FALSE(ready_to_send_);
|
|
||||||
socket_->SignalWriteEvent(socket_);
|
|
||||||
EXPECT_TRUE(ready_to_send_);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,149 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_ATOMICOPS_H_
|
|
||||||
#define WEBRTC_BASE_ATOMICOPS_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// A single-producer, single-consumer, fixed-size queue.
|
|
||||||
// All methods not ending in Unsafe can be safely called without locking,
|
|
||||||
// provided that calls to consumer methods (Peek/Pop) or producer methods (Push)
|
|
||||||
// only happen on a single thread per method type. If multiple threads need to
|
|
||||||
// read simultaneously or write simultaneously, other synchronization is
|
|
||||||
// necessary. Synchronization is also required if a call into any Unsafe method
|
|
||||||
// could happen at the same time as a call to any other method.
|
|
||||||
template <typename T>
|
|
||||||
class FixedSizeLockFreeQueue {
|
|
||||||
private:
|
|
||||||
// Atomic primitives and memory barrier
|
|
||||||
#if defined(__arm__)
|
|
||||||
typedef uint32 Atomic32;
|
|
||||||
|
|
||||||
// Copied from google3/base/atomicops-internals-arm-v6plus.h
|
|
||||||
static inline void MemoryBarrier() {
|
|
||||||
asm volatile("dmb":::"memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adapted from google3/base/atomicops-internals-arm-v6plus.h
|
|
||||||
static inline void AtomicIncrement(volatile Atomic32* ptr) {
|
|
||||||
Atomic32 str_success, value;
|
|
||||||
asm volatile (
|
|
||||||
"1:\n"
|
|
||||||
"ldrex %1, [%2]\n"
|
|
||||||
"add %1, %1, #1\n"
|
|
||||||
"strex %0, %1, [%2]\n"
|
|
||||||
"teq %0, #0\n"
|
|
||||||
"bne 1b"
|
|
||||||
: "=&r"(str_success), "=&r"(value)
|
|
||||||
: "r" (ptr)
|
|
||||||
: "cc", "memory");
|
|
||||||
}
|
|
||||||
#elif !defined(SKIP_ATOMIC_CHECK)
|
|
||||||
#error "No atomic operations defined for the given architecture."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Constructs an empty queue, with capacity 0.
|
|
||||||
FixedSizeLockFreeQueue() : pushed_count_(0),
|
|
||||||
popped_count_(0),
|
|
||||||
capacity_(0),
|
|
||||||
data_() {}
|
|
||||||
// Constructs an empty queue with the given capacity.
|
|
||||||
FixedSizeLockFreeQueue(size_t capacity) : pushed_count_(0),
|
|
||||||
popped_count_(0),
|
|
||||||
capacity_(capacity),
|
|
||||||
data_(new T[capacity]) {}
|
|
||||||
|
|
||||||
// Pushes a value onto the queue. Returns true if the value was successfully
|
|
||||||
// pushed (there was space in the queue). This method can be safely called at
|
|
||||||
// the same time as PeekFront/PopFront.
|
|
||||||
bool PushBack(T value) {
|
|
||||||
if (capacity_ == 0) {
|
|
||||||
LOG(LS_WARNING) << "Queue capacity is 0.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (IsFull()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
data_[pushed_count_ % capacity_] = value;
|
|
||||||
// Make sure the data is written before the count is incremented, so other
|
|
||||||
// threads can't see the value exists before being able to read it.
|
|
||||||
MemoryBarrier();
|
|
||||||
AtomicIncrement(&pushed_count_);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieves the oldest value pushed onto the queue. Returns true if there was
|
|
||||||
// an item to peek (the queue was non-empty). This method can be safely called
|
|
||||||
// at the same time as PushBack.
|
|
||||||
bool PeekFront(T* value_out) {
|
|
||||||
if (capacity_ == 0) {
|
|
||||||
LOG(LS_WARNING) << "Queue capacity is 0.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (IsEmpty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*value_out = data_[popped_count_ % capacity_];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieves the oldest value pushed onto the queue and removes it from the
|
|
||||||
// queue. Returns true if there was an item to pop (the queue was non-empty).
|
|
||||||
// This method can be safely called at the same time as PushBack.
|
|
||||||
bool PopFront(T* value_out) {
|
|
||||||
if (PeekFront(value_out)) {
|
|
||||||
AtomicIncrement(&popped_count_);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clears the current items in the queue and sets the new (fixed) size. This
|
|
||||||
// method cannot be called at the same time as any other method.
|
|
||||||
void ClearAndResizeUnsafe(int new_capacity) {
|
|
||||||
capacity_ = new_capacity;
|
|
||||||
data_.reset(new T[new_capacity]);
|
|
||||||
pushed_count_ = 0;
|
|
||||||
popped_count_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if there is no space left in the queue for new elements.
|
|
||||||
int IsFull() const { return pushed_count_ == popped_count_ + capacity_; }
|
|
||||||
// Returns true if there are no elements in the queue.
|
|
||||||
int IsEmpty() const { return pushed_count_ == popped_count_; }
|
|
||||||
// Returns the current number of elements in the queue. This is always in the
|
|
||||||
// range [0, capacity]
|
|
||||||
size_t Size() const { return pushed_count_ - popped_count_; }
|
|
||||||
|
|
||||||
// Returns the capacity of the queue (max size).
|
|
||||||
size_t capacity() const { return capacity_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
volatile Atomic32 pushed_count_;
|
|
||||||
volatile Atomic32 popped_count_;
|
|
||||||
size_t capacity_;
|
|
||||||
rtc::scoped_ptr<T[]> data_;
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(FixedSizeLockFreeQueue);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_ATOMICOPS_H_
|
|
@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if !defined(__arm__)
|
|
||||||
// For testing purposes, define faked versions of the atomic operations
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
namespace rtc {
|
|
||||||
typedef uint32 Atomic32;
|
|
||||||
static inline void MemoryBarrier() { }
|
|
||||||
static inline void AtomicIncrement(volatile Atomic32* ptr) {
|
|
||||||
*ptr = *ptr + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#define SKIP_ATOMIC_CHECK
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "webrtc/base/atomicops.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/helpers.h"
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
|
|
||||||
TEST(FixedSizeLockFreeQueueTest, TestDefaultConstruct) {
|
|
||||||
rtc::FixedSizeLockFreeQueue<int> queue;
|
|
||||||
EXPECT_EQ(0u, queue.capacity());
|
|
||||||
EXPECT_EQ(0u, queue.Size());
|
|
||||||
EXPECT_FALSE(queue.PushBack(1));
|
|
||||||
int val;
|
|
||||||
EXPECT_FALSE(queue.PopFront(&val));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FixedSizeLockFreeQueueTest, TestConstruct) {
|
|
||||||
rtc::FixedSizeLockFreeQueue<int> queue(5);
|
|
||||||
EXPECT_EQ(5u, queue.capacity());
|
|
||||||
EXPECT_EQ(0u, queue.Size());
|
|
||||||
int val;
|
|
||||||
EXPECT_FALSE(queue.PopFront(&val));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FixedSizeLockFreeQueueTest, TestPushPop) {
|
|
||||||
rtc::FixedSizeLockFreeQueue<int> queue(2);
|
|
||||||
EXPECT_EQ(2u, queue.capacity());
|
|
||||||
EXPECT_EQ(0u, queue.Size());
|
|
||||||
EXPECT_TRUE(queue.PushBack(1));
|
|
||||||
EXPECT_EQ(1u, queue.Size());
|
|
||||||
EXPECT_TRUE(queue.PushBack(2));
|
|
||||||
EXPECT_EQ(2u, queue.Size());
|
|
||||||
EXPECT_FALSE(queue.PushBack(3));
|
|
||||||
EXPECT_EQ(2u, queue.Size());
|
|
||||||
int val;
|
|
||||||
EXPECT_TRUE(queue.PopFront(&val));
|
|
||||||
EXPECT_EQ(1, val);
|
|
||||||
EXPECT_EQ(1u, queue.Size());
|
|
||||||
EXPECT_TRUE(queue.PopFront(&val));
|
|
||||||
EXPECT_EQ(2, val);
|
|
||||||
EXPECT_EQ(0u, queue.Size());
|
|
||||||
EXPECT_FALSE(queue.PopFront(&val));
|
|
||||||
EXPECT_EQ(0u, queue.Size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FixedSizeLockFreeQueueTest, TestResize) {
|
|
||||||
rtc::FixedSizeLockFreeQueue<int> queue(2);
|
|
||||||
EXPECT_EQ(2u, queue.capacity());
|
|
||||||
EXPECT_EQ(0u, queue.Size());
|
|
||||||
EXPECT_TRUE(queue.PushBack(1));
|
|
||||||
EXPECT_EQ(1u, queue.Size());
|
|
||||||
|
|
||||||
queue.ClearAndResizeUnsafe(5);
|
|
||||||
EXPECT_EQ(5u, queue.capacity());
|
|
||||||
EXPECT_EQ(0u, queue.Size());
|
|
||||||
int val;
|
|
||||||
EXPECT_FALSE(queue.PopFront(&val));
|
|
||||||
}
|
|
@ -1,282 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/autodetectproxy.h"
|
|
||||||
#include "webrtc/base/httpcommon.h"
|
|
||||||
#include "webrtc/base/httpcommon-inl.h"
|
|
||||||
#include "webrtc/base/nethelpers.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
static const ProxyType TEST_ORDER[] = {
|
|
||||||
PROXY_HTTPS, PROXY_SOCKS5, PROXY_UNKNOWN
|
|
||||||
};
|
|
||||||
|
|
||||||
static const int kSavedStringLimit = 128;
|
|
||||||
|
|
||||||
static void SaveStringToStack(char *dst,
|
|
||||||
const std::string &src,
|
|
||||||
size_t dst_size) {
|
|
||||||
strncpy(dst, src.c_str(), dst_size - 1);
|
|
||||||
dst[dst_size - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoDetectProxy::AutoDetectProxy(const std::string& user_agent)
|
|
||||||
: agent_(user_agent), resolver_(NULL), socket_(NULL), next_(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoDetectProxy::~AutoDetectProxy() {
|
|
||||||
if (resolver_) {
|
|
||||||
resolver_->Destroy(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDetectProxy::DoWork() {
|
|
||||||
// TODO: Try connecting to server_url without proxy first here?
|
|
||||||
if (!server_url_.empty()) {
|
|
||||||
LOG(LS_INFO) << "GetProxySettingsForUrl(" << server_url_ << ") - start";
|
|
||||||
GetProxyForUrl(agent_.c_str(), server_url_.c_str(), &proxy_);
|
|
||||||
LOG(LS_INFO) << "GetProxySettingsForUrl - stop";
|
|
||||||
}
|
|
||||||
Url<char> url(proxy_.address.HostAsURIString());
|
|
||||||
if (url.valid()) {
|
|
||||||
LOG(LS_WARNING) << "AutoDetectProxy removing http prefix on proxy host";
|
|
||||||
proxy_.address.SetIP(url.host());
|
|
||||||
}
|
|
||||||
LOG(LS_INFO) << "AutoDetectProxy found proxy at " << proxy_.address;
|
|
||||||
if (proxy_.type == PROXY_UNKNOWN) {
|
|
||||||
LOG(LS_INFO) << "AutoDetectProxy initiating proxy classification";
|
|
||||||
Next();
|
|
||||||
// Process I/O until Stop()
|
|
||||||
Thread::Current()->ProcessMessages(kForever);
|
|
||||||
// Clean up the autodetect socket, from the thread that created it
|
|
||||||
delete socket_;
|
|
||||||
}
|
|
||||||
// TODO: If we found a proxy, try to use it to verify that it
|
|
||||||
// works by sending a request to server_url. This could either be
|
|
||||||
// done here or by the HttpPortAllocator.
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDetectProxy::OnMessage(Message *msg) {
|
|
||||||
if (MSG_UNRESOLVABLE == msg->message_id) {
|
|
||||||
// If we can't resolve the proxy, skip straight to failure.
|
|
||||||
Complete(PROXY_UNKNOWN);
|
|
||||||
} else if (MSG_TIMEOUT == msg->message_id) {
|
|
||||||
OnCloseEvent(socket_, ETIMEDOUT);
|
|
||||||
} else {
|
|
||||||
// This must be the ST_MSG_WORKER_DONE message that deletes the
|
|
||||||
// AutoDetectProxy object. We have observed crashes within this stack that
|
|
||||||
// seem to be highly reproducible for a small subset of users and thus are
|
|
||||||
// probably correlated with a specific proxy setting, so copy potentially
|
|
||||||
// relevant information onto the stack to make it available in Windows
|
|
||||||
// minidumps.
|
|
||||||
|
|
||||||
// Save the user agent and the number of auto-detection passes that we
|
|
||||||
// needed.
|
|
||||||
char agent[kSavedStringLimit];
|
|
||||||
SaveStringToStack(agent, agent_, sizeof agent);
|
|
||||||
|
|
||||||
int next = next_;
|
|
||||||
|
|
||||||
// Now the detected proxy config (minus the password field, which could be
|
|
||||||
// sensitive).
|
|
||||||
ProxyType type = proxy().type;
|
|
||||||
|
|
||||||
char address_hostname[kSavedStringLimit];
|
|
||||||
SaveStringToStack(address_hostname,
|
|
||||||
proxy().address.hostname(),
|
|
||||||
sizeof address_hostname);
|
|
||||||
|
|
||||||
IPAddress address_ip = proxy().address.ipaddr();
|
|
||||||
|
|
||||||
uint16 address_port = proxy().address.port();
|
|
||||||
|
|
||||||
char autoconfig_url[kSavedStringLimit];
|
|
||||||
SaveStringToStack(autoconfig_url,
|
|
||||||
proxy().autoconfig_url,
|
|
||||||
sizeof autoconfig_url);
|
|
||||||
|
|
||||||
bool autodetect = proxy().autodetect;
|
|
||||||
|
|
||||||
char bypass_list[kSavedStringLimit];
|
|
||||||
SaveStringToStack(bypass_list, proxy().bypass_list, sizeof bypass_list);
|
|
||||||
|
|
||||||
char username[kSavedStringLimit];
|
|
||||||
SaveStringToStack(username, proxy().username, sizeof username);
|
|
||||||
|
|
||||||
SignalThread::OnMessage(msg);
|
|
||||||
|
|
||||||
// Log the gathered data at a log level that will never actually be enabled
|
|
||||||
// so that the compiler is forced to retain the data on the stack.
|
|
||||||
LOG(LS_SENSITIVE) << agent << " " << next << " " << type << " "
|
|
||||||
<< address_hostname << " " << address_ip << " "
|
|
||||||
<< address_port << " " << autoconfig_url << " "
|
|
||||||
<< autodetect << " " << bypass_list << " " << username;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDetectProxy::OnResolveResult(AsyncResolverInterface* resolver) {
|
|
||||||
if (resolver != resolver_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int error = resolver_->GetError();
|
|
||||||
if (error == 0) {
|
|
||||||
LOG(LS_VERBOSE) << "Resolved " << proxy_.address << " to "
|
|
||||||
<< resolver_->address();
|
|
||||||
proxy_.address = resolver_->address();
|
|
||||||
if (!DoConnect()) {
|
|
||||||
Thread::Current()->Post(this, MSG_TIMEOUT);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(LS_INFO) << "Failed to resolve " << resolver_->address();
|
|
||||||
resolver_->Destroy(false);
|
|
||||||
resolver_ = NULL;
|
|
||||||
proxy_.address = SocketAddress();
|
|
||||||
Thread::Current()->Post(this, MSG_UNRESOLVABLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDetectProxy::Next() {
|
|
||||||
if (TEST_ORDER[next_] >= PROXY_UNKNOWN) {
|
|
||||||
Complete(PROXY_UNKNOWN);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(LS_VERBOSE) << "AutoDetectProxy connecting to "
|
|
||||||
<< proxy_.address.ToSensitiveString();
|
|
||||||
|
|
||||||
if (socket_) {
|
|
||||||
Thread::Current()->Clear(this, MSG_TIMEOUT);
|
|
||||||
Thread::Current()->Clear(this, MSG_UNRESOLVABLE);
|
|
||||||
socket_->Close();
|
|
||||||
Thread::Current()->Dispose(socket_);
|
|
||||||
socket_ = NULL;
|
|
||||||
}
|
|
||||||
int timeout = 2000;
|
|
||||||
if (proxy_.address.IsUnresolvedIP()) {
|
|
||||||
// Launch an asyncresolver. This thread will spin waiting for it.
|
|
||||||
timeout += 2000;
|
|
||||||
if (!resolver_) {
|
|
||||||
resolver_ = new AsyncResolver();
|
|
||||||
}
|
|
||||||
resolver_->SignalDone.connect(this, &AutoDetectProxy::OnResolveResult);
|
|
||||||
resolver_->Start(proxy_.address);
|
|
||||||
} else {
|
|
||||||
if (!DoConnect()) {
|
|
||||||
Thread::Current()->Post(this, MSG_TIMEOUT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Thread::Current()->PostDelayed(timeout, this, MSG_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AutoDetectProxy::DoConnect() {
|
|
||||||
if (resolver_) {
|
|
||||||
resolver_->Destroy(false);
|
|
||||||
resolver_ = NULL;
|
|
||||||
}
|
|
||||||
socket_ =
|
|
||||||
Thread::Current()->socketserver()->CreateAsyncSocket(
|
|
||||||
proxy_.address.family(), SOCK_STREAM);
|
|
||||||
if (!socket_) {
|
|
||||||
LOG(LS_VERBOSE) << "Unable to create socket for " << proxy_.address;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
socket_->SignalConnectEvent.connect(this, &AutoDetectProxy::OnConnectEvent);
|
|
||||||
socket_->SignalReadEvent.connect(this, &AutoDetectProxy::OnReadEvent);
|
|
||||||
socket_->SignalCloseEvent.connect(this, &AutoDetectProxy::OnCloseEvent);
|
|
||||||
socket_->Connect(proxy_.address);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDetectProxy::Complete(ProxyType type) {
|
|
||||||
Thread::Current()->Clear(this, MSG_TIMEOUT);
|
|
||||||
Thread::Current()->Clear(this, MSG_UNRESOLVABLE);
|
|
||||||
if (socket_) {
|
|
||||||
socket_->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy_.type = type;
|
|
||||||
LoggingSeverity sev = (proxy_.type == PROXY_UNKNOWN) ? LS_ERROR : LS_INFO;
|
|
||||||
LOG_V(sev) << "AutoDetectProxy detected "
|
|
||||||
<< proxy_.address.ToSensitiveString()
|
|
||||||
<< " as type " << proxy_.type;
|
|
||||||
|
|
||||||
Thread::Current()->Quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDetectProxy::OnConnectEvent(AsyncSocket * socket) {
|
|
||||||
std::string probe;
|
|
||||||
|
|
||||||
switch (TEST_ORDER[next_]) {
|
|
||||||
case PROXY_HTTPS:
|
|
||||||
probe.assign("CONNECT www.google.com:443 HTTP/1.0\r\n"
|
|
||||||
"User-Agent: ");
|
|
||||||
probe.append(agent_);
|
|
||||||
probe.append("\r\n"
|
|
||||||
"Host: www.google.com\r\n"
|
|
||||||
"Content-Length: 0\r\n"
|
|
||||||
"Proxy-Connection: Keep-Alive\r\n"
|
|
||||||
"\r\n");
|
|
||||||
break;
|
|
||||||
case PROXY_SOCKS5:
|
|
||||||
probe.assign("\005\001\000", 3);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ASSERT(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(LS_VERBOSE) << "AutoDetectProxy probing type " << TEST_ORDER[next_]
|
|
||||||
<< " sending " << probe.size() << " bytes";
|
|
||||||
socket_->Send(probe.data(), probe.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDetectProxy::OnReadEvent(AsyncSocket * socket) {
|
|
||||||
char data[257];
|
|
||||||
int len = socket_->Recv(data, 256);
|
|
||||||
if (len > 0) {
|
|
||||||
data[len] = 0;
|
|
||||||
LOG(LS_VERBOSE) << "AutoDetectProxy read " << len << " bytes";
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (TEST_ORDER[next_]) {
|
|
||||||
case PROXY_HTTPS:
|
|
||||||
if ((len >= 2) && (data[0] == '\x05')) {
|
|
||||||
Complete(PROXY_SOCKS5);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((len >= 5) && (strncmp(data, "HTTP/", 5) == 0)) {
|
|
||||||
Complete(PROXY_HTTPS);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PROXY_SOCKS5:
|
|
||||||
if ((len >= 2) && (data[0] == '\x05')) {
|
|
||||||
Complete(PROXY_SOCKS5);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ASSERT(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
++next_;
|
|
||||||
Next();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AutoDetectProxy::OnCloseEvent(AsyncSocket * socket, int error) {
|
|
||||||
LOG(LS_VERBOSE) << "AutoDetectProxy closed with error: " << error;
|
|
||||||
++next_;
|
|
||||||
Next();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_AUTODETECTPROXY_H_
|
|
||||||
#define WEBRTC_BASE_AUTODETECTPROXY_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "webrtc/base/constructormagic.h"
|
|
||||||
#include "webrtc/base/cryptstring.h"
|
|
||||||
#include "webrtc/base/proxydetect.h"
|
|
||||||
#include "webrtc/base/proxyinfo.h"
|
|
||||||
#include "webrtc/base/signalthread.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// AutoDetectProxy
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class AsyncResolverInterface;
|
|
||||||
class AsyncSocket;
|
|
||||||
|
|
||||||
class AutoDetectProxy : public SignalThread {
|
|
||||||
public:
|
|
||||||
explicit AutoDetectProxy(const std::string& user_agent);
|
|
||||||
|
|
||||||
const ProxyInfo& proxy() const { return proxy_; }
|
|
||||||
|
|
||||||
void set_server_url(const std::string& url) {
|
|
||||||
server_url_ = url;
|
|
||||||
}
|
|
||||||
void set_proxy(const SocketAddress& proxy) {
|
|
||||||
proxy_.type = PROXY_UNKNOWN;
|
|
||||||
proxy_.address = proxy;
|
|
||||||
}
|
|
||||||
void set_auth_info(bool use_auth, const std::string& username,
|
|
||||||
const CryptString& password) {
|
|
||||||
if (use_auth) {
|
|
||||||
proxy_.username = username;
|
|
||||||
proxy_.password = password;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Default implementation of GetProxySettingsForUrl. Override for special
|
|
||||||
// implementation.
|
|
||||||
virtual bool GetProxyForUrl(const char* agent, const char* url,
|
|
||||||
rtc::ProxyInfo* proxy) {
|
|
||||||
return GetProxySettingsForUrl(agent, url, proxy, true);
|
|
||||||
}
|
|
||||||
enum { MSG_TIMEOUT = SignalThread::ST_MSG_FIRST_AVAILABLE,
|
|
||||||
MSG_UNRESOLVABLE,
|
|
||||||
ADP_MSG_FIRST_AVAILABLE};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~AutoDetectProxy();
|
|
||||||
|
|
||||||
// SignalThread Interface
|
|
||||||
virtual void DoWork();
|
|
||||||
virtual void OnMessage(Message *msg);
|
|
||||||
|
|
||||||
void Next();
|
|
||||||
void Complete(ProxyType type);
|
|
||||||
|
|
||||||
void OnConnectEvent(AsyncSocket * socket);
|
|
||||||
void OnReadEvent(AsyncSocket * socket);
|
|
||||||
void OnCloseEvent(AsyncSocket * socket, int error);
|
|
||||||
void OnResolveResult(AsyncResolverInterface* resolver);
|
|
||||||
bool DoConnect();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string agent_;
|
|
||||||
std::string server_url_;
|
|
||||||
ProxyInfo proxy_;
|
|
||||||
AsyncResolverInterface* resolver_;
|
|
||||||
AsyncSocket* socket_;
|
|
||||||
int next_;
|
|
||||||
|
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(AutoDetectProxy);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_AUTODETECTPROXY_H_
|
|
@ -1,131 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/autodetectproxy.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/httpcommon.h"
|
|
||||||
#include "webrtc/base/httpcommon-inl.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
static const char kUserAgent[] = "";
|
|
||||||
static const char kPath[] = "/";
|
|
||||||
static const char kHost[] = "relay.google.com";
|
|
||||||
static const uint16 kPort = 443;
|
|
||||||
static const bool kSecure = true;
|
|
||||||
// At most, AutoDetectProxy should take ~6 seconds. Each connect step is
|
|
||||||
// allotted 2 seconds, with the initial resolution + connect given an
|
|
||||||
// extra 2 seconds. The slowest case is:
|
|
||||||
// 1) Resolution + HTTPS takes full 4 seconds and fails (but resolution
|
|
||||||
// succeeds).
|
|
||||||
// 2) SOCKS5 takes the full 2 seconds.
|
|
||||||
// Socket creation time seems unbounded, and has been observed to take >1 second
|
|
||||||
// on a linux machine under load. As such, we allow for 10 seconds for timeout,
|
|
||||||
// though could still end up with some flakiness.
|
|
||||||
static const int kTimeoutMs = 10000;
|
|
||||||
|
|
||||||
class AutoDetectProxyTest : public testing::Test, public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
AutoDetectProxyTest() : auto_detect_proxy_(NULL), done_(false) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool Create(const std::string &user_agent,
|
|
||||||
const std::string &path,
|
|
||||||
const std::string &host,
|
|
||||||
uint16 port,
|
|
||||||
bool secure,
|
|
||||||
bool startnow) {
|
|
||||||
auto_detect_proxy_ = new AutoDetectProxy(user_agent);
|
|
||||||
EXPECT_TRUE(auto_detect_proxy_ != NULL);
|
|
||||||
if (!auto_detect_proxy_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Url<char> host_url(path, host, port);
|
|
||||||
host_url.set_secure(secure);
|
|
||||||
auto_detect_proxy_->set_server_url(host_url.url());
|
|
||||||
auto_detect_proxy_->SignalWorkDone.connect(
|
|
||||||
this,
|
|
||||||
&AutoDetectProxyTest::OnWorkDone);
|
|
||||||
if (startnow) {
|
|
||||||
auto_detect_proxy_->Start();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Run(int timeout_ms) {
|
|
||||||
EXPECT_TRUE_WAIT(done_, timeout_ms);
|
|
||||||
return done_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetProxy(const SocketAddress& proxy) {
|
|
||||||
auto_detect_proxy_->set_proxy(proxy);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Start() {
|
|
||||||
auto_detect_proxy_->Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestCopesWithProxy(const SocketAddress& proxy) {
|
|
||||||
// Tests that at least autodetect doesn't crash for a given proxy address.
|
|
||||||
ASSERT_TRUE(Create(kUserAgent,
|
|
||||||
kPath,
|
|
||||||
kHost,
|
|
||||||
kPort,
|
|
||||||
kSecure,
|
|
||||||
false));
|
|
||||||
SetProxy(proxy);
|
|
||||||
Start();
|
|
||||||
ASSERT_TRUE(Run(kTimeoutMs));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnWorkDone(rtc::SignalThread *thread) {
|
|
||||||
AutoDetectProxy *auto_detect_proxy =
|
|
||||||
static_cast<rtc::AutoDetectProxy *>(thread);
|
|
||||||
EXPECT_TRUE(auto_detect_proxy == auto_detect_proxy_);
|
|
||||||
auto_detect_proxy_ = NULL;
|
|
||||||
auto_detect_proxy->Release();
|
|
||||||
done_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoDetectProxy *auto_detect_proxy_;
|
|
||||||
bool done_;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(AutoDetectProxyTest, TestDetectUnresolvedProxy) {
|
|
||||||
TestCopesWithProxy(rtc::SocketAddress("localhost", 9999));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AutoDetectProxyTest, TestDetectUnresolvableProxy) {
|
|
||||||
TestCopesWithProxy(rtc::SocketAddress("invalid", 9999));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AutoDetectProxyTest, TestDetectIPv6Proxy) {
|
|
||||||
TestCopesWithProxy(rtc::SocketAddress("::1", 9999));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AutoDetectProxyTest, TestDetectIPv4Proxy) {
|
|
||||||
TestCopesWithProxy(rtc::SocketAddress("127.0.0.1", 9999));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that proxy detection completes successfully. (Does not actually verify
|
|
||||||
// the correct detection result since we don't know what proxy to expect on an
|
|
||||||
// arbitrary machine.)
|
|
||||||
TEST_F(AutoDetectProxyTest, TestProxyDetection) {
|
|
||||||
ASSERT_TRUE(Create(kUserAgent,
|
|
||||||
kPath,
|
|
||||||
kHost,
|
|
||||||
kPort,
|
|
||||||
kSecure,
|
|
||||||
true));
|
|
||||||
ASSERT_TRUE(Run(kTimeoutMs));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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 "webrtc/base/bandwidthsmoother.h"
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
BandwidthSmoother::BandwidthSmoother(int initial_bandwidth_guess,
|
|
||||||
uint32 time_between_increase,
|
|
||||||
double percent_increase,
|
|
||||||
size_t samples_count_to_average,
|
|
||||||
double min_sample_count_percent)
|
|
||||||
: time_between_increase_(time_between_increase),
|
|
||||||
percent_increase_(rtc::_max(1.0, percent_increase)),
|
|
||||||
time_at_last_change_(0),
|
|
||||||
bandwidth_estimation_(initial_bandwidth_guess),
|
|
||||||
accumulator_(samples_count_to_average),
|
|
||||||
min_sample_count_percent_(
|
|
||||||
rtc::_min(1.0,
|
|
||||||
rtc::_max(0.0, min_sample_count_percent))) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Samples a new bandwidth measurement
|
|
||||||
// returns true if the bandwidth estimation changed
|
|
||||||
bool BandwidthSmoother::Sample(uint32 sample_time, int bandwidth) {
|
|
||||||
if (bandwidth < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
accumulator_.AddSample(bandwidth);
|
|
||||||
|
|
||||||
if (accumulator_.count() < static_cast<size_t>(
|
|
||||||
accumulator_.max_count() * min_sample_count_percent_)) {
|
|
||||||
// We have not collected enough samples yet.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace bandwidth with the mean of sampled bandwidths.
|
|
||||||
const int mean_bandwidth = static_cast<int>(accumulator_.ComputeMean());
|
|
||||||
|
|
||||||
if (mean_bandwidth < bandwidth_estimation_) {
|
|
||||||
time_at_last_change_ = sample_time;
|
|
||||||
bandwidth_estimation_ = mean_bandwidth;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int old_bandwidth_estimation = bandwidth_estimation_;
|
|
||||||
const double increase_threshold_d = percent_increase_ * bandwidth_estimation_;
|
|
||||||
if (increase_threshold_d > INT_MAX) {
|
|
||||||
// If bandwidth goes any higher we would overflow.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int increase_threshold = static_cast<int>(increase_threshold_d);
|
|
||||||
if (mean_bandwidth < increase_threshold) {
|
|
||||||
time_at_last_change_ = sample_time;
|
|
||||||
// The value of bandwidth_estimation remains the same if we don't exceed
|
|
||||||
// percent_increase_ * bandwidth_estimation_ for at least
|
|
||||||
// time_between_increase_ time.
|
|
||||||
} else if (sample_time >= time_at_last_change_ + time_between_increase_) {
|
|
||||||
time_at_last_change_ = sample_time;
|
|
||||||
if (increase_threshold == 0) {
|
|
||||||
// Bandwidth_estimation_ must be zero. Assume a jump from zero to a
|
|
||||||
// positive bandwidth means we have regained connectivity.
|
|
||||||
bandwidth_estimation_ = mean_bandwidth;
|
|
||||||
} else {
|
|
||||||
bandwidth_estimation_ = increase_threshold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Else don't make a change.
|
|
||||||
|
|
||||||
return old_bandwidth_estimation != bandwidth_estimation_;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_BANDWIDTHSMOOTHER_H_
|
|
||||||
#define WEBRTC_BASE_BANDWIDTHSMOOTHER_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/rollingaccumulator.h"
|
|
||||||
#include "webrtc/base/timeutils.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// The purpose of BandwidthSmoother is to smooth out bandwidth
|
|
||||||
// estimations so that 'trstate' messages can be triggered when we
|
|
||||||
// are "sure" there is sufficient bandwidth. To avoid frequent fluctuations,
|
|
||||||
// we take a slightly pessimistic view of our bandwidth. We only increase
|
|
||||||
// our estimation when we have sampled bandwidth measurements of values
|
|
||||||
// at least as large as the current estimation * percent_increase
|
|
||||||
// for at least time_between_increase time. If a sampled bandwidth
|
|
||||||
// is less than our current estimation we immediately decrease our estimation
|
|
||||||
// to that sampled value.
|
|
||||||
// We retain the initial bandwidth guess as our current bandwidth estimation
|
|
||||||
// until we have received (min_sample_count_percent * samples_count_to_average)
|
|
||||||
// number of samples. Min_sample_count_percent must be in range [0, 1].
|
|
||||||
class BandwidthSmoother {
|
|
||||||
public:
|
|
||||||
BandwidthSmoother(int initial_bandwidth_guess,
|
|
||||||
uint32 time_between_increase,
|
|
||||||
double percent_increase,
|
|
||||||
size_t samples_count_to_average,
|
|
||||||
double min_sample_count_percent);
|
|
||||||
|
|
||||||
// Samples a new bandwidth measurement.
|
|
||||||
// bandwidth is expected to be non-negative.
|
|
||||||
// returns true if the bandwidth estimation changed
|
|
||||||
bool Sample(uint32 sample_time, int bandwidth);
|
|
||||||
|
|
||||||
int get_bandwidth_estimation() const {
|
|
||||||
return bandwidth_estimation_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32 time_between_increase_;
|
|
||||||
double percent_increase_;
|
|
||||||
uint32 time_at_last_change_;
|
|
||||||
int bandwidth_estimation_;
|
|
||||||
RollingAccumulator<int> accumulator_;
|
|
||||||
double min_sample_count_percent_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_BANDWIDTHSMOOTHER_H_
|
|
@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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 <limits.h>
|
|
||||||
|
|
||||||
#include "webrtc/base/bandwidthsmoother.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
static const int kTimeBetweenIncrease = 10;
|
|
||||||
static const double kPercentIncrease = 1.1;
|
|
||||||
static const size_t kSamplesCountToAverage = 2;
|
|
||||||
static const double kMinSampleCountPercent = 1.0;
|
|
||||||
|
|
||||||
TEST(BandwidthSmootherTest, TestSampleIncrease) {
|
|
||||||
BandwidthSmoother mon(1000, // initial_bandwidth_guess
|
|
||||||
kTimeBetweenIncrease,
|
|
||||||
kPercentIncrease,
|
|
||||||
kSamplesCountToAverage,
|
|
||||||
kMinSampleCountPercent);
|
|
||||||
|
|
||||||
int bandwidth_sample = 1000;
|
|
||||||
EXPECT_EQ(bandwidth_sample, mon.get_bandwidth_estimation());
|
|
||||||
bandwidth_sample =
|
|
||||||
static_cast<int>(bandwidth_sample * kPercentIncrease);
|
|
||||||
EXPECT_FALSE(mon.Sample(9, bandwidth_sample));
|
|
||||||
EXPECT_TRUE(mon.Sample(10, bandwidth_sample));
|
|
||||||
EXPECT_EQ(bandwidth_sample, mon.get_bandwidth_estimation());
|
|
||||||
int next_expected_est =
|
|
||||||
static_cast<int>(bandwidth_sample * kPercentIncrease);
|
|
||||||
bandwidth_sample *= 2;
|
|
||||||
EXPECT_TRUE(mon.Sample(20, bandwidth_sample));
|
|
||||||
EXPECT_EQ(next_expected_est, mon.get_bandwidth_estimation());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BandwidthSmootherTest, TestSampleIncreaseFromZero) {
|
|
||||||
BandwidthSmoother mon(0, // initial_bandwidth_guess
|
|
||||||
kTimeBetweenIncrease,
|
|
||||||
kPercentIncrease,
|
|
||||||
kSamplesCountToAverage,
|
|
||||||
kMinSampleCountPercent);
|
|
||||||
|
|
||||||
const int kBandwidthSample = 1000;
|
|
||||||
EXPECT_EQ(0, mon.get_bandwidth_estimation());
|
|
||||||
EXPECT_FALSE(mon.Sample(9, kBandwidthSample));
|
|
||||||
EXPECT_TRUE(mon.Sample(10, kBandwidthSample));
|
|
||||||
EXPECT_EQ(kBandwidthSample, mon.get_bandwidth_estimation());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BandwidthSmootherTest, TestSampleDecrease) {
|
|
||||||
BandwidthSmoother mon(1000, // initial_bandwidth_guess
|
|
||||||
kTimeBetweenIncrease,
|
|
||||||
kPercentIncrease,
|
|
||||||
kSamplesCountToAverage,
|
|
||||||
kMinSampleCountPercent);
|
|
||||||
|
|
||||||
const int kBandwidthSample = 999;
|
|
||||||
EXPECT_EQ(1000, mon.get_bandwidth_estimation());
|
|
||||||
EXPECT_FALSE(mon.Sample(1, kBandwidthSample));
|
|
||||||
EXPECT_EQ(1000, mon.get_bandwidth_estimation());
|
|
||||||
EXPECT_TRUE(mon.Sample(2, kBandwidthSample));
|
|
||||||
EXPECT_EQ(kBandwidthSample, mon.get_bandwidth_estimation());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BandwidthSmootherTest, TestSampleTooFewSamples) {
|
|
||||||
BandwidthSmoother mon(1000, // initial_bandwidth_guess
|
|
||||||
kTimeBetweenIncrease,
|
|
||||||
kPercentIncrease,
|
|
||||||
10, // 10 samples.
|
|
||||||
0.5); // 5 min samples.
|
|
||||||
|
|
||||||
const int kBandwidthSample = 500;
|
|
||||||
EXPECT_EQ(1000, mon.get_bandwidth_estimation());
|
|
||||||
EXPECT_FALSE(mon.Sample(1, kBandwidthSample));
|
|
||||||
EXPECT_FALSE(mon.Sample(2, kBandwidthSample));
|
|
||||||
EXPECT_FALSE(mon.Sample(3, kBandwidthSample));
|
|
||||||
EXPECT_FALSE(mon.Sample(4, kBandwidthSample));
|
|
||||||
EXPECT_EQ(1000, mon.get_bandwidth_estimation());
|
|
||||||
EXPECT_TRUE(mon.Sample(5, kBandwidthSample));
|
|
||||||
EXPECT_EQ(kBandwidthSample, mon.get_bandwidth_estimation());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BandwidthSmootherTest, TestSampleRollover) {
|
|
||||||
const int kHugeBandwidth = 2000000000; // > INT_MAX/1.1
|
|
||||||
BandwidthSmoother mon(kHugeBandwidth,
|
|
||||||
kTimeBetweenIncrease,
|
|
||||||
kPercentIncrease,
|
|
||||||
kSamplesCountToAverage,
|
|
||||||
kMinSampleCountPercent);
|
|
||||||
|
|
||||||
EXPECT_FALSE(mon.Sample(10, INT_MAX));
|
|
||||||
EXPECT_FALSE(mon.Sample(11, INT_MAX));
|
|
||||||
EXPECT_EQ(kHugeBandwidth, mon.get_bandwidth_estimation());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BandwidthSmootherTest, TestSampleNegative) {
|
|
||||||
BandwidthSmoother mon(1000, // initial_bandwidth_guess
|
|
||||||
kTimeBetweenIncrease,
|
|
||||||
kPercentIncrease,
|
|
||||||
kSamplesCountToAverage,
|
|
||||||
kMinSampleCountPercent);
|
|
||||||
|
|
||||||
EXPECT_FALSE(mon.Sample(10, -1));
|
|
||||||
EXPECT_FALSE(mon.Sample(11, -1));
|
|
||||||
EXPECT_EQ(1000, mon.get_bandwidth_estimation());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,708 +0,0 @@
|
|||||||
# Copyright (c) 2014 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.
|
|
||||||
|
|
||||||
{
|
|
||||||
'includes': [ '../build/common.gypi', ],
|
|
||||||
'conditions': [
|
|
||||||
['os_posix == 1 and OS != "mac" and OS != "ios"', {
|
|
||||||
'conditions': [
|
|
||||||
['sysroot!=""', {
|
|
||||||
'variables': {
|
|
||||||
'pkg-config': '../../../build/linux/pkg-config-wrapper "<(sysroot)" "<(target_arch)"',
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
'variables': {
|
|
||||||
'pkg-config': 'pkg-config'
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
],
|
|
||||||
'targets': [
|
|
||||||
{
|
|
||||||
'target_name': 'webrtc_base',
|
|
||||||
'type': 'static_library',
|
|
||||||
'defines': [
|
|
||||||
'FEATURE_ENABLE_SSL',
|
|
||||||
'GTEST_RELATIVE_PATH',
|
|
||||||
'LOGGING=1',
|
|
||||||
'USE_WEBRTC_DEV_BRANCH',
|
|
||||||
],
|
|
||||||
'sources': [
|
|
||||||
'asyncfile.cc',
|
|
||||||
'asyncfile.h',
|
|
||||||
'asynchttprequest.cc',
|
|
||||||
'asynchttprequest.h',
|
|
||||||
'asyncinvoker.cc',
|
|
||||||
'asyncinvoker.h',
|
|
||||||
'asyncpacketsocket.h',
|
|
||||||
'asyncresolverinterface.h',
|
|
||||||
'asyncsocket.cc',
|
|
||||||
'asyncsocket.h',
|
|
||||||
'asynctcpsocket.cc',
|
|
||||||
'asynctcpsocket.h',
|
|
||||||
'asyncudpsocket.cc',
|
|
||||||
'asyncudpsocket.h',
|
|
||||||
'atomicops.h',
|
|
||||||
'autodetectproxy.cc',
|
|
||||||
'autodetectproxy.h',
|
|
||||||
'bandwidthsmoother.cc',
|
|
||||||
'bandwidthsmoother.h',
|
|
||||||
'base64.cc',
|
|
||||||
'base64.h',
|
|
||||||
'basicdefs.h',
|
|
||||||
'basictypes.h',
|
|
||||||
'bind.h',
|
|
||||||
'buffer.h',
|
|
||||||
'bytebuffer.cc',
|
|
||||||
'bytebuffer.h',
|
|
||||||
'byteorder.h',
|
|
||||||
'callback.h',
|
|
||||||
'checks.cc',
|
|
||||||
'checks.h',
|
|
||||||
'common.cc',
|
|
||||||
'common.h',
|
|
||||||
'constructormagic.h',
|
|
||||||
'cpumonitor.cc',
|
|
||||||
'cpumonitor.h',
|
|
||||||
'crc32.cc',
|
|
||||||
'crc32.h',
|
|
||||||
'criticalsection.h',
|
|
||||||
'cryptstring.h',
|
|
||||||
'dbus.cc',
|
|
||||||
'dbus.h',
|
|
||||||
'diskcache.cc',
|
|
||||||
'diskcache.h',
|
|
||||||
'diskcache_win32.cc',
|
|
||||||
'diskcache_win32.h',
|
|
||||||
'event.cc',
|
|
||||||
'event.h',
|
|
||||||
'filelock.cc',
|
|
||||||
'filelock.h',
|
|
||||||
'fileutils.cc',
|
|
||||||
'fileutils.h',
|
|
||||||
'fileutils_mock.h',
|
|
||||||
'firewallsocketserver.cc',
|
|
||||||
'firewallsocketserver.h',
|
|
||||||
'flags.cc',
|
|
||||||
'flags.h',
|
|
||||||
'gunit_prod.h',
|
|
||||||
'helpers.cc',
|
|
||||||
'helpers.h',
|
|
||||||
'httpbase.cc',
|
|
||||||
'httpbase.h',
|
|
||||||
'httpclient.cc',
|
|
||||||
'httpclient.h',
|
|
||||||
'httpcommon-inl.h',
|
|
||||||
'httpcommon.cc',
|
|
||||||
'httpcommon.h',
|
|
||||||
'httprequest.cc',
|
|
||||||
'httprequest.h',
|
|
||||||
'httpserver.cc',
|
|
||||||
'httpserver.h',
|
|
||||||
'ifaddrs-android.cc',
|
|
||||||
'ifaddrs-android.h',
|
|
||||||
'iosfilesystem.mm',
|
|
||||||
'ipaddress.cc',
|
|
||||||
'ipaddress.h',
|
|
||||||
'json.cc',
|
|
||||||
'json.h',
|
|
||||||
'latebindingsymboltable.cc',
|
|
||||||
'latebindingsymboltable.h',
|
|
||||||
'libdbusglibsymboltable.cc',
|
|
||||||
'libdbusglibsymboltable.h',
|
|
||||||
'linux.cc',
|
|
||||||
'linux.h',
|
|
||||||
'linuxfdwalk.c',
|
|
||||||
'linuxwindowpicker.cc',
|
|
||||||
'linuxwindowpicker.h',
|
|
||||||
'linked_ptr.h',
|
|
||||||
'logging.cc',
|
|
||||||
'logging.h',
|
|
||||||
'macasyncsocket.cc',
|
|
||||||
'macasyncsocket.h',
|
|
||||||
'maccocoasocketserver.h',
|
|
||||||
'maccocoasocketserver.mm',
|
|
||||||
'maccocoathreadhelper.h',
|
|
||||||
'maccocoathreadhelper.mm',
|
|
||||||
'macconversion.cc',
|
|
||||||
'macconversion.h',
|
|
||||||
'macsocketserver.cc',
|
|
||||||
'macsocketserver.h',
|
|
||||||
'macutils.cc',
|
|
||||||
'macutils.h',
|
|
||||||
'macwindowpicker.cc',
|
|
||||||
'macwindowpicker.h',
|
|
||||||
'mathutils.h',
|
|
||||||
'md5.cc',
|
|
||||||
'md5.h',
|
|
||||||
'md5digest.h',
|
|
||||||
'messagedigest.cc',
|
|
||||||
'messagedigest.h',
|
|
||||||
'messagehandler.cc',
|
|
||||||
'messagehandler.h',
|
|
||||||
'messagequeue.cc',
|
|
||||||
'messagequeue.h',
|
|
||||||
'multipart.cc',
|
|
||||||
'multipart.h',
|
|
||||||
'natserver.cc',
|
|
||||||
'natserver.h',
|
|
||||||
'natsocketfactory.cc',
|
|
||||||
'natsocketfactory.h',
|
|
||||||
'nattypes.cc',
|
|
||||||
'nattypes.h',
|
|
||||||
'nethelpers.cc',
|
|
||||||
'nethelpers.h',
|
|
||||||
'network.cc',
|
|
||||||
'network.h',
|
|
||||||
'nssidentity.cc',
|
|
||||||
'nssidentity.h',
|
|
||||||
'nssstreamadapter.cc',
|
|
||||||
'nssstreamadapter.h',
|
|
||||||
'nullsocketserver.h',
|
|
||||||
'openssl.h',
|
|
||||||
'openssladapter.cc',
|
|
||||||
'openssladapter.h',
|
|
||||||
'openssldigest.cc',
|
|
||||||
'openssldigest.h',
|
|
||||||
'opensslidentity.cc',
|
|
||||||
'opensslidentity.h',
|
|
||||||
'opensslstreamadapter.cc',
|
|
||||||
'opensslstreamadapter.h',
|
|
||||||
'optionsfile.cc',
|
|
||||||
'optionsfile.h',
|
|
||||||
'pathutils.cc',
|
|
||||||
'pathutils.h',
|
|
||||||
'physicalsocketserver.cc',
|
|
||||||
'physicalsocketserver.h',
|
|
||||||
'posix.cc',
|
|
||||||
'posix.h',
|
|
||||||
'profiler.cc',
|
|
||||||
'profiler.h',
|
|
||||||
'proxydetect.cc',
|
|
||||||
'proxydetect.h',
|
|
||||||
'proxyinfo.cc',
|
|
||||||
'proxyinfo.h',
|
|
||||||
'proxyserver.cc',
|
|
||||||
'proxyserver.h',
|
|
||||||
'ratelimiter.cc',
|
|
||||||
'ratelimiter.h',
|
|
||||||
'ratetracker.cc',
|
|
||||||
'ratetracker.h',
|
|
||||||
'refcount.h',
|
|
||||||
'referencecountedsingletonfactory.h',
|
|
||||||
'rollingaccumulator.h',
|
|
||||||
'schanneladapter.cc',
|
|
||||||
'schanneladapter.h',
|
|
||||||
'scoped_autorelease_pool.h',
|
|
||||||
'scoped_autorelease_pool.mm',
|
|
||||||
'scoped_ptr.h',
|
|
||||||
'scoped_ref_ptr.h',
|
|
||||||
'scopedptrcollection.h',
|
|
||||||
'sec_buffer.h',
|
|
||||||
'sha1.cc',
|
|
||||||
'sha1.h',
|
|
||||||
'sha1digest.h',
|
|
||||||
'sharedexclusivelock.cc',
|
|
||||||
'sharedexclusivelock.h',
|
|
||||||
'signalthread.cc',
|
|
||||||
'signalthread.h',
|
|
||||||
'sigslot.h',
|
|
||||||
'sigslotrepeater.h',
|
|
||||||
'socket.h',
|
|
||||||
'socketadapters.cc',
|
|
||||||
'socketadapters.h',
|
|
||||||
'socketaddress.cc',
|
|
||||||
'socketaddress.h',
|
|
||||||
'socketaddresspair.cc',
|
|
||||||
'socketaddresspair.h',
|
|
||||||
'socketfactory.h',
|
|
||||||
'socketpool.cc',
|
|
||||||
'socketpool.h',
|
|
||||||
'socketserver.h',
|
|
||||||
'socketstream.cc',
|
|
||||||
'socketstream.h',
|
|
||||||
'ssladapter.cc',
|
|
||||||
'ssladapter.h',
|
|
||||||
'sslconfig.h',
|
|
||||||
'sslfingerprint.cc',
|
|
||||||
'sslfingerprint.h',
|
|
||||||
'sslidentity.cc',
|
|
||||||
'sslidentity.h',
|
|
||||||
'sslroots.h',
|
|
||||||
'sslsocketfactory.cc',
|
|
||||||
'sslsocketfactory.h',
|
|
||||||
'sslstreamadapter.cc',
|
|
||||||
'sslstreamadapter.h',
|
|
||||||
'sslstreamadapterhelper.cc',
|
|
||||||
'sslstreamadapterhelper.h',
|
|
||||||
'stream.cc',
|
|
||||||
'stream.h',
|
|
||||||
'stringdigest.h',
|
|
||||||
'stringencode.cc',
|
|
||||||
'stringencode.h',
|
|
||||||
'stringutils.cc',
|
|
||||||
'stringutils.h',
|
|
||||||
'systeminfo.cc',
|
|
||||||
'systeminfo.h',
|
|
||||||
'task.cc',
|
|
||||||
'task.h',
|
|
||||||
'taskparent.cc',
|
|
||||||
'taskparent.h',
|
|
||||||
'taskrunner.cc',
|
|
||||||
'taskrunner.h',
|
|
||||||
'testclient.cc',
|
|
||||||
'testclient.h',
|
|
||||||
'thread.cc',
|
|
||||||
'thread.h',
|
|
||||||
'timeutils.cc',
|
|
||||||
'timeutils.h',
|
|
||||||
'timing.cc',
|
|
||||||
'timing.h',
|
|
||||||
'transformadapter.cc',
|
|
||||||
'transformadapter.h',
|
|
||||||
'unixfilesystem.cc',
|
|
||||||
'unixfilesystem.h',
|
|
||||||
'urlencode.cc',
|
|
||||||
'urlencode.h',
|
|
||||||
'versionparsing.cc',
|
|
||||||
'versionparsing.h',
|
|
||||||
'virtualsocketserver.cc',
|
|
||||||
'virtualsocketserver.h',
|
|
||||||
'win32.cc',
|
|
||||||
'win32.h',
|
|
||||||
'win32filesystem.cc',
|
|
||||||
'win32filesystem.h',
|
|
||||||
'win32regkey.cc',
|
|
||||||
'win32regkey.h',
|
|
||||||
'win32securityerrors.cc',
|
|
||||||
'win32socketinit.cc',
|
|
||||||
'win32socketinit.h',
|
|
||||||
'win32socketserver.cc',
|
|
||||||
'win32socketserver.h',
|
|
||||||
'win32window.cc',
|
|
||||||
'win32window.h',
|
|
||||||
'win32windowpicker.cc',
|
|
||||||
'win32windowpicker.h',
|
|
||||||
'window.h',
|
|
||||||
'windowpicker.h',
|
|
||||||
'windowpickerfactory.h',
|
|
||||||
'winfirewall.cc',
|
|
||||||
'winfirewall.h',
|
|
||||||
'winping.cc',
|
|
||||||
'winping.h',
|
|
||||||
'worker.cc',
|
|
||||||
'worker.h',
|
|
||||||
'../overrides/webrtc/base/basictypes.h',
|
|
||||||
'../overrides/webrtc/base/constructormagic.h',
|
|
||||||
'../overrides/webrtc/base/logging.cc',
|
|
||||||
'../overrides/webrtc/base/logging.h',
|
|
||||||
'../overrides/webrtc/base/win32socketinit.cc',
|
|
||||||
],
|
|
||||||
# TODO(henrike): issue 3307, make webrtc_base build without disabling
|
|
||||||
# these flags.
|
|
||||||
'cflags!': [
|
|
||||||
'-Wextra',
|
|
||||||
'-Wall',
|
|
||||||
],
|
|
||||||
'cflags_cc!': [
|
|
||||||
'-Wnon-virtual-dtor',
|
|
||||||
],
|
|
||||||
'direct_dependent_settings': {
|
|
||||||
'cflags_cc!': [
|
|
||||||
'-Wnon-virtual-dtor',
|
|
||||||
],
|
|
||||||
'defines': [
|
|
||||||
'FEATURE_ENABLE_SSL',
|
|
||||||
'GTEST_RELATIVE_PATH',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'include_dirs': [
|
|
||||||
'../../third_party/jsoncpp/overrides/include',
|
|
||||||
'../../third_party/jsoncpp/source/include',
|
|
||||||
],
|
|
||||||
'conditions': [
|
|
||||||
['build_with_chromium==1', {
|
|
||||||
'include_dirs': [
|
|
||||||
'../overrides',
|
|
||||||
'../../openssl/openssl/include',
|
|
||||||
],
|
|
||||||
'sources!': [
|
|
||||||
'asyncinvoker.cc',
|
|
||||||
'asyncinvoker.h',
|
|
||||||
'asyncinvoker-inl.h',
|
|
||||||
'asyncresolverinterface.h',
|
|
||||||
'atomicops.h',
|
|
||||||
'bandwidthsmoother.cc',
|
|
||||||
'bandwidthsmoother.h',
|
|
||||||
'basictypes.h',
|
|
||||||
'bind.h',
|
|
||||||
'bind.h.pump',
|
|
||||||
'buffer.h',
|
|
||||||
'callback.h',
|
|
||||||
'callback.h.pump',
|
|
||||||
'constructormagic.h',
|
|
||||||
'dbus.cc',
|
|
||||||
'dbus.h',
|
|
||||||
'diskcache_win32.cc',
|
|
||||||
'diskcache_win32.h',
|
|
||||||
'fakecpumonitor.h',
|
|
||||||
'fakenetwork.h',
|
|
||||||
'fakesslidentity.h',
|
|
||||||
'faketaskrunner.h',
|
|
||||||
'filelock.cc',
|
|
||||||
'filelock.h',
|
|
||||||
'fileutils_mock.h',
|
|
||||||
'genericslot.h',
|
|
||||||
'genericslot.h.pump',
|
|
||||||
'httpserver.cc',
|
|
||||||
'httpserver.h',
|
|
||||||
'json.cc',
|
|
||||||
'json.h',
|
|
||||||
'latebindingsymboltable.cc',
|
|
||||||
'latebindingsymboltable.cc.def',
|
|
||||||
'latebindingsymboltable.h',
|
|
||||||
'latebindingsymboltable.h.def',
|
|
||||||
'libdbusglibsymboltable.cc',
|
|
||||||
'libdbusglibsymboltable.h',
|
|
||||||
'linuxfdwalk.c',
|
|
||||||
'linuxfdwalk.h',
|
|
||||||
'linuxwindowpicker.cc',
|
|
||||||
'linuxwindowpicker.h',
|
|
||||||
'logging.cc',
|
|
||||||
'logging.h',
|
|
||||||
'macasyncsocket.cc',
|
|
||||||
'macasyncsocket.h',
|
|
||||||
'maccocoasocketserver.h',
|
|
||||||
'maccocoasocketserver.mm',
|
|
||||||
'macsocketserver.cc',
|
|
||||||
'macsocketserver.h',
|
|
||||||
'macwindowpicker.cc',
|
|
||||||
'macwindowpicker.h',
|
|
||||||
'mathutils.h',
|
|
||||||
'multipart.cc',
|
|
||||||
'multipart.h',
|
|
||||||
'natserver.cc',
|
|
||||||
'natserver.h',
|
|
||||||
'natserver_main.cc',
|
|
||||||
'natsocketfactory.cc',
|
|
||||||
'natsocketfactory.h',
|
|
||||||
'nattypes.cc',
|
|
||||||
'nattypes.h',
|
|
||||||
'openssl.h',
|
|
||||||
'optionsfile.cc',
|
|
||||||
'optionsfile.h',
|
|
||||||
'posix.cc',
|
|
||||||
'posix.h',
|
|
||||||
'profiler.cc',
|
|
||||||
'profiler.h',
|
|
||||||
'proxyserver.cc',
|
|
||||||
'proxyserver.h',
|
|
||||||
'refcount.h',
|
|
||||||
'referencecountedsingletonfactory.h',
|
|
||||||
'rollingaccumulator.h',
|
|
||||||
'safe_conversions.h',
|
|
||||||
'safe_conversions_impl.h',
|
|
||||||
'scopedptrcollection.h',
|
|
||||||
'scoped_ref_ptr.h',
|
|
||||||
'sec_buffer.h',
|
|
||||||
'sharedexclusivelock.cc',
|
|
||||||
'sharedexclusivelock.h',
|
|
||||||
'sslconfig.h',
|
|
||||||
'sslroots.h',
|
|
||||||
'stringdigest.h',
|
|
||||||
'testbase64.h',
|
|
||||||
'testclient.cc',
|
|
||||||
'testclient.h',
|
|
||||||
'testechoserver.h',
|
|
||||||
'testutils.h',
|
|
||||||
'transformadapter.cc',
|
|
||||||
'transformadapter.h',
|
|
||||||
'versionparsing.cc',
|
|
||||||
'versionparsing.h',
|
|
||||||
'virtualsocketserver.cc',
|
|
||||||
'virtualsocketserver.h',
|
|
||||||
'win32regkey.cc',
|
|
||||||
'win32regkey.h',
|
|
||||||
'win32socketinit.cc',
|
|
||||||
'win32socketinit.h',
|
|
||||||
'win32socketserver.cc',
|
|
||||||
'win32socketserver.h',
|
|
||||||
'win32toolhelp.h',
|
|
||||||
'window.h',
|
|
||||||
'windowpickerfactory.h',
|
|
||||||
'windowpicker.h',
|
|
||||||
],
|
|
||||||
'defines': [
|
|
||||||
'NO_MAIN_THREAD_WRAPPING',
|
|
||||||
'SSL_USE_NSS',
|
|
||||||
],
|
|
||||||
'direct_dependent_settings': {
|
|
||||||
'defines': [
|
|
||||||
'NO_MAIN_THREAD_WRAPPING',
|
|
||||||
'SSL_USE_NSS',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
'dependencies': [
|
|
||||||
'<(DEPTH)/third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
|
|
||||||
],
|
|
||||||
'sources!': [
|
|
||||||
'../overrides/webrtc/base/basictypes.h',
|
|
||||||
'../overrides/webrtc/base/constructormagic.h',
|
|
||||||
'../overrides/webrtc/base/win32socketinit.cc',
|
|
||||||
'../overrides/webrtc/base/logging.cc',
|
|
||||||
'../overrides/webrtc/base/logging.h',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['use_openssl==1', {
|
|
||||||
'defines': [
|
|
||||||
'SSL_USE_OPENSSL',
|
|
||||||
'HAVE_OPENSSL_SSL_H',
|
|
||||||
],
|
|
||||||
'direct_dependent_settings': {
|
|
||||||
'defines': [
|
|
||||||
'SSL_USE_OPENSSL',
|
|
||||||
'HAVE_OPENSSL_SSL_H',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'dependencies': [
|
|
||||||
'<(DEPTH)/third_party/openssl/openssl.gyp:openssl',
|
|
||||||
],
|
|
||||||
}, {
|
|
||||||
'defines': [
|
|
||||||
'SSL_USE_NSS',
|
|
||||||
'HAVE_NSS_SSL_H',
|
|
||||||
'SSL_USE_NSS_RNG',
|
|
||||||
],
|
|
||||||
'direct_dependent_settings': {
|
|
||||||
'defines': [
|
|
||||||
'SSL_USE_NSS',
|
|
||||||
'HAVE_NSS_SSL_H',
|
|
||||||
'SSL_USE_NSS_RNG',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
['OS == "android"', {
|
|
||||||
'defines': [
|
|
||||||
'HAVE_OPENSSL_SSL_H'
|
|
||||||
],
|
|
||||||
'direct_dependent_settings': {
|
|
||||||
'defines': [
|
|
||||||
'HAVE_OPENSSL_SSL_H'
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'link_settings': {
|
|
||||||
'libraries': [
|
|
||||||
'-llog',
|
|
||||||
'-lGLESv2',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
'defines': [
|
|
||||||
'HAVE_NSS_SSL_H'
|
|
||||||
'SSL_USE_NSS_RNG',
|
|
||||||
],
|
|
||||||
'direct_dependent_settings': {
|
|
||||||
'defines': [
|
|
||||||
'HAVE_NSS_SSL_H'
|
|
||||||
'SSL_USE_NSS_RNG',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'sources!': [
|
|
||||||
'ifaddrs-android.cc',
|
|
||||||
'ifaddrs-android.h',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['OS=="ios"', {
|
|
||||||
'all_dependent_settings': {
|
|
||||||
'xcode_settings': {
|
|
||||||
'OTHER_LDFLAGS': [
|
|
||||||
'-framework Foundation',
|
|
||||||
'-framework IOKit',
|
|
||||||
'-framework Security',
|
|
||||||
'-framework SystemConfiguration',
|
|
||||||
'-framework UIKit',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'dependencies': [
|
|
||||||
'<(DEPTH)/net/third_party/nss/ssl.gyp:libssl',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['OS=="linux"', {
|
|
||||||
'link_settings': {
|
|
||||||
'libraries': [
|
|
||||||
'-lcrypto',
|
|
||||||
'-ldl',
|
|
||||||
'-lrt',
|
|
||||||
'-lXext',
|
|
||||||
'-lX11',
|
|
||||||
'-lXcomposite',
|
|
||||||
'-lXrender',
|
|
||||||
'<!@(<(pkg-config) --libs-only-l nss | sed -e "s/-lssl3//")',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'cflags': [
|
|
||||||
'<!@(<(pkg-config) --cflags nss)',
|
|
||||||
],
|
|
||||||
'ldflags': [
|
|
||||||
'<!@(<(pkg-config) --libs-only-L --libs-only-other nss)',
|
|
||||||
],
|
|
||||||
}, {
|
|
||||||
'sources!': [
|
|
||||||
'dbus.cc',
|
|
||||||
'dbus.h',
|
|
||||||
'libdbusglibsymboltable.cc',
|
|
||||||
'libdbusglibsymboltable.h',
|
|
||||||
'linuxfdwalk.c',
|
|
||||||
'linuxwindowpicker.cc',
|
|
||||||
'linuxwindowpicker.h',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['OS=="mac"', {
|
|
||||||
'link_settings': {
|
|
||||||
'libraries': [
|
|
||||||
'$(SDKROOT)/usr/lib/libcrypto.dylib',
|
|
||||||
'$(SDKROOT)/usr/lib/libssl.dylib',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'all_dependent_settings': {
|
|
||||||
'link_settings': {
|
|
||||||
'xcode_settings': {
|
|
||||||
'OTHER_LDFLAGS': [
|
|
||||||
'-framework Cocoa',
|
|
||||||
'-framework Foundation',
|
|
||||||
'-framework IOKit',
|
|
||||||
'-framework Security',
|
|
||||||
'-framework SystemConfiguration',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'conditions': [
|
|
||||||
['target_arch=="ia32"', {
|
|
||||||
'all_dependent_settings': {
|
|
||||||
'link_settings': {
|
|
||||||
'xcode_settings': {
|
|
||||||
'OTHER_LDFLAGS': [
|
|
||||||
'-framework Carbon',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
],
|
|
||||||
}, {
|
|
||||||
'sources!': [
|
|
||||||
'macasyncsocket.cc',
|
|
||||||
'macasyncsocket.h',
|
|
||||||
'maccocoasocketserver.h',
|
|
||||||
'maccocoasocketserver.mm',
|
|
||||||
'macconversion.cc',
|
|
||||||
'macconversion.h',
|
|
||||||
'macsocketserver.cc',
|
|
||||||
'macsocketserver.h',
|
|
||||||
'macutils.cc',
|
|
||||||
'macutils.h',
|
|
||||||
'macwindowpicker.cc',
|
|
||||||
'macwindowpicker.h',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['OS=="win"', {
|
|
||||||
'link_settings': {
|
|
||||||
'libraries': [
|
|
||||||
'-lcrypt32.lib',
|
|
||||||
'-liphlpapi.lib',
|
|
||||||
'-lsecur32.lib',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
# Suppress warnings about WIN32_LEAN_AND_MEAN.
|
|
||||||
'msvs_disabled_warnings': [4005, 4703],
|
|
||||||
'defines': [
|
|
||||||
'_CRT_NONSTDC_NO_DEPRECATE',
|
|
||||||
],
|
|
||||||
}, {
|
|
||||||
'sources/': [
|
|
||||||
['exclude', 'win32[a-z0-9]*\\.(h|cc)$'],
|
|
||||||
],
|
|
||||||
'sources!': [
|
|
||||||
'schanneladapter.cc',
|
|
||||||
'schanneladapter.h',
|
|
||||||
'winping.cc',
|
|
||||||
'winping.h',
|
|
||||||
'winfirewall.cc',
|
|
||||||
'winfirewall.h',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['os_posix==0', {
|
|
||||||
'sources!': [
|
|
||||||
'latebindingsymboltable.cc',
|
|
||||||
'latebindingsymboltable.h',
|
|
||||||
'posix.cc',
|
|
||||||
'posix.h',
|
|
||||||
'unixfilesystem.cc',
|
|
||||||
'unixfilesystem.h',
|
|
||||||
],
|
|
||||||
}, {
|
|
||||||
'configurations': {
|
|
||||||
'Debug_Base': {
|
|
||||||
'defines': [
|
|
||||||
# Chromium's build/common.gypi defines this for all posix
|
|
||||||
# _except_ for ios & mac. We want it there as well, e.g.
|
|
||||||
# because ASSERT and friends trigger off of it.
|
|
||||||
'_DEBUG',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
['OS=="ios" or (OS=="mac" and target_arch!="ia32")', {
|
|
||||||
'defines': [
|
|
||||||
'CARBON_DEPRECATED=YES',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['OS!="ios" and OS!="mac"', {
|
|
||||||
'sources!': [
|
|
||||||
'scoped_autorelease_pool.mm',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['OS=="ios" or os_posix==0', {
|
|
||||||
'sources!': [
|
|
||||||
'openssl.h',
|
|
||||||
'openssladapter.cc',
|
|
||||||
'openssladapter.h',
|
|
||||||
'openssldigest.cc',
|
|
||||||
'openssldigest.h',
|
|
||||||
'opensslidentity.cc',
|
|
||||||
'opensslidentity.h',
|
|
||||||
'opensslstreamadapter.cc',
|
|
||||||
'opensslstreamadapter.h',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['OS!="linux" and OS!="android"', {
|
|
||||||
'sources!': [
|
|
||||||
'linux.cc',
|
|
||||||
'linux.h',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['OS == "mac" or OS == "ios" or OS == "win"', {
|
|
||||||
'dependencies': [
|
|
||||||
'<(DEPTH)/net/third_party/nss/ssl.gyp:libssl',
|
|
||||||
'<(DEPTH)/third_party/nss/nss.gyp:nspr',
|
|
||||||
'<(DEPTH)/third_party/nss/nss.gyp:nss',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['os_posix == 1 and OS != "mac" and OS != "ios" and OS != "android"', {
|
|
||||||
'dependencies': [
|
|
||||||
'<(DEPTH)/build/linux/system.gyp:ssl',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
@ -1,260 +0,0 @@
|
|||||||
|
|
||||||
//*********************************************************************
|
|
||||||
//* Base64 - a simple base64 encoder and decoder.
|
|
||||||
//*
|
|
||||||
//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
|
|
||||||
//*
|
|
||||||
//* This code may be freely used for any purpose, either personal
|
|
||||||
//* or commercial, provided the authors copyright notice remains
|
|
||||||
//* intact.
|
|
||||||
//*
|
|
||||||
//* Enhancements by Stanley Yamane:
|
|
||||||
//* o reverse lookup table for the decode function
|
|
||||||
//* o reserve string buffer space in advance
|
|
||||||
//*
|
|
||||||
//*********************************************************************
|
|
||||||
|
|
||||||
#include "webrtc/base/base64.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
static const char kPad = '=';
|
|
||||||
static const unsigned char pd = 0xFD; // Padding
|
|
||||||
static const unsigned char sp = 0xFE; // Whitespace
|
|
||||||
static const unsigned char il = 0xFF; // Illegal base64 character
|
|
||||||
|
|
||||||
const char Base64::Base64Table[] =
|
|
||||||
// 0000000000111111111122222222223333333333444444444455555555556666
|
|
||||||
// 0123456789012345678901234567890123456789012345678901234567890123
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
||||||
|
|
||||||
// Decode Table gives the index of any valid base64 character in the
|
|
||||||
// Base64 table
|
|
||||||
// 65 == A, 97 == a, 48 == 0, 43 == +, 47 == /
|
|
||||||
|
|
||||||
const unsigned char Base64::DecodeTable[] = {
|
|
||||||
// 0 1 2 3 4 5 6 7 8 9
|
|
||||||
il,il,il,il,il,il,il,il,il,sp, // 0 - 9
|
|
||||||
sp,sp,sp,sp,il,il,il,il,il,il, // 10 - 19
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 20 - 29
|
|
||||||
il,il,sp,il,il,il,il,il,il,il, // 30 - 39
|
|
||||||
il,il,il,62,il,il,il,63,52,53, // 40 - 49
|
|
||||||
54,55,56,57,58,59,60,61,il,il, // 50 - 59
|
|
||||||
il,pd,il,il,il, 0, 1, 2, 3, 4, // 60 - 69
|
|
||||||
5, 6, 7, 8, 9,10,11,12,13,14, // 70 - 79
|
|
||||||
15,16,17,18,19,20,21,22,23,24, // 80 - 89
|
|
||||||
25,il,il,il,il,il,il,26,27,28, // 90 - 99
|
|
||||||
29,30,31,32,33,34,35,36,37,38, // 100 - 109
|
|
||||||
39,40,41,42,43,44,45,46,47,48, // 110 - 119
|
|
||||||
49,50,51,il,il,il,il,il,il,il, // 120 - 129
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 130 - 139
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 140 - 149
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 150 - 159
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 160 - 169
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 170 - 179
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 180 - 189
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 190 - 199
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 200 - 209
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 210 - 219
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 220 - 229
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 230 - 239
|
|
||||||
il,il,il,il,il,il,il,il,il,il, // 240 - 249
|
|
||||||
il,il,il,il,il,il // 250 - 255
|
|
||||||
};
|
|
||||||
|
|
||||||
bool Base64::IsBase64Char(char ch) {
|
|
||||||
return (('A' <= ch) && (ch <= 'Z')) ||
|
|
||||||
(('a' <= ch) && (ch <= 'z')) ||
|
|
||||||
(('0' <= ch) && (ch <= '9')) ||
|
|
||||||
(ch == '+') || (ch == '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Base64::GetNextBase64Char(char ch, char* next_ch) {
|
|
||||||
if (next_ch == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const char* p = strchr(Base64Table, ch);
|
|
||||||
if (!p)
|
|
||||||
return false;
|
|
||||||
++p;
|
|
||||||
*next_ch = (*p) ? *p : Base64Table[0];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Base64::IsBase64Encoded(const std::string& str) {
|
|
||||||
for (size_t i = 0; i < str.size(); ++i) {
|
|
||||||
if (!IsBase64Char(str.at(i)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Base64::EncodeFromArray(const void* data, size_t len,
|
|
||||||
std::string* result) {
|
|
||||||
ASSERT(NULL != result);
|
|
||||||
result->clear();
|
|
||||||
result->resize(((len + 2) / 3) * 4);
|
|
||||||
const unsigned char* byte_data = static_cast<const unsigned char*>(data);
|
|
||||||
|
|
||||||
unsigned char c;
|
|
||||||
size_t i = 0;
|
|
||||||
size_t dest_ix = 0;
|
|
||||||
while (i < len) {
|
|
||||||
c = (byte_data[i] >> 2) & 0x3f;
|
|
||||||
(*result)[dest_ix++] = Base64Table[c];
|
|
||||||
|
|
||||||
c = (byte_data[i] << 4) & 0x3f;
|
|
||||||
if (++i < len) {
|
|
||||||
c |= (byte_data[i] >> 4) & 0x0f;
|
|
||||||
}
|
|
||||||
(*result)[dest_ix++] = Base64Table[c];
|
|
||||||
|
|
||||||
if (i < len) {
|
|
||||||
c = (byte_data[i] << 2) & 0x3f;
|
|
||||||
if (++i < len) {
|
|
||||||
c |= (byte_data[i] >> 6) & 0x03;
|
|
||||||
}
|
|
||||||
(*result)[dest_ix++] = Base64Table[c];
|
|
||||||
} else {
|
|
||||||
(*result)[dest_ix++] = kPad;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < len) {
|
|
||||||
c = byte_data[i] & 0x3f;
|
|
||||||
(*result)[dest_ix++] = Base64Table[c];
|
|
||||||
++i;
|
|
||||||
} else {
|
|
||||||
(*result)[dest_ix++] = kPad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Base64::GetNextQuantum(DecodeFlags parse_flags, bool illegal_pads,
|
|
||||||
const char* data, size_t len, size_t* dpos,
|
|
||||||
unsigned char qbuf[4], bool* padded)
|
|
||||||
{
|
|
||||||
size_t byte_len = 0, pad_len = 0, pad_start = 0;
|
|
||||||
for (; (byte_len < 4) && (*dpos < len); ++*dpos) {
|
|
||||||
qbuf[byte_len] = DecodeTable[static_cast<unsigned char>(data[*dpos])];
|
|
||||||
if ((il == qbuf[byte_len]) || (illegal_pads && (pd == qbuf[byte_len]))) {
|
|
||||||
if (parse_flags != DO_PARSE_ANY)
|
|
||||||
break;
|
|
||||||
// Ignore illegal characters
|
|
||||||
} else if (sp == qbuf[byte_len]) {
|
|
||||||
if (parse_flags == DO_PARSE_STRICT)
|
|
||||||
break;
|
|
||||||
// Ignore spaces
|
|
||||||
} else if (pd == qbuf[byte_len]) {
|
|
||||||
if (byte_len < 2) {
|
|
||||||
if (parse_flags != DO_PARSE_ANY)
|
|
||||||
break;
|
|
||||||
// Ignore unexpected padding
|
|
||||||
} else if (byte_len + pad_len >= 4) {
|
|
||||||
if (parse_flags != DO_PARSE_ANY)
|
|
||||||
break;
|
|
||||||
// Ignore extra pads
|
|
||||||
} else {
|
|
||||||
if (1 == ++pad_len) {
|
|
||||||
pad_start = *dpos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (pad_len > 0) {
|
|
||||||
if (parse_flags != DO_PARSE_ANY)
|
|
||||||
break;
|
|
||||||
// Ignore pads which are followed by data
|
|
||||||
pad_len = 0;
|
|
||||||
}
|
|
||||||
++byte_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (size_t i = byte_len; i < 4; ++i) {
|
|
||||||
qbuf[i] = 0;
|
|
||||||
}
|
|
||||||
if (4 == byte_len + pad_len) {
|
|
||||||
*padded = true;
|
|
||||||
} else {
|
|
||||||
*padded = false;
|
|
||||||
if (pad_len) {
|
|
||||||
// Roll back illegal padding
|
|
||||||
*dpos = pad_start;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return byte_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Base64::DecodeFromArray(const char* data, size_t len, DecodeFlags flags,
|
|
||||||
std::string* result, size_t* data_used) {
|
|
||||||
return DecodeFromArrayTemplate<std::string>(
|
|
||||||
data, len, flags, result, data_used);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Base64::DecodeFromArray(const char* data, size_t len, DecodeFlags flags,
|
|
||||||
vector<char>* result, size_t* data_used) {
|
|
||||||
return DecodeFromArrayTemplate<vector<char> >(data, len, flags, result,
|
|
||||||
data_used);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool Base64::DecodeFromArrayTemplate(const char* data, size_t len,
|
|
||||||
DecodeFlags flags, T* result,
|
|
||||||
size_t* data_used)
|
|
||||||
{
|
|
||||||
ASSERT(NULL != result);
|
|
||||||
ASSERT(flags <= (DO_PARSE_MASK | DO_PAD_MASK | DO_TERM_MASK));
|
|
||||||
|
|
||||||
const DecodeFlags parse_flags = flags & DO_PARSE_MASK;
|
|
||||||
const DecodeFlags pad_flags = flags & DO_PAD_MASK;
|
|
||||||
const DecodeFlags term_flags = flags & DO_TERM_MASK;
|
|
||||||
ASSERT(0 != parse_flags);
|
|
||||||
ASSERT(0 != pad_flags);
|
|
||||||
ASSERT(0 != term_flags);
|
|
||||||
|
|
||||||
result->clear();
|
|
||||||
result->reserve(len);
|
|
||||||
|
|
||||||
size_t dpos = 0;
|
|
||||||
bool success = true, padded;
|
|
||||||
unsigned char c, qbuf[4];
|
|
||||||
while (dpos < len) {
|
|
||||||
size_t qlen = GetNextQuantum(parse_flags, (DO_PAD_NO == pad_flags),
|
|
||||||
data, len, &dpos, qbuf, &padded);
|
|
||||||
c = (qbuf[0] << 2) | ((qbuf[1] >> 4) & 0x3);
|
|
||||||
if (qlen >= 2) {
|
|
||||||
result->push_back(c);
|
|
||||||
c = ((qbuf[1] << 4) & 0xf0) | ((qbuf[2] >> 2) & 0xf);
|
|
||||||
if (qlen >= 3) {
|
|
||||||
result->push_back(c);
|
|
||||||
c = ((qbuf[2] << 6) & 0xc0) | qbuf[3];
|
|
||||||
if (qlen >= 4) {
|
|
||||||
result->push_back(c);
|
|
||||||
c = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (qlen < 4) {
|
|
||||||
if ((DO_TERM_ANY != term_flags) && (0 != c)) {
|
|
||||||
success = false; // unused bits
|
|
||||||
}
|
|
||||||
if ((DO_PAD_YES == pad_flags) && !padded) {
|
|
||||||
success = false; // expected padding
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((DO_TERM_BUFFER == term_flags) && (dpos != len)) {
|
|
||||||
success = false; // unused chars
|
|
||||||
}
|
|
||||||
if (data_used) {
|
|
||||||
*data_used = dpos;
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,104 +0,0 @@
|
|||||||
|
|
||||||
//*********************************************************************
|
|
||||||
//* C_Base64 - a simple base64 encoder and decoder.
|
|
||||||
//*
|
|
||||||
//* Copyright (c) 1999, Bob Withers - bwit@pobox.com
|
|
||||||
//*
|
|
||||||
//* This code may be freely used for any purpose, either personal
|
|
||||||
//* or commercial, provided the authors copyright notice remains
|
|
||||||
//* intact.
|
|
||||||
//*********************************************************************
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_BASE64_H__
|
|
||||||
#define WEBRTC_BASE_BASE64_H__
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class Base64
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum DecodeOption {
|
|
||||||
DO_PARSE_STRICT = 1, // Parse only base64 characters
|
|
||||||
DO_PARSE_WHITE = 2, // Parse only base64 and whitespace characters
|
|
||||||
DO_PARSE_ANY = 3, // Parse all characters
|
|
||||||
DO_PARSE_MASK = 3,
|
|
||||||
|
|
||||||
DO_PAD_YES = 4, // Padding is required
|
|
||||||
DO_PAD_ANY = 8, // Padding is optional
|
|
||||||
DO_PAD_NO = 12, // Padding is disallowed
|
|
||||||
DO_PAD_MASK = 12,
|
|
||||||
|
|
||||||
DO_TERM_BUFFER = 16, // Must termiante at end of buffer
|
|
||||||
DO_TERM_CHAR = 32, // May terminate at any character boundary
|
|
||||||
DO_TERM_ANY = 48, // May terminate at a sub-character bit offset
|
|
||||||
DO_TERM_MASK = 48,
|
|
||||||
|
|
||||||
// Strictest interpretation
|
|
||||||
DO_STRICT = DO_PARSE_STRICT | DO_PAD_YES | DO_TERM_BUFFER,
|
|
||||||
|
|
||||||
DO_LAX = DO_PARSE_ANY | DO_PAD_ANY | DO_TERM_CHAR,
|
|
||||||
};
|
|
||||||
typedef int DecodeFlags;
|
|
||||||
|
|
||||||
static bool IsBase64Char(char ch);
|
|
||||||
|
|
||||||
// Get the char next to the |ch| from the Base64Table.
|
|
||||||
// If the |ch| is the last one in the Base64Table then returns
|
|
||||||
// the first one from the table.
|
|
||||||
// Expects the |ch| be a base64 char.
|
|
||||||
// The result will be saved in |next_ch|.
|
|
||||||
// Returns true on success.
|
|
||||||
static bool GetNextBase64Char(char ch, char* next_ch);
|
|
||||||
|
|
||||||
// Determines whether the given string consists entirely of valid base64
|
|
||||||
// encoded characters.
|
|
||||||
static bool IsBase64Encoded(const std::string& str);
|
|
||||||
|
|
||||||
static void EncodeFromArray(const void* data, size_t len,
|
|
||||||
std::string* result);
|
|
||||||
static bool DecodeFromArray(const char* data, size_t len, DecodeFlags flags,
|
|
||||||
std::string* result, size_t* data_used);
|
|
||||||
static bool DecodeFromArray(const char* data, size_t len, DecodeFlags flags,
|
|
||||||
std::vector<char>* result, size_t* data_used);
|
|
||||||
|
|
||||||
// Convenience Methods
|
|
||||||
static inline std::string Encode(const std::string& data) {
|
|
||||||
std::string result;
|
|
||||||
EncodeFromArray(data.data(), data.size(), &result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
static inline std::string Decode(const std::string& data, DecodeFlags flags) {
|
|
||||||
std::string result;
|
|
||||||
DecodeFromArray(data.data(), data.size(), flags, &result, NULL);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
static inline bool Decode(const std::string& data, DecodeFlags flags,
|
|
||||||
std::string* result, size_t* data_used)
|
|
||||||
{
|
|
||||||
return DecodeFromArray(data.data(), data.size(), flags, result, data_used);
|
|
||||||
}
|
|
||||||
static inline bool Decode(const std::string& data, DecodeFlags flags,
|
|
||||||
std::vector<char>* result, size_t* data_used)
|
|
||||||
{
|
|
||||||
return DecodeFromArray(data.data(), data.size(), flags, result, data_used);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const char Base64Table[];
|
|
||||||
static const unsigned char DecodeTable[];
|
|
||||||
|
|
||||||
static size_t GetNextQuantum(DecodeFlags parse_flags, bool illegal_pads,
|
|
||||||
const char* data, size_t len, size_t* dpos,
|
|
||||||
unsigned char qbuf[4], bool* padded);
|
|
||||||
template<typename T>
|
|
||||||
static bool DecodeFromArrayTemplate(const char* data, size_t len,
|
|
||||||
DecodeFlags flags, T* result,
|
|
||||||
size_t* data_used);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_BASE64_H__
|
|
File diff suppressed because it is too large
Load Diff
@ -1,152 +0,0 @@
|
|||||||
# 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.
|
|
||||||
{
|
|
||||||
'includes': [ '../build/common.gypi', ],
|
|
||||||
'targets': [
|
|
||||||
{
|
|
||||||
'target_name': 'webrtc_base_tests_utils',
|
|
||||||
'type': 'static_library',
|
|
||||||
'sources': [
|
|
||||||
'unittest_main.cc',
|
|
||||||
# Also use this as a convenient dumping ground for misc files that are
|
|
||||||
# included by multiple targets below.
|
|
||||||
'fakecpumonitor.h',
|
|
||||||
'fakenetwork.h',
|
|
||||||
'fakesslidentity.h',
|
|
||||||
'faketaskrunner.h',
|
|
||||||
'gunit.h',
|
|
||||||
'testbase64.h',
|
|
||||||
'testechoserver.h',
|
|
||||||
'win32toolhelp.h',
|
|
||||||
],
|
|
||||||
'dependencies': [
|
|
||||||
'base.gyp:webrtc_base',
|
|
||||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'target_name': 'webrtc_base_tests',
|
|
||||||
'type': 'executable',
|
|
||||||
'dependencies': [
|
|
||||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
|
||||||
'base.gyp:webrtc_base',
|
|
||||||
'webrtc_base_tests_utils',
|
|
||||||
],
|
|
||||||
'sources': [
|
|
||||||
'asynchttprequest_unittest.cc',
|
|
||||||
'atomicops_unittest.cc',
|
|
||||||
'autodetectproxy_unittest.cc',
|
|
||||||
'bandwidthsmoother_unittest.cc',
|
|
||||||
'base64_unittest.cc',
|
|
||||||
'basictypes_unittest.cc',
|
|
||||||
'bind_unittest.cc',
|
|
||||||
'buffer_unittest.cc',
|
|
||||||
'bytebuffer_unittest.cc',
|
|
||||||
'byteorder_unittest.cc',
|
|
||||||
'callback_unittest.cc',
|
|
||||||
'cpumonitor_unittest.cc',
|
|
||||||
'crc32_unittest.cc',
|
|
||||||
'criticalsection_unittest.cc',
|
|
||||||
'event_unittest.cc',
|
|
||||||
'filelock_unittest.cc',
|
|
||||||
'fileutils_unittest.cc',
|
|
||||||
'helpers_unittest.cc',
|
|
||||||
'httpbase_unittest.cc',
|
|
||||||
'httpcommon_unittest.cc',
|
|
||||||
'httpserver_unittest.cc',
|
|
||||||
'ipaddress_unittest.cc',
|
|
||||||
'logging_unittest.cc',
|
|
||||||
'md5digest_unittest.cc',
|
|
||||||
'messagedigest_unittest.cc',
|
|
||||||
'messagequeue_unittest.cc',
|
|
||||||
'multipart_unittest.cc',
|
|
||||||
'nat_unittest.cc',
|
|
||||||
'network_unittest.cc',
|
|
||||||
'nullsocketserver_unittest.cc',
|
|
||||||
'optionsfile_unittest.cc',
|
|
||||||
'pathutils_unittest.cc',
|
|
||||||
'physicalsocketserver_unittest.cc',
|
|
||||||
'profiler_unittest.cc',
|
|
||||||
'proxy_unittest.cc',
|
|
||||||
'proxydetect_unittest.cc',
|
|
||||||
'ratelimiter_unittest.cc',
|
|
||||||
'ratetracker_unittest.cc',
|
|
||||||
'referencecountedsingletonfactory_unittest.cc',
|
|
||||||
'rollingaccumulator_unittest.cc',
|
|
||||||
'scopedptrcollection_unittest.cc',
|
|
||||||
'sha1digest_unittest.cc',
|
|
||||||
'sharedexclusivelock_unittest.cc',
|
|
||||||
'signalthread_unittest.cc',
|
|
||||||
'sigslot_unittest.cc',
|
|
||||||
'socket_unittest.cc',
|
|
||||||
'socket_unittest.h',
|
|
||||||
'socketaddress_unittest.cc',
|
|
||||||
'stream_unittest.cc',
|
|
||||||
'stringencode_unittest.cc',
|
|
||||||
'stringutils_unittest.cc',
|
|
||||||
# TODO(ronghuawu): Reenable this test.
|
|
||||||
# 'systeminfo_unittest.cc',
|
|
||||||
'task_unittest.cc',
|
|
||||||
'testclient_unittest.cc',
|
|
||||||
'thread_unittest.cc',
|
|
||||||
'timeutils_unittest.cc',
|
|
||||||
'urlencode_unittest.cc',
|
|
||||||
'versionparsing_unittest.cc',
|
|
||||||
'virtualsocket_unittest.cc',
|
|
||||||
# TODO(ronghuawu): Reenable this test.
|
|
||||||
# 'windowpicker_unittest.cc',
|
|
||||||
],
|
|
||||||
'conditions': [
|
|
||||||
['OS=="linux"', {
|
|
||||||
'sources': [
|
|
||||||
'latebindingsymboltable_unittest.cc',
|
|
||||||
# TODO(ronghuawu): Reenable this test.
|
|
||||||
# 'linux_unittest.cc',
|
|
||||||
'linuxfdwalk_unittest.cc',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['OS=="win"', {
|
|
||||||
'sources': [
|
|
||||||
'win32_unittest.cc',
|
|
||||||
'win32regkey_unittest.cc',
|
|
||||||
'win32socketserver_unittest.cc',
|
|
||||||
'win32toolhelp_unittest.cc',
|
|
||||||
'win32window_unittest.cc',
|
|
||||||
'win32windowpicker_unittest.cc',
|
|
||||||
'winfirewall_unittest.cc',
|
|
||||||
],
|
|
||||||
'sources!': [
|
|
||||||
# TODO(ronghuawu): Fix TestUdpReadyToSendIPv6 on windows bot
|
|
||||||
# then reenable these tests.
|
|
||||||
'physicalsocketserver_unittest.cc',
|
|
||||||
'socket_unittest.cc',
|
|
||||||
'win32socketserver_unittest.cc',
|
|
||||||
'win32windowpicker_unittest.cc',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['OS=="mac"', {
|
|
||||||
'sources': [
|
|
||||||
'macsocketserver_unittest.cc',
|
|
||||||
'macutils_unittest.cc',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['os_posix==1', {
|
|
||||||
'sources': [
|
|
||||||
'sslidentity_unittest.cc',
|
|
||||||
'sslstreamadapter_unittest.cc',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
['OS=="ios" or (OS=="mac" and target_arch!="ia32")', {
|
|
||||||
'defines': [
|
|
||||||
'CARBON_DEPRECATED=YES',
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
], # conditions
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_BASICDEFS_H_
|
|
||||||
#define WEBRTC_BASE_BASICDEFS_H_
|
|
||||||
|
|
||||||
#if HAVE_CONFIG_H
|
|
||||||
#include "config.h" // NOLINT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ARRAY_SIZE(x) (static_cast<int>(sizeof(x) / sizeof(x[0])))
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_BASICDEFS_H_
|
|
@ -1,154 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_BASICTYPES_H_
|
|
||||||
#define WEBRTC_BASE_BASICTYPES_H_
|
|
||||||
|
|
||||||
#include <stddef.h> // for NULL, size_t
|
|
||||||
|
|
||||||
#if !(defined(_MSC_VER) && (_MSC_VER < 1600))
|
|
||||||
#include <stdint.h> // for uintptr_t
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h" // NOLINT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "webrtc/base/constructormagic.h"
|
|
||||||
|
|
||||||
#if !defined(INT_TYPES_DEFINED)
|
|
||||||
#define INT_TYPES_DEFINED
|
|
||||||
#ifdef COMPILER_MSVC
|
|
||||||
typedef unsigned __int64 uint64;
|
|
||||||
typedef __int64 int64;
|
|
||||||
#ifndef INT64_C
|
|
||||||
#define INT64_C(x) x ## I64
|
|
||||||
#endif
|
|
||||||
#ifndef UINT64_C
|
|
||||||
#define UINT64_C(x) x ## UI64
|
|
||||||
#endif
|
|
||||||
#define INT64_F "I64"
|
|
||||||
#else // COMPILER_MSVC
|
|
||||||
// On Mac OS X, cssmconfig.h defines uint64 as uint64_t
|
|
||||||
// TODO(fbarchard): Use long long for compatibility with chromium on BSD/OSX.
|
|
||||||
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
|
|
||||||
typedef uint64_t uint64;
|
|
||||||
typedef int64_t int64;
|
|
||||||
#ifndef INT64_C
|
|
||||||
#define INT64_C(x) x ## LL
|
|
||||||
#endif
|
|
||||||
#ifndef UINT64_C
|
|
||||||
#define UINT64_C(x) x ## ULL
|
|
||||||
#endif
|
|
||||||
#define INT64_F "l"
|
|
||||||
#elif defined(__LP64__)
|
|
||||||
typedef unsigned long uint64; // NOLINT
|
|
||||||
typedef long int64; // NOLINT
|
|
||||||
#ifndef INT64_C
|
|
||||||
#define INT64_C(x) x ## L
|
|
||||||
#endif
|
|
||||||
#ifndef UINT64_C
|
|
||||||
#define UINT64_C(x) x ## UL
|
|
||||||
#endif
|
|
||||||
#define INT64_F "l"
|
|
||||||
#else // __LP64__
|
|
||||||
typedef unsigned long long uint64; // NOLINT
|
|
||||||
typedef long long int64; // NOLINT
|
|
||||||
#ifndef INT64_C
|
|
||||||
#define INT64_C(x) x ## LL
|
|
||||||
#endif
|
|
||||||
#ifndef UINT64_C
|
|
||||||
#define UINT64_C(x) x ## ULL
|
|
||||||
#endif
|
|
||||||
#define INT64_F "ll"
|
|
||||||
#endif // __LP64__
|
|
||||||
#endif // COMPILER_MSVC
|
|
||||||
typedef unsigned int uint32;
|
|
||||||
typedef int int32;
|
|
||||||
typedef unsigned short uint16; // NOLINT
|
|
||||||
typedef short int16; // NOLINT
|
|
||||||
typedef unsigned char uint8;
|
|
||||||
typedef signed char int8;
|
|
||||||
#endif // INT_TYPES_DEFINED
|
|
||||||
|
|
||||||
// Detect compiler is for x86 or x64.
|
|
||||||
#if defined(__x86_64__) || defined(_M_X64) || \
|
|
||||||
defined(__i386__) || defined(_M_IX86)
|
|
||||||
#define CPU_X86 1
|
|
||||||
#endif
|
|
||||||
// Detect compiler is for arm.
|
|
||||||
#if defined(__arm__) || defined(_M_ARM)
|
|
||||||
#define CPU_ARM 1
|
|
||||||
#endif
|
|
||||||
#if defined(CPU_X86) && defined(CPU_ARM)
|
|
||||||
#error CPU_X86 and CPU_ARM both defined.
|
|
||||||
#endif
|
|
||||||
#if !defined(ARCH_CPU_BIG_ENDIAN) && !defined(ARCH_CPU_LITTLE_ENDIAN)
|
|
||||||
// x86, arm or GCC provided __BYTE_ORDER__ macros
|
|
||||||
#if CPU_X86 || CPU_ARM || \
|
|
||||||
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
|
||||||
#define ARCH_CPU_LITTLE_ENDIAN
|
|
||||||
#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
||||||
#define ARCH_CPU_BIG_ENDIAN
|
|
||||||
#else
|
|
||||||
#error ARCH_CPU_BIG_ENDIAN or ARCH_CPU_LITTLE_ENDIAN should be defined.
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#if defined(ARCH_CPU_BIG_ENDIAN) && defined(ARCH_CPU_LITTLE_ENDIAN)
|
|
||||||
#error ARCH_CPU_BIG_ENDIAN and ARCH_CPU_LITTLE_ENDIAN both defined.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
typedef int socklen_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// The following only works for C++
|
|
||||||
#ifdef __cplusplus
|
|
||||||
namespace rtc {
|
|
||||||
template<class T> inline T _min(T a, T b) { return (a > b) ? b : a; }
|
|
||||||
template<class T> inline T _max(T a, T b) { return (a < b) ? b : a; }
|
|
||||||
|
|
||||||
// For wait functions that take a number of milliseconds, kForever indicates
|
|
||||||
// unlimited time.
|
|
||||||
const int kForever = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ALIGNP(p, t) \
|
|
||||||
(reinterpret_cast<uint8*>(((reinterpret_cast<uintptr_t>(p) + \
|
|
||||||
((t) - 1)) & ~((t) - 1))))
|
|
||||||
#define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a) - 1)))
|
|
||||||
|
|
||||||
// Note: UNUSED is also defined in common.h
|
|
||||||
#ifndef UNUSED
|
|
||||||
#define UNUSED(x) Unused(static_cast<const void*>(&x))
|
|
||||||
#define UNUSED2(x, y) Unused(static_cast<const void*>(&x)); \
|
|
||||||
Unused(static_cast<const void*>(&y))
|
|
||||||
#define UNUSED3(x, y, z) Unused(static_cast<const void*>(&x)); \
|
|
||||||
Unused(static_cast<const void*>(&y)); \
|
|
||||||
Unused(static_cast<const void*>(&z))
|
|
||||||
#define UNUSED4(x, y, z, a) Unused(static_cast<const void*>(&x)); \
|
|
||||||
Unused(static_cast<const void*>(&y)); \
|
|
||||||
Unused(static_cast<const void*>(&z)); \
|
|
||||||
Unused(static_cast<const void*>(&a))
|
|
||||||
#define UNUSED5(x, y, z, a, b) Unused(static_cast<const void*>(&x)); \
|
|
||||||
Unused(static_cast<const void*>(&y)); \
|
|
||||||
Unused(static_cast<const void*>(&z)); \
|
|
||||||
Unused(static_cast<const void*>(&a)); \
|
|
||||||
Unused(static_cast<const void*>(&b))
|
|
||||||
inline void Unused(const void*) {}
|
|
||||||
#endif // UNUSED
|
|
||||||
|
|
||||||
// Use these to declare and define a static local variable (static T;) so that
|
|
||||||
// it is leaked so that its destructors are not called at exit.
|
|
||||||
#define LIBJINGLE_DEFINE_STATIC_LOCAL(type, name, arguments) \
|
|
||||||
static type& name = *new type arguments
|
|
||||||
|
|
||||||
#endif // __cplusplus
|
|
||||||
#endif // WEBRTC_BASE_BASICTYPES_H_
|
|
@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 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 "webrtc/base/basictypes.h"
|
|
||||||
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
TEST(BasicTypesTest, Endian) {
|
|
||||||
uint16 v16 = 0x1234u;
|
|
||||||
uint8 first_byte = *reinterpret_cast<uint8*>(&v16);
|
|
||||||
#if defined(ARCH_CPU_LITTLE_ENDIAN)
|
|
||||||
EXPECT_EQ(0x34u, first_byte);
|
|
||||||
#elif defined(ARCH_CPU_BIG_ENDIAN)
|
|
||||||
EXPECT_EQ(0x12u, first_byte);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BasicTypesTest, SizeOfTypes) {
|
|
||||||
int8 i8 = -1;
|
|
||||||
uint8 u8 = 1u;
|
|
||||||
int16 i16 = -1;
|
|
||||||
uint16 u16 = 1u;
|
|
||||||
int32 i32 = -1;
|
|
||||||
uint32 u32 = 1u;
|
|
||||||
int64 i64 = -1;
|
|
||||||
uint64 u64 = 1u;
|
|
||||||
EXPECT_EQ(1u, sizeof(i8));
|
|
||||||
EXPECT_EQ(1u, sizeof(u8));
|
|
||||||
EXPECT_EQ(2u, sizeof(i16));
|
|
||||||
EXPECT_EQ(2u, sizeof(u16));
|
|
||||||
EXPECT_EQ(4u, sizeof(i32));
|
|
||||||
EXPECT_EQ(4u, sizeof(u32));
|
|
||||||
EXPECT_EQ(8u, sizeof(i64));
|
|
||||||
EXPECT_EQ(8u, sizeof(u64));
|
|
||||||
EXPECT_GT(0, i8);
|
|
||||||
EXPECT_LT(0u, u8);
|
|
||||||
EXPECT_GT(0, i16);
|
|
||||||
EXPECT_LT(0u, u16);
|
|
||||||
EXPECT_GT(0, i32);
|
|
||||||
EXPECT_LT(0u, u32);
|
|
||||||
EXPECT_GT(0, i64);
|
|
||||||
EXPECT_LT(0u, u64);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BasicTypesTest, SizeOfConstants) {
|
|
||||||
EXPECT_EQ(8u, sizeof(INT64_C(0)));
|
|
||||||
EXPECT_EQ(8u, sizeof(UINT64_C(0)));
|
|
||||||
EXPECT_EQ(8u, sizeof(INT64_C(0x1234567887654321)));
|
|
||||||
EXPECT_EQ(8u, sizeof(UINT64_C(0x8765432112345678)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test CPU_ macros
|
|
||||||
#if !defined(CPU_ARM) && defined(__arm__)
|
|
||||||
#error expected CPU_ARM to be defined.
|
|
||||||
#endif
|
|
||||||
#if !defined(CPU_X86) && (defined(WEBRTC_WIN) || defined(WEBRTC_MAC) && !defined(WEBRTC_IOS))
|
|
||||||
#error expected CPU_X86 to be defined.
|
|
||||||
#endif
|
|
||||||
#if !defined(ARCH_CPU_LITTLE_ENDIAN) && \
|
|
||||||
(defined(WEBRTC_WIN) || defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) || defined(CPU_X86))
|
|
||||||
#error expected ARCH_CPU_LITTLE_ENDIAN to be defined.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO(fbarchard): Test all macros in basictypes.h
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,587 +0,0 @@
|
|||||||
// This file was GENERATED by command:
|
|
||||||
// pump.py bind.h.pump
|
|
||||||
// DO NOT EDIT BY HAND!!!
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2012 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// To generate bind.h from bind.h.pump, execute:
|
|
||||||
// /home/build/google3/third_party/gtest/scripts/pump.py bind.h.pump
|
|
||||||
|
|
||||||
// Bind() is an overloaded function that converts method calls into function
|
|
||||||
// objects (aka functors). It captures any arguments to the method by value
|
|
||||||
// when Bind is called, producing a stateful, nullary function object. Care
|
|
||||||
// should be taken about the lifetime of objects captured by Bind(); the
|
|
||||||
// returned functor knows nothing about the lifetime of the method's object or
|
|
||||||
// any arguments passed by pointer, and calling the functor with a destroyed
|
|
||||||
// object will surely do bad things.
|
|
||||||
//
|
|
||||||
// Example usage:
|
|
||||||
// struct Foo {
|
|
||||||
// int Test1() { return 42; }
|
|
||||||
// int Test2() const { return 52; }
|
|
||||||
// int Test3(int x) { return x*x; }
|
|
||||||
// float Test4(int x, float y) { return x + y; }
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// int main() {
|
|
||||||
// Foo foo;
|
|
||||||
// cout << rtc::Bind(&Foo::Test1, &foo)() << endl;
|
|
||||||
// cout << rtc::Bind(&Foo::Test2, &foo)() << endl;
|
|
||||||
// cout << rtc::Bind(&Foo::Test3, &foo, 3)() << endl;
|
|
||||||
// cout << rtc::Bind(&Foo::Test4, &foo, 7, 8.5f)() << endl;
|
|
||||||
// }
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_BIND_H_
|
|
||||||
#define WEBRTC_BASE_BIND_H_
|
|
||||||
|
|
||||||
#define NONAME
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
namespace detail {
|
|
||||||
// This is needed because the template parameters in Bind can't be resolved
|
|
||||||
// if they're used both as parameters of the function pointer type and as
|
|
||||||
// parameters to Bind itself: the function pointer parameters are exact
|
|
||||||
// matches to the function prototype, but the parameters to bind have
|
|
||||||
// references stripped. This trick allows the compiler to dictate the Bind
|
|
||||||
// parameter types rather than deduce them.
|
|
||||||
template <class T> struct identity { typedef T type; };
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template <class ObjectT, class MethodT, class R>
|
|
||||||
class MethodFunctor0 {
|
|
||||||
public:
|
|
||||||
MethodFunctor0(MethodT method, ObjectT* object)
|
|
||||||
: method_(method), object_(object) {}
|
|
||||||
R operator()() const {
|
|
||||||
return (object_->*method_)(); }
|
|
||||||
private:
|
|
||||||
MethodT method_;
|
|
||||||
ObjectT* object_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class FunctorT, class R>
|
|
||||||
class Functor0 {
|
|
||||||
public:
|
|
||||||
explicit Functor0(const FunctorT& functor)
|
|
||||||
: functor_(functor) {}
|
|
||||||
R operator()() const {
|
|
||||||
return functor_(); }
|
|
||||||
private:
|
|
||||||
FunctorT functor_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define FP_T(x) R (ObjectT::*x)()
|
|
||||||
|
|
||||||
template <class ObjectT, class R>
|
|
||||||
MethodFunctor0<ObjectT, FP_T(NONAME), R>
|
|
||||||
Bind(FP_T(method), ObjectT* object) {
|
|
||||||
return MethodFunctor0<ObjectT, FP_T(NONAME), R>(
|
|
||||||
method, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (ObjectT::*x)() const
|
|
||||||
|
|
||||||
template <class ObjectT, class R>
|
|
||||||
MethodFunctor0<const ObjectT, FP_T(NONAME), R>
|
|
||||||
Bind(FP_T(method), const ObjectT* object) {
|
|
||||||
return MethodFunctor0<const ObjectT, FP_T(NONAME), R>(
|
|
||||||
method, object);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (*x)()
|
|
||||||
|
|
||||||
template <class R>
|
|
||||||
Functor0<FP_T(NONAME), R>
|
|
||||||
Bind(FP_T(function)) {
|
|
||||||
return Functor0<FP_T(NONAME), R>(
|
|
||||||
function);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
|
|
||||||
template <class ObjectT, class MethodT, class R,
|
|
||||||
class P1>
|
|
||||||
class MethodFunctor1 {
|
|
||||||
public:
|
|
||||||
MethodFunctor1(MethodT method, ObjectT* object,
|
|
||||||
P1 p1)
|
|
||||||
: method_(method), object_(object),
|
|
||||||
p1_(p1) {}
|
|
||||||
R operator()() const {
|
|
||||||
return (object_->*method_)(p1_); }
|
|
||||||
private:
|
|
||||||
MethodT method_;
|
|
||||||
ObjectT* object_;
|
|
||||||
P1 p1_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class FunctorT, class R,
|
|
||||||
class P1>
|
|
||||||
class Functor1 {
|
|
||||||
public:
|
|
||||||
Functor1(const FunctorT& functor, P1 p1)
|
|
||||||
: functor_(functor),
|
|
||||||
p1_(p1) {}
|
|
||||||
R operator()() const {
|
|
||||||
return functor_(p1_); }
|
|
||||||
private:
|
|
||||||
FunctorT functor_;
|
|
||||||
P1 p1_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define FP_T(x) R (ObjectT::*x)(P1)
|
|
||||||
|
|
||||||
template <class ObjectT, class R,
|
|
||||||
class P1>
|
|
||||||
MethodFunctor1<ObjectT, FP_T(NONAME), R, P1>
|
|
||||||
Bind(FP_T(method), ObjectT* object,
|
|
||||||
typename detail::identity<P1>::type p1) {
|
|
||||||
return MethodFunctor1<ObjectT, FP_T(NONAME), R, P1>(
|
|
||||||
method, object, p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (ObjectT::*x)(P1) const
|
|
||||||
|
|
||||||
template <class ObjectT, class R,
|
|
||||||
class P1>
|
|
||||||
MethodFunctor1<const ObjectT, FP_T(NONAME), R, P1>
|
|
||||||
Bind(FP_T(method), const ObjectT* object,
|
|
||||||
typename detail::identity<P1>::type p1) {
|
|
||||||
return MethodFunctor1<const ObjectT, FP_T(NONAME), R, P1>(
|
|
||||||
method, object, p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (*x)(P1)
|
|
||||||
|
|
||||||
template <class R,
|
|
||||||
class P1>
|
|
||||||
Functor1<FP_T(NONAME), R, P1>
|
|
||||||
Bind(FP_T(function),
|
|
||||||
typename detail::identity<P1>::type p1) {
|
|
||||||
return Functor1<FP_T(NONAME), R, P1>(
|
|
||||||
function, p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
|
|
||||||
template <class ObjectT, class MethodT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2>
|
|
||||||
class MethodFunctor2 {
|
|
||||||
public:
|
|
||||||
MethodFunctor2(MethodT method, ObjectT* object,
|
|
||||||
P1 p1,
|
|
||||||
P2 p2)
|
|
||||||
: method_(method), object_(object),
|
|
||||||
p1_(p1),
|
|
||||||
p2_(p2) {}
|
|
||||||
R operator()() const {
|
|
||||||
return (object_->*method_)(p1_, p2_); }
|
|
||||||
private:
|
|
||||||
MethodT method_;
|
|
||||||
ObjectT* object_;
|
|
||||||
P1 p1_;
|
|
||||||
P2 p2_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class FunctorT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2>
|
|
||||||
class Functor2 {
|
|
||||||
public:
|
|
||||||
Functor2(const FunctorT& functor, P1 p1, P2 p2)
|
|
||||||
: functor_(functor),
|
|
||||||
p1_(p1),
|
|
||||||
p2_(p2) {}
|
|
||||||
R operator()() const {
|
|
||||||
return functor_(p1_, p2_); }
|
|
||||||
private:
|
|
||||||
FunctorT functor_;
|
|
||||||
P1 p1_;
|
|
||||||
P2 p2_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define FP_T(x) R (ObjectT::*x)(P1, P2)
|
|
||||||
|
|
||||||
template <class ObjectT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2>
|
|
||||||
MethodFunctor2<ObjectT, FP_T(NONAME), R, P1, P2>
|
|
||||||
Bind(FP_T(method), ObjectT* object,
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2) {
|
|
||||||
return MethodFunctor2<ObjectT, FP_T(NONAME), R, P1, P2>(
|
|
||||||
method, object, p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (ObjectT::*x)(P1, P2) const
|
|
||||||
|
|
||||||
template <class ObjectT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2>
|
|
||||||
MethodFunctor2<const ObjectT, FP_T(NONAME), R, P1, P2>
|
|
||||||
Bind(FP_T(method), const ObjectT* object,
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2) {
|
|
||||||
return MethodFunctor2<const ObjectT, FP_T(NONAME), R, P1, P2>(
|
|
||||||
method, object, p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (*x)(P1, P2)
|
|
||||||
|
|
||||||
template <class R,
|
|
||||||
class P1,
|
|
||||||
class P2>
|
|
||||||
Functor2<FP_T(NONAME), R, P1, P2>
|
|
||||||
Bind(FP_T(function),
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2) {
|
|
||||||
return Functor2<FP_T(NONAME), R, P1, P2>(
|
|
||||||
function, p1, p2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
|
|
||||||
template <class ObjectT, class MethodT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3>
|
|
||||||
class MethodFunctor3 {
|
|
||||||
public:
|
|
||||||
MethodFunctor3(MethodT method, ObjectT* object,
|
|
||||||
P1 p1,
|
|
||||||
P2 p2,
|
|
||||||
P3 p3)
|
|
||||||
: method_(method), object_(object),
|
|
||||||
p1_(p1),
|
|
||||||
p2_(p2),
|
|
||||||
p3_(p3) {}
|
|
||||||
R operator()() const {
|
|
||||||
return (object_->*method_)(p1_, p2_, p3_); }
|
|
||||||
private:
|
|
||||||
MethodT method_;
|
|
||||||
ObjectT* object_;
|
|
||||||
P1 p1_;
|
|
||||||
P2 p2_;
|
|
||||||
P3 p3_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class FunctorT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3>
|
|
||||||
class Functor3 {
|
|
||||||
public:
|
|
||||||
Functor3(const FunctorT& functor, P1 p1, P2 p2, P3 p3)
|
|
||||||
: functor_(functor),
|
|
||||||
p1_(p1),
|
|
||||||
p2_(p2),
|
|
||||||
p3_(p3) {}
|
|
||||||
R operator()() const {
|
|
||||||
return functor_(p1_, p2_, p3_); }
|
|
||||||
private:
|
|
||||||
FunctorT functor_;
|
|
||||||
P1 p1_;
|
|
||||||
P2 p2_;
|
|
||||||
P3 p3_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3)
|
|
||||||
|
|
||||||
template <class ObjectT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3>
|
|
||||||
MethodFunctor3<ObjectT, FP_T(NONAME), R, P1, P2, P3>
|
|
||||||
Bind(FP_T(method), ObjectT* object,
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2,
|
|
||||||
typename detail::identity<P3>::type p3) {
|
|
||||||
return MethodFunctor3<ObjectT, FP_T(NONAME), R, P1, P2, P3>(
|
|
||||||
method, object, p1, p2, p3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3) const
|
|
||||||
|
|
||||||
template <class ObjectT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3>
|
|
||||||
MethodFunctor3<const ObjectT, FP_T(NONAME), R, P1, P2, P3>
|
|
||||||
Bind(FP_T(method), const ObjectT* object,
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2,
|
|
||||||
typename detail::identity<P3>::type p3) {
|
|
||||||
return MethodFunctor3<const ObjectT, FP_T(NONAME), R, P1, P2, P3>(
|
|
||||||
method, object, p1, p2, p3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (*x)(P1, P2, P3)
|
|
||||||
|
|
||||||
template <class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3>
|
|
||||||
Functor3<FP_T(NONAME), R, P1, P2, P3>
|
|
||||||
Bind(FP_T(function),
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2,
|
|
||||||
typename detail::identity<P3>::type p3) {
|
|
||||||
return Functor3<FP_T(NONAME), R, P1, P2, P3>(
|
|
||||||
function, p1, p2, p3);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
|
|
||||||
template <class ObjectT, class MethodT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4>
|
|
||||||
class MethodFunctor4 {
|
|
||||||
public:
|
|
||||||
MethodFunctor4(MethodT method, ObjectT* object,
|
|
||||||
P1 p1,
|
|
||||||
P2 p2,
|
|
||||||
P3 p3,
|
|
||||||
P4 p4)
|
|
||||||
: method_(method), object_(object),
|
|
||||||
p1_(p1),
|
|
||||||
p2_(p2),
|
|
||||||
p3_(p3),
|
|
||||||
p4_(p4) {}
|
|
||||||
R operator()() const {
|
|
||||||
return (object_->*method_)(p1_, p2_, p3_, p4_); }
|
|
||||||
private:
|
|
||||||
MethodT method_;
|
|
||||||
ObjectT* object_;
|
|
||||||
P1 p1_;
|
|
||||||
P2 p2_;
|
|
||||||
P3 p3_;
|
|
||||||
P4 p4_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class FunctorT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4>
|
|
||||||
class Functor4 {
|
|
||||||
public:
|
|
||||||
Functor4(const FunctorT& functor, P1 p1, P2 p2, P3 p3, P4 p4)
|
|
||||||
: functor_(functor),
|
|
||||||
p1_(p1),
|
|
||||||
p2_(p2),
|
|
||||||
p3_(p3),
|
|
||||||
p4_(p4) {}
|
|
||||||
R operator()() const {
|
|
||||||
return functor_(p1_, p2_, p3_, p4_); }
|
|
||||||
private:
|
|
||||||
FunctorT functor_;
|
|
||||||
P1 p1_;
|
|
||||||
P2 p2_;
|
|
||||||
P3 p3_;
|
|
||||||
P4 p4_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4)
|
|
||||||
|
|
||||||
template <class ObjectT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4>
|
|
||||||
MethodFunctor4<ObjectT, FP_T(NONAME), R, P1, P2, P3, P4>
|
|
||||||
Bind(FP_T(method), ObjectT* object,
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2,
|
|
||||||
typename detail::identity<P3>::type p3,
|
|
||||||
typename detail::identity<P4>::type p4) {
|
|
||||||
return MethodFunctor4<ObjectT, FP_T(NONAME), R, P1, P2, P3, P4>(
|
|
||||||
method, object, p1, p2, p3, p4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4) const
|
|
||||||
|
|
||||||
template <class ObjectT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4>
|
|
||||||
MethodFunctor4<const ObjectT, FP_T(NONAME), R, P1, P2, P3, P4>
|
|
||||||
Bind(FP_T(method), const ObjectT* object,
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2,
|
|
||||||
typename detail::identity<P3>::type p3,
|
|
||||||
typename detail::identity<P4>::type p4) {
|
|
||||||
return MethodFunctor4<const ObjectT, FP_T(NONAME), R, P1, P2, P3, P4>(
|
|
||||||
method, object, p1, p2, p3, p4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (*x)(P1, P2, P3, P4)
|
|
||||||
|
|
||||||
template <class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4>
|
|
||||||
Functor4<FP_T(NONAME), R, P1, P2, P3, P4>
|
|
||||||
Bind(FP_T(function),
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2,
|
|
||||||
typename detail::identity<P3>::type p3,
|
|
||||||
typename detail::identity<P4>::type p4) {
|
|
||||||
return Functor4<FP_T(NONAME), R, P1, P2, P3, P4>(
|
|
||||||
function, p1, p2, p3, p4);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
|
|
||||||
template <class ObjectT, class MethodT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4,
|
|
||||||
class P5>
|
|
||||||
class MethodFunctor5 {
|
|
||||||
public:
|
|
||||||
MethodFunctor5(MethodT method, ObjectT* object,
|
|
||||||
P1 p1,
|
|
||||||
P2 p2,
|
|
||||||
P3 p3,
|
|
||||||
P4 p4,
|
|
||||||
P5 p5)
|
|
||||||
: method_(method), object_(object),
|
|
||||||
p1_(p1),
|
|
||||||
p2_(p2),
|
|
||||||
p3_(p3),
|
|
||||||
p4_(p4),
|
|
||||||
p5_(p5) {}
|
|
||||||
R operator()() const {
|
|
||||||
return (object_->*method_)(p1_, p2_, p3_, p4_, p5_); }
|
|
||||||
private:
|
|
||||||
MethodT method_;
|
|
||||||
ObjectT* object_;
|
|
||||||
P1 p1_;
|
|
||||||
P2 p2_;
|
|
||||||
P3 p3_;
|
|
||||||
P4 p4_;
|
|
||||||
P5 p5_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class FunctorT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4,
|
|
||||||
class P5>
|
|
||||||
class Functor5 {
|
|
||||||
public:
|
|
||||||
Functor5(const FunctorT& functor, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
|
|
||||||
: functor_(functor),
|
|
||||||
p1_(p1),
|
|
||||||
p2_(p2),
|
|
||||||
p3_(p3),
|
|
||||||
p4_(p4),
|
|
||||||
p5_(p5) {}
|
|
||||||
R operator()() const {
|
|
||||||
return functor_(p1_, p2_, p3_, p4_, p5_); }
|
|
||||||
private:
|
|
||||||
FunctorT functor_;
|
|
||||||
P1 p1_;
|
|
||||||
P2 p2_;
|
|
||||||
P3 p3_;
|
|
||||||
P4 p4_;
|
|
||||||
P5 p5_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4, P5)
|
|
||||||
|
|
||||||
template <class ObjectT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4,
|
|
||||||
class P5>
|
|
||||||
MethodFunctor5<ObjectT, FP_T(NONAME), R, P1, P2, P3, P4, P5>
|
|
||||||
Bind(FP_T(method), ObjectT* object,
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2,
|
|
||||||
typename detail::identity<P3>::type p3,
|
|
||||||
typename detail::identity<P4>::type p4,
|
|
||||||
typename detail::identity<P5>::type p5) {
|
|
||||||
return MethodFunctor5<ObjectT, FP_T(NONAME), R, P1, P2, P3, P4, P5>(
|
|
||||||
method, object, p1, p2, p3, p4, p5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4, P5) const
|
|
||||||
|
|
||||||
template <class ObjectT, class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4,
|
|
||||||
class P5>
|
|
||||||
MethodFunctor5<const ObjectT, FP_T(NONAME), R, P1, P2, P3, P4, P5>
|
|
||||||
Bind(FP_T(method), const ObjectT* object,
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2,
|
|
||||||
typename detail::identity<P3>::type p3,
|
|
||||||
typename detail::identity<P4>::type p4,
|
|
||||||
typename detail::identity<P5>::type p5) {
|
|
||||||
return MethodFunctor5<const ObjectT, FP_T(NONAME), R, P1, P2, P3, P4, P5>(
|
|
||||||
method, object, p1, p2, p3, p4, p5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (*x)(P1, P2, P3, P4, P5)
|
|
||||||
|
|
||||||
template <class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4,
|
|
||||||
class P5>
|
|
||||||
Functor5<FP_T(NONAME), R, P1, P2, P3, P4, P5>
|
|
||||||
Bind(FP_T(function),
|
|
||||||
typename detail::identity<P1>::type p1,
|
|
||||||
typename detail::identity<P2>::type p2,
|
|
||||||
typename detail::identity<P3>::type p3,
|
|
||||||
typename detail::identity<P4>::type p4,
|
|
||||||
typename detail::identity<P5>::type p5) {
|
|
||||||
return Functor5<FP_T(NONAME), R, P1, P2, P3, P4, P5>(
|
|
||||||
function, p1, p2, p3, p4, p5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#undef NONAME
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_BIND_H_
|
|
@ -1,138 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// To generate bind.h from bind.h.pump, execute:
|
|
||||||
// /home/build/google3/third_party/gtest/scripts/pump.py bind.h.pump
|
|
||||||
|
|
||||||
// Bind() is an overloaded function that converts method calls into function
|
|
||||||
// objects (aka functors). It captures any arguments to the method by value
|
|
||||||
// when Bind is called, producing a stateful, nullary function object. Care
|
|
||||||
// should be taken about the lifetime of objects captured by Bind(); the
|
|
||||||
// returned functor knows nothing about the lifetime of the method's object or
|
|
||||||
// any arguments passed by pointer, and calling the functor with a destroyed
|
|
||||||
// object will surely do bad things.
|
|
||||||
//
|
|
||||||
// Example usage:
|
|
||||||
// struct Foo {
|
|
||||||
// int Test1() { return 42; }
|
|
||||||
// int Test2() const { return 52; }
|
|
||||||
// int Test3(int x) { return x*x; }
|
|
||||||
// float Test4(int x, float y) { return x + y; }
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// int main() {
|
|
||||||
// Foo foo;
|
|
||||||
// cout << rtc::Bind(&Foo::Test1, &foo)() << endl;
|
|
||||||
// cout << rtc::Bind(&Foo::Test2, &foo)() << endl;
|
|
||||||
// cout << rtc::Bind(&Foo::Test3, &foo, 3)() << endl;
|
|
||||||
// cout << rtc::Bind(&Foo::Test4, &foo, 7, 8.5f)() << endl;
|
|
||||||
// }
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_BIND_H_
|
|
||||||
#define WEBRTC_BASE_BIND_H_
|
|
||||||
|
|
||||||
#define NONAME
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
namespace detail {
|
|
||||||
// This is needed because the template parameters in Bind can't be resolved
|
|
||||||
// if they're used both as parameters of the function pointer type and as
|
|
||||||
// parameters to Bind itself: the function pointer parameters are exact
|
|
||||||
// matches to the function prototype, but the parameters to bind have
|
|
||||||
// references stripped. This trick allows the compiler to dictate the Bind
|
|
||||||
// parameter types rather than deduce them.
|
|
||||||
template <class T> struct identity { typedef T type; };
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
$var n = 5
|
|
||||||
$range i 0..n
|
|
||||||
$for i [[
|
|
||||||
$range j 1..i
|
|
||||||
|
|
||||||
template <class ObjectT, class MethodT, class R$for j [[,
|
|
||||||
class P$j]]>
|
|
||||||
class MethodFunctor$i {
|
|
||||||
public:
|
|
||||||
MethodFunctor$i(MethodT method, ObjectT* object$for j [[,
|
|
||||||
P$j p$j]])
|
|
||||||
: method_(method), object_(object)$for j [[,
|
|
||||||
p$(j)_(p$j)]] {}
|
|
||||||
R operator()() const {
|
|
||||||
return (object_->*method_)($for j , [[p$(j)_]]); }
|
|
||||||
private:
|
|
||||||
MethodT method_;
|
|
||||||
ObjectT* object_;$for j [[
|
|
||||||
|
|
||||||
P$j p$(j)_;]]
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class FunctorT, class R$for j [[,
|
|
||||||
class P$j]]>
|
|
||||||
class Functor$i {
|
|
||||||
public:
|
|
||||||
$if i == 0 [[explicit ]]
|
|
||||||
Functor$i(const FunctorT& functor$for j [[, P$j p$j]])
|
|
||||||
: functor_(functor)$for j [[,
|
|
||||||
p$(j)_(p$j)]] {}
|
|
||||||
R operator()() const {
|
|
||||||
return functor_($for j , [[p$(j)_]]); }
|
|
||||||
private:
|
|
||||||
FunctorT functor_;$for j [[
|
|
||||||
|
|
||||||
P$j p$(j)_;]]
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#define FP_T(x) R (ObjectT::*x)($for j , [[P$j]])
|
|
||||||
|
|
||||||
template <class ObjectT, class R$for j [[,
|
|
||||||
class P$j]]>
|
|
||||||
MethodFunctor$i<ObjectT, FP_T(NONAME), R$for j [[, P$j]]>
|
|
||||||
Bind(FP_T(method), ObjectT* object$for j [[,
|
|
||||||
typename detail::identity<P$j>::type p$j]]) {
|
|
||||||
return MethodFunctor$i<ObjectT, FP_T(NONAME), R$for j [[, P$j]]>(
|
|
||||||
method, object$for j [[, p$j]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (ObjectT::*x)($for j , [[P$j]]) const
|
|
||||||
|
|
||||||
template <class ObjectT, class R$for j [[,
|
|
||||||
class P$j]]>
|
|
||||||
MethodFunctor$i<const ObjectT, FP_T(NONAME), R$for j [[, P$j]]>
|
|
||||||
Bind(FP_T(method), const ObjectT* object$for j [[,
|
|
||||||
typename detail::identity<P$j>::type p$j]]) {
|
|
||||||
return MethodFunctor$i<const ObjectT, FP_T(NONAME), R$for j [[, P$j]]>(
|
|
||||||
method, object$for j [[, p$j]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
#define FP_T(x) R (*x)($for j , [[P$j]])
|
|
||||||
|
|
||||||
template <class R$for j [[,
|
|
||||||
class P$j]]>
|
|
||||||
Functor$i<FP_T(NONAME), R$for j [[, P$j]]>
|
|
||||||
Bind(FP_T(function)$for j [[,
|
|
||||||
typename detail::identity<P$j>::type p$j]]) {
|
|
||||||
return Functor$i<FP_T(NONAME), R$for j [[, P$j]]>(
|
|
||||||
function$for j [[, p$j]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FP_T
|
|
||||||
|
|
||||||
]]
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#undef NONAME
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_BIND_H_
|
|
@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/bind.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
struct MethodBindTester {
|
|
||||||
void NullaryVoid() { ++call_count; }
|
|
||||||
int NullaryInt() { ++call_count; return 1; }
|
|
||||||
int NullaryConst() const { ++call_count; return 2; }
|
|
||||||
void UnaryVoid(int dummy) { ++call_count; }
|
|
||||||
template <class T> T Identity(T value) { ++call_count; return value; }
|
|
||||||
int UnaryByRef(int& value) const { ++call_count; return ++value; } // NOLINT
|
|
||||||
int Multiply(int a, int b) const { ++call_count; return a * b; }
|
|
||||||
mutable int call_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
int Return42() { return 42; }
|
|
||||||
int Negate(int a) { return -a; }
|
|
||||||
int Multiply(int a, int b) { return a * b; }
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
TEST(BindTest, BindToMethod) {
|
|
||||||
MethodBindTester object = {0};
|
|
||||||
EXPECT_EQ(0, object.call_count);
|
|
||||||
Bind(&MethodBindTester::NullaryVoid, &object)();
|
|
||||||
EXPECT_EQ(1, object.call_count);
|
|
||||||
EXPECT_EQ(1, Bind(&MethodBindTester::NullaryInt, &object)());
|
|
||||||
EXPECT_EQ(2, object.call_count);
|
|
||||||
EXPECT_EQ(2, Bind(&MethodBindTester::NullaryConst,
|
|
||||||
static_cast<const MethodBindTester*>(&object))());
|
|
||||||
EXPECT_EQ(3, object.call_count);
|
|
||||||
Bind(&MethodBindTester::UnaryVoid, &object, 5)();
|
|
||||||
EXPECT_EQ(4, object.call_count);
|
|
||||||
EXPECT_EQ(100, Bind(&MethodBindTester::Identity<int>, &object, 100)());
|
|
||||||
EXPECT_EQ(5, object.call_count);
|
|
||||||
const std::string string_value("test string");
|
|
||||||
EXPECT_EQ(string_value, Bind(&MethodBindTester::Identity<std::string>,
|
|
||||||
&object, string_value)());
|
|
||||||
EXPECT_EQ(6, object.call_count);
|
|
||||||
int value = 11;
|
|
||||||
EXPECT_EQ(12, Bind(&MethodBindTester::UnaryByRef, &object, value)());
|
|
||||||
EXPECT_EQ(12, value);
|
|
||||||
EXPECT_EQ(7, object.call_count);
|
|
||||||
EXPECT_EQ(56, Bind(&MethodBindTester::Multiply, &object, 7, 8)());
|
|
||||||
EXPECT_EQ(8, object.call_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BindTest, BindToFunction) {
|
|
||||||
EXPECT_EQ(42, Bind(&Return42)());
|
|
||||||
EXPECT_EQ(3, Bind(&Negate, -3)());
|
|
||||||
EXPECT_EQ(56, Bind(&Multiply, 8, 7)());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_BUFFER_H_
|
|
||||||
#define WEBRTC_BASE_BUFFER_H_
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Basic buffer class, can be grown and shrunk dynamically.
|
|
||||||
// Unlike std::string/vector, does not initialize data when expanding capacity.
|
|
||||||
class Buffer {
|
|
||||||
public:
|
|
||||||
Buffer() {
|
|
||||||
Construct(NULL, 0, 0);
|
|
||||||
}
|
|
||||||
Buffer(const void* data, size_t length) {
|
|
||||||
Construct(data, length, length);
|
|
||||||
}
|
|
||||||
Buffer(const void* data, size_t length, size_t capacity) {
|
|
||||||
Construct(data, length, capacity);
|
|
||||||
}
|
|
||||||
Buffer(const Buffer& buf) {
|
|
||||||
Construct(buf.data(), buf.length(), buf.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* data() const { return data_.get(); }
|
|
||||||
char* data() { return data_.get(); }
|
|
||||||
// TODO: should this be size(), like STL?
|
|
||||||
size_t length() const { return length_; }
|
|
||||||
size_t capacity() const { return capacity_; }
|
|
||||||
|
|
||||||
Buffer& operator=(const Buffer& buf) {
|
|
||||||
if (&buf != this) {
|
|
||||||
Construct(buf.data(), buf.length(), buf.length());
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
bool operator==(const Buffer& buf) const {
|
|
||||||
return (length_ == buf.length() &&
|
|
||||||
memcmp(data_.get(), buf.data(), length_) == 0);
|
|
||||||
}
|
|
||||||
bool operator!=(const Buffer& buf) const {
|
|
||||||
return !operator==(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetData(const void* data, size_t length) {
|
|
||||||
ASSERT(data != NULL || length == 0);
|
|
||||||
SetLength(length);
|
|
||||||
memcpy(data_.get(), data, length);
|
|
||||||
}
|
|
||||||
void AppendData(const void* data, size_t length) {
|
|
||||||
ASSERT(data != NULL || length == 0);
|
|
||||||
size_t old_length = length_;
|
|
||||||
SetLength(length_ + length);
|
|
||||||
memcpy(data_.get() + old_length, data, length);
|
|
||||||
}
|
|
||||||
void SetLength(size_t length) {
|
|
||||||
SetCapacity(length);
|
|
||||||
length_ = length;
|
|
||||||
}
|
|
||||||
void SetCapacity(size_t capacity) {
|
|
||||||
if (capacity > capacity_) {
|
|
||||||
rtc::scoped_ptr<char[]> data(new char[capacity]);
|
|
||||||
memcpy(data.get(), data_.get(), length_);
|
|
||||||
data_.swap(data);
|
|
||||||
capacity_ = capacity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TransferTo(Buffer* buf) {
|
|
||||||
ASSERT(buf != NULL);
|
|
||||||
buf->data_.reset(data_.release());
|
|
||||||
buf->length_ = length_;
|
|
||||||
buf->capacity_ = capacity_;
|
|
||||||
Construct(NULL, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void Construct(const void* data, size_t length, size_t capacity) {
|
|
||||||
data_.reset(new char[capacity_ = capacity]);
|
|
||||||
SetData(data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
scoped_ptr<char[]> data_;
|
|
||||||
size_t length_;
|
|
||||||
size_t capacity_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_BUFFER_H_
|
|
@ -1,143 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/buffer.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
static const char kTestData[] = {
|
|
||||||
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(BufferTest, TestConstructDefault) {
|
|
||||||
Buffer buf;
|
|
||||||
EXPECT_EQ(0U, buf.length());
|
|
||||||
EXPECT_EQ(0U, buf.capacity());
|
|
||||||
EXPECT_EQ(Buffer(), buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestConstructEmptyWithCapacity) {
|
|
||||||
Buffer buf(NULL, 0, 256U);
|
|
||||||
EXPECT_EQ(0U, buf.length());
|
|
||||||
EXPECT_EQ(256U, buf.capacity());
|
|
||||||
EXPECT_EQ(Buffer(), buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestConstructData) {
|
|
||||||
Buffer buf(kTestData, sizeof(kTestData));
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf.length());
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf.capacity());
|
|
||||||
EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData)));
|
|
||||||
EXPECT_EQ(Buffer(kTestData, sizeof(kTestData)), buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestConstructDataWithCapacity) {
|
|
||||||
Buffer buf(kTestData, sizeof(kTestData), 256U);
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf.length());
|
|
||||||
EXPECT_EQ(256U, buf.capacity());
|
|
||||||
EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData)));
|
|
||||||
EXPECT_EQ(Buffer(kTestData, sizeof(kTestData)), buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestConstructCopy) {
|
|
||||||
Buffer buf1(kTestData, sizeof(kTestData), 256), buf2(buf1);
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf2.length());
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf2.capacity()); // capacity isn't copied
|
|
||||||
EXPECT_EQ(0, memcmp(buf2.data(), kTestData, sizeof(kTestData)));
|
|
||||||
EXPECT_EQ(buf1, buf2);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestAssign) {
|
|
||||||
Buffer buf1, buf2(kTestData, sizeof(kTestData), 256);
|
|
||||||
EXPECT_NE(buf1, buf2);
|
|
||||||
buf1 = buf2;
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf1.length());
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf1.capacity()); // capacity isn't copied
|
|
||||||
EXPECT_EQ(0, memcmp(buf1.data(), kTestData, sizeof(kTestData)));
|
|
||||||
EXPECT_EQ(buf1, buf2);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestSetData) {
|
|
||||||
Buffer buf;
|
|
||||||
buf.SetData(kTestData, sizeof(kTestData));
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf.length());
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf.capacity());
|
|
||||||
EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData)));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestAppendData) {
|
|
||||||
Buffer buf(kTestData, sizeof(kTestData));
|
|
||||||
buf.AppendData(kTestData, sizeof(kTestData));
|
|
||||||
EXPECT_EQ(2 * sizeof(kTestData), buf.length());
|
|
||||||
EXPECT_EQ(2 * sizeof(kTestData), buf.capacity());
|
|
||||||
EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData)));
|
|
||||||
EXPECT_EQ(0, memcmp(buf.data() + sizeof(kTestData),
|
|
||||||
kTestData, sizeof(kTestData)));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestSetLengthSmaller) {
|
|
||||||
Buffer buf;
|
|
||||||
buf.SetData(kTestData, sizeof(kTestData));
|
|
||||||
buf.SetLength(sizeof(kTestData) / 2);
|
|
||||||
EXPECT_EQ(sizeof(kTestData) / 2, buf.length());
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf.capacity());
|
|
||||||
EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData) / 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestSetLengthLarger) {
|
|
||||||
Buffer buf;
|
|
||||||
buf.SetData(kTestData, sizeof(kTestData));
|
|
||||||
buf.SetLength(sizeof(kTestData) * 2);
|
|
||||||
EXPECT_EQ(sizeof(kTestData) * 2, buf.length());
|
|
||||||
EXPECT_EQ(sizeof(kTestData) * 2, buf.capacity());
|
|
||||||
EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData)));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestSetCapacitySmaller) {
|
|
||||||
Buffer buf;
|
|
||||||
buf.SetData(kTestData, sizeof(kTestData));
|
|
||||||
buf.SetCapacity(sizeof(kTestData) / 2); // should be ignored
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf.length());
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf.capacity());
|
|
||||||
EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData)));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestSetCapacityLarger) {
|
|
||||||
Buffer buf(kTestData, sizeof(kTestData));
|
|
||||||
buf.SetCapacity(sizeof(kTestData) * 2);
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf.length());
|
|
||||||
EXPECT_EQ(sizeof(kTestData) * 2, buf.capacity());
|
|
||||||
EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData)));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestSetCapacityThenSetLength) {
|
|
||||||
Buffer buf(kTestData, sizeof(kTestData));
|
|
||||||
buf.SetCapacity(sizeof(kTestData) * 4);
|
|
||||||
memcpy(buf.data() + sizeof(kTestData), kTestData, sizeof(kTestData));
|
|
||||||
buf.SetLength(sizeof(kTestData) * 2);
|
|
||||||
EXPECT_EQ(sizeof(kTestData) * 2, buf.length());
|
|
||||||
EXPECT_EQ(sizeof(kTestData) * 4, buf.capacity());
|
|
||||||
EXPECT_EQ(0, memcmp(buf.data(), kTestData, sizeof(kTestData)));
|
|
||||||
EXPECT_EQ(0, memcmp(buf.data() + sizeof(kTestData),
|
|
||||||
kTestData, sizeof(kTestData)));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BufferTest, TestTransfer) {
|
|
||||||
Buffer buf1(kTestData, sizeof(kTestData), 256U), buf2;
|
|
||||||
buf1.TransferTo(&buf2);
|
|
||||||
EXPECT_EQ(0U, buf1.length());
|
|
||||||
EXPECT_EQ(0U, buf1.capacity());
|
|
||||||
EXPECT_EQ(sizeof(kTestData), buf2.length());
|
|
||||||
EXPECT_EQ(256U, buf2.capacity()); // capacity does transfer
|
|
||||||
EXPECT_EQ(0, memcmp(buf2.data(), kTestData, sizeof(kTestData)));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,234 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/bytebuffer.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
#include "webrtc/base/byteorder.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
static const int DEFAULT_SIZE = 4096;
|
|
||||||
|
|
||||||
ByteBuffer::ByteBuffer() {
|
|
||||||
Construct(NULL, DEFAULT_SIZE, ORDER_NETWORK);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer::ByteBuffer(ByteOrder byte_order) {
|
|
||||||
Construct(NULL, DEFAULT_SIZE, byte_order);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer::ByteBuffer(const char* bytes, size_t len) {
|
|
||||||
Construct(bytes, len, ORDER_NETWORK);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer::ByteBuffer(const char* bytes, size_t len, ByteOrder byte_order) {
|
|
||||||
Construct(bytes, len, byte_order);
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer::ByteBuffer(const char* bytes) {
|
|
||||||
Construct(bytes, strlen(bytes), ORDER_NETWORK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteBuffer::Construct(const char* bytes, size_t len,
|
|
||||||
ByteOrder byte_order) {
|
|
||||||
version_ = 0;
|
|
||||||
start_ = 0;
|
|
||||||
size_ = len;
|
|
||||||
byte_order_ = byte_order;
|
|
||||||
bytes_ = new char[size_];
|
|
||||||
|
|
||||||
if (bytes) {
|
|
||||||
end_ = len;
|
|
||||||
memcpy(bytes_, bytes, end_);
|
|
||||||
} else {
|
|
||||||
end_ = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer::~ByteBuffer() {
|
|
||||||
delete[] bytes_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ByteBuffer::ReadUInt8(uint8* val) {
|
|
||||||
if (!val) return false;
|
|
||||||
|
|
||||||
return ReadBytes(reinterpret_cast<char*>(val), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ByteBuffer::ReadUInt16(uint16* val) {
|
|
||||||
if (!val) return false;
|
|
||||||
|
|
||||||
uint16 v;
|
|
||||||
if (!ReadBytes(reinterpret_cast<char*>(&v), 2)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
*val = (byte_order_ == ORDER_NETWORK) ? NetworkToHost16(v) : v;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ByteBuffer::ReadUInt24(uint32* val) {
|
|
||||||
if (!val) return false;
|
|
||||||
|
|
||||||
uint32 v = 0;
|
|
||||||
char* read_into = reinterpret_cast<char*>(&v);
|
|
||||||
if (byte_order_ == ORDER_NETWORK || IsHostBigEndian()) {
|
|
||||||
++read_into;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ReadBytes(read_into, 3)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
*val = (byte_order_ == ORDER_NETWORK) ? NetworkToHost32(v) : v;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ByteBuffer::ReadUInt32(uint32* val) {
|
|
||||||
if (!val) return false;
|
|
||||||
|
|
||||||
uint32 v;
|
|
||||||
if (!ReadBytes(reinterpret_cast<char*>(&v), 4)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
*val = (byte_order_ == ORDER_NETWORK) ? NetworkToHost32(v) : v;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ByteBuffer::ReadUInt64(uint64* val) {
|
|
||||||
if (!val) return false;
|
|
||||||
|
|
||||||
uint64 v;
|
|
||||||
if (!ReadBytes(reinterpret_cast<char*>(&v), 8)) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
*val = (byte_order_ == ORDER_NETWORK) ? NetworkToHost64(v) : v;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ByteBuffer::ReadString(std::string* val, size_t len) {
|
|
||||||
if (!val) return false;
|
|
||||||
|
|
||||||
if (len > Length()) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
val->append(bytes_ + start_, len);
|
|
||||||
start_ += len;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ByteBuffer::ReadBytes(char* val, size_t len) {
|
|
||||||
if (len > Length()) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
memcpy(val, bytes_ + start_, len);
|
|
||||||
start_ += len;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteBuffer::WriteUInt8(uint8 val) {
|
|
||||||
WriteBytes(reinterpret_cast<const char*>(&val), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteBuffer::WriteUInt16(uint16 val) {
|
|
||||||
uint16 v = (byte_order_ == ORDER_NETWORK) ? HostToNetwork16(val) : val;
|
|
||||||
WriteBytes(reinterpret_cast<const char*>(&v), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteBuffer::WriteUInt24(uint32 val) {
|
|
||||||
uint32 v = (byte_order_ == ORDER_NETWORK) ? HostToNetwork32(val) : val;
|
|
||||||
char* start = reinterpret_cast<char*>(&v);
|
|
||||||
if (byte_order_ == ORDER_NETWORK || IsHostBigEndian()) {
|
|
||||||
++start;
|
|
||||||
}
|
|
||||||
WriteBytes(start, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteBuffer::WriteUInt32(uint32 val) {
|
|
||||||
uint32 v = (byte_order_ == ORDER_NETWORK) ? HostToNetwork32(val) : val;
|
|
||||||
WriteBytes(reinterpret_cast<const char*>(&v), 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteBuffer::WriteUInt64(uint64 val) {
|
|
||||||
uint64 v = (byte_order_ == ORDER_NETWORK) ? HostToNetwork64(val) : val;
|
|
||||||
WriteBytes(reinterpret_cast<const char*>(&v), 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteBuffer::WriteString(const std::string& val) {
|
|
||||||
WriteBytes(val.c_str(), val.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteBuffer::WriteBytes(const char* val, size_t len) {
|
|
||||||
memcpy(ReserveWriteBuffer(len), val, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* ByteBuffer::ReserveWriteBuffer(size_t len) {
|
|
||||||
if (Length() + len > Capacity())
|
|
||||||
Resize(Length() + len);
|
|
||||||
|
|
||||||
char* start = bytes_ + end_;
|
|
||||||
end_ += len;
|
|
||||||
return start;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteBuffer::Resize(size_t size) {
|
|
||||||
size_t len = _min(end_ - start_, size);
|
|
||||||
if (size <= size_) {
|
|
||||||
// Don't reallocate, just move data backwards
|
|
||||||
memmove(bytes_, bytes_ + start_, len);
|
|
||||||
} else {
|
|
||||||
// Reallocate a larger buffer.
|
|
||||||
size_ = _max(size, 3 * size_ / 2);
|
|
||||||
char* new_bytes = new char[size_];
|
|
||||||
memcpy(new_bytes, bytes_ + start_, len);
|
|
||||||
delete [] bytes_;
|
|
||||||
bytes_ = new_bytes;
|
|
||||||
}
|
|
||||||
start_ = 0;
|
|
||||||
end_ = len;
|
|
||||||
++version_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ByteBuffer::Consume(size_t size) {
|
|
||||||
if (size > Length())
|
|
||||||
return false;
|
|
||||||
start_ += size;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer::ReadPosition ByteBuffer::GetReadPosition() const {
|
|
||||||
return ReadPosition(start_, version_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ByteBuffer::SetReadPosition(const ReadPosition &position) {
|
|
||||||
if (position.version_ != version_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
start_ = position.start_;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ByteBuffer::Clear() {
|
|
||||||
memset(bytes_, 0, size_);
|
|
||||||
start_ = end_ = 0;
|
|
||||||
++version_;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,119 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_BYTEBUFFER_H_
|
|
||||||
#define WEBRTC_BASE_BYTEBUFFER_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
#include "webrtc/base/constructormagic.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class ByteBuffer {
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum ByteOrder {
|
|
||||||
ORDER_NETWORK = 0, // Default, use network byte order (big endian).
|
|
||||||
ORDER_HOST, // Use the native order of the host.
|
|
||||||
};
|
|
||||||
|
|
||||||
// |byte_order| defines order of bytes in the buffer.
|
|
||||||
ByteBuffer();
|
|
||||||
explicit ByteBuffer(ByteOrder byte_order);
|
|
||||||
ByteBuffer(const char* bytes, size_t len);
|
|
||||||
ByteBuffer(const char* bytes, size_t len, ByteOrder byte_order);
|
|
||||||
|
|
||||||
// Initializes buffer from a zero-terminated string.
|
|
||||||
explicit ByteBuffer(const char* bytes);
|
|
||||||
|
|
||||||
~ByteBuffer();
|
|
||||||
|
|
||||||
const char* Data() const { return bytes_ + start_; }
|
|
||||||
size_t Length() const { return end_ - start_; }
|
|
||||||
size_t Capacity() const { return size_ - start_; }
|
|
||||||
ByteOrder Order() const { return byte_order_; }
|
|
||||||
|
|
||||||
// Read a next value from the buffer. Return false if there isn't
|
|
||||||
// enough data left for the specified type.
|
|
||||||
bool ReadUInt8(uint8* val);
|
|
||||||
bool ReadUInt16(uint16* val);
|
|
||||||
bool ReadUInt24(uint32* val);
|
|
||||||
bool ReadUInt32(uint32* val);
|
|
||||||
bool ReadUInt64(uint64* val);
|
|
||||||
bool ReadBytes(char* val, size_t len);
|
|
||||||
|
|
||||||
// Appends next |len| bytes from the buffer to |val|. Returns false
|
|
||||||
// if there is less than |len| bytes left.
|
|
||||||
bool ReadString(std::string* val, size_t len);
|
|
||||||
|
|
||||||
// Write value to the buffer. Resizes the buffer when it is
|
|
||||||
// neccessary.
|
|
||||||
void WriteUInt8(uint8 val);
|
|
||||||
void WriteUInt16(uint16 val);
|
|
||||||
void WriteUInt24(uint32 val);
|
|
||||||
void WriteUInt32(uint32 val);
|
|
||||||
void WriteUInt64(uint64 val);
|
|
||||||
void WriteString(const std::string& val);
|
|
||||||
void WriteBytes(const char* val, size_t len);
|
|
||||||
|
|
||||||
// Reserves the given number of bytes and returns a char* that can be written
|
|
||||||
// into. Useful for functions that require a char* buffer and not a
|
|
||||||
// ByteBuffer.
|
|
||||||
char* ReserveWriteBuffer(size_t len);
|
|
||||||
|
|
||||||
// Resize the buffer to the specified |size|. This invalidates any remembered
|
|
||||||
// seek positions.
|
|
||||||
void Resize(size_t size);
|
|
||||||
|
|
||||||
// Moves current position |size| bytes forward. Returns false if
|
|
||||||
// there is less than |size| bytes left in the buffer. Consume doesn't
|
|
||||||
// permanently remove data, so remembered read positions are still valid
|
|
||||||
// after this call.
|
|
||||||
bool Consume(size_t size);
|
|
||||||
|
|
||||||
// Clears the contents of the buffer. After this, Length() will be 0.
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
// Used with GetReadPosition/SetReadPosition.
|
|
||||||
class ReadPosition {
|
|
||||||
friend class ByteBuffer;
|
|
||||||
ReadPosition(size_t start, int version)
|
|
||||||
: start_(start), version_(version) { }
|
|
||||||
size_t start_;
|
|
||||||
int version_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remembers the current read position for a future SetReadPosition. Any
|
|
||||||
// calls to Shift or Resize in the interim will invalidate the position.
|
|
||||||
ReadPosition GetReadPosition() const;
|
|
||||||
|
|
||||||
// If the given position is still valid, restores that read position.
|
|
||||||
bool SetReadPosition(const ReadPosition &position);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Construct(const char* bytes, size_t size, ByteOrder byte_order);
|
|
||||||
|
|
||||||
char* bytes_;
|
|
||||||
size_t size_;
|
|
||||||
size_t start_;
|
|
||||||
size_t end_;
|
|
||||||
int version_;
|
|
||||||
ByteOrder byte_order_;
|
|
||||||
|
|
||||||
// There are sensible ways to define these, but they aren't needed in our code
|
|
||||||
// base.
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(ByteBuffer);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_BYTEBUFFER_H_
|
|
@ -1,211 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/bytebuffer.h"
|
|
||||||
#include "webrtc/base/byteorder.h"
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
TEST(ByteBufferTest, TestByteOrder) {
|
|
||||||
uint16 n16 = 1;
|
|
||||||
uint32 n32 = 1;
|
|
||||||
uint64 n64 = 1;
|
|
||||||
|
|
||||||
EXPECT_EQ(n16, NetworkToHost16(HostToNetwork16(n16)));
|
|
||||||
EXPECT_EQ(n32, NetworkToHost32(HostToNetwork32(n32)));
|
|
||||||
EXPECT_EQ(n64, NetworkToHost64(HostToNetwork64(n64)));
|
|
||||||
|
|
||||||
if (IsHostBigEndian()) {
|
|
||||||
// The host is the network (big) endian.
|
|
||||||
EXPECT_EQ(n16, HostToNetwork16(n16));
|
|
||||||
EXPECT_EQ(n32, HostToNetwork32(n32));
|
|
||||||
EXPECT_EQ(n64, HostToNetwork64(n64));
|
|
||||||
|
|
||||||
// GetBE converts big endian to little endian here.
|
|
||||||
EXPECT_EQ(n16 >> 8, GetBE16(&n16));
|
|
||||||
EXPECT_EQ(n32 >> 24, GetBE32(&n32));
|
|
||||||
EXPECT_EQ(n64 >> 56, GetBE64(&n64));
|
|
||||||
} else {
|
|
||||||
// The host is little endian.
|
|
||||||
EXPECT_NE(n16, HostToNetwork16(n16));
|
|
||||||
EXPECT_NE(n32, HostToNetwork32(n32));
|
|
||||||
EXPECT_NE(n64, HostToNetwork64(n64));
|
|
||||||
|
|
||||||
// GetBE converts little endian to big endian here.
|
|
||||||
EXPECT_EQ(GetBE16(&n16), HostToNetwork16(n16));
|
|
||||||
EXPECT_EQ(GetBE32(&n32), HostToNetwork32(n32));
|
|
||||||
EXPECT_EQ(GetBE64(&n64), HostToNetwork64(n64));
|
|
||||||
|
|
||||||
// GetBE converts little endian to big endian here.
|
|
||||||
EXPECT_EQ(n16 << 8, GetBE16(&n16));
|
|
||||||
EXPECT_EQ(n32 << 24, GetBE32(&n32));
|
|
||||||
EXPECT_EQ(n64 << 56, GetBE64(&n64));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ByteBufferTest, TestBufferLength) {
|
|
||||||
ByteBuffer buffer;
|
|
||||||
size_t size = 0;
|
|
||||||
EXPECT_EQ(size, buffer.Length());
|
|
||||||
|
|
||||||
buffer.WriteUInt8(1);
|
|
||||||
++size;
|
|
||||||
EXPECT_EQ(size, buffer.Length());
|
|
||||||
|
|
||||||
buffer.WriteUInt16(1);
|
|
||||||
size += 2;
|
|
||||||
EXPECT_EQ(size, buffer.Length());
|
|
||||||
|
|
||||||
buffer.WriteUInt24(1);
|
|
||||||
size += 3;
|
|
||||||
EXPECT_EQ(size, buffer.Length());
|
|
||||||
|
|
||||||
buffer.WriteUInt32(1);
|
|
||||||
size += 4;
|
|
||||||
EXPECT_EQ(size, buffer.Length());
|
|
||||||
|
|
||||||
buffer.WriteUInt64(1);
|
|
||||||
size += 8;
|
|
||||||
EXPECT_EQ(size, buffer.Length());
|
|
||||||
|
|
||||||
EXPECT_TRUE(buffer.Consume(0));
|
|
||||||
EXPECT_EQ(size, buffer.Length());
|
|
||||||
|
|
||||||
EXPECT_TRUE(buffer.Consume(4));
|
|
||||||
size -= 4;
|
|
||||||
EXPECT_EQ(size, buffer.Length());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ByteBufferTest, TestGetSetReadPosition) {
|
|
||||||
ByteBuffer buffer("ABCDEF", 6);
|
|
||||||
EXPECT_EQ(6U, buffer.Length());
|
|
||||||
ByteBuffer::ReadPosition pos(buffer.GetReadPosition());
|
|
||||||
EXPECT_TRUE(buffer.SetReadPosition(pos));
|
|
||||||
EXPECT_EQ(6U, buffer.Length());
|
|
||||||
std::string read;
|
|
||||||
EXPECT_TRUE(buffer.ReadString(&read, 3));
|
|
||||||
EXPECT_EQ("ABC", read);
|
|
||||||
EXPECT_EQ(3U, buffer.Length());
|
|
||||||
EXPECT_TRUE(buffer.SetReadPosition(pos));
|
|
||||||
EXPECT_EQ(6U, buffer.Length());
|
|
||||||
read.clear();
|
|
||||||
EXPECT_TRUE(buffer.ReadString(&read, 3));
|
|
||||||
EXPECT_EQ("ABC", read);
|
|
||||||
EXPECT_EQ(3U, buffer.Length());
|
|
||||||
// For a resize by writing Capacity() number of bytes.
|
|
||||||
size_t capacity = buffer.Capacity();
|
|
||||||
buffer.ReserveWriteBuffer(buffer.Capacity());
|
|
||||||
EXPECT_EQ(capacity + 3U, buffer.Length());
|
|
||||||
EXPECT_FALSE(buffer.SetReadPosition(pos));
|
|
||||||
read.clear();
|
|
||||||
EXPECT_TRUE(buffer.ReadString(&read, 3));
|
|
||||||
EXPECT_EQ("DEF", read);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ByteBufferTest, TestReadWriteBuffer) {
|
|
||||||
ByteBuffer::ByteOrder orders[2] = { ByteBuffer::ORDER_HOST,
|
|
||||||
ByteBuffer::ORDER_NETWORK };
|
|
||||||
for (size_t i = 0; i < ARRAY_SIZE(orders); i++) {
|
|
||||||
ByteBuffer buffer(orders[i]);
|
|
||||||
EXPECT_EQ(orders[i], buffer.Order());
|
|
||||||
uint8 ru8;
|
|
||||||
EXPECT_FALSE(buffer.ReadUInt8(&ru8));
|
|
||||||
|
|
||||||
// Write and read uint8.
|
|
||||||
uint8 wu8 = 1;
|
|
||||||
buffer.WriteUInt8(wu8);
|
|
||||||
EXPECT_TRUE(buffer.ReadUInt8(&ru8));
|
|
||||||
EXPECT_EQ(wu8, ru8);
|
|
||||||
EXPECT_EQ(0U, buffer.Length());
|
|
||||||
|
|
||||||
// Write and read uint16.
|
|
||||||
uint16 wu16 = (1 << 8) + 1;
|
|
||||||
buffer.WriteUInt16(wu16);
|
|
||||||
uint16 ru16;
|
|
||||||
EXPECT_TRUE(buffer.ReadUInt16(&ru16));
|
|
||||||
EXPECT_EQ(wu16, ru16);
|
|
||||||
EXPECT_EQ(0U, buffer.Length());
|
|
||||||
|
|
||||||
// Write and read uint24.
|
|
||||||
uint32 wu24 = (3 << 16) + (2 << 8) + 1;
|
|
||||||
buffer.WriteUInt24(wu24);
|
|
||||||
uint32 ru24;
|
|
||||||
EXPECT_TRUE(buffer.ReadUInt24(&ru24));
|
|
||||||
EXPECT_EQ(wu24, ru24);
|
|
||||||
EXPECT_EQ(0U, buffer.Length());
|
|
||||||
|
|
||||||
// Write and read uint32.
|
|
||||||
uint32 wu32 = (4 << 24) + (3 << 16) + (2 << 8) + 1;
|
|
||||||
buffer.WriteUInt32(wu32);
|
|
||||||
uint32 ru32;
|
|
||||||
EXPECT_TRUE(buffer.ReadUInt32(&ru32));
|
|
||||||
EXPECT_EQ(wu32, ru32);
|
|
||||||
EXPECT_EQ(0U, buffer.Length());
|
|
||||||
|
|
||||||
// Write and read uint64.
|
|
||||||
uint32 another32 = (8 << 24) + (7 << 16) + (6 << 8) + 5;
|
|
||||||
uint64 wu64 = (static_cast<uint64>(another32) << 32) + wu32;
|
|
||||||
buffer.WriteUInt64(wu64);
|
|
||||||
uint64 ru64;
|
|
||||||
EXPECT_TRUE(buffer.ReadUInt64(&ru64));
|
|
||||||
EXPECT_EQ(wu64, ru64);
|
|
||||||
EXPECT_EQ(0U, buffer.Length());
|
|
||||||
|
|
||||||
// Write and read string.
|
|
||||||
std::string write_string("hello");
|
|
||||||
buffer.WriteString(write_string);
|
|
||||||
std::string read_string;
|
|
||||||
EXPECT_TRUE(buffer.ReadString(&read_string, write_string.size()));
|
|
||||||
EXPECT_EQ(write_string, read_string);
|
|
||||||
EXPECT_EQ(0U, buffer.Length());
|
|
||||||
|
|
||||||
// Write and read bytes
|
|
||||||
char write_bytes[] = "foo";
|
|
||||||
buffer.WriteBytes(write_bytes, 3);
|
|
||||||
char read_bytes[3];
|
|
||||||
EXPECT_TRUE(buffer.ReadBytes(read_bytes, 3));
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
|
||||||
EXPECT_EQ(write_bytes[i], read_bytes[i]);
|
|
||||||
}
|
|
||||||
EXPECT_EQ(0U, buffer.Length());
|
|
||||||
|
|
||||||
// Write and read reserved buffer space
|
|
||||||
char* write_dst = buffer.ReserveWriteBuffer(3);
|
|
||||||
memcpy(write_dst, write_bytes, 3);
|
|
||||||
memset(read_bytes, 0, 3);
|
|
||||||
EXPECT_TRUE(buffer.ReadBytes(read_bytes, 3));
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
|
||||||
EXPECT_EQ(write_bytes[i], read_bytes[i]);
|
|
||||||
}
|
|
||||||
EXPECT_EQ(0U, buffer.Length());
|
|
||||||
|
|
||||||
// Write and read in order.
|
|
||||||
buffer.WriteUInt8(wu8);
|
|
||||||
buffer.WriteUInt16(wu16);
|
|
||||||
buffer.WriteUInt24(wu24);
|
|
||||||
buffer.WriteUInt32(wu32);
|
|
||||||
buffer.WriteUInt64(wu64);
|
|
||||||
EXPECT_TRUE(buffer.ReadUInt8(&ru8));
|
|
||||||
EXPECT_EQ(wu8, ru8);
|
|
||||||
EXPECT_TRUE(buffer.ReadUInt16(&ru16));
|
|
||||||
EXPECT_EQ(wu16, ru16);
|
|
||||||
EXPECT_TRUE(buffer.ReadUInt24(&ru24));
|
|
||||||
EXPECT_EQ(wu24, ru24);
|
|
||||||
EXPECT_TRUE(buffer.ReadUInt32(&ru32));
|
|
||||||
EXPECT_EQ(wu32, ru32);
|
|
||||||
EXPECT_TRUE(buffer.ReadUInt64(&ru64));
|
|
||||||
EXPECT_EQ(wu64, ru64);
|
|
||||||
EXPECT_EQ(0U, buffer.Length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_BYTEORDER_H_
|
|
||||||
#define WEBRTC_BASE_BYTEORDER_H_
|
|
||||||
|
|
||||||
#if defined(WEBRTC_POSIX) && !defined(__native_client__)
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#include <stdlib.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Reading and writing of little and big-endian numbers from memory
|
|
||||||
// TODO: Optimized versions, with direct read/writes of
|
|
||||||
// integers in host-endian format, when the platform supports it.
|
|
||||||
|
|
||||||
inline void Set8(void* memory, size_t offset, uint8 v) {
|
|
||||||
static_cast<uint8*>(memory)[offset] = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8 Get8(const void* memory, size_t offset) {
|
|
||||||
return static_cast<const uint8*>(memory)[offset];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SetBE16(void* memory, uint16 v) {
|
|
||||||
Set8(memory, 0, static_cast<uint8>(v >> 8));
|
|
||||||
Set8(memory, 1, static_cast<uint8>(v >> 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SetBE32(void* memory, uint32 v) {
|
|
||||||
Set8(memory, 0, static_cast<uint8>(v >> 24));
|
|
||||||
Set8(memory, 1, static_cast<uint8>(v >> 16));
|
|
||||||
Set8(memory, 2, static_cast<uint8>(v >> 8));
|
|
||||||
Set8(memory, 3, static_cast<uint8>(v >> 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SetBE64(void* memory, uint64 v) {
|
|
||||||
Set8(memory, 0, static_cast<uint8>(v >> 56));
|
|
||||||
Set8(memory, 1, static_cast<uint8>(v >> 48));
|
|
||||||
Set8(memory, 2, static_cast<uint8>(v >> 40));
|
|
||||||
Set8(memory, 3, static_cast<uint8>(v >> 32));
|
|
||||||
Set8(memory, 4, static_cast<uint8>(v >> 24));
|
|
||||||
Set8(memory, 5, static_cast<uint8>(v >> 16));
|
|
||||||
Set8(memory, 6, static_cast<uint8>(v >> 8));
|
|
||||||
Set8(memory, 7, static_cast<uint8>(v >> 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16 GetBE16(const void* memory) {
|
|
||||||
return static_cast<uint16>((Get8(memory, 0) << 8) |
|
|
||||||
(Get8(memory, 1) << 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32 GetBE32(const void* memory) {
|
|
||||||
return (static_cast<uint32>(Get8(memory, 0)) << 24) |
|
|
||||||
(static_cast<uint32>(Get8(memory, 1)) << 16) |
|
|
||||||
(static_cast<uint32>(Get8(memory, 2)) << 8) |
|
|
||||||
(static_cast<uint32>(Get8(memory, 3)) << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint64 GetBE64(const void* memory) {
|
|
||||||
return (static_cast<uint64>(Get8(memory, 0)) << 56) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 1)) << 48) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 2)) << 40) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 3)) << 32) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 4)) << 24) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 5)) << 16) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 6)) << 8) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 7)) << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SetLE16(void* memory, uint16 v) {
|
|
||||||
Set8(memory, 0, static_cast<uint8>(v >> 0));
|
|
||||||
Set8(memory, 1, static_cast<uint8>(v >> 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SetLE32(void* memory, uint32 v) {
|
|
||||||
Set8(memory, 0, static_cast<uint8>(v >> 0));
|
|
||||||
Set8(memory, 1, static_cast<uint8>(v >> 8));
|
|
||||||
Set8(memory, 2, static_cast<uint8>(v >> 16));
|
|
||||||
Set8(memory, 3, static_cast<uint8>(v >> 24));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SetLE64(void* memory, uint64 v) {
|
|
||||||
Set8(memory, 0, static_cast<uint8>(v >> 0));
|
|
||||||
Set8(memory, 1, static_cast<uint8>(v >> 8));
|
|
||||||
Set8(memory, 2, static_cast<uint8>(v >> 16));
|
|
||||||
Set8(memory, 3, static_cast<uint8>(v >> 24));
|
|
||||||
Set8(memory, 4, static_cast<uint8>(v >> 32));
|
|
||||||
Set8(memory, 5, static_cast<uint8>(v >> 40));
|
|
||||||
Set8(memory, 6, static_cast<uint8>(v >> 48));
|
|
||||||
Set8(memory, 7, static_cast<uint8>(v >> 56));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16 GetLE16(const void* memory) {
|
|
||||||
return static_cast<uint16>((Get8(memory, 0) << 0) |
|
|
||||||
(Get8(memory, 1) << 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32 GetLE32(const void* memory) {
|
|
||||||
return (static_cast<uint32>(Get8(memory, 0)) << 0) |
|
|
||||||
(static_cast<uint32>(Get8(memory, 1)) << 8) |
|
|
||||||
(static_cast<uint32>(Get8(memory, 2)) << 16) |
|
|
||||||
(static_cast<uint32>(Get8(memory, 3)) << 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint64 GetLE64(const void* memory) {
|
|
||||||
return (static_cast<uint64>(Get8(memory, 0)) << 0) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 1)) << 8) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 2)) << 16) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 3)) << 24) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 4)) << 32) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 5)) << 40) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 6)) << 48) |
|
|
||||||
(static_cast<uint64>(Get8(memory, 7)) << 56);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the current host is big endian.
|
|
||||||
inline bool IsHostBigEndian() {
|
|
||||||
static const int number = 1;
|
|
||||||
return 0 == *reinterpret_cast<const char*>(&number);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16 HostToNetwork16(uint16 n) {
|
|
||||||
uint16 result;
|
|
||||||
SetBE16(&result, n);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32 HostToNetwork32(uint32 n) {
|
|
||||||
uint32 result;
|
|
||||||
SetBE32(&result, n);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint64 HostToNetwork64(uint64 n) {
|
|
||||||
uint64 result;
|
|
||||||
SetBE64(&result, n);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16 NetworkToHost16(uint16 n) {
|
|
||||||
return GetBE16(&n);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32 NetworkToHost32(uint32 n) {
|
|
||||||
return GetBE32(&n);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint64 NetworkToHost64(uint64 n) {
|
|
||||||
return GetBE64(&n);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_BYTEORDER_H_
|
|
@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 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 "webrtc/base/byteorder.h"
|
|
||||||
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Test memory set functions put values into memory in expected order.
|
|
||||||
TEST(ByteOrderTest, TestSet) {
|
|
||||||
uint8 buf[8] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u };
|
|
||||||
Set8(buf, 0, 0xfb);
|
|
||||||
Set8(buf, 1, 0x12);
|
|
||||||
EXPECT_EQ(0xfb, buf[0]);
|
|
||||||
EXPECT_EQ(0x12, buf[1]);
|
|
||||||
SetBE16(buf, 0x1234);
|
|
||||||
EXPECT_EQ(0x12, buf[0]);
|
|
||||||
EXPECT_EQ(0x34, buf[1]);
|
|
||||||
SetLE16(buf, 0x1234);
|
|
||||||
EXPECT_EQ(0x34, buf[0]);
|
|
||||||
EXPECT_EQ(0x12, buf[1]);
|
|
||||||
SetBE32(buf, 0x12345678);
|
|
||||||
EXPECT_EQ(0x12, buf[0]);
|
|
||||||
EXPECT_EQ(0x34, buf[1]);
|
|
||||||
EXPECT_EQ(0x56, buf[2]);
|
|
||||||
EXPECT_EQ(0x78, buf[3]);
|
|
||||||
SetLE32(buf, 0x12345678);
|
|
||||||
EXPECT_EQ(0x78, buf[0]);
|
|
||||||
EXPECT_EQ(0x56, buf[1]);
|
|
||||||
EXPECT_EQ(0x34, buf[2]);
|
|
||||||
EXPECT_EQ(0x12, buf[3]);
|
|
||||||
SetBE64(buf, UINT64_C(0x0123456789abcdef));
|
|
||||||
EXPECT_EQ(0x01, buf[0]);
|
|
||||||
EXPECT_EQ(0x23, buf[1]);
|
|
||||||
EXPECT_EQ(0x45, buf[2]);
|
|
||||||
EXPECT_EQ(0x67, buf[3]);
|
|
||||||
EXPECT_EQ(0x89, buf[4]);
|
|
||||||
EXPECT_EQ(0xab, buf[5]);
|
|
||||||
EXPECT_EQ(0xcd, buf[6]);
|
|
||||||
EXPECT_EQ(0xef, buf[7]);
|
|
||||||
SetLE64(buf, UINT64_C(0x0123456789abcdef));
|
|
||||||
EXPECT_EQ(0xef, buf[0]);
|
|
||||||
EXPECT_EQ(0xcd, buf[1]);
|
|
||||||
EXPECT_EQ(0xab, buf[2]);
|
|
||||||
EXPECT_EQ(0x89, buf[3]);
|
|
||||||
EXPECT_EQ(0x67, buf[4]);
|
|
||||||
EXPECT_EQ(0x45, buf[5]);
|
|
||||||
EXPECT_EQ(0x23, buf[6]);
|
|
||||||
EXPECT_EQ(0x01, buf[7]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test memory get functions get values from memory in expected order.
|
|
||||||
TEST(ByteOrderTest, TestGet) {
|
|
||||||
uint8 buf[8];
|
|
||||||
buf[0] = 0x01u;
|
|
||||||
buf[1] = 0x23u;
|
|
||||||
buf[2] = 0x45u;
|
|
||||||
buf[3] = 0x67u;
|
|
||||||
buf[4] = 0x89u;
|
|
||||||
buf[5] = 0xabu;
|
|
||||||
buf[6] = 0xcdu;
|
|
||||||
buf[7] = 0xefu;
|
|
||||||
EXPECT_EQ(0x01u, Get8(buf, 0));
|
|
||||||
EXPECT_EQ(0x23u, Get8(buf, 1));
|
|
||||||
EXPECT_EQ(0x0123u, GetBE16(buf));
|
|
||||||
EXPECT_EQ(0x2301u, GetLE16(buf));
|
|
||||||
EXPECT_EQ(0x01234567u, GetBE32(buf));
|
|
||||||
EXPECT_EQ(0x67452301u, GetLE32(buf));
|
|
||||||
EXPECT_EQ(UINT64_C(0x0123456789abcdef), GetBE64(buf));
|
|
||||||
EXPECT_EQ(UINT64_C(0xefcdab8967452301), GetLE64(buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
@ -1,261 +0,0 @@
|
|||||||
// This file was GENERATED by command:
|
|
||||||
// pump.py callback.h.pump
|
|
||||||
// DO NOT EDIT BY HAND!!!
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2012 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// To generate callback.h from callback.h.pump, execute:
|
|
||||||
// /home/build/google3/third_party/gtest/scripts/pump.py callback.h.pump
|
|
||||||
|
|
||||||
// Callbacks are callable object containers. They can hold a function pointer
|
|
||||||
// or a function object and behave like a value type. Internally, data is
|
|
||||||
// reference-counted, making copies and pass-by-value inexpensive.
|
|
||||||
//
|
|
||||||
// Callbacks are typed using template arguments. The format is:
|
|
||||||
// CallbackN<ReturnType, ParamType1, ..., ParamTypeN>
|
|
||||||
// where N is the number of arguments supplied to the callable object.
|
|
||||||
// Callbacks are invoked using operator(), just like a function or a function
|
|
||||||
// object. Default-constructed callbacks are "empty," and executing an empty
|
|
||||||
// callback does nothing. A callback can be made empty by assigning it from
|
|
||||||
// a default-constructed callback.
|
|
||||||
//
|
|
||||||
// Callbacks are similar in purpose to std::function (which isn't available on
|
|
||||||
// all platforms we support) and a lightweight alternative to sigslots. Since
|
|
||||||
// they effectively hide the type of the object they call, they're useful in
|
|
||||||
// breaking dependencies between objects that need to interact with one another.
|
|
||||||
// Notably, they can hold the results of Bind(), std::bind*, etc, without
|
|
||||||
// needing
|
|
||||||
// to know the resulting object type of those calls.
|
|
||||||
//
|
|
||||||
// Sigslots, on the other hand, provide a fuller feature set, such as multiple
|
|
||||||
// subscriptions to a signal, optional thread-safety, and lifetime tracking of
|
|
||||||
// slots. When these features are needed, choose sigslots.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// int sqr(int x) { return x * x; }
|
|
||||||
// struct AddK {
|
|
||||||
// int k;
|
|
||||||
// int operator()(int x) const { return x + k; }
|
|
||||||
// } add_k = {5};
|
|
||||||
//
|
|
||||||
// Callback1<int, int> my_callback;
|
|
||||||
// cout << my_callback.empty() << endl; // true
|
|
||||||
//
|
|
||||||
// my_callback = Callback1<int, int>(&sqr);
|
|
||||||
// cout << my_callback.empty() << endl; // false
|
|
||||||
// cout << my_callback(3) << endl; // 9
|
|
||||||
//
|
|
||||||
// my_callback = Callback1<int, int>(add_k);
|
|
||||||
// cout << my_callback(10) << endl; // 15
|
|
||||||
//
|
|
||||||
// my_callback = Callback1<int, int>();
|
|
||||||
// cout << my_callback.empty() << endl; // true
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_CALLBACK_H_
|
|
||||||
#define WEBRTC_BASE_CALLBACK_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
#include "webrtc/base/refcount.h"
|
|
||||||
#include "webrtc/base/scoped_ref_ptr.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
template <class R>
|
|
||||||
class Callback0 {
|
|
||||||
public:
|
|
||||||
// Default copy operations are appropriate for this class.
|
|
||||||
Callback0() {}
|
|
||||||
template <class T> Callback0(const T& functor)
|
|
||||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
|
||||||
R operator()() {
|
|
||||||
if (empty())
|
|
||||||
return R();
|
|
||||||
return helper_->Run();
|
|
||||||
}
|
|
||||||
bool empty() const { return !helper_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Helper : RefCountInterface {
|
|
||||||
virtual ~Helper() {}
|
|
||||||
virtual R Run() = 0;
|
|
||||||
};
|
|
||||||
template <class T> struct HelperImpl : Helper {
|
|
||||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
|
||||||
virtual R Run() {
|
|
||||||
return functor_();
|
|
||||||
}
|
|
||||||
T functor_;
|
|
||||||
};
|
|
||||||
scoped_refptr<Helper> helper_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class R,
|
|
||||||
class P1>
|
|
||||||
class Callback1 {
|
|
||||||
public:
|
|
||||||
// Default copy operations are appropriate for this class.
|
|
||||||
Callback1() {}
|
|
||||||
template <class T> Callback1(const T& functor)
|
|
||||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
|
||||||
R operator()(P1 p1) {
|
|
||||||
if (empty())
|
|
||||||
return R();
|
|
||||||
return helper_->Run(p1);
|
|
||||||
}
|
|
||||||
bool empty() const { return !helper_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Helper : RefCountInterface {
|
|
||||||
virtual ~Helper() {}
|
|
||||||
virtual R Run(P1 p1) = 0;
|
|
||||||
};
|
|
||||||
template <class T> struct HelperImpl : Helper {
|
|
||||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
|
||||||
virtual R Run(P1 p1) {
|
|
||||||
return functor_(p1);
|
|
||||||
}
|
|
||||||
T functor_;
|
|
||||||
};
|
|
||||||
scoped_refptr<Helper> helper_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class R,
|
|
||||||
class P1,
|
|
||||||
class P2>
|
|
||||||
class Callback2 {
|
|
||||||
public:
|
|
||||||
// Default copy operations are appropriate for this class.
|
|
||||||
Callback2() {}
|
|
||||||
template <class T> Callback2(const T& functor)
|
|
||||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
|
||||||
R operator()(P1 p1, P2 p2) {
|
|
||||||
if (empty())
|
|
||||||
return R();
|
|
||||||
return helper_->Run(p1, p2);
|
|
||||||
}
|
|
||||||
bool empty() const { return !helper_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Helper : RefCountInterface {
|
|
||||||
virtual ~Helper() {}
|
|
||||||
virtual R Run(P1 p1, P2 p2) = 0;
|
|
||||||
};
|
|
||||||
template <class T> struct HelperImpl : Helper {
|
|
||||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
|
||||||
virtual R Run(P1 p1, P2 p2) {
|
|
||||||
return functor_(p1, p2);
|
|
||||||
}
|
|
||||||
T functor_;
|
|
||||||
};
|
|
||||||
scoped_refptr<Helper> helper_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3>
|
|
||||||
class Callback3 {
|
|
||||||
public:
|
|
||||||
// Default copy operations are appropriate for this class.
|
|
||||||
Callback3() {}
|
|
||||||
template <class T> Callback3(const T& functor)
|
|
||||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
|
||||||
R operator()(P1 p1, P2 p2, P3 p3) {
|
|
||||||
if (empty())
|
|
||||||
return R();
|
|
||||||
return helper_->Run(p1, p2, p3);
|
|
||||||
}
|
|
||||||
bool empty() const { return !helper_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Helper : RefCountInterface {
|
|
||||||
virtual ~Helper() {}
|
|
||||||
virtual R Run(P1 p1, P2 p2, P3 p3) = 0;
|
|
||||||
};
|
|
||||||
template <class T> struct HelperImpl : Helper {
|
|
||||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
|
||||||
virtual R Run(P1 p1, P2 p2, P3 p3) {
|
|
||||||
return functor_(p1, p2, p3);
|
|
||||||
}
|
|
||||||
T functor_;
|
|
||||||
};
|
|
||||||
scoped_refptr<Helper> helper_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4>
|
|
||||||
class Callback4 {
|
|
||||||
public:
|
|
||||||
// Default copy operations are appropriate for this class.
|
|
||||||
Callback4() {}
|
|
||||||
template <class T> Callback4(const T& functor)
|
|
||||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
|
||||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4) {
|
|
||||||
if (empty())
|
|
||||||
return R();
|
|
||||||
return helper_->Run(p1, p2, p3, p4);
|
|
||||||
}
|
|
||||||
bool empty() const { return !helper_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Helper : RefCountInterface {
|
|
||||||
virtual ~Helper() {}
|
|
||||||
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) = 0;
|
|
||||||
};
|
|
||||||
template <class T> struct HelperImpl : Helper {
|
|
||||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
|
||||||
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) {
|
|
||||||
return functor_(p1, p2, p3, p4);
|
|
||||||
}
|
|
||||||
T functor_;
|
|
||||||
};
|
|
||||||
scoped_refptr<Helper> helper_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class R,
|
|
||||||
class P1,
|
|
||||||
class P2,
|
|
||||||
class P3,
|
|
||||||
class P4,
|
|
||||||
class P5>
|
|
||||||
class Callback5 {
|
|
||||||
public:
|
|
||||||
// Default copy operations are appropriate for this class.
|
|
||||||
Callback5() {}
|
|
||||||
template <class T> Callback5(const T& functor)
|
|
||||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
|
||||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
|
|
||||||
if (empty())
|
|
||||||
return R();
|
|
||||||
return helper_->Run(p1, p2, p3, p4, p5);
|
|
||||||
}
|
|
||||||
bool empty() const { return !helper_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Helper : RefCountInterface {
|
|
||||||
virtual ~Helper() {}
|
|
||||||
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) = 0;
|
|
||||||
};
|
|
||||||
template <class T> struct HelperImpl : Helper {
|
|
||||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
|
||||||
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
|
|
||||||
return functor_(p1, p2, p3, p4, p5);
|
|
||||||
}
|
|
||||||
T functor_;
|
|
||||||
};
|
|
||||||
scoped_refptr<Helper> helper_;
|
|
||||||
};
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_CALLBACK_H_
|
|
@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// To generate callback.h from callback.h.pump, execute:
|
|
||||||
// /home/build/google3/third_party/gtest/scripts/pump.py callback.h.pump
|
|
||||||
|
|
||||||
// Callbacks are callable object containers. They can hold a function pointer
|
|
||||||
// or a function object and behave like a value type. Internally, data is
|
|
||||||
// reference-counted, making copies and pass-by-value inexpensive.
|
|
||||||
//
|
|
||||||
// Callbacks are typed using template arguments. The format is:
|
|
||||||
// CallbackN<ReturnType, ParamType1, ..., ParamTypeN>
|
|
||||||
// where N is the number of arguments supplied to the callable object.
|
|
||||||
// Callbacks are invoked using operator(), just like a function or a function
|
|
||||||
// object. Default-constructed callbacks are "empty," and executing an empty
|
|
||||||
// callback does nothing. A callback can be made empty by assigning it from
|
|
||||||
// a default-constructed callback.
|
|
||||||
//
|
|
||||||
// Callbacks are similar in purpose to std::function (which isn't available on
|
|
||||||
// all platforms we support) and a lightweight alternative to sigslots. Since
|
|
||||||
// they effectively hide the type of the object they call, they're useful in
|
|
||||||
// breaking dependencies between objects that need to interact with one another.
|
|
||||||
// Notably, they can hold the results of Bind(), std::bind*, etc, without needing
|
|
||||||
// to know the resulting object type of those calls.
|
|
||||||
//
|
|
||||||
// Sigslots, on the other hand, provide a fuller feature set, such as multiple
|
|
||||||
// subscriptions to a signal, optional thread-safety, and lifetime tracking of
|
|
||||||
// slots. When these features are needed, choose sigslots.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// int sqr(int x) { return x * x; }
|
|
||||||
// struct AddK {
|
|
||||||
// int k;
|
|
||||||
// int operator()(int x) const { return x + k; }
|
|
||||||
// } add_k = {5};
|
|
||||||
//
|
|
||||||
// Callback1<int, int> my_callback;
|
|
||||||
// cout << my_callback.empty() << endl; // true
|
|
||||||
//
|
|
||||||
// my_callback = Callback1<int, int>(&sqr);
|
|
||||||
// cout << my_callback.empty() << endl; // false
|
|
||||||
// cout << my_callback(3) << endl; // 9
|
|
||||||
//
|
|
||||||
// my_callback = Callback1<int, int>(add_k);
|
|
||||||
// cout << my_callback(10) << endl; // 15
|
|
||||||
//
|
|
||||||
// my_callback = Callback1<int, int>();
|
|
||||||
// cout << my_callback.empty() << endl; // true
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_CALLBACK_H_
|
|
||||||
#define WEBRTC_BASE_CALLBACK_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/refcount.h"
|
|
||||||
#include "webrtc/base/scoped_ref_ptr.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
$var n = 5
|
|
||||||
$range i 0..n
|
|
||||||
$for i [[
|
|
||||||
$range j 1..i
|
|
||||||
|
|
||||||
template <class R$for j [[,
|
|
||||||
class P$j]]>
|
|
||||||
class Callback$i {
|
|
||||||
public:
|
|
||||||
// Default copy operations are appropriate for this class.
|
|
||||||
Callback$i() {}
|
|
||||||
template <class T> Callback$i(const T& functor)
|
|
||||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
|
||||||
R operator()($for j , [[P$j p$j]]) {
|
|
||||||
if (empty())
|
|
||||||
return R();
|
|
||||||
return helper_->Run($for j , [[p$j]]);
|
|
||||||
}
|
|
||||||
bool empty() const { return !helper_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Helper : RefCountInterface {
|
|
||||||
virtual ~Helper() {}
|
|
||||||
virtual R Run($for j , [[P$j p$j]]) = 0;
|
|
||||||
};
|
|
||||||
template <class T> struct HelperImpl : Helper {
|
|
||||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
|
||||||
virtual R Run($for j , [[P$j p$j]]) {
|
|
||||||
return functor_($for j , [[p$j]]);
|
|
||||||
}
|
|
||||||
T functor_;
|
|
||||||
};
|
|
||||||
scoped_refptr<Helper> helper_;
|
|
||||||
};
|
|
||||||
|
|
||||||
]]
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_CALLBACK_H_
|
|
@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/bind.h"
|
|
||||||
#include "webrtc/base/callback.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void f() {}
|
|
||||||
int g() { return 42; }
|
|
||||||
int h(int x) { return x * x; }
|
|
||||||
void i(int& x) { x *= x; } // NOLINT: Testing refs
|
|
||||||
|
|
||||||
struct BindTester {
|
|
||||||
int a() { return 24; }
|
|
||||||
int b(int x) const { return x * x; }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
TEST(CallbackTest, VoidReturn) {
|
|
||||||
Callback0<void> cb;
|
|
||||||
EXPECT_TRUE(cb.empty());
|
|
||||||
cb(); // Executing an empty callback should not crash.
|
|
||||||
cb = Callback0<void>(&f);
|
|
||||||
EXPECT_FALSE(cb.empty());
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CallbackTest, IntReturn) {
|
|
||||||
Callback0<int> cb;
|
|
||||||
EXPECT_TRUE(cb.empty());
|
|
||||||
cb = Callback0<int>(&g);
|
|
||||||
EXPECT_FALSE(cb.empty());
|
|
||||||
EXPECT_EQ(42, cb());
|
|
||||||
EXPECT_EQ(42, cb());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CallbackTest, OneParam) {
|
|
||||||
Callback1<int, int> cb1(&h);
|
|
||||||
EXPECT_FALSE(cb1.empty());
|
|
||||||
EXPECT_EQ(9, cb1(-3));
|
|
||||||
EXPECT_EQ(100, cb1(10));
|
|
||||||
|
|
||||||
// Try clearing a callback.
|
|
||||||
cb1 = Callback1<int, int>();
|
|
||||||
EXPECT_TRUE(cb1.empty());
|
|
||||||
|
|
||||||
// Try a callback with a ref parameter.
|
|
||||||
Callback1<void, int&> cb2(&i);
|
|
||||||
int x = 3;
|
|
||||||
cb2(x);
|
|
||||||
EXPECT_EQ(9, x);
|
|
||||||
cb2(x);
|
|
||||||
EXPECT_EQ(81, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CallbackTest, WithBind) {
|
|
||||||
BindTester t;
|
|
||||||
Callback0<int> cb1 = Bind(&BindTester::a, &t);
|
|
||||||
EXPECT_EQ(24, cb1());
|
|
||||||
EXPECT_EQ(24, cb1());
|
|
||||||
cb1 = Bind(&BindTester::b, &t, 10);
|
|
||||||
EXPECT_EQ(100, cb1());
|
|
||||||
EXPECT_EQ(100, cb1());
|
|
||||||
cb1 = Bind(&BindTester::b, &t, 5);
|
|
||||||
EXPECT_EQ(25, cb1());
|
|
||||||
EXPECT_EQ(25, cb1());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006 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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#include "webrtc/base/checks.h"
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
|
|
||||||
void Fatal(const char* file, int line, const char* format, ...) {
|
|
||||||
char msg[256];
|
|
||||||
|
|
||||||
va_list arguments;
|
|
||||||
va_start(arguments, format);
|
|
||||||
vsnprintf(msg, sizeof(msg), format, arguments);
|
|
||||||
va_end(arguments);
|
|
||||||
|
|
||||||
LOG(LS_ERROR) << "\n\n#\n# Fatal error in " << file
|
|
||||||
<< ", line " << line << "\n#" << msg
|
|
||||||
<< "\n#\n";
|
|
||||||
abort();
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This module contains some basic debugging facilities.
|
|
||||||
// Originally comes from shared/commandlineflags/checks.h
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_CHECKS_H_
|
|
||||||
#define WEBRTC_BASE_CHECKS_H_
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
// Prints an error message to stderr and aborts execution.
|
|
||||||
void Fatal(const char* file, int line, const char* format, ...);
|
|
||||||
|
|
||||||
|
|
||||||
// The UNREACHABLE macro is very useful during development.
|
|
||||||
#define UNREACHABLE() \
|
|
||||||
Fatal(__FILE__, __LINE__, "unreachable code")
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_CHECKS_H_
|
|
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 <signal.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#if WEBRTC_WIN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
#endif // WEBRTC_WIN
|
|
||||||
|
|
||||||
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
|
|
||||||
#include <CoreServices/CoreServices.h>
|
|
||||||
#endif // WEBRTC_MAC && !defined(WEBRTC_IOS)
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// Assertions
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
void Break() {
|
|
||||||
#if WEBRTC_WIN
|
|
||||||
::DebugBreak();
|
|
||||||
#else // !WEBRTC_WIN
|
|
||||||
// On POSIX systems, SIGTRAP signals debuggers to break without killing the
|
|
||||||
// process. If a debugger isn't attached, the uncaught SIGTRAP will crash the
|
|
||||||
// app.
|
|
||||||
raise(SIGTRAP);
|
|
||||||
#endif
|
|
||||||
// If a debugger wasn't attached, we will have crashed by this point. If a
|
|
||||||
// debugger is attached, we'll continue from here.
|
|
||||||
}
|
|
||||||
|
|
||||||
static AssertLogger custom_assert_logger_ = NULL;
|
|
||||||
|
|
||||||
void SetCustomAssertLogger(AssertLogger logger) {
|
|
||||||
custom_assert_logger_ = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogAssert(const char* function, const char* file, int line,
|
|
||||||
const char* expression) {
|
|
||||||
if (custom_assert_logger_) {
|
|
||||||
custom_assert_logger_(function, file, line, expression);
|
|
||||||
} else {
|
|
||||||
LOG(LS_ERROR) << file << "(" << line << ")" << ": ASSERT FAILED: "
|
|
||||||
<< expression << " @ " << function;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,201 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_COMMON_H_ // NOLINT
|
|
||||||
#define WEBRTC_BASE_COMMON_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
#include "webrtc/base/constructormagic.h"
|
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
// warning C4355: 'this' : used in base member initializer list
|
|
||||||
#pragma warning(disable:4355)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// General Utilities
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Note: UNUSED is also defined in basictypes.h
|
|
||||||
#ifndef UNUSED
|
|
||||||
#define UNUSED(x) Unused(static_cast<const void*>(&x))
|
|
||||||
#define UNUSED2(x, y) Unused(static_cast<const void*>(&x)); \
|
|
||||||
Unused(static_cast<const void*>(&y))
|
|
||||||
#define UNUSED3(x, y, z) Unused(static_cast<const void*>(&x)); \
|
|
||||||
Unused(static_cast<const void*>(&y)); \
|
|
||||||
Unused(static_cast<const void*>(&z))
|
|
||||||
#define UNUSED4(x, y, z, a) Unused(static_cast<const void*>(&x)); \
|
|
||||||
Unused(static_cast<const void*>(&y)); \
|
|
||||||
Unused(static_cast<const void*>(&z)); \
|
|
||||||
Unused(static_cast<const void*>(&a))
|
|
||||||
#define UNUSED5(x, y, z, a, b) Unused(static_cast<const void*>(&x)); \
|
|
||||||
Unused(static_cast<const void*>(&y)); \
|
|
||||||
Unused(static_cast<const void*>(&z)); \
|
|
||||||
Unused(static_cast<const void*>(&a)); \
|
|
||||||
Unused(static_cast<const void*>(&b))
|
|
||||||
inline void Unused(const void*) {}
|
|
||||||
#endif // UNUSED
|
|
||||||
|
|
||||||
#if !defined(WEBRTC_WIN)
|
|
||||||
|
|
||||||
#ifndef strnicmp
|
|
||||||
#define strnicmp(x, y, n) strncasecmp(x, y, n)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef stricmp
|
|
||||||
#define stricmp(x, y) strcasecmp(x, y)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO(fbarchard): Remove this. std::max should be used everywhere in the code.
|
|
||||||
// NOMINMAX must be defined where we include <windows.h>.
|
|
||||||
#define stdmax(x, y) std::max(x, y)
|
|
||||||
#else
|
|
||||||
#define stdmax(x, y) rtc::_max(x, y)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ARRAY_SIZE(x) (static_cast<int>(sizeof(x) / sizeof(x[0])))
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Assertions
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#ifndef ENABLE_DEBUG
|
|
||||||
#define ENABLE_DEBUG _DEBUG
|
|
||||||
#endif // !defined(ENABLE_DEBUG)
|
|
||||||
|
|
||||||
// Even for release builds, allow for the override of LogAssert. Though no
|
|
||||||
// macro is provided, this can still be used for explicit runtime asserts
|
|
||||||
// and allow applications to override the assert behavior.
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
|
|
||||||
// If a debugger is attached, triggers a debugger breakpoint. If a debugger is
|
|
||||||
// not attached, forces program termination.
|
|
||||||
void Break();
|
|
||||||
|
|
||||||
// LogAssert writes information about an assertion to the log. It's called by
|
|
||||||
// Assert (and from the ASSERT macro in debug mode) before any other action
|
|
||||||
// is taken (e.g. breaking the debugger, abort()ing, etc.).
|
|
||||||
void LogAssert(const char* function, const char* file, int line,
|
|
||||||
const char* expression);
|
|
||||||
|
|
||||||
typedef void (*AssertLogger)(const char* function,
|
|
||||||
const char* file,
|
|
||||||
int line,
|
|
||||||
const char* expression);
|
|
||||||
|
|
||||||
// Sets a custom assert logger to be used instead of the default LogAssert
|
|
||||||
// behavior. To clear the custom assert logger, pass NULL for |logger| and the
|
|
||||||
// default behavior will be restored. Only one custom assert logger can be set
|
|
||||||
// at a time, so this should generally be set during application startup and
|
|
||||||
// only by one component.
|
|
||||||
void SetCustomAssertLogger(AssertLogger logger);
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#if ENABLE_DEBUG
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
inline bool Assert(bool result, const char* function, const char* file,
|
|
||||||
int line, const char* expression) {
|
|
||||||
if (!result) {
|
|
||||||
LogAssert(function, file, line, expression);
|
|
||||||
Break();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1300
|
|
||||||
#define __FUNCTION__ ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ASSERT
|
|
||||||
#define ASSERT(x) \
|
|
||||||
(void)rtc::Assert((x), __FUNCTION__, __FILE__, __LINE__, #x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef VERIFY
|
|
||||||
#define VERIFY(x) rtc::Assert((x), __FUNCTION__, __FILE__, __LINE__, #x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else // !ENABLE_DEBUG
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
inline bool ImplicitCastToBool(bool result) { return result; }
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#ifndef ASSERT
|
|
||||||
#define ASSERT(x) (void)0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef VERIFY
|
|
||||||
#define VERIFY(x) rtc::ImplicitCastToBool(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // !ENABLE_DEBUG
|
|
||||||
|
|
||||||
#define COMPILE_TIME_ASSERT(expr) char CTA_UNIQUE_NAME[expr]
|
|
||||||
#define CTA_UNIQUE_NAME CTA_MAKE_NAME(__LINE__)
|
|
||||||
#define CTA_MAKE_NAME(line) CTA_MAKE_NAME2(line)
|
|
||||||
#define CTA_MAKE_NAME2(line) constraint_ ## line
|
|
||||||
|
|
||||||
// Forces compiler to inline, even against its better judgement. Use wisely.
|
|
||||||
#if defined(__GNUC__)
|
|
||||||
#define FORCE_INLINE __attribute__((always_inline))
|
|
||||||
#elif defined(WEBRTC_WIN)
|
|
||||||
#define FORCE_INLINE __forceinline
|
|
||||||
#else
|
|
||||||
#define FORCE_INLINE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Borrowed from Chromium's base/compiler_specific.h.
|
|
||||||
// Annotate a virtual method indicating it must be overriding a virtual
|
|
||||||
// method in the parent class.
|
|
||||||
// Use like:
|
|
||||||
// virtual void foo() OVERRIDE;
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#define OVERRIDE override
|
|
||||||
#elif defined(__clang__)
|
|
||||||
// Clang defaults to C++03 and warns about using override. Squelch that.
|
|
||||||
// Intentionally no push/pop here so all users of OVERRIDE ignore the warning
|
|
||||||
// too. This is like passing -Wno-c++11-extensions, except that GCC won't die
|
|
||||||
// (because it won't see this pragma).
|
|
||||||
#pragma clang diagnostic ignored "-Wc++11-extensions"
|
|
||||||
#define OVERRIDE override
|
|
||||||
#elif defined(__GNUC__) && __cplusplus >= 201103 && \
|
|
||||||
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40700
|
|
||||||
// GCC 4.7 supports explicit virtual overrides when C++11 support is enabled.
|
|
||||||
#define OVERRIDE override
|
|
||||||
#else
|
|
||||||
#define OVERRIDE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Annotate a function indicating the caller must examine the return value.
|
|
||||||
// Use like:
|
|
||||||
// int foo() WARN_UNUSED_RESULT;
|
|
||||||
// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>.
|
|
||||||
// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and
|
|
||||||
// libjingle are merged.
|
|
||||||
#if !defined(WARN_UNUSED_RESULT)
|
|
||||||
#if defined(__GNUC__)
|
|
||||||
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
|
||||||
#else
|
|
||||||
#define WARN_UNUSED_RESULT
|
|
||||||
#endif
|
|
||||||
#endif // WARN_UNUSED_RESULT
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_COMMON_H_ // NOLINT
|
|
@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// COMPILE_ASSERT macro, borrowed from google3/base/macros.h.
|
|
||||||
#ifndef WEBRTC_BASE_COMPILE_ASSERT_H_
|
|
||||||
#define WEBRTC_BASE_COMPILE_ASSERT_H_
|
|
||||||
|
|
||||||
// The COMPILE_ASSERT macro can be used to verify that a compile time
|
|
||||||
// expression is true. For example, you could use it to verify the
|
|
||||||
// size of a static array:
|
|
||||||
//
|
|
||||||
// COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
|
|
||||||
// content_type_names_incorrect_size);
|
|
||||||
//
|
|
||||||
// or to make sure a struct is smaller than a certain size:
|
|
||||||
//
|
|
||||||
// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
|
|
||||||
//
|
|
||||||
// The second argument to the macro is the name of the variable. If
|
|
||||||
// the expression is false, most compilers will issue a warning/error
|
|
||||||
// containing the name of the variable.
|
|
||||||
|
|
||||||
// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and
|
|
||||||
// libjingle are merged.
|
|
||||||
#if !defined(COMPILE_ASSERT)
|
|
||||||
template <bool>
|
|
||||||
struct CompileAssert {
|
|
||||||
};
|
|
||||||
|
|
||||||
#define COMPILE_ASSERT(expr, msg) \
|
|
||||||
typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] // NOLINT
|
|
||||||
#endif // COMPILE_ASSERT
|
|
||||||
|
|
||||||
// Implementation details of COMPILE_ASSERT:
|
|
||||||
//
|
|
||||||
// - COMPILE_ASSERT works by defining an array type that has -1
|
|
||||||
// elements (and thus is invalid) when the expression is false.
|
|
||||||
//
|
|
||||||
// - The simpler definition
|
|
||||||
//
|
|
||||||
// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
|
|
||||||
//
|
|
||||||
// does not work, as gcc supports variable-length arrays whose sizes
|
|
||||||
// are determined at run-time (this is gcc's extension and not part
|
|
||||||
// of the C++ standard). As a result, gcc fails to reject the
|
|
||||||
// following code with the simple definition:
|
|
||||||
//
|
|
||||||
// int foo;
|
|
||||||
// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
|
|
||||||
// // not a compile-time constant.
|
|
||||||
//
|
|
||||||
// - By using the type CompileAssert<(bool(expr))>, we ensures that
|
|
||||||
// expr is a compile-time constant. (Template arguments must be
|
|
||||||
// determined at compile-time.)
|
|
||||||
//
|
|
||||||
// - The outer parentheses in CompileAssert<(bool(expr))> are necessary
|
|
||||||
// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
|
|
||||||
//
|
|
||||||
// CompileAssert<bool(expr)>
|
|
||||||
//
|
|
||||||
// instead, these compilers will refuse to compile
|
|
||||||
//
|
|
||||||
// COMPILE_ASSERT(5 > 0, some_message);
|
|
||||||
//
|
|
||||||
// (They seem to think the ">" in "5 > 0" marks the end of the
|
|
||||||
// template argument list.)
|
|
||||||
//
|
|
||||||
// - The array size is (bool(expr) ? 1 : -1), instead of simply
|
|
||||||
//
|
|
||||||
// ((expr) ? 1 : -1).
|
|
||||||
//
|
|
||||||
// This is to avoid running into a bug in MS VC 7.1, which
|
|
||||||
// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_COMPILE_ASSERT_H_
|
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_CONSTRUCTORMAGIC_H_
|
|
||||||
#define WEBRTC_BASE_CONSTRUCTORMAGIC_H_
|
|
||||||
|
|
||||||
#define DISALLOW_ASSIGN(TypeName) \
|
|
||||||
void operator=(const TypeName&)
|
|
||||||
|
|
||||||
// A macro to disallow the evil copy constructor and operator= functions
|
|
||||||
// This should be used in the private: declarations for a class.
|
|
||||||
// Undefine this, just in case. Some third-party includes have their own
|
|
||||||
// version.
|
|
||||||
#undef DISALLOW_COPY_AND_ASSIGN
|
|
||||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
|
||||||
TypeName(const TypeName&); \
|
|
||||||
DISALLOW_ASSIGN(TypeName)
|
|
||||||
|
|
||||||
// Alternative, less-accurate legacy name.
|
|
||||||
#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) \
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(TypeName)
|
|
||||||
|
|
||||||
// A macro to disallow all the implicit constructors, namely the
|
|
||||||
// default constructor, copy constructor and operator= functions.
|
|
||||||
//
|
|
||||||
// This should be used in the private: declarations for a class
|
|
||||||
// that wants to prevent anyone from instantiating it. This is
|
|
||||||
// especially useful for classes containing only static methods.
|
|
||||||
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
|
|
||||||
TypeName(); \
|
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(TypeName)
|
|
||||||
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_CONSTRUCTORMAGIC_H_
|
|
@ -1,419 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 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 "webrtc/base/cpumonitor.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
#include "webrtc/base/systeminfo.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
#include "webrtc/base/timeutils.h"
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#include "webrtc/base/win32.h"
|
|
||||||
#include <winternl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(WEBRTC_POSIX)
|
|
||||||
#include <sys/time.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(WEBRTC_MAC)
|
|
||||||
#include <mach/mach_host.h>
|
|
||||||
#include <mach/mach_init.h>
|
|
||||||
#include <mach/host_info.h>
|
|
||||||
#include <mach/task.h>
|
|
||||||
#endif // defined(WEBRTC_MAC)
|
|
||||||
|
|
||||||
#if defined(WEBRTC_LINUX)
|
|
||||||
#include <sys/resource.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "webrtc/base/fileutils.h"
|
|
||||||
#include "webrtc/base/pathutils.h"
|
|
||||||
#endif // defined(WEBRTC_LINUX)
|
|
||||||
|
|
||||||
#if defined(WEBRTC_MAC)
|
|
||||||
static uint64 TimeValueTToInt64(const time_value_t &time_value) {
|
|
||||||
return rtc::kNumMicrosecsPerSec * time_value.seconds +
|
|
||||||
time_value.microseconds;
|
|
||||||
}
|
|
||||||
#endif // defined(WEBRTC_MAC)
|
|
||||||
|
|
||||||
// How CpuSampler works
|
|
||||||
// When threads switch, the time they spent is accumulated to system counters.
|
|
||||||
// The time can be treated as user, kernel or idle.
|
|
||||||
// user time is applications.
|
|
||||||
// kernel time is the OS, including the thread switching code itself.
|
|
||||||
// typically kernel time indicates IO.
|
|
||||||
// idle time is a process that wastes time when nothing is ready to run.
|
|
||||||
//
|
|
||||||
// User time is broken down by process (application). One of the applications
|
|
||||||
// is the current process. When you add up all application times, this is
|
|
||||||
// system time. If only your application is running, system time should be the
|
|
||||||
// same as process time.
|
|
||||||
//
|
|
||||||
// All cores contribute to these accumulators. A dual core process is able to
|
|
||||||
// process twice as many cycles as a single core. The actual code efficiency
|
|
||||||
// may be worse, due to contention, but the available cycles is exactly twice
|
|
||||||
// as many, and the cpu load will reflect the efficiency. Hyperthreads behave
|
|
||||||
// the same way. The load will reflect 200%, but the actual amount of work
|
|
||||||
// completed will be much less than a true dual core.
|
|
||||||
//
|
|
||||||
// Total available performance is the sum of all accumulators.
|
|
||||||
// If you tracked this for 1 second, it would essentially give you the clock
|
|
||||||
// rate - number of cycles per second.
|
|
||||||
// Speed step / Turbo Boost is not considered, so infact more processing time
|
|
||||||
// may be available.
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Note Tests on Windows show 600 ms is minimum stable interval for Windows 7.
|
|
||||||
static const int32 kDefaultInterval = 950; // Slightly under 1 second.
|
|
||||||
|
|
||||||
CpuSampler::CpuSampler()
|
|
||||||
: min_load_interval_(kDefaultInterval)
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
, get_system_times_(NULL),
|
|
||||||
nt_query_system_information_(NULL),
|
|
||||||
force_fallback_(false)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CpuSampler::~CpuSampler() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set minimum interval in ms between computing new load values. Default 950.
|
|
||||||
void CpuSampler::set_load_interval(int min_load_interval) {
|
|
||||||
min_load_interval_ = min_load_interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CpuSampler::Init() {
|
|
||||||
sysinfo_.reset(new SystemInfo);
|
|
||||||
cpus_ = sysinfo_->GetMaxCpus();
|
|
||||||
if (cpus_ == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
// Note that GetSystemTimes is available in Windows XP SP1 or later.
|
|
||||||
// http://msdn.microsoft.com/en-us/library/ms724400.aspx
|
|
||||||
// NtQuerySystemInformation is used as a fallback.
|
|
||||||
if (!force_fallback_) {
|
|
||||||
get_system_times_ = GetProcAddress(GetModuleHandle(L"kernel32.dll"),
|
|
||||||
"GetSystemTimes");
|
|
||||||
}
|
|
||||||
nt_query_system_information_ = GetProcAddress(GetModuleHandle(L"ntdll.dll"),
|
|
||||||
"NtQuerySystemInformation");
|
|
||||||
if ((get_system_times_ == NULL) && (nt_query_system_information_ == NULL)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(WEBRTC_LINUX)
|
|
||||||
Pathname sname("/proc/stat");
|
|
||||||
sfile_.reset(Filesystem::OpenFile(sname, "rb"));
|
|
||||||
if (!sfile_) {
|
|
||||||
LOG_ERR(LS_ERROR) << "open proc/stat failed:";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!sfile_->DisableBuffering()) {
|
|
||||||
LOG_ERR(LS_ERROR) << "could not disable buffering for proc/stat";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif // defined(WEBRTC_LINUX)
|
|
||||||
GetProcessLoad(); // Initialize values.
|
|
||||||
GetSystemLoad();
|
|
||||||
// Help next user call return valid data by recomputing load.
|
|
||||||
process_.prev_load_time_ = 0u;
|
|
||||||
system_.prev_load_time_ = 0u;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
float CpuSampler::UpdateCpuLoad(uint64 current_total_times,
|
|
||||||
uint64 current_cpu_times,
|
|
||||||
uint64 *prev_total_times,
|
|
||||||
uint64 *prev_cpu_times) {
|
|
||||||
float result = 0.f;
|
|
||||||
if (current_total_times < *prev_total_times ||
|
|
||||||
current_cpu_times < *prev_cpu_times) {
|
|
||||||
LOG(LS_ERROR) << "Inconsistent time values are passed. ignored";
|
|
||||||
} else {
|
|
||||||
const uint64 cpu_diff = current_cpu_times - *prev_cpu_times;
|
|
||||||
const uint64 total_diff = current_total_times - *prev_total_times;
|
|
||||||
result = (total_diff == 0ULL ? 0.f :
|
|
||||||
static_cast<float>(1.0f * cpu_diff / total_diff));
|
|
||||||
if (result > static_cast<float>(cpus_)) {
|
|
||||||
result = static_cast<float>(cpus_);
|
|
||||||
}
|
|
||||||
*prev_total_times = current_total_times;
|
|
||||||
*prev_cpu_times = current_cpu_times;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
float CpuSampler::GetSystemLoad() {
|
|
||||||
uint32 timenow = Time();
|
|
||||||
int elapsed = static_cast<int>(TimeDiff(timenow, system_.prev_load_time_));
|
|
||||||
if (min_load_interval_ != 0 && system_.prev_load_time_ != 0u &&
|
|
||||||
elapsed < min_load_interval_) {
|
|
||||||
return system_.prev_load_;
|
|
||||||
}
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
uint64 total_times, cpu_times;
|
|
||||||
|
|
||||||
typedef BOOL (_stdcall *GST_PROC)(LPFILETIME, LPFILETIME, LPFILETIME);
|
|
||||||
typedef NTSTATUS (WINAPI *QSI_PROC)(SYSTEM_INFORMATION_CLASS,
|
|
||||||
PVOID, ULONG, PULONG);
|
|
||||||
|
|
||||||
GST_PROC get_system_times = reinterpret_cast<GST_PROC>(get_system_times_);
|
|
||||||
QSI_PROC nt_query_system_information = reinterpret_cast<QSI_PROC>(
|
|
||||||
nt_query_system_information_);
|
|
||||||
|
|
||||||
if (get_system_times) {
|
|
||||||
FILETIME idle_time, kernel_time, user_time;
|
|
||||||
if (!get_system_times(&idle_time, &kernel_time, &user_time)) {
|
|
||||||
LOG(LS_ERROR) << "::GetSystemTimes() failed: " << ::GetLastError();
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
// kernel_time includes Kernel idle time, so no need to
|
|
||||||
// include cpu_time as total_times
|
|
||||||
total_times = ToUInt64(kernel_time) + ToUInt64(user_time);
|
|
||||||
cpu_times = total_times - ToUInt64(idle_time);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (nt_query_system_information) {
|
|
||||||
ULONG returned_length = 0;
|
|
||||||
scoped_ptr<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[]> processor_info(
|
|
||||||
new SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[cpus_]);
|
|
||||||
nt_query_system_information(
|
|
||||||
::SystemProcessorPerformanceInformation,
|
|
||||||
reinterpret_cast<void*>(processor_info.get()),
|
|
||||||
cpus_ * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION),
|
|
||||||
&returned_length);
|
|
||||||
|
|
||||||
if (returned_length !=
|
|
||||||
(cpus_ * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION))) {
|
|
||||||
LOG(LS_ERROR) << "NtQuerySystemInformation has unexpected size";
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64 current_idle = 0;
|
|
||||||
uint64 current_kernel = 0;
|
|
||||||
uint64 current_user = 0;
|
|
||||||
for (int ix = 0; ix < cpus_; ++ix) {
|
|
||||||
current_idle += processor_info[ix].IdleTime.QuadPart;
|
|
||||||
current_kernel += processor_info[ix].UserTime.QuadPart;
|
|
||||||
current_user += processor_info[ix].KernelTime.QuadPart;
|
|
||||||
}
|
|
||||||
total_times = current_kernel + current_user;
|
|
||||||
cpu_times = total_times - current_idle;
|
|
||||||
} else {
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // WEBRTC_WIN
|
|
||||||
|
|
||||||
#if defined(WEBRTC_MAC)
|
|
||||||
host_cpu_load_info_data_t cpu_info;
|
|
||||||
mach_msg_type_number_t info_count = HOST_CPU_LOAD_INFO_COUNT;
|
|
||||||
if (KERN_SUCCESS != host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO,
|
|
||||||
reinterpret_cast<host_info_t>(&cpu_info),
|
|
||||||
&info_count)) {
|
|
||||||
LOG(LS_ERROR) << "::host_statistics() failed";
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64 cpu_times = cpu_info.cpu_ticks[CPU_STATE_NICE] +
|
|
||||||
cpu_info.cpu_ticks[CPU_STATE_SYSTEM] +
|
|
||||||
cpu_info.cpu_ticks[CPU_STATE_USER];
|
|
||||||
const uint64 total_times = cpu_times + cpu_info.cpu_ticks[CPU_STATE_IDLE];
|
|
||||||
#endif // defined(WEBRTC_MAC)
|
|
||||||
|
|
||||||
#if defined(WEBRTC_LINUX)
|
|
||||||
if (!sfile_) {
|
|
||||||
LOG(LS_ERROR) << "Invalid handle for proc/stat";
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
std::string statbuf;
|
|
||||||
sfile_->SetPosition(0);
|
|
||||||
if (!sfile_->ReadLine(&statbuf)) {
|
|
||||||
LOG_ERR(LS_ERROR) << "Could not read proc/stat file";
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long long user;
|
|
||||||
unsigned long long nice;
|
|
||||||
unsigned long long system;
|
|
||||||
unsigned long long idle;
|
|
||||||
if (sscanf(statbuf.c_str(), "cpu %Lu %Lu %Lu %Lu",
|
|
||||||
&user, &nice,
|
|
||||||
&system, &idle) != 4) {
|
|
||||||
LOG_ERR(LS_ERROR) << "Could not parse cpu info";
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
const uint64 cpu_times = nice + system + user;
|
|
||||||
const uint64 total_times = cpu_times + idle;
|
|
||||||
#endif // defined(WEBRTC_LINUX)
|
|
||||||
|
|
||||||
#if defined(__native_client__)
|
|
||||||
// TODO(ryanpetrie): Implement this via PPAPI when it's available.
|
|
||||||
const uint64 cpu_times = 0;
|
|
||||||
const uint64 total_times = 0;
|
|
||||||
#endif // defined(__native_client__)
|
|
||||||
|
|
||||||
system_.prev_load_time_ = timenow;
|
|
||||||
system_.prev_load_ = UpdateCpuLoad(total_times,
|
|
||||||
cpu_times * cpus_,
|
|
||||||
&system_.prev_total_times_,
|
|
||||||
&system_.prev_cpu_times_);
|
|
||||||
return system_.prev_load_;
|
|
||||||
}
|
|
||||||
|
|
||||||
float CpuSampler::GetProcessLoad() {
|
|
||||||
uint32 timenow = Time();
|
|
||||||
int elapsed = static_cast<int>(TimeDiff(timenow, process_.prev_load_time_));
|
|
||||||
if (min_load_interval_ != 0 && process_.prev_load_time_ != 0u &&
|
|
||||||
elapsed < min_load_interval_) {
|
|
||||||
return process_.prev_load_;
|
|
||||||
}
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
FILETIME current_file_time;
|
|
||||||
::GetSystemTimeAsFileTime(¤t_file_time);
|
|
||||||
|
|
||||||
FILETIME create_time, exit_time, kernel_time, user_time;
|
|
||||||
if (!::GetProcessTimes(::GetCurrentProcess(),
|
|
||||||
&create_time, &exit_time, &kernel_time, &user_time)) {
|
|
||||||
LOG(LS_ERROR) << "::GetProcessTimes() failed: " << ::GetLastError();
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64 total_times =
|
|
||||||
ToUInt64(current_file_time) - ToUInt64(create_time);
|
|
||||||
const uint64 cpu_times =
|
|
||||||
(ToUInt64(kernel_time) + ToUInt64(user_time));
|
|
||||||
#endif // WEBRTC_WIN
|
|
||||||
|
|
||||||
#if defined(WEBRTC_POSIX)
|
|
||||||
// Common to both OSX and Linux.
|
|
||||||
struct timeval tv;
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
const uint64 total_times = tv.tv_sec * kNumMicrosecsPerSec + tv.tv_usec;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(WEBRTC_MAC)
|
|
||||||
// Get live thread usage.
|
|
||||||
task_thread_times_info task_times_info;
|
|
||||||
mach_msg_type_number_t info_count = TASK_THREAD_TIMES_INFO_COUNT;
|
|
||||||
|
|
||||||
if (KERN_SUCCESS != task_info(mach_task_self(), TASK_THREAD_TIMES_INFO,
|
|
||||||
reinterpret_cast<task_info_t>(&task_times_info),
|
|
||||||
&info_count)) {
|
|
||||||
LOG(LS_ERROR) << "::task_info(TASK_THREAD_TIMES_INFO) failed";
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get terminated thread usage.
|
|
||||||
task_basic_info task_term_info;
|
|
||||||
info_count = TASK_BASIC_INFO_COUNT;
|
|
||||||
if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO,
|
|
||||||
reinterpret_cast<task_info_t>(&task_term_info),
|
|
||||||
&info_count)) {
|
|
||||||
LOG(LS_ERROR) << "::task_info(TASK_BASIC_INFO) failed";
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64 cpu_times = (TimeValueTToInt64(task_times_info.user_time) +
|
|
||||||
TimeValueTToInt64(task_times_info.system_time) +
|
|
||||||
TimeValueTToInt64(task_term_info.user_time) +
|
|
||||||
TimeValueTToInt64(task_term_info.system_time));
|
|
||||||
#endif // defined(WEBRTC_MAC)
|
|
||||||
|
|
||||||
#if defined(WEBRTC_LINUX)
|
|
||||||
rusage usage;
|
|
||||||
if (getrusage(RUSAGE_SELF, &usage) < 0) {
|
|
||||||
LOG_ERR(LS_ERROR) << "getrusage failed";
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint64 cpu_times =
|
|
||||||
(usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) * kNumMicrosecsPerSec +
|
|
||||||
usage.ru_utime.tv_usec + usage.ru_stime.tv_usec;
|
|
||||||
#endif // defined(WEBRTC_LINUX)
|
|
||||||
|
|
||||||
#if defined(__native_client__)
|
|
||||||
// TODO(ryanpetrie): Implement this via PPAPI when it's available.
|
|
||||||
const uint64 cpu_times = 0;
|
|
||||||
#endif // defined(__native_client__)
|
|
||||||
|
|
||||||
process_.prev_load_time_ = timenow;
|
|
||||||
process_.prev_load_ = UpdateCpuLoad(total_times,
|
|
||||||
cpu_times,
|
|
||||||
&process_.prev_total_times_,
|
|
||||||
&process_.prev_cpu_times_);
|
|
||||||
return process_.prev_load_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CpuSampler::GetMaxCpus() const {
|
|
||||||
return cpus_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CpuSampler::GetCurrentCpus() {
|
|
||||||
return sysinfo_->GetCurCpus();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////
|
|
||||||
// Implementation of class CpuMonitor.
|
|
||||||
CpuMonitor::CpuMonitor(Thread* thread)
|
|
||||||
: monitor_thread_(thread) {
|
|
||||||
}
|
|
||||||
|
|
||||||
CpuMonitor::~CpuMonitor() {
|
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CpuMonitor::set_thread(Thread* thread) {
|
|
||||||
ASSERT(monitor_thread_ == NULL || monitor_thread_ == thread);
|
|
||||||
monitor_thread_ = thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CpuMonitor::Start(int period_ms) {
|
|
||||||
if (!monitor_thread_ || !sampler_.Init()) return false;
|
|
||||||
|
|
||||||
monitor_thread_->SignalQueueDestroyed.connect(
|
|
||||||
this, &CpuMonitor::OnMessageQueueDestroyed);
|
|
||||||
|
|
||||||
period_ms_ = period_ms;
|
|
||||||
monitor_thread_->PostDelayed(period_ms_, this);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CpuMonitor::Stop() {
|
|
||||||
if (monitor_thread_) {
|
|
||||||
monitor_thread_->Clear(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CpuMonitor::OnMessage(Message* msg) {
|
|
||||||
int max_cpus = sampler_.GetMaxCpus();
|
|
||||||
int current_cpus = sampler_.GetCurrentCpus();
|
|
||||||
float process_load = sampler_.GetProcessLoad();
|
|
||||||
float system_load = sampler_.GetSystemLoad();
|
|
||||||
SignalUpdate(current_cpus, max_cpus, process_load, system_load);
|
|
||||||
|
|
||||||
if (monitor_thread_) {
|
|
||||||
monitor_thread_->PostDelayed(period_ms_, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,123 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_CPUMONITOR_H_
|
|
||||||
#define WEBRTC_BASE_CPUMONITOR_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
#include "webrtc/base/messagehandler.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
#include "webrtc/base/sigslot.h"
|
|
||||||
#if defined(WEBRTC_LINUX)
|
|
||||||
#include "webrtc/base/stream.h"
|
|
||||||
#endif // defined(WEBRTC_LINUX)
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
class Thread;
|
|
||||||
class SystemInfo;
|
|
||||||
|
|
||||||
struct CpuStats {
|
|
||||||
CpuStats()
|
|
||||||
: prev_total_times_(0),
|
|
||||||
prev_cpu_times_(0),
|
|
||||||
prev_load_(0.f),
|
|
||||||
prev_load_time_(0u) {
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64 prev_total_times_;
|
|
||||||
uint64 prev_cpu_times_;
|
|
||||||
float prev_load_; // Previous load value.
|
|
||||||
uint32 prev_load_time_; // Time previous load value was taken.
|
|
||||||
};
|
|
||||||
|
|
||||||
// CpuSampler samples the process and system load.
|
|
||||||
class CpuSampler {
|
|
||||||
public:
|
|
||||||
CpuSampler();
|
|
||||||
~CpuSampler();
|
|
||||||
|
|
||||||
// Initialize CpuSampler. Returns true if successful.
|
|
||||||
bool Init();
|
|
||||||
|
|
||||||
// Set minimum interval in ms between computing new load values.
|
|
||||||
// Default 950 ms. Set to 0 to disable interval.
|
|
||||||
void set_load_interval(int min_load_interval);
|
|
||||||
|
|
||||||
// Return CPU load of current process as a float from 0 to 1.
|
|
||||||
float GetProcessLoad();
|
|
||||||
|
|
||||||
// Return CPU load of current process as a float from 0 to 1.
|
|
||||||
float GetSystemLoad();
|
|
||||||
|
|
||||||
// Return number of cpus. Includes hyperthreads.
|
|
||||||
int GetMaxCpus() const;
|
|
||||||
|
|
||||||
// Return current number of cpus available to this process.
|
|
||||||
int GetCurrentCpus();
|
|
||||||
|
|
||||||
// For testing. Allows forcing of fallback to using NTDLL functions.
|
|
||||||
void set_force_fallback(bool fallback) {
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
force_fallback_ = fallback;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
float UpdateCpuLoad(uint64 current_total_times,
|
|
||||||
uint64 current_cpu_times,
|
|
||||||
uint64 *prev_total_times,
|
|
||||||
uint64 *prev_cpu_times);
|
|
||||||
CpuStats process_;
|
|
||||||
CpuStats system_;
|
|
||||||
int cpus_;
|
|
||||||
int min_load_interval_; // Minimum time between computing new load.
|
|
||||||
scoped_ptr<SystemInfo> sysinfo_;
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
void* get_system_times_;
|
|
||||||
void* nt_query_system_information_;
|
|
||||||
bool force_fallback_;
|
|
||||||
#endif
|
|
||||||
#if defined(WEBRTC_LINUX)
|
|
||||||
// File for reading /proc/stat
|
|
||||||
scoped_ptr<FileStream> sfile_;
|
|
||||||
#endif // defined(WEBRTC_LINUX)
|
|
||||||
};
|
|
||||||
|
|
||||||
// CpuMonitor samples and signals the CPU load periodically.
|
|
||||||
class CpuMonitor
|
|
||||||
: public rtc::MessageHandler, public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
explicit CpuMonitor(Thread* thread);
|
|
||||||
virtual ~CpuMonitor();
|
|
||||||
void set_thread(Thread* thread);
|
|
||||||
|
|
||||||
bool Start(int period_ms);
|
|
||||||
void Stop();
|
|
||||||
// Signal parameters are current cpus, max cpus, process load and system load.
|
|
||||||
sigslot::signal4<int, int, float, float> SignalUpdate;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Override virtual method of parent MessageHandler.
|
|
||||||
virtual void OnMessage(rtc::Message* msg);
|
|
||||||
// Clear the monitor thread and stop sending it messages if the thread goes
|
|
||||||
// away before our lifetime.
|
|
||||||
void OnMessageQueueDestroyed() { monitor_thread_ = NULL; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Thread* monitor_thread_;
|
|
||||||
CpuSampler sampler_;
|
|
||||||
int period_ms_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(CpuMonitor);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_CPUMONITOR_H_
|
|
@ -1,388 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 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 <iomanip>
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#include "webrtc/base/win32.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "webrtc/base/cpumonitor.h"
|
|
||||||
#include "webrtc/base/flags.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
#include "webrtc/base/timeutils.h"
|
|
||||||
#include "webrtc/base/timing.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
static const int kMaxCpus = 1024;
|
|
||||||
static const int kSettleTime = 100; // Amount of time to between tests.
|
|
||||||
static const int kIdleTime = 500; // Amount of time to be idle in ms.
|
|
||||||
static const int kBusyTime = 1000; // Amount of time to be busy in ms.
|
|
||||||
static const int kLongInterval = 2000; // Interval longer than busy times
|
|
||||||
|
|
||||||
class BusyThread : public rtc::Thread {
|
|
||||||
public:
|
|
||||||
BusyThread(double load, double duration, double interval) :
|
|
||||||
load_(load), duration_(duration), interval_(interval) {
|
|
||||||
}
|
|
||||||
virtual ~BusyThread() {
|
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
void Run() {
|
|
||||||
Timing time;
|
|
||||||
double busy_time = interval_ * load_ / 100.0;
|
|
||||||
for (;;) {
|
|
||||||
time.BusyWait(busy_time);
|
|
||||||
time.IdleWait(interval_ - busy_time);
|
|
||||||
if (duration_) {
|
|
||||||
duration_ -= interval_;
|
|
||||||
if (duration_ <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
double load_;
|
|
||||||
double duration_;
|
|
||||||
double interval_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CpuLoadListener : public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
CpuLoadListener()
|
|
||||||
: current_cpus_(0),
|
|
||||||
cpus_(0),
|
|
||||||
process_load_(.0f),
|
|
||||||
system_load_(.0f),
|
|
||||||
count_(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnCpuLoad(int current_cpus, int cpus, float proc_load, float sys_load) {
|
|
||||||
current_cpus_ = current_cpus;
|
|
||||||
cpus_ = cpus;
|
|
||||||
process_load_ = proc_load;
|
|
||||||
system_load_ = sys_load;
|
|
||||||
++count_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int current_cpus() const { return current_cpus_; }
|
|
||||||
int cpus() const { return cpus_; }
|
|
||||||
float process_load() const { return process_load_; }
|
|
||||||
float system_load() const { return system_load_; }
|
|
||||||
int count() const { return count_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int current_cpus_;
|
|
||||||
int cpus_;
|
|
||||||
float process_load_;
|
|
||||||
float system_load_;
|
|
||||||
int count_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set affinity (which cpu to run on), but respecting FLAG_affinity:
|
|
||||||
// -1 means no affinity - run on whatever cpu is available.
|
|
||||||
// 0 .. N means run on specific cpu. The tool will create N threads and call
|
|
||||||
// SetThreadAffinity on 0 to N - 1 as cpu. FLAG_affinity sets the first cpu
|
|
||||||
// so the range becomes affinity to affinity + N - 1
|
|
||||||
// Note that this function affects Windows scheduling, effectively giving
|
|
||||||
// the thread with affinity for a specified CPU more priority on that CPU.
|
|
||||||
bool SetThreadAffinity(BusyThread* t, int cpu, int affinity) {
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
if (affinity >= 0) {
|
|
||||||
return ::SetThreadAffinityMask(t->GetHandle(),
|
|
||||||
1 << (cpu + affinity)) != FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SetThreadPriority(BusyThread* t, int prio) {
|
|
||||||
if (!prio) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool ok = t->SetPriority(static_cast<rtc::ThreadPriority>(prio));
|
|
||||||
if (!ok) {
|
|
||||||
std::cout << "Error setting thread priority." << std::endl;
|
|
||||||
}
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CpuLoad(double cpuload, double duration, int numthreads,
|
|
||||||
int priority, double interval, int affinity) {
|
|
||||||
int ret = 0;
|
|
||||||
std::vector<BusyThread*> threads;
|
|
||||||
for (int i = 0; i < numthreads; ++i) {
|
|
||||||
threads.push_back(new BusyThread(cpuload, duration, interval));
|
|
||||||
// NOTE(fbarchard): Priority must be done before Start.
|
|
||||||
if (!SetThreadPriority(threads[i], priority) ||
|
|
||||||
!threads[i]->Start() ||
|
|
||||||
!SetThreadAffinity(threads[i], i, affinity)) {
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Wait on each thread
|
|
||||||
if (ret == 0) {
|
|
||||||
for (int i = 0; i < numthreads; ++i) {
|
|
||||||
threads[i]->Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < numthreads; ++i) {
|
|
||||||
delete threads[i];
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make 2 CPUs busy
|
|
||||||
static void CpuTwoBusyLoop(int busytime) {
|
|
||||||
CpuLoad(100.0, busytime / 1000.0, 2, 1, 0.050, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make 1 CPUs busy
|
|
||||||
static void CpuBusyLoop(int busytime) {
|
|
||||||
CpuLoad(100.0, busytime / 1000.0, 1, 1, 0.050, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make 1 use half CPU time.
|
|
||||||
static void CpuHalfBusyLoop(int busytime) {
|
|
||||||
CpuLoad(50.0, busytime / 1000.0, 1, 1, 0.050, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestCpuSampler(bool test_proc, bool test_sys, bool force_fallback) {
|
|
||||||
CpuSampler sampler;
|
|
||||||
sampler.set_force_fallback(force_fallback);
|
|
||||||
EXPECT_TRUE(sampler.Init());
|
|
||||||
sampler.set_load_interval(100);
|
|
||||||
int cpus = sampler.GetMaxCpus();
|
|
||||||
|
|
||||||
// Test1: CpuSampler under idle situation.
|
|
||||||
Thread::SleepMs(kSettleTime);
|
|
||||||
sampler.GetProcessLoad();
|
|
||||||
sampler.GetSystemLoad();
|
|
||||||
|
|
||||||
Thread::SleepMs(kIdleTime);
|
|
||||||
|
|
||||||
float proc_idle = 0.f, sys_idle = 0.f;
|
|
||||||
if (test_proc) {
|
|
||||||
proc_idle = sampler.GetProcessLoad();
|
|
||||||
}
|
|
||||||
if (test_sys) {
|
|
||||||
sys_idle = sampler.GetSystemLoad();
|
|
||||||
}
|
|
||||||
if (test_proc) {
|
|
||||||
LOG(LS_INFO) << "ProcessLoad Idle: "
|
|
||||||
<< std::setiosflags(std::ios_base::fixed)
|
|
||||||
<< std::setprecision(2) << std::setw(6) << proc_idle;
|
|
||||||
EXPECT_GE(proc_idle, 0.f);
|
|
||||||
EXPECT_LE(proc_idle, static_cast<float>(cpus));
|
|
||||||
}
|
|
||||||
if (test_sys) {
|
|
||||||
LOG(LS_INFO) << "SystemLoad Idle: "
|
|
||||||
<< std::setiosflags(std::ios_base::fixed)
|
|
||||||
<< std::setprecision(2) << std::setw(6) << sys_idle;
|
|
||||||
EXPECT_GE(sys_idle, 0.f);
|
|
||||||
EXPECT_LE(sys_idle, static_cast<float>(cpus));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test2: CpuSampler with main process at 50% busy.
|
|
||||||
Thread::SleepMs(kSettleTime);
|
|
||||||
sampler.GetProcessLoad();
|
|
||||||
sampler.GetSystemLoad();
|
|
||||||
|
|
||||||
CpuHalfBusyLoop(kBusyTime);
|
|
||||||
|
|
||||||
float proc_halfbusy = 0.f, sys_halfbusy = 0.f;
|
|
||||||
if (test_proc) {
|
|
||||||
proc_halfbusy = sampler.GetProcessLoad();
|
|
||||||
}
|
|
||||||
if (test_sys) {
|
|
||||||
sys_halfbusy = sampler.GetSystemLoad();
|
|
||||||
}
|
|
||||||
if (test_proc) {
|
|
||||||
LOG(LS_INFO) << "ProcessLoad Halfbusy: "
|
|
||||||
<< std::setiosflags(std::ios_base::fixed)
|
|
||||||
<< std::setprecision(2) << std::setw(6) << proc_halfbusy;
|
|
||||||
EXPECT_GE(proc_halfbusy, 0.f);
|
|
||||||
EXPECT_LE(proc_halfbusy, static_cast<float>(cpus));
|
|
||||||
}
|
|
||||||
if (test_sys) {
|
|
||||||
LOG(LS_INFO) << "SystemLoad Halfbusy: "
|
|
||||||
<< std::setiosflags(std::ios_base::fixed)
|
|
||||||
<< std::setprecision(2) << std::setw(6) << sys_halfbusy;
|
|
||||||
EXPECT_GE(sys_halfbusy, 0.f);
|
|
||||||
EXPECT_LE(sys_halfbusy, static_cast<float>(cpus));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test3: CpuSampler with main process busy.
|
|
||||||
Thread::SleepMs(kSettleTime);
|
|
||||||
sampler.GetProcessLoad();
|
|
||||||
sampler.GetSystemLoad();
|
|
||||||
|
|
||||||
CpuBusyLoop(kBusyTime);
|
|
||||||
|
|
||||||
float proc_busy = 0.f, sys_busy = 0.f;
|
|
||||||
if (test_proc) {
|
|
||||||
proc_busy = sampler.GetProcessLoad();
|
|
||||||
}
|
|
||||||
if (test_sys) {
|
|
||||||
sys_busy = sampler.GetSystemLoad();
|
|
||||||
}
|
|
||||||
if (test_proc) {
|
|
||||||
LOG(LS_INFO) << "ProcessLoad Busy: "
|
|
||||||
<< std::setiosflags(std::ios_base::fixed)
|
|
||||||
<< std::setprecision(2) << std::setw(6) << proc_busy;
|
|
||||||
EXPECT_GE(proc_busy, 0.f);
|
|
||||||
EXPECT_LE(proc_busy, static_cast<float>(cpus));
|
|
||||||
}
|
|
||||||
if (test_sys) {
|
|
||||||
LOG(LS_INFO) << "SystemLoad Busy: "
|
|
||||||
<< std::setiosflags(std::ios_base::fixed)
|
|
||||||
<< std::setprecision(2) << std::setw(6) << sys_busy;
|
|
||||||
EXPECT_GE(sys_busy, 0.f);
|
|
||||||
EXPECT_LE(sys_busy, static_cast<float>(cpus));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test4: CpuSampler with 2 cpus process busy.
|
|
||||||
if (cpus >= 2) {
|
|
||||||
Thread::SleepMs(kSettleTime);
|
|
||||||
sampler.GetProcessLoad();
|
|
||||||
sampler.GetSystemLoad();
|
|
||||||
|
|
||||||
CpuTwoBusyLoop(kBusyTime);
|
|
||||||
|
|
||||||
float proc_twobusy = 0.f, sys_twobusy = 0.f;
|
|
||||||
if (test_proc) {
|
|
||||||
proc_twobusy = sampler.GetProcessLoad();
|
|
||||||
}
|
|
||||||
if (test_sys) {
|
|
||||||
sys_twobusy = sampler.GetSystemLoad();
|
|
||||||
}
|
|
||||||
if (test_proc) {
|
|
||||||
LOG(LS_INFO) << "ProcessLoad 2 CPU Busy:"
|
|
||||||
<< std::setiosflags(std::ios_base::fixed)
|
|
||||||
<< std::setprecision(2) << std::setw(6) << proc_twobusy;
|
|
||||||
EXPECT_GE(proc_twobusy, 0.f);
|
|
||||||
EXPECT_LE(proc_twobusy, static_cast<float>(cpus));
|
|
||||||
}
|
|
||||||
if (test_sys) {
|
|
||||||
LOG(LS_INFO) << "SystemLoad 2 CPU Busy: "
|
|
||||||
<< std::setiosflags(std::ios_base::fixed)
|
|
||||||
<< std::setprecision(2) << std::setw(6) << sys_twobusy;
|
|
||||||
EXPECT_GE(sys_twobusy, 0.f);
|
|
||||||
EXPECT_LE(sys_twobusy, static_cast<float>(cpus));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test5: CpuSampler with idle process after being busy.
|
|
||||||
Thread::SleepMs(kSettleTime);
|
|
||||||
sampler.GetProcessLoad();
|
|
||||||
sampler.GetSystemLoad();
|
|
||||||
|
|
||||||
Thread::SleepMs(kIdleTime);
|
|
||||||
|
|
||||||
if (test_proc) {
|
|
||||||
proc_idle = sampler.GetProcessLoad();
|
|
||||||
}
|
|
||||||
if (test_sys) {
|
|
||||||
sys_idle = sampler.GetSystemLoad();
|
|
||||||
}
|
|
||||||
if (test_proc) {
|
|
||||||
LOG(LS_INFO) << "ProcessLoad Idle: "
|
|
||||||
<< std::setiosflags(std::ios_base::fixed)
|
|
||||||
<< std::setprecision(2) << std::setw(6) << proc_idle;
|
|
||||||
EXPECT_GE(proc_idle, 0.f);
|
|
||||||
EXPECT_LE(proc_idle, proc_busy);
|
|
||||||
}
|
|
||||||
if (test_sys) {
|
|
||||||
LOG(LS_INFO) << "SystemLoad Idle: "
|
|
||||||
<< std::setiosflags(std::ios_base::fixed)
|
|
||||||
<< std::setprecision(2) << std::setw(6) << sys_idle;
|
|
||||||
EXPECT_GE(sys_idle, 0.f);
|
|
||||||
EXPECT_LE(sys_idle, static_cast<float>(cpus));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CpuMonitorTest, TestCpus) {
|
|
||||||
CpuSampler sampler;
|
|
||||||
EXPECT_TRUE(sampler.Init());
|
|
||||||
int current_cpus = sampler.GetCurrentCpus();
|
|
||||||
int cpus = sampler.GetMaxCpus();
|
|
||||||
LOG(LS_INFO) << "Current Cpus: " << std::setw(9) << current_cpus;
|
|
||||||
LOG(LS_INFO) << "Maximum Cpus: " << std::setw(9) << cpus;
|
|
||||||
EXPECT_GT(cpus, 0);
|
|
||||||
EXPECT_LE(cpus, kMaxCpus);
|
|
||||||
EXPECT_GT(current_cpus, 0);
|
|
||||||
EXPECT_LE(current_cpus, cpus);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
// Tests overall system CpuSampler using legacy OS fallback code if applicable.
|
|
||||||
TEST(CpuMonitorTest, TestGetSystemLoadForceFallback) {
|
|
||||||
TestCpuSampler(false, true, true);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Tests both process and system functions in use at same time.
|
|
||||||
TEST(CpuMonitorTest, TestGetBothLoad) {
|
|
||||||
TestCpuSampler(true, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests a query less than the interval produces the same value.
|
|
||||||
TEST(CpuMonitorTest, TestInterval) {
|
|
||||||
CpuSampler sampler;
|
|
||||||
EXPECT_TRUE(sampler.Init());
|
|
||||||
|
|
||||||
// Test1: Set interval to large value so sampler will not update.
|
|
||||||
sampler.set_load_interval(kLongInterval);
|
|
||||||
|
|
||||||
sampler.GetProcessLoad();
|
|
||||||
sampler.GetSystemLoad();
|
|
||||||
|
|
||||||
float proc_orig = sampler.GetProcessLoad();
|
|
||||||
float sys_orig = sampler.GetSystemLoad();
|
|
||||||
|
|
||||||
Thread::SleepMs(kIdleTime);
|
|
||||||
|
|
||||||
float proc_halftime = sampler.GetProcessLoad();
|
|
||||||
float sys_halftime = sampler.GetSystemLoad();
|
|
||||||
|
|
||||||
EXPECT_EQ(proc_orig, proc_halftime);
|
|
||||||
EXPECT_EQ(sys_orig, sys_halftime);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(CpuMonitorTest, TestCpuMonitor) {
|
|
||||||
CpuMonitor monitor(Thread::Current());
|
|
||||||
CpuLoadListener listener;
|
|
||||||
monitor.SignalUpdate.connect(&listener, &CpuLoadListener::OnCpuLoad);
|
|
||||||
EXPECT_TRUE(monitor.Start(10));
|
|
||||||
// We have checked cpu load more than twice.
|
|
||||||
EXPECT_TRUE_WAIT(listener.count() > 2, 1000);
|
|
||||||
EXPECT_GT(listener.current_cpus(), 0);
|
|
||||||
EXPECT_GT(listener.cpus(), 0);
|
|
||||||
EXPECT_GE(listener.process_load(), .0f);
|
|
||||||
EXPECT_GE(listener.system_load(), .0f);
|
|
||||||
|
|
||||||
monitor.Stop();
|
|
||||||
// Wait 20 ms to ake sure all signals are delivered.
|
|
||||||
Thread::Current()->ProcessMessages(20);
|
|
||||||
int old_count = listener.count();
|
|
||||||
Thread::Current()->ProcessMessages(20);
|
|
||||||
// Verfy no more siganls.
|
|
||||||
EXPECT_EQ(old_count, listener.count());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 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 "webrtc/base/crc32.h"
|
|
||||||
|
|
||||||
#include "webrtc/base/basicdefs.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// This implementation is based on the sample implementation in RFC 1952.
|
|
||||||
|
|
||||||
// CRC32 polynomial, in reversed form.
|
|
||||||
// See RFC 1952, or http://en.wikipedia.org/wiki/Cyclic_redundancy_check
|
|
||||||
static const uint32 kCrc32Polynomial = 0xEDB88320;
|
|
||||||
static uint32 kCrc32Table[256] = { 0 };
|
|
||||||
|
|
||||||
static void EnsureCrc32TableInited() {
|
|
||||||
if (kCrc32Table[ARRAY_SIZE(kCrc32Table) - 1])
|
|
||||||
return; // already inited
|
|
||||||
for (uint32 i = 0; i < ARRAY_SIZE(kCrc32Table); ++i) {
|
|
||||||
uint32 c = i;
|
|
||||||
for (size_t j = 0; j < 8; ++j) {
|
|
||||||
if (c & 1) {
|
|
||||||
c = kCrc32Polynomial ^ (c >> 1);
|
|
||||||
} else {
|
|
||||||
c >>= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kCrc32Table[i] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 UpdateCrc32(uint32 start, const void* buf, size_t len) {
|
|
||||||
EnsureCrc32TableInited();
|
|
||||||
|
|
||||||
uint32 c = start ^ 0xFFFFFFFF;
|
|
||||||
const uint8* u = static_cast<const uint8*>(buf);
|
|
||||||
for (size_t i = 0; i < len; ++i) {
|
|
||||||
c = kCrc32Table[(c ^ u[i]) & 0xFF] ^ (c >> 8);
|
|
||||||
}
|
|
||||||
return c ^ 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_CRC32_H_
|
|
||||||
#define WEBRTC_BASE_CRC32_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Updates a CRC32 checksum with |len| bytes from |buf|. |initial| holds the
|
|
||||||
// checksum result from the previous update; for the first call, it should be 0.
|
|
||||||
uint32 UpdateCrc32(uint32 initial, const void* buf, size_t len);
|
|
||||||
|
|
||||||
// Computes a CRC32 checksum using |len| bytes from |buf|.
|
|
||||||
inline uint32 ComputeCrc32(const void* buf, size_t len) {
|
|
||||||
return UpdateCrc32(0, buf, len);
|
|
||||||
}
|
|
||||||
inline uint32 ComputeCrc32(const std::string& str) {
|
|
||||||
return ComputeCrc32(str.c_str(), str.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_CRC32_H_
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 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 "webrtc/base/crc32.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
TEST(Crc32Test, TestBasic) {
|
|
||||||
EXPECT_EQ(0U, ComputeCrc32(""));
|
|
||||||
EXPECT_EQ(0x352441C2U, ComputeCrc32("abc"));
|
|
||||||
EXPECT_EQ(0x171A3F5FU,
|
|
||||||
ComputeCrc32("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(Crc32Test, TestMultipleUpdates) {
|
|
||||||
std::string input =
|
|
||||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
|
|
||||||
uint32 c = 0;
|
|
||||||
for (size_t i = 0; i < input.size(); ++i) {
|
|
||||||
c = UpdateCrc32(c, &input[i], 1);
|
|
||||||
}
|
|
||||||
EXPECT_EQ(0x171A3F5FU, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,179 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_CRITICALSECTION_H__
|
|
||||||
#define WEBRTC_BASE_CRITICALSECTION_H__
|
|
||||||
|
|
||||||
#include "webrtc/base/constructormagic.h"
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#include "webrtc/base/win32.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(WEBRTC_POSIX)
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
#define CS_TRACK_OWNER 1
|
|
||||||
#endif // _DEBUG
|
|
||||||
|
|
||||||
#if CS_TRACK_OWNER
|
|
||||||
#define TRACK_OWNER(x) x
|
|
||||||
#else // !CS_TRACK_OWNER
|
|
||||||
#define TRACK_OWNER(x)
|
|
||||||
#endif // !CS_TRACK_OWNER
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
class CriticalSection {
|
|
||||||
public:
|
|
||||||
CriticalSection() {
|
|
||||||
InitializeCriticalSection(&crit_);
|
|
||||||
// Windows docs say 0 is not a valid thread id
|
|
||||||
TRACK_OWNER(thread_ = 0);
|
|
||||||
}
|
|
||||||
~CriticalSection() {
|
|
||||||
DeleteCriticalSection(&crit_);
|
|
||||||
}
|
|
||||||
void Enter() {
|
|
||||||
EnterCriticalSection(&crit_);
|
|
||||||
TRACK_OWNER(thread_ = GetCurrentThreadId());
|
|
||||||
}
|
|
||||||
bool TryEnter() {
|
|
||||||
if (TryEnterCriticalSection(&crit_) != FALSE) {
|
|
||||||
TRACK_OWNER(thread_ = GetCurrentThreadId());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void Leave() {
|
|
||||||
TRACK_OWNER(thread_ = 0);
|
|
||||||
LeaveCriticalSection(&crit_);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CS_TRACK_OWNER
|
|
||||||
bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); }
|
|
||||||
#endif // CS_TRACK_OWNER
|
|
||||||
|
|
||||||
private:
|
|
||||||
CRITICAL_SECTION crit_;
|
|
||||||
TRACK_OWNER(DWORD thread_); // The section's owning thread id
|
|
||||||
};
|
|
||||||
#endif // WEBRTC_WIN
|
|
||||||
|
|
||||||
#if defined(WEBRTC_POSIX)
|
|
||||||
class CriticalSection {
|
|
||||||
public:
|
|
||||||
CriticalSection() {
|
|
||||||
pthread_mutexattr_t mutex_attribute;
|
|
||||||
pthread_mutexattr_init(&mutex_attribute);
|
|
||||||
pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
|
|
||||||
pthread_mutex_init(&mutex_, &mutex_attribute);
|
|
||||||
pthread_mutexattr_destroy(&mutex_attribute);
|
|
||||||
TRACK_OWNER(thread_ = 0);
|
|
||||||
}
|
|
||||||
~CriticalSection() {
|
|
||||||
pthread_mutex_destroy(&mutex_);
|
|
||||||
}
|
|
||||||
void Enter() {
|
|
||||||
pthread_mutex_lock(&mutex_);
|
|
||||||
TRACK_OWNER(thread_ = pthread_self());
|
|
||||||
}
|
|
||||||
bool TryEnter() {
|
|
||||||
if (pthread_mutex_trylock(&mutex_) == 0) {
|
|
||||||
TRACK_OWNER(thread_ = pthread_self());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void Leave() {
|
|
||||||
TRACK_OWNER(thread_ = 0);
|
|
||||||
pthread_mutex_unlock(&mutex_);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CS_TRACK_OWNER
|
|
||||||
bool CurrentThreadIsOwner() const { return pthread_equal(thread_, pthread_self()); }
|
|
||||||
#endif // CS_TRACK_OWNER
|
|
||||||
|
|
||||||
private:
|
|
||||||
pthread_mutex_t mutex_;
|
|
||||||
TRACK_OWNER(pthread_t thread_);
|
|
||||||
};
|
|
||||||
#endif // WEBRTC_POSIX
|
|
||||||
|
|
||||||
// CritScope, for serializing execution through a scope.
|
|
||||||
class CritScope {
|
|
||||||
public:
|
|
||||||
explicit CritScope(CriticalSection *pcrit) {
|
|
||||||
pcrit_ = pcrit;
|
|
||||||
pcrit_->Enter();
|
|
||||||
}
|
|
||||||
~CritScope() {
|
|
||||||
pcrit_->Leave();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
CriticalSection *pcrit_;
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(CritScope);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Tries to lock a critical section on construction via
|
|
||||||
// CriticalSection::TryEnter, and unlocks on destruction if the
|
|
||||||
// lock was taken. Never blocks.
|
|
||||||
//
|
|
||||||
// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
|
|
||||||
// subsequent code. Users *must* check locked() to determine if the
|
|
||||||
// lock was taken. If you're not calling locked(), you're doing it wrong!
|
|
||||||
class TryCritScope {
|
|
||||||
public:
|
|
||||||
explicit TryCritScope(CriticalSection *pcrit) {
|
|
||||||
pcrit_ = pcrit;
|
|
||||||
locked_ = pcrit_->TryEnter();
|
|
||||||
}
|
|
||||||
~TryCritScope() {
|
|
||||||
if (locked_) {
|
|
||||||
pcrit_->Leave();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool locked() const {
|
|
||||||
return locked_;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
CriticalSection *pcrit_;
|
|
||||||
bool locked_;
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(TryCritScope);
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Move this to atomicops.h, which can't be done easily because of
|
|
||||||
// complex compile rules.
|
|
||||||
class AtomicOps {
|
|
||||||
public:
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
// Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
|
|
||||||
static int Increment(int* i) {
|
|
||||||
return ::InterlockedIncrement(reinterpret_cast<LONG*>(i));
|
|
||||||
}
|
|
||||||
static int Decrement(int* i) {
|
|
||||||
return ::InterlockedDecrement(reinterpret_cast<LONG*>(i));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static int Increment(int* i) {
|
|
||||||
return __sync_add_and_fetch(i, 1);
|
|
||||||
}
|
|
||||||
static int Decrement(int* i) {
|
|
||||||
return __sync_sub_and_fetch(i, 1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_CRITICALSECTION_H__
|
|
@ -1,146 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 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 <set>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "webrtc/base/criticalsection.h"
|
|
||||||
#include "webrtc/base/event.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/scopedptrcollection.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const int kLongTime = 10000; // 10 seconds
|
|
||||||
const int kNumThreads = 16;
|
|
||||||
const int kOperationsToRun = 1000;
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class AtomicOpRunner : public MessageHandler {
|
|
||||||
public:
|
|
||||||
explicit AtomicOpRunner(int initial_value)
|
|
||||||
: value_(initial_value),
|
|
||||||
threads_active_(0),
|
|
||||||
start_event_(true, false),
|
|
||||||
done_event_(true, false) {}
|
|
||||||
|
|
||||||
int value() const { return value_; }
|
|
||||||
|
|
||||||
bool Run() {
|
|
||||||
// Signal all threads to start.
|
|
||||||
start_event_.Set();
|
|
||||||
|
|
||||||
// Wait for all threads to finish.
|
|
||||||
return done_event_.Wait(kLongTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetExpectedThreadCount(int count) {
|
|
||||||
threads_active_ = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnMessage(Message* msg) {
|
|
||||||
std::vector<int> values;
|
|
||||||
values.reserve(kOperationsToRun);
|
|
||||||
|
|
||||||
// Wait to start.
|
|
||||||
ASSERT_TRUE(start_event_.Wait(kLongTime));
|
|
||||||
|
|
||||||
// Generate a bunch of values by updating value_ atomically.
|
|
||||||
for (int i = 0; i < kOperationsToRun; ++i) {
|
|
||||||
values.push_back(T::AtomicOp(&value_));
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Add them all to the set.
|
|
||||||
CritScope cs(&all_values_crit_);
|
|
||||||
for (size_t i = 0; i < values.size(); ++i) {
|
|
||||||
std::pair<std::set<int>::iterator, bool> result =
|
|
||||||
all_values_.insert(values[i]);
|
|
||||||
// Each value should only be taken by one thread, so if this value
|
|
||||||
// has already been added, something went wrong.
|
|
||||||
EXPECT_TRUE(result.second)
|
|
||||||
<< "Thread=" << Thread::Current() << " value=" << values[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal that we're done.
|
|
||||||
if (AtomicOps::Decrement(&threads_active_) == 0) {
|
|
||||||
done_event_.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int value_;
|
|
||||||
int threads_active_;
|
|
||||||
CriticalSection all_values_crit_;
|
|
||||||
std::set<int> all_values_;
|
|
||||||
Event start_event_;
|
|
||||||
Event done_event_;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IncrementOp {
|
|
||||||
static int AtomicOp(int* i) { return AtomicOps::Increment(i); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DecrementOp {
|
|
||||||
static int AtomicOp(int* i) { return AtomicOps::Decrement(i); }
|
|
||||||
};
|
|
||||||
|
|
||||||
void StartThreads(ScopedPtrCollection<Thread>* threads,
|
|
||||||
MessageHandler* handler) {
|
|
||||||
for (int i = 0; i < kNumThreads; ++i) {
|
|
||||||
Thread* thread = new Thread();
|
|
||||||
thread->Start();
|
|
||||||
thread->Post(handler);
|
|
||||||
threads->PushBack(thread);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
TEST(AtomicOpsTest, Simple) {
|
|
||||||
int value = 0;
|
|
||||||
EXPECT_EQ(1, AtomicOps::Increment(&value));
|
|
||||||
EXPECT_EQ(1, value);
|
|
||||||
EXPECT_EQ(2, AtomicOps::Increment(&value));
|
|
||||||
EXPECT_EQ(2, value);
|
|
||||||
EXPECT_EQ(1, AtomicOps::Decrement(&value));
|
|
||||||
EXPECT_EQ(1, value);
|
|
||||||
EXPECT_EQ(0, AtomicOps::Decrement(&value));
|
|
||||||
EXPECT_EQ(0, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(AtomicOpsTest, Increment) {
|
|
||||||
// Create and start lots of threads.
|
|
||||||
AtomicOpRunner<IncrementOp> runner(0);
|
|
||||||
ScopedPtrCollection<Thread> threads;
|
|
||||||
StartThreads(&threads, &runner);
|
|
||||||
runner.SetExpectedThreadCount(kNumThreads);
|
|
||||||
|
|
||||||
// Release the hounds!
|
|
||||||
EXPECT_TRUE(runner.Run());
|
|
||||||
EXPECT_EQ(kOperationsToRun * kNumThreads, runner.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(AtomicOpsTest, Decrement) {
|
|
||||||
// Create and start lots of threads.
|
|
||||||
AtomicOpRunner<DecrementOp> runner(kOperationsToRun * kNumThreads);
|
|
||||||
ScopedPtrCollection<Thread> threads;
|
|
||||||
StartThreads(&threads, &runner);
|
|
||||||
runner.SetExpectedThreadCount(kNumThreads);
|
|
||||||
|
|
||||||
// Release the hounds!
|
|
||||||
EXPECT_TRUE(runner.Run());
|
|
||||||
EXPECT_EQ(0, runner.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,183 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _WEBRTC_BASE_CRYPTSTRING_H_
|
|
||||||
#define _WEBRTC_BASE_CRYPTSTRING_H_
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "webrtc/base/linked_ptr.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class CryptStringImpl {
|
|
||||||
public:
|
|
||||||
virtual ~CryptStringImpl() {}
|
|
||||||
virtual size_t GetLength() const = 0;
|
|
||||||
virtual void CopyTo(char * dest, bool nullterminate) const = 0;
|
|
||||||
virtual std::string UrlEncode() const = 0;
|
|
||||||
virtual CryptStringImpl * Copy() const = 0;
|
|
||||||
virtual void CopyRawTo(std::vector<unsigned char> * dest) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EmptyCryptStringImpl : public CryptStringImpl {
|
|
||||||
public:
|
|
||||||
virtual ~EmptyCryptStringImpl() {}
|
|
||||||
virtual size_t GetLength() const { return 0; }
|
|
||||||
virtual void CopyTo(char * dest, bool nullterminate) const {
|
|
||||||
if (nullterminate) {
|
|
||||||
*dest = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual std::string UrlEncode() const { return ""; }
|
|
||||||
virtual CryptStringImpl * Copy() const { return new EmptyCryptStringImpl(); }
|
|
||||||
virtual void CopyRawTo(std::vector<unsigned char> * dest) const {
|
|
||||||
dest->clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CryptString {
|
|
||||||
public:
|
|
||||||
CryptString() : impl_(new EmptyCryptStringImpl()) {}
|
|
||||||
size_t GetLength() const { return impl_->GetLength(); }
|
|
||||||
void CopyTo(char * dest, bool nullterminate) const { impl_->CopyTo(dest, nullterminate); }
|
|
||||||
CryptString(const CryptString & other) : impl_(other.impl_->Copy()) {}
|
|
||||||
explicit CryptString(const CryptStringImpl & impl) : impl_(impl.Copy()) {}
|
|
||||||
CryptString & operator=(const CryptString & other) {
|
|
||||||
if (this != &other) {
|
|
||||||
impl_.reset(other.impl_->Copy());
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
void Clear() { impl_.reset(new EmptyCryptStringImpl()); }
|
|
||||||
std::string UrlEncode() const { return impl_->UrlEncode(); }
|
|
||||||
void CopyRawTo(std::vector<unsigned char> * dest) const {
|
|
||||||
return impl_->CopyRawTo(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
scoped_ptr<const CryptStringImpl> impl_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Used for constructing strings where a password is involved and we
|
|
||||||
// need to ensure that we zero memory afterwards
|
|
||||||
class FormatCryptString {
|
|
||||||
public:
|
|
||||||
FormatCryptString() {
|
|
||||||
storage_ = new char[32];
|
|
||||||
capacity_ = 32;
|
|
||||||
length_ = 0;
|
|
||||||
storage_[0] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Append(const std::string & text) {
|
|
||||||
Append(text.data(), text.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Append(const char * data, size_t length) {
|
|
||||||
EnsureStorage(length_ + length + 1);
|
|
||||||
memcpy(storage_ + length_, data, length);
|
|
||||||
length_ += length;
|
|
||||||
storage_[length_] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void Append(const CryptString * password) {
|
|
||||||
size_t len = password->GetLength();
|
|
||||||
EnsureStorage(length_ + len + 1);
|
|
||||||
password->CopyTo(storage_ + length_, true);
|
|
||||||
length_ += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t GetLength() {
|
|
||||||
return length_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * GetData() {
|
|
||||||
return storage_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Ensures storage of at least n bytes
|
|
||||||
void EnsureStorage(size_t n) {
|
|
||||||
if (capacity_ >= n) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t old_capacity = capacity_;
|
|
||||||
char * old_storage = storage_;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
capacity_ *= 2;
|
|
||||||
if (capacity_ >= n)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
storage_ = new char[capacity_];
|
|
||||||
|
|
||||||
if (old_capacity) {
|
|
||||||
memcpy(storage_, old_storage, length_);
|
|
||||||
|
|
||||||
// zero memory in a way that an optimizer won't optimize it out
|
|
||||||
old_storage[0] = 0;
|
|
||||||
for (size_t i = 1; i < old_capacity; i++) {
|
|
||||||
old_storage[i] = old_storage[i - 1];
|
|
||||||
}
|
|
||||||
delete[] old_storage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~FormatCryptString() {
|
|
||||||
if (capacity_) {
|
|
||||||
storage_[0] = 0;
|
|
||||||
for (size_t i = 1; i < capacity_; i++) {
|
|
||||||
storage_[i] = storage_[i - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete[] storage_;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
char * storage_;
|
|
||||||
size_t capacity_;
|
|
||||||
size_t length_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class InsecureCryptStringImpl : public CryptStringImpl {
|
|
||||||
public:
|
|
||||||
std::string& password() { return password_; }
|
|
||||||
const std::string& password() const { return password_; }
|
|
||||||
|
|
||||||
virtual ~InsecureCryptStringImpl() {}
|
|
||||||
virtual size_t GetLength() const { return password_.size(); }
|
|
||||||
virtual void CopyTo(char * dest, bool nullterminate) const {
|
|
||||||
memcpy(dest, password_.data(), password_.size());
|
|
||||||
if (nullterminate) dest[password_.size()] = 0;
|
|
||||||
}
|
|
||||||
virtual std::string UrlEncode() const { return password_; }
|
|
||||||
virtual CryptStringImpl * Copy() const {
|
|
||||||
InsecureCryptStringImpl * copy = new InsecureCryptStringImpl;
|
|
||||||
copy->password() = password_;
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
virtual void CopyRawTo(std::vector<unsigned char> * dest) const {
|
|
||||||
dest->resize(password_.size());
|
|
||||||
memcpy(&dest->front(), password_.data(), password_.size());
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
std::string password_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _WEBRTC_BASE_CRYPTSTRING_H_
|
|
@ -1,396 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_DBUS_GLIB
|
|
||||||
|
|
||||||
#include "webrtc/base/dbus.h"
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Avoid static object construction/destruction on startup/shutdown.
|
|
||||||
static pthread_once_t g_dbus_init_once = PTHREAD_ONCE_INIT;
|
|
||||||
static LibDBusGlibSymbolTable *g_dbus_symbol = NULL;
|
|
||||||
|
|
||||||
// Releases DBus-Glib symbols.
|
|
||||||
static void ReleaseDBusGlibSymbol() {
|
|
||||||
if (g_dbus_symbol != NULL) {
|
|
||||||
delete g_dbus_symbol;
|
|
||||||
g_dbus_symbol = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loads DBus-Glib symbols.
|
|
||||||
static void InitializeDBusGlibSymbol() {
|
|
||||||
// This is thread safe.
|
|
||||||
if (NULL == g_dbus_symbol) {
|
|
||||||
g_dbus_symbol = new LibDBusGlibSymbolTable();
|
|
||||||
|
|
||||||
// Loads dbus-glib
|
|
||||||
if (NULL == g_dbus_symbol || !g_dbus_symbol->Load()) {
|
|
||||||
LOG(LS_WARNING) << "Failed to load dbus-glib symbol table.";
|
|
||||||
ReleaseDBusGlibSymbol();
|
|
||||||
} else {
|
|
||||||
// Nothing we can do if atexit() failed. Just ignore its returned value.
|
|
||||||
atexit(ReleaseDBusGlibSymbol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static LibDBusGlibSymbolTable *GetSymbols() {
|
|
||||||
return DBusMonitor::GetDBusGlibSymbolTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementation of class DBusSigMessageData
|
|
||||||
DBusSigMessageData::DBusSigMessageData(DBusMessage *message)
|
|
||||||
: TypedMessageData<DBusMessage *>(message) {
|
|
||||||
GetSymbols()->dbus_message_ref()(data());
|
|
||||||
}
|
|
||||||
|
|
||||||
DBusSigMessageData::~DBusSigMessageData() {
|
|
||||||
GetSymbols()->dbus_message_unref()(data());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementation of class DBusSigFilter
|
|
||||||
|
|
||||||
// Builds a DBus filter string from given DBus path, interface and member.
|
|
||||||
std::string DBusSigFilter::BuildFilterString(const std::string &path,
|
|
||||||
const std::string &interface,
|
|
||||||
const std::string &member) {
|
|
||||||
std::string ret(DBUS_TYPE "='" DBUS_SIGNAL "'");
|
|
||||||
if (!path.empty()) {
|
|
||||||
ret += ("," DBUS_PATH "='");
|
|
||||||
ret += path;
|
|
||||||
ret += "'";
|
|
||||||
}
|
|
||||||
if (!interface.empty()) {
|
|
||||||
ret += ("," DBUS_INTERFACE "='");
|
|
||||||
ret += interface;
|
|
||||||
ret += "'";
|
|
||||||
}
|
|
||||||
if (!member.empty()) {
|
|
||||||
ret += ("," DBUS_MEMBER "='");
|
|
||||||
ret += member;
|
|
||||||
ret += "'";
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forwards the message to the given instance.
|
|
||||||
DBusHandlerResult DBusSigFilter::DBusCallback(DBusConnection *dbus_conn,
|
|
||||||
DBusMessage *message,
|
|
||||||
void *instance) {
|
|
||||||
ASSERT(instance);
|
|
||||||
if (instance) {
|
|
||||||
return static_cast<DBusSigFilter *>(instance)->Callback(message);
|
|
||||||
}
|
|
||||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Posts a message to caller thread.
|
|
||||||
DBusHandlerResult DBusSigFilter::Callback(DBusMessage *message) {
|
|
||||||
if (caller_thread_) {
|
|
||||||
caller_thread_->Post(this, DSM_SIGNAL, new DBusSigMessageData(message));
|
|
||||||
}
|
|
||||||
// Don't "eat" the message here. Let it pop up.
|
|
||||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// From MessageHandler.
|
|
||||||
void DBusSigFilter::OnMessage(Message *message) {
|
|
||||||
if (message != NULL && DSM_SIGNAL == message->message_id) {
|
|
||||||
DBusSigMessageData *msg =
|
|
||||||
static_cast<DBusSigMessageData *>(message->pdata);
|
|
||||||
if (msg) {
|
|
||||||
ProcessSignal(msg->data());
|
|
||||||
delete msg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Definition of private class DBusMonitoringThread.
|
|
||||||
// It creates a worker-thread to listen signals on DBus. The worker-thread will
|
|
||||||
// be running in a priate GMainLoop forever until either Stop() has been invoked
|
|
||||||
// or it hits an error.
|
|
||||||
class DBusMonitor::DBusMonitoringThread : public rtc::Thread {
|
|
||||||
public:
|
|
||||||
explicit DBusMonitoringThread(DBusMonitor *monitor,
|
|
||||||
GMainContext *context,
|
|
||||||
GMainLoop *mainloop,
|
|
||||||
std::vector<DBusSigFilter *> *filter_list)
|
|
||||||
: monitor_(monitor),
|
|
||||||
context_(context),
|
|
||||||
mainloop_(mainloop),
|
|
||||||
connection_(NULL),
|
|
||||||
idle_source_(NULL),
|
|
||||||
filter_list_(filter_list) {
|
|
||||||
ASSERT(monitor_);
|
|
||||||
ASSERT(context_);
|
|
||||||
ASSERT(mainloop_);
|
|
||||||
ASSERT(filter_list_);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~DBusMonitoringThread() {
|
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override virtual method of Thread. Context: worker-thread.
|
|
||||||
virtual void Run() {
|
|
||||||
ASSERT(NULL == connection_);
|
|
||||||
|
|
||||||
// Setup DBus connection and start monitoring.
|
|
||||||
monitor_->OnMonitoringStatusChanged(DMS_INITIALIZING);
|
|
||||||
if (!Setup()) {
|
|
||||||
LOG(LS_ERROR) << "DBus monitoring setup failed.";
|
|
||||||
monitor_->OnMonitoringStatusChanged(DMS_FAILED);
|
|
||||||
CleanUp();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
monitor_->OnMonitoringStatusChanged(DMS_RUNNING);
|
|
||||||
g_main_loop_run(mainloop_);
|
|
||||||
monitor_->OnMonitoringStatusChanged(DMS_STOPPED);
|
|
||||||
|
|
||||||
// Done normally. Clean up DBus connection.
|
|
||||||
CleanUp();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override virtual method of Thread. Context: caller-thread.
|
|
||||||
virtual void Stop() {
|
|
||||||
ASSERT(NULL == idle_source_);
|
|
||||||
// Add an idle source and let the gmainloop quit on idle.
|
|
||||||
idle_source_ = g_idle_source_new();
|
|
||||||
if (idle_source_) {
|
|
||||||
g_source_set_callback(idle_source_, &Idle, this, NULL);
|
|
||||||
g_source_attach(idle_source_, context_);
|
|
||||||
} else {
|
|
||||||
LOG(LS_ERROR) << "g_idle_source_new() failed.";
|
|
||||||
QuitGMainloop(); // Try to quit anyway.
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread::Stop(); // Wait for the thread.
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Registers all DBus filters.
|
|
||||||
void RegisterAllFilters() {
|
|
||||||
ASSERT(NULL != GetSymbols()->dbus_g_connection_get_connection()(
|
|
||||||
connection_));
|
|
||||||
|
|
||||||
for (std::vector<DBusSigFilter *>::iterator it = filter_list_->begin();
|
|
||||||
it != filter_list_->end(); ++it) {
|
|
||||||
DBusSigFilter *filter = (*it);
|
|
||||||
if (!filter) {
|
|
||||||
LOG(LS_ERROR) << "DBusSigFilter list corrupted.";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetSymbols()->dbus_bus_add_match()(
|
|
||||||
GetSymbols()->dbus_g_connection_get_connection()(connection_),
|
|
||||||
filter->filter().c_str(), NULL);
|
|
||||||
|
|
||||||
if (!GetSymbols()->dbus_connection_add_filter()(
|
|
||||||
GetSymbols()->dbus_g_connection_get_connection()(connection_),
|
|
||||||
&DBusSigFilter::DBusCallback, filter, NULL)) {
|
|
||||||
LOG(LS_ERROR) << "dbus_connection_add_filter() failed."
|
|
||||||
<< "Filter: " << filter->filter();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unregisters all DBus filters.
|
|
||||||
void UnRegisterAllFilters() {
|
|
||||||
ASSERT(NULL != GetSymbols()->dbus_g_connection_get_connection()(
|
|
||||||
connection_));
|
|
||||||
|
|
||||||
for (std::vector<DBusSigFilter *>::iterator it = filter_list_->begin();
|
|
||||||
it != filter_list_->end(); ++it) {
|
|
||||||
DBusSigFilter *filter = (*it);
|
|
||||||
if (!filter) {
|
|
||||||
LOG(LS_ERROR) << "DBusSigFilter list corrupted.";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
GetSymbols()->dbus_connection_remove_filter()(
|
|
||||||
GetSymbols()->dbus_g_connection_get_connection()(connection_),
|
|
||||||
&DBusSigFilter::DBusCallback, filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets up the monitoring thread.
|
|
||||||
bool Setup() {
|
|
||||||
g_main_context_push_thread_default(context_);
|
|
||||||
|
|
||||||
// Start connection to dbus.
|
|
||||||
// If dbus daemon is not running, returns false immediately.
|
|
||||||
connection_ = GetSymbols()->dbus_g_bus_get_private()(monitor_->type_,
|
|
||||||
context_, NULL);
|
|
||||||
if (NULL == connection_) {
|
|
||||||
LOG(LS_ERROR) << "dbus_g_bus_get_private() unable to get connection.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (NULL == GetSymbols()->dbus_g_connection_get_connection()(connection_)) {
|
|
||||||
LOG(LS_ERROR) << "dbus_g_connection_get_connection() returns NULL. "
|
|
||||||
<< "DBus daemon is probably not running.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Application don't exit if DBus daemon die.
|
|
||||||
GetSymbols()->dbus_connection_set_exit_on_disconnect()(
|
|
||||||
GetSymbols()->dbus_g_connection_get_connection()(connection_), FALSE);
|
|
||||||
|
|
||||||
// Connect all filters.
|
|
||||||
RegisterAllFilters();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleans up the monitoring thread.
|
|
||||||
void CleanUp() {
|
|
||||||
if (idle_source_) {
|
|
||||||
// We did an attach() with the GSource, so we need to destroy() it.
|
|
||||||
g_source_destroy(idle_source_);
|
|
||||||
// We need to unref() the GSource to end the last reference we got.
|
|
||||||
g_source_unref(idle_source_);
|
|
||||||
idle_source_ = NULL;
|
|
||||||
}
|
|
||||||
if (connection_) {
|
|
||||||
if (GetSymbols()->dbus_g_connection_get_connection()(connection_)) {
|
|
||||||
UnRegisterAllFilters();
|
|
||||||
GetSymbols()->dbus_connection_close()(
|
|
||||||
GetSymbols()->dbus_g_connection_get_connection()(connection_));
|
|
||||||
}
|
|
||||||
GetSymbols()->dbus_g_connection_unref()(connection_);
|
|
||||||
connection_ = NULL;
|
|
||||||
}
|
|
||||||
g_main_loop_unref(mainloop_);
|
|
||||||
mainloop_ = NULL;
|
|
||||||
g_main_context_unref(context_);
|
|
||||||
context_ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handles callback on Idle. We only add this source when ready to stop.
|
|
||||||
static gboolean Idle(gpointer data) {
|
|
||||||
static_cast<DBusMonitoringThread *>(data)->QuitGMainloop();
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only hit this when ready to quit.
|
|
||||||
void QuitGMainloop() {
|
|
||||||
g_main_loop_quit(mainloop_);
|
|
||||||
}
|
|
||||||
|
|
||||||
DBusMonitor *monitor_;
|
|
||||||
|
|
||||||
GMainContext *context_;
|
|
||||||
GMainLoop *mainloop_;
|
|
||||||
DBusGConnection *connection_;
|
|
||||||
GSource *idle_source_;
|
|
||||||
|
|
||||||
std::vector<DBusSigFilter *> *filter_list_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Implementation of class DBusMonitor
|
|
||||||
|
|
||||||
// Returns DBus-Glib symbol handle. Initialize it first if hasn't.
|
|
||||||
LibDBusGlibSymbolTable *DBusMonitor::GetDBusGlibSymbolTable() {
|
|
||||||
// This is multi-thread safe.
|
|
||||||
pthread_once(&g_dbus_init_once, InitializeDBusGlibSymbol);
|
|
||||||
|
|
||||||
return g_dbus_symbol;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Creates an instance of DBusMonitor
|
|
||||||
DBusMonitor *DBusMonitor::Create(DBusBusType type) {
|
|
||||||
if (NULL == DBusMonitor::GetDBusGlibSymbolTable()) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return new DBusMonitor(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
DBusMonitor::DBusMonitor(DBusBusType type)
|
|
||||||
: type_(type),
|
|
||||||
status_(DMS_NOT_INITIALIZED),
|
|
||||||
monitoring_thread_(NULL) {
|
|
||||||
ASSERT(type_ == DBUS_BUS_SYSTEM || type_ == DBUS_BUS_SESSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
DBusMonitor::~DBusMonitor() {
|
|
||||||
StopMonitoring();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DBusMonitor::AddFilter(DBusSigFilter *filter) {
|
|
||||||
if (monitoring_thread_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!filter) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
filter_list_.push_back(filter);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DBusMonitor::StartMonitoring() {
|
|
||||||
if (!monitoring_thread_) {
|
|
||||||
g_type_init();
|
|
||||||
g_thread_init(NULL);
|
|
||||||
GetSymbols()->dbus_g_thread_init()();
|
|
||||||
|
|
||||||
GMainContext *context = g_main_context_new();
|
|
||||||
if (NULL == context) {
|
|
||||||
LOG(LS_ERROR) << "g_main_context_new() failed.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GMainLoop *mainloop = g_main_loop_new(context, FALSE);
|
|
||||||
if (NULL == mainloop) {
|
|
||||||
LOG(LS_ERROR) << "g_main_loop_new() failed.";
|
|
||||||
g_main_context_unref(context);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
monitoring_thread_ = new DBusMonitoringThread(this, context, mainloop,
|
|
||||||
&filter_list_);
|
|
||||||
if (monitoring_thread_ == NULL) {
|
|
||||||
LOG(LS_ERROR) << "Failed to create DBus monitoring thread.";
|
|
||||||
g_main_context_unref(context);
|
|
||||||
g_main_loop_unref(mainloop);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
monitoring_thread_->Start();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DBusMonitor::StopMonitoring() {
|
|
||||||
if (monitoring_thread_) {
|
|
||||||
monitoring_thread_->Stop();
|
|
||||||
monitoring_thread_ = NULL;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBusMonitor::DBusMonitorStatus DBusMonitor::GetStatus() {
|
|
||||||
return status_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DBusMonitor::OnMonitoringStatusChanged(DBusMonitorStatus status) {
|
|
||||||
status_ = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef LATE
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // HAVE_DBUS_GLIB
|
|
@ -1,168 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_DBUS_H_
|
|
||||||
#define WEBRTC_BASE_DBUS_H_
|
|
||||||
|
|
||||||
#ifdef HAVE_DBUS_GLIB
|
|
||||||
|
|
||||||
#include <dbus/dbus.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "webrtc/base/libdbusglibsymboltable.h"
|
|
||||||
#include "webrtc/base/messagehandler.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
#define DBUS_TYPE "type"
|
|
||||||
#define DBUS_SIGNAL "signal"
|
|
||||||
#define DBUS_PATH "path"
|
|
||||||
#define DBUS_INTERFACE "interface"
|
|
||||||
#define DBUS_MEMBER "member"
|
|
||||||
|
|
||||||
#ifdef CHROMEOS
|
|
||||||
#define CROS_PM_PATH "/"
|
|
||||||
#define CROS_PM_INTERFACE "org.chromium.PowerManager"
|
|
||||||
#define CROS_SIG_POWERCHANGED "PowerStateChanged"
|
|
||||||
#define CROS_VALUE_SLEEP "mem"
|
|
||||||
#define CROS_VALUE_RESUME "on"
|
|
||||||
#else
|
|
||||||
#define UP_PATH "/org/freedesktop/UPower"
|
|
||||||
#define UP_INTERFACE "org.freedesktop.UPower"
|
|
||||||
#define UP_SIG_SLEEPING "Sleeping"
|
|
||||||
#define UP_SIG_RESUMING "Resuming"
|
|
||||||
#endif // CHROMEOS
|
|
||||||
|
|
||||||
// Wraps a DBus messages.
|
|
||||||
class DBusSigMessageData : public TypedMessageData<DBusMessage *> {
|
|
||||||
public:
|
|
||||||
explicit DBusSigMessageData(DBusMessage *message);
|
|
||||||
~DBusSigMessageData();
|
|
||||||
};
|
|
||||||
|
|
||||||
// DBusSigFilter is an abstract class that defines the interface of DBus
|
|
||||||
// signal handling.
|
|
||||||
// The subclasses implement ProcessSignal() for various purposes.
|
|
||||||
// When a DBus signal comes, a DSM_SIGNAL message is posted to the caller thread
|
|
||||||
// which will then invokes ProcessSignal().
|
|
||||||
class DBusSigFilter : protected MessageHandler {
|
|
||||||
public:
|
|
||||||
enum DBusSigMessage { DSM_SIGNAL };
|
|
||||||
|
|
||||||
// This filter string should ususally come from BuildFilterString()
|
|
||||||
explicit DBusSigFilter(const std::string &filter)
|
|
||||||
: caller_thread_(Thread::Current()), filter_(filter) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Builds a DBus monitor filter string from given DBus path, interface, and
|
|
||||||
// member.
|
|
||||||
// See http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
|
|
||||||
static std::string BuildFilterString(const std::string &path,
|
|
||||||
const std::string &interface,
|
|
||||||
const std::string &member);
|
|
||||||
|
|
||||||
// Handles callback on DBus messages by DBus system.
|
|
||||||
static DBusHandlerResult DBusCallback(DBusConnection *dbus_conn,
|
|
||||||
DBusMessage *message,
|
|
||||||
void *instance);
|
|
||||||
|
|
||||||
// Handles callback on DBus messages to each DBusSigFilter instance.
|
|
||||||
DBusHandlerResult Callback(DBusMessage *message);
|
|
||||||
|
|
||||||
// From MessageHandler.
|
|
||||||
virtual void OnMessage(Message *message);
|
|
||||||
|
|
||||||
// Returns the DBus monitor filter string.
|
|
||||||
const std::string &filter() const { return filter_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
// On caller thread.
|
|
||||||
virtual void ProcessSignal(DBusMessage *message) = 0;
|
|
||||||
|
|
||||||
Thread *caller_thread_;
|
|
||||||
const std::string filter_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// DBusMonitor is a class for DBus signal monitoring.
|
|
||||||
//
|
|
||||||
// The caller-thread calls AddFilter() first to add the signals that it wants to
|
|
||||||
// monitor and then calls StartMonitoring() to start the monitoring.
|
|
||||||
// This will create a worker-thread which listens on DBus connection and sends
|
|
||||||
// DBus signals back through the callback.
|
|
||||||
// The worker-thread will be running forever until either StopMonitoring() is
|
|
||||||
// called from the caller-thread or the worker-thread hit some error.
|
|
||||||
//
|
|
||||||
// Programming model:
|
|
||||||
// 1. Caller-thread: Creates an object of DBusMonitor.
|
|
||||||
// 2. Caller-thread: Calls DBusMonitor::AddFilter() one or several times.
|
|
||||||
// 3. Caller-thread: StartMonitoring().
|
|
||||||
// ...
|
|
||||||
// 4. Worker-thread: DBus signal recieved. Post a message to caller-thread.
|
|
||||||
// 5. Caller-thread: DBusFilterBase::ProcessSignal() is invoked.
|
|
||||||
// ...
|
|
||||||
// 6. Caller-thread: StopMonitoring().
|
|
||||||
//
|
|
||||||
// Assumption:
|
|
||||||
// AddFilter(), StartMonitoring(), and StopMonitoring() methods are called by
|
|
||||||
// a single thread. Hence, there is no need to make them thread safe.
|
|
||||||
class DBusMonitor {
|
|
||||||
public:
|
|
||||||
// Status of DBus monitoring.
|
|
||||||
enum DBusMonitorStatus {
|
|
||||||
DMS_NOT_INITIALIZED, // Not initialized.
|
|
||||||
DMS_INITIALIZING, // Initializing the monitoring thread.
|
|
||||||
DMS_RUNNING, // Monitoring.
|
|
||||||
DMS_STOPPED, // Not monitoring. Stopped normally.
|
|
||||||
DMS_FAILED, // Not monitoring. Failed.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns the DBus-Glib symbol table.
|
|
||||||
// We should only use this function to access DBus-Glib symbols.
|
|
||||||
static LibDBusGlibSymbolTable *GetDBusGlibSymbolTable();
|
|
||||||
|
|
||||||
// Creates an instance of DBusMonitor.
|
|
||||||
static DBusMonitor *Create(DBusBusType type);
|
|
||||||
~DBusMonitor();
|
|
||||||
|
|
||||||
// Adds a filter to DBusMonitor.
|
|
||||||
bool AddFilter(DBusSigFilter *filter);
|
|
||||||
|
|
||||||
// Starts DBus message monitoring.
|
|
||||||
bool StartMonitoring();
|
|
||||||
|
|
||||||
// Stops DBus message monitoring.
|
|
||||||
bool StopMonitoring();
|
|
||||||
|
|
||||||
// Gets the status of DBus monitoring.
|
|
||||||
DBusMonitorStatus GetStatus();
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Forward declaration. Defined in the .cc file.
|
|
||||||
class DBusMonitoringThread;
|
|
||||||
|
|
||||||
explicit DBusMonitor(DBusBusType type);
|
|
||||||
|
|
||||||
// Updates status_ when monitoring status has changed.
|
|
||||||
void OnMonitoringStatusChanged(DBusMonitorStatus status);
|
|
||||||
|
|
||||||
DBusBusType type_;
|
|
||||||
DBusMonitorStatus status_;
|
|
||||||
DBusMonitoringThread *monitoring_thread_;
|
|
||||||
std::vector<DBusSigFilter *> filter_list_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // HAVE_DBUS_GLIB
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_DBUS_H_
|
|
@ -1,232 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_DBUS_GLIB
|
|
||||||
|
|
||||||
#include "webrtc/base/dbus.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
#define SIG_NAME "NameAcquired"
|
|
||||||
|
|
||||||
static const uint32 kTimeoutMs = 5000U;
|
|
||||||
|
|
||||||
class DBusSigFilterTest : public DBusSigFilter {
|
|
||||||
public:
|
|
||||||
// DBusSigFilterTest listens on DBus service itself for "NameAcquired" signal.
|
|
||||||
// This signal should be received when the application connects to DBus
|
|
||||||
// service and gains ownership of a name.
|
|
||||||
// http://dbus.freedesktop.org/doc/dbus-specification.html
|
|
||||||
DBusSigFilterTest()
|
|
||||||
: DBusSigFilter(GetFilter()),
|
|
||||||
message_received_(false) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MessageReceived() {
|
|
||||||
return message_received_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::string GetFilter() {
|
|
||||||
return rtc::DBusSigFilter::BuildFilterString("", "", SIG_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implement virtual method of DBusSigFilter. On caller thread.
|
|
||||||
virtual void ProcessSignal(DBusMessage *message) {
|
|
||||||
EXPECT_TRUE(message != NULL);
|
|
||||||
message_received_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool message_received_;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(DBusMonitorTest, StartStopStartStop) {
|
|
||||||
DBusSigFilterTest filter;
|
|
||||||
rtc::scoped_ptr<rtc::DBusMonitor> monitor;
|
|
||||||
monitor.reset(rtc::DBusMonitor::Create(DBUS_BUS_SYSTEM));
|
|
||||||
if (monitor) {
|
|
||||||
EXPECT_TRUE(monitor->AddFilter(&filter));
|
|
||||||
|
|
||||||
EXPECT_TRUE(monitor->StopMonitoring());
|
|
||||||
EXPECT_EQ(monitor->GetStatus(), DBusMonitor::DMS_NOT_INITIALIZED);
|
|
||||||
|
|
||||||
EXPECT_TRUE(monitor->StartMonitoring());
|
|
||||||
EXPECT_EQ_WAIT(DBusMonitor::DMS_RUNNING, monitor->GetStatus(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE(monitor->StopMonitoring());
|
|
||||||
EXPECT_EQ(monitor->GetStatus(), DBusMonitor::DMS_STOPPED);
|
|
||||||
EXPECT_TRUE(monitor->StopMonitoring());
|
|
||||||
EXPECT_EQ(monitor->GetStatus(), DBusMonitor::DMS_STOPPED);
|
|
||||||
|
|
||||||
EXPECT_TRUE(monitor->StartMonitoring());
|
|
||||||
EXPECT_EQ_WAIT(DBusMonitor::DMS_RUNNING, monitor->GetStatus(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE(monitor->StartMonitoring());
|
|
||||||
EXPECT_EQ(monitor->GetStatus(), DBusMonitor::DMS_RUNNING);
|
|
||||||
EXPECT_TRUE(monitor->StopMonitoring());
|
|
||||||
EXPECT_EQ(monitor->GetStatus(), DBusMonitor::DMS_STOPPED);
|
|
||||||
} else {
|
|
||||||
LOG(LS_WARNING) << "DBus Monitor not started. Skipping test.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DBusMonitorTest listens on DBus service itself for "NameAcquired" signal.
|
|
||||||
// This signal should be received when the application connects to DBus
|
|
||||||
// service and gains ownership of a name.
|
|
||||||
// This test is to make sure that we capture the "NameAcquired" signal.
|
|
||||||
TEST(DBusMonitorTest, ReceivedNameAcquiredSignal) {
|
|
||||||
DBusSigFilterTest filter;
|
|
||||||
rtc::scoped_ptr<rtc::DBusMonitor> monitor;
|
|
||||||
monitor.reset(rtc::DBusMonitor::Create(DBUS_BUS_SYSTEM));
|
|
||||||
if (monitor) {
|
|
||||||
EXPECT_TRUE(monitor->AddFilter(&filter));
|
|
||||||
|
|
||||||
EXPECT_TRUE(monitor->StartMonitoring());
|
|
||||||
EXPECT_EQ_WAIT(DBusMonitor::DMS_RUNNING, monitor->GetStatus(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE_WAIT(filter.MessageReceived(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE(monitor->StopMonitoring());
|
|
||||||
EXPECT_EQ(monitor->GetStatus(), DBusMonitor::DMS_STOPPED);
|
|
||||||
} else {
|
|
||||||
LOG(LS_WARNING) << "DBus Monitor not started. Skipping test.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DBusMonitorTest, ConcurrentMonitors) {
|
|
||||||
DBusSigFilterTest filter1;
|
|
||||||
rtc::scoped_ptr<rtc::DBusMonitor> monitor1;
|
|
||||||
monitor1.reset(rtc::DBusMonitor::Create(DBUS_BUS_SYSTEM));
|
|
||||||
if (monitor1) {
|
|
||||||
EXPECT_TRUE(monitor1->AddFilter(&filter1));
|
|
||||||
DBusSigFilterTest filter2;
|
|
||||||
rtc::scoped_ptr<rtc::DBusMonitor> monitor2;
|
|
||||||
monitor2.reset(rtc::DBusMonitor::Create(DBUS_BUS_SYSTEM));
|
|
||||||
EXPECT_TRUE(monitor2->AddFilter(&filter2));
|
|
||||||
|
|
||||||
EXPECT_TRUE(monitor1->StartMonitoring());
|
|
||||||
EXPECT_EQ_WAIT(DBusMonitor::DMS_RUNNING, monitor1->GetStatus(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE(monitor2->StartMonitoring());
|
|
||||||
EXPECT_EQ_WAIT(DBusMonitor::DMS_RUNNING, monitor2->GetStatus(), kTimeoutMs);
|
|
||||||
|
|
||||||
EXPECT_TRUE_WAIT(filter2.MessageReceived(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE(monitor2->StopMonitoring());
|
|
||||||
EXPECT_EQ(monitor2->GetStatus(), DBusMonitor::DMS_STOPPED);
|
|
||||||
|
|
||||||
EXPECT_TRUE_WAIT(filter1.MessageReceived(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE(monitor1->StopMonitoring());
|
|
||||||
EXPECT_EQ(monitor1->GetStatus(), DBusMonitor::DMS_STOPPED);
|
|
||||||
} else {
|
|
||||||
LOG(LS_WARNING) << "DBus Monitor not started. Skipping test.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DBusMonitorTest, ConcurrentFilters) {
|
|
||||||
DBusSigFilterTest filter1;
|
|
||||||
DBusSigFilterTest filter2;
|
|
||||||
rtc::scoped_ptr<rtc::DBusMonitor> monitor;
|
|
||||||
monitor.reset(rtc::DBusMonitor::Create(DBUS_BUS_SYSTEM));
|
|
||||||
if (monitor) {
|
|
||||||
EXPECT_TRUE(monitor->AddFilter(&filter1));
|
|
||||||
EXPECT_TRUE(monitor->AddFilter(&filter2));
|
|
||||||
|
|
||||||
EXPECT_TRUE(monitor->StartMonitoring());
|
|
||||||
EXPECT_EQ_WAIT(DBusMonitor::DMS_RUNNING, monitor->GetStatus(), kTimeoutMs);
|
|
||||||
|
|
||||||
EXPECT_TRUE_WAIT(filter1.MessageReceived(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE_WAIT(filter2.MessageReceived(), kTimeoutMs);
|
|
||||||
|
|
||||||
EXPECT_TRUE(monitor->StopMonitoring());
|
|
||||||
EXPECT_EQ(monitor->GetStatus(), DBusMonitor::DMS_STOPPED);
|
|
||||||
} else {
|
|
||||||
LOG(LS_WARNING) << "DBus Monitor not started. Skipping test.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DBusMonitorTest, NoAddFilterIfRunning) {
|
|
||||||
DBusSigFilterTest filter1;
|
|
||||||
DBusSigFilterTest filter2;
|
|
||||||
rtc::scoped_ptr<rtc::DBusMonitor> monitor;
|
|
||||||
monitor.reset(rtc::DBusMonitor::Create(DBUS_BUS_SYSTEM));
|
|
||||||
if (monitor) {
|
|
||||||
EXPECT_TRUE(monitor->AddFilter(&filter1));
|
|
||||||
|
|
||||||
EXPECT_TRUE(monitor->StartMonitoring());
|
|
||||||
EXPECT_EQ_WAIT(DBusMonitor::DMS_RUNNING, monitor->GetStatus(), kTimeoutMs);
|
|
||||||
EXPECT_FALSE(monitor->AddFilter(&filter2));
|
|
||||||
|
|
||||||
EXPECT_TRUE(monitor->StopMonitoring());
|
|
||||||
EXPECT_EQ(monitor->GetStatus(), DBusMonitor::DMS_STOPPED);
|
|
||||||
} else {
|
|
||||||
LOG(LS_WARNING) << "DBus Monitor not started. Skipping test.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DBusMonitorTest, AddFilterAfterStop) {
|
|
||||||
DBusSigFilterTest filter1;
|
|
||||||
DBusSigFilterTest filter2;
|
|
||||||
rtc::scoped_ptr<rtc::DBusMonitor> monitor;
|
|
||||||
monitor.reset(rtc::DBusMonitor::Create(DBUS_BUS_SYSTEM));
|
|
||||||
if (monitor) {
|
|
||||||
EXPECT_TRUE(monitor->AddFilter(&filter1));
|
|
||||||
EXPECT_TRUE(monitor->StartMonitoring());
|
|
||||||
EXPECT_EQ_WAIT(DBusMonitor::DMS_RUNNING, monitor->GetStatus(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE_WAIT(filter1.MessageReceived(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE(monitor->StopMonitoring());
|
|
||||||
EXPECT_EQ(monitor->GetStatus(), DBusMonitor::DMS_STOPPED);
|
|
||||||
|
|
||||||
EXPECT_TRUE(monitor->AddFilter(&filter2));
|
|
||||||
EXPECT_TRUE(monitor->StartMonitoring());
|
|
||||||
EXPECT_EQ_WAIT(DBusMonitor::DMS_RUNNING, monitor->GetStatus(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE_WAIT(filter1.MessageReceived(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE_WAIT(filter2.MessageReceived(), kTimeoutMs);
|
|
||||||
EXPECT_TRUE(monitor->StopMonitoring());
|
|
||||||
EXPECT_EQ(monitor->GetStatus(), DBusMonitor::DMS_STOPPED);
|
|
||||||
} else {
|
|
||||||
LOG(LS_WARNING) << "DBus Monitor not started. Skipping test.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DBusMonitorTest, StopRightAfterStart) {
|
|
||||||
DBusSigFilterTest filter;
|
|
||||||
rtc::scoped_ptr<rtc::DBusMonitor> monitor;
|
|
||||||
monitor.reset(rtc::DBusMonitor::Create(DBUS_BUS_SYSTEM));
|
|
||||||
if (monitor) {
|
|
||||||
EXPECT_TRUE(monitor->AddFilter(&filter));
|
|
||||||
|
|
||||||
EXPECT_TRUE(monitor->StartMonitoring());
|
|
||||||
EXPECT_TRUE(monitor->StopMonitoring());
|
|
||||||
|
|
||||||
// Stop the monitoring thread right after it had been started.
|
|
||||||
// If the monitoring thread got a chance to receive a DBus signal, it would
|
|
||||||
// post a message to the main thread and signal the main thread wakeup.
|
|
||||||
// This message will be cleaned out automatically when the filter get
|
|
||||||
// destructed. Here we also consume the wakeup signal (if there is one) so
|
|
||||||
// that the testing (main) thread is reset to a clean state.
|
|
||||||
rtc::Thread::Current()->ProcessMessages(1);
|
|
||||||
} else {
|
|
||||||
LOG(LS_WARNING) << "DBus Monitor not started.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(DBusSigFilter, BuildFilterString) {
|
|
||||||
EXPECT_EQ(DBusSigFilter::BuildFilterString("", "", ""),
|
|
||||||
(DBUS_TYPE "='" DBUS_SIGNAL "'"));
|
|
||||||
EXPECT_EQ(DBusSigFilter::BuildFilterString("p", "", ""),
|
|
||||||
(DBUS_TYPE "='" DBUS_SIGNAL "'," DBUS_PATH "='p'"));
|
|
||||||
EXPECT_EQ(DBusSigFilter::BuildFilterString("p","i", ""),
|
|
||||||
(DBUS_TYPE "='" DBUS_SIGNAL "'," DBUS_PATH "='p',"
|
|
||||||
DBUS_INTERFACE "='i'"));
|
|
||||||
EXPECT_EQ(DBusSigFilter::BuildFilterString("p","i","m"),
|
|
||||||
(DBUS_TYPE "='" DBUS_SIGNAL "'," DBUS_PATH "='p',"
|
|
||||||
DBUS_INTERFACE "='i'," DBUS_MEMBER "='m'"));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // HAVE_DBUS_GLIB
|
|
@ -1,347 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 <time.h>
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#include "webrtc/base/win32.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
#include "webrtc/base/diskcache.h"
|
|
||||||
#include "webrtc/base/fileutils.h"
|
|
||||||
#include "webrtc/base/pathutils.h"
|
|
||||||
#include "webrtc/base/stream.h"
|
|
||||||
#include "webrtc/base/stringencode.h"
|
|
||||||
#include "webrtc/base/stringutils.h"
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
#define TRANSPARENT_CACHE_NAMES 1
|
|
||||||
#else // !_DEBUG
|
|
||||||
#define TRANSPARENT_CACHE_NAMES 0
|
|
||||||
#endif // !_DEBUG
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class DiskCache;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// DiskCacheAdapter
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class DiskCacheAdapter : public StreamAdapterInterface {
|
|
||||||
public:
|
|
||||||
DiskCacheAdapter(const DiskCache* cache, const std::string& id, size_t index,
|
|
||||||
StreamInterface* stream)
|
|
||||||
: StreamAdapterInterface(stream), cache_(cache), id_(id), index_(index)
|
|
||||||
{ }
|
|
||||||
virtual ~DiskCacheAdapter() {
|
|
||||||
Close();
|
|
||||||
cache_->ReleaseResource(id_, index_);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const DiskCache* cache_;
|
|
||||||
std::string id_;
|
|
||||||
size_t index_;
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// DiskCache
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
DiskCache::DiskCache() : max_cache_(0), total_size_(0), total_accessors_(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
DiskCache::~DiskCache() {
|
|
||||||
ASSERT(0 == total_accessors_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCache::Initialize(const std::string& folder, size_t size) {
|
|
||||||
if (!folder_.empty() || !Filesystem::CreateFolder(folder))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
folder_ = folder;
|
|
||||||
max_cache_ = size;
|
|
||||||
ASSERT(0 == total_size_);
|
|
||||||
|
|
||||||
if (!InitializeEntries())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return CheckLimit();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCache::Purge() {
|
|
||||||
if (folder_.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (total_accessors_ > 0) {
|
|
||||||
LOG_F(LS_WARNING) << "Cache files open";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PurgeFiles())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
map_.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCache::LockResource(const std::string& id) {
|
|
||||||
Entry* entry = GetOrCreateEntry(id, true);
|
|
||||||
if (LS_LOCKED == entry->lock_state)
|
|
||||||
return false;
|
|
||||||
if ((LS_UNLOCKED == entry->lock_state) && (entry->accessors > 0))
|
|
||||||
return false;
|
|
||||||
if ((total_size_ > max_cache_) && !CheckLimit()) {
|
|
||||||
LOG_F(LS_WARNING) << "Cache overfull";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
entry->lock_state = LS_LOCKED;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamInterface* DiskCache::WriteResource(const std::string& id, size_t index) {
|
|
||||||
Entry* entry = GetOrCreateEntry(id, false);
|
|
||||||
if (LS_LOCKED != entry->lock_state)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
size_t previous_size = 0;
|
|
||||||
std::string filename(IdToFilename(id, index));
|
|
||||||
FileStream::GetSize(filename, &previous_size);
|
|
||||||
ASSERT(previous_size <= entry->size);
|
|
||||||
if (previous_size > entry->size) {
|
|
||||||
previous_size = entry->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
scoped_ptr<FileStream> file(new FileStream);
|
|
||||||
if (!file->Open(filename, "wb", NULL)) {
|
|
||||||
LOG_F(LS_ERROR) << "Couldn't create cache file";
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry->streams = stdmax(entry->streams, index + 1);
|
|
||||||
entry->size -= previous_size;
|
|
||||||
total_size_ -= previous_size;
|
|
||||||
|
|
||||||
entry->accessors += 1;
|
|
||||||
total_accessors_ += 1;
|
|
||||||
return new DiskCacheAdapter(this, id, index, file.release());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCache::UnlockResource(const std::string& id) {
|
|
||||||
Entry* entry = GetOrCreateEntry(id, false);
|
|
||||||
if (LS_LOCKED != entry->lock_state)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (entry->accessors > 0) {
|
|
||||||
entry->lock_state = LS_UNLOCKING;
|
|
||||||
} else {
|
|
||||||
entry->lock_state = LS_UNLOCKED;
|
|
||||||
entry->last_modified = time(0);
|
|
||||||
CheckLimit();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamInterface* DiskCache::ReadResource(const std::string& id,
|
|
||||||
size_t index) const {
|
|
||||||
const Entry* entry = GetEntry(id);
|
|
||||||
if (LS_UNLOCKED != entry->lock_state)
|
|
||||||
return NULL;
|
|
||||||
if (index >= entry->streams)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
scoped_ptr<FileStream> file(new FileStream);
|
|
||||||
if (!file->Open(IdToFilename(id, index), "rb", NULL))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
entry->accessors += 1;
|
|
||||||
total_accessors_ += 1;
|
|
||||||
return new DiskCacheAdapter(this, id, index, file.release());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCache::HasResource(const std::string& id) const {
|
|
||||||
const Entry* entry = GetEntry(id);
|
|
||||||
return (NULL != entry) && (entry->streams > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCache::HasResourceStream(const std::string& id, size_t index) const {
|
|
||||||
const Entry* entry = GetEntry(id);
|
|
||||||
if ((NULL == entry) || (index >= entry->streams))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::string filename = IdToFilename(id, index);
|
|
||||||
|
|
||||||
return FileExists(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCache::DeleteResource(const std::string& id) {
|
|
||||||
Entry* entry = GetOrCreateEntry(id, false);
|
|
||||||
if (!entry)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if ((LS_UNLOCKED != entry->lock_state) || (entry->accessors > 0))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool success = true;
|
|
||||||
for (size_t index = 0; index < entry->streams; ++index) {
|
|
||||||
std::string filename = IdToFilename(id, index);
|
|
||||||
|
|
||||||
if (!FileExists(filename))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!DeleteFile(filename)) {
|
|
||||||
LOG_F(LS_ERROR) << "Couldn't remove cache file: " << filename;
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
total_size_ -= entry->size;
|
|
||||||
map_.erase(id);
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCache::CheckLimit() {
|
|
||||||
#ifdef _DEBUG
|
|
||||||
// Temporary check to make sure everything is working correctly.
|
|
||||||
size_t cache_size = 0;
|
|
||||||
for (EntryMap::iterator it = map_.begin(); it != map_.end(); ++it) {
|
|
||||||
cache_size += it->second.size;
|
|
||||||
}
|
|
||||||
ASSERT(cache_size == total_size_);
|
|
||||||
#endif // _DEBUG
|
|
||||||
|
|
||||||
// TODO: Replace this with a non-brain-dead algorithm for clearing out the
|
|
||||||
// oldest resources... something that isn't O(n^2)
|
|
||||||
while (total_size_ > max_cache_) {
|
|
||||||
EntryMap::iterator oldest = map_.end();
|
|
||||||
for (EntryMap::iterator it = map_.begin(); it != map_.end(); ++it) {
|
|
||||||
if ((LS_UNLOCKED != it->second.lock_state) || (it->second.accessors > 0))
|
|
||||||
continue;
|
|
||||||
oldest = it;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (oldest == map_.end()) {
|
|
||||||
LOG_F(LS_WARNING) << "All resources are locked!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (EntryMap::iterator it = oldest++; it != map_.end(); ++it) {
|
|
||||||
if (it->second.last_modified < oldest->second.last_modified) {
|
|
||||||
oldest = it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!DeleteResource(oldest->first)) {
|
|
||||||
LOG_F(LS_ERROR) << "Couldn't delete from cache!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string DiskCache::IdToFilename(const std::string& id, size_t index) const {
|
|
||||||
#ifdef TRANSPARENT_CACHE_NAMES
|
|
||||||
// This escapes colons and other filesystem characters, so the user can't open
|
|
||||||
// special devices (like "COM1:"), or access other directories.
|
|
||||||
size_t buffer_size = id.length()*3 + 1;
|
|
||||||
char* buffer = new char[buffer_size];
|
|
||||||
encode(buffer, buffer_size, id.data(), id.length(),
|
|
||||||
unsafe_filename_characters(), '%');
|
|
||||||
// TODO: ASSERT(strlen(buffer) < FileSystem::MaxBasenameLength());
|
|
||||||
#else // !TRANSPARENT_CACHE_NAMES
|
|
||||||
// We might want to just use a hash of the filename at some point, both for
|
|
||||||
// obfuscation, and to avoid both filename length and escaping issues.
|
|
||||||
ASSERT(false);
|
|
||||||
#endif // !TRANSPARENT_CACHE_NAMES
|
|
||||||
|
|
||||||
char extension[32];
|
|
||||||
sprintfn(extension, ARRAY_SIZE(extension), ".%u", index);
|
|
||||||
|
|
||||||
Pathname pathname;
|
|
||||||
pathname.SetFolder(folder_);
|
|
||||||
pathname.SetBasename(buffer);
|
|
||||||
pathname.SetExtension(extension);
|
|
||||||
|
|
||||||
#ifdef TRANSPARENT_CACHE_NAMES
|
|
||||||
delete [] buffer;
|
|
||||||
#endif // TRANSPARENT_CACHE_NAMES
|
|
||||||
|
|
||||||
return pathname.pathname();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCache::FilenameToId(const std::string& filename, std::string* id,
|
|
||||||
size_t* index) const {
|
|
||||||
Pathname pathname(filename);
|
|
||||||
unsigned tempdex;
|
|
||||||
if (1 != sscanf(pathname.extension().c_str(), ".%u", &tempdex))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*index = static_cast<size_t>(tempdex);
|
|
||||||
|
|
||||||
size_t buffer_size = pathname.basename().length() + 1;
|
|
||||||
char* buffer = new char[buffer_size];
|
|
||||||
decode(buffer, buffer_size, pathname.basename().data(),
|
|
||||||
pathname.basename().length(), '%');
|
|
||||||
id->assign(buffer);
|
|
||||||
delete [] buffer;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DiskCache::Entry* DiskCache::GetOrCreateEntry(const std::string& id,
|
|
||||||
bool create) {
|
|
||||||
EntryMap::iterator it = map_.find(id);
|
|
||||||
if (it != map_.end())
|
|
||||||
return &it->second;
|
|
||||||
if (!create)
|
|
||||||
return NULL;
|
|
||||||
Entry e;
|
|
||||||
e.lock_state = LS_UNLOCKED;
|
|
||||||
e.accessors = 0;
|
|
||||||
e.size = 0;
|
|
||||||
e.streams = 0;
|
|
||||||
e.last_modified = time(0);
|
|
||||||
it = map_.insert(EntryMap::value_type(id, e)).first;
|
|
||||||
return &it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DiskCache::ReleaseResource(const std::string& id, size_t index) const {
|
|
||||||
const Entry* entry = GetEntry(id);
|
|
||||||
if (!entry) {
|
|
||||||
LOG_F(LS_WARNING) << "Missing cache entry";
|
|
||||||
ASSERT(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry->accessors -= 1;
|
|
||||||
total_accessors_ -= 1;
|
|
||||||
|
|
||||||
if (LS_UNLOCKED != entry->lock_state) {
|
|
||||||
// This is safe, because locked resources only issue WriteResource, which
|
|
||||||
// is non-const. Think about a better way to handle it.
|
|
||||||
DiskCache* this2 = const_cast<DiskCache*>(this);
|
|
||||||
Entry* entry2 = this2->GetOrCreateEntry(id, false);
|
|
||||||
|
|
||||||
size_t new_size = 0;
|
|
||||||
std::string filename(IdToFilename(id, index));
|
|
||||||
FileStream::GetSize(filename, &new_size);
|
|
||||||
entry2->size += new_size;
|
|
||||||
this2->total_size_ += new_size;
|
|
||||||
|
|
||||||
if ((LS_UNLOCKING == entry->lock_state) && (0 == entry->accessors)) {
|
|
||||||
entry2->last_modified = time(0);
|
|
||||||
entry2->lock_state = LS_UNLOCKED;
|
|
||||||
this2->CheckLimit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_DISKCACHE_H__
|
|
||||||
#define WEBRTC_BASE_DISKCACHE_H__
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#undef UnlockResource
|
|
||||||
#endif // WEBRTC_WIN
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class StreamInterface;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// DiskCache - An LRU cache of streams, stored on disk.
|
|
||||||
//
|
|
||||||
// Streams are identified by a unique resource id. Multiple streams can be
|
|
||||||
// associated with each resource id, distinguished by an index. When old
|
|
||||||
// resources are flushed from the cache, all streams associated with those
|
|
||||||
// resources are removed together.
|
|
||||||
// DiskCache is designed to persist across executions of the program. It is
|
|
||||||
// safe for use from an arbitrary number of users on a single thread, but not
|
|
||||||
// from multiple threads or other processes.
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class DiskCache {
|
|
||||||
public:
|
|
||||||
DiskCache();
|
|
||||||
virtual ~DiskCache();
|
|
||||||
|
|
||||||
bool Initialize(const std::string& folder, size_t size);
|
|
||||||
bool Purge();
|
|
||||||
|
|
||||||
bool LockResource(const std::string& id);
|
|
||||||
StreamInterface* WriteResource(const std::string& id, size_t index);
|
|
||||||
bool UnlockResource(const std::string& id);
|
|
||||||
|
|
||||||
StreamInterface* ReadResource(const std::string& id, size_t index) const;
|
|
||||||
|
|
||||||
bool HasResource(const std::string& id) const;
|
|
||||||
bool HasResourceStream(const std::string& id, size_t index) const;
|
|
||||||
bool DeleteResource(const std::string& id);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual bool InitializeEntries() = 0;
|
|
||||||
virtual bool PurgeFiles() = 0;
|
|
||||||
|
|
||||||
virtual bool FileExists(const std::string& filename) const = 0;
|
|
||||||
virtual bool DeleteFile(const std::string& filename) const = 0;
|
|
||||||
|
|
||||||
enum LockState { LS_UNLOCKED, LS_LOCKED, LS_UNLOCKING };
|
|
||||||
struct Entry {
|
|
||||||
LockState lock_state;
|
|
||||||
mutable size_t accessors;
|
|
||||||
size_t size;
|
|
||||||
size_t streams;
|
|
||||||
time_t last_modified;
|
|
||||||
};
|
|
||||||
typedef std::map<std::string, Entry> EntryMap;
|
|
||||||
friend class DiskCacheAdapter;
|
|
||||||
|
|
||||||
bool CheckLimit();
|
|
||||||
|
|
||||||
std::string IdToFilename(const std::string& id, size_t index) const;
|
|
||||||
bool FilenameToId(const std::string& filename, std::string* id,
|
|
||||||
size_t* index) const;
|
|
||||||
|
|
||||||
const Entry* GetEntry(const std::string& id) const {
|
|
||||||
return const_cast<DiskCache*>(this)->GetOrCreateEntry(id, false);
|
|
||||||
}
|
|
||||||
Entry* GetOrCreateEntry(const std::string& id, bool create);
|
|
||||||
|
|
||||||
void ReleaseResource(const std::string& id, size_t index) const;
|
|
||||||
|
|
||||||
std::string folder_;
|
|
||||||
size_t max_cache_, total_size_;
|
|
||||||
EntryMap map_;
|
|
||||||
mutable size_t total_accessors_;
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// CacheLock - Automatically manage locking and unlocking, with optional
|
|
||||||
// rollback semantics
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
class CacheLock {
|
|
||||||
public:
|
|
||||||
CacheLock(DiskCache* cache, const std::string& id, bool rollback = false)
|
|
||||||
: cache_(cache), id_(id), rollback_(rollback)
|
|
||||||
{
|
|
||||||
locked_ = cache_->LockResource(id_);
|
|
||||||
}
|
|
||||||
~CacheLock() {
|
|
||||||
if (locked_) {
|
|
||||||
cache_->UnlockResource(id_);
|
|
||||||
if (rollback_) {
|
|
||||||
cache_->DeleteResource(id_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool IsLocked() const { return locked_; }
|
|
||||||
void Commit() { rollback_ = false; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
DiskCache* cache_;
|
|
||||||
std::string id_;
|
|
||||||
bool rollback_, locked_;
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_DISKCACHE_H__
|
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006 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 "webrtc/base/win32.h"
|
|
||||||
#include <shellapi.h>
|
|
||||||
#include <shlobj.h>
|
|
||||||
#include <tchar.h>
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
#include "webrtc/base/diskcache.h"
|
|
||||||
#include "webrtc/base/pathutils.h"
|
|
||||||
#include "webrtc/base/stream.h"
|
|
||||||
#include "webrtc/base/stringencode.h"
|
|
||||||
#include "webrtc/base/stringutils.h"
|
|
||||||
|
|
||||||
#include "webrtc/base/diskcache_win32.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
bool DiskCacheWin32::InitializeEntries() {
|
|
||||||
// Note: We could store the cache information in a separate file, for faster
|
|
||||||
// initialization. Figuring it out empirically works, too.
|
|
||||||
|
|
||||||
std::wstring path16 = ToUtf16(folder_);
|
|
||||||
path16.append(1, '*');
|
|
||||||
|
|
||||||
WIN32_FIND_DATA find_data;
|
|
||||||
HANDLE find_handle = FindFirstFile(path16.c_str(), &find_data);
|
|
||||||
if (find_handle != INVALID_HANDLE_VALUE) {
|
|
||||||
do {
|
|
||||||
size_t index;
|
|
||||||
std::string id;
|
|
||||||
if (!FilenameToId(ToUtf8(find_data.cFileName), &id, &index))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Entry* entry = GetOrCreateEntry(id, true);
|
|
||||||
entry->size += find_data.nFileSizeLow;
|
|
||||||
total_size_ += find_data.nFileSizeLow;
|
|
||||||
entry->streams = _max(entry->streams, index + 1);
|
|
||||||
FileTimeToUnixTime(find_data.ftLastWriteTime, &entry->last_modified);
|
|
||||||
|
|
||||||
} while (FindNextFile(find_handle, &find_data));
|
|
||||||
|
|
||||||
FindClose(find_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCacheWin32::PurgeFiles() {
|
|
||||||
std::wstring path16 = ToUtf16(folder_);
|
|
||||||
path16.append(1, '*');
|
|
||||||
path16.append(1, '\0');
|
|
||||||
|
|
||||||
SHFILEOPSTRUCT file_op = { 0 };
|
|
||||||
file_op.wFunc = FO_DELETE;
|
|
||||||
file_op.pFrom = path16.c_str();
|
|
||||||
file_op.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT
|
|
||||||
| FOF_NORECURSION | FOF_FILESONLY;
|
|
||||||
if (0 != SHFileOperation(&file_op)) {
|
|
||||||
LOG_F(LS_ERROR) << "Couldn't delete cache files";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCacheWin32::FileExists(const std::string& filename) const {
|
|
||||||
DWORD result = ::GetFileAttributes(ToUtf16(filename).c_str());
|
|
||||||
return (INVALID_FILE_ATTRIBUTES != result);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DiskCacheWin32::DeleteFile(const std::string& filename) const {
|
|
||||||
return ::DeleteFile(ToUtf16(filename).c_str()) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_DISKCACHEWIN32_H__
|
|
||||||
#define WEBRTC_BASE_DISKCACHEWIN32_H__
|
|
||||||
|
|
||||||
#include "webrtc/base/diskcache.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class DiskCacheWin32 : public DiskCache {
|
|
||||||
protected:
|
|
||||||
virtual bool InitializeEntries();
|
|
||||||
virtual bool PurgeFiles();
|
|
||||||
|
|
||||||
virtual bool FileExists(const std::string& filename) const;
|
|
||||||
virtual bool DeleteFile(const std::string& filename) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_DISKCACHEWIN32_H__
|
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_DSCP_H_
|
|
||||||
#define WEBRTC_BASE_DSCP_H_
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
// Differentiated Services Code Point.
|
|
||||||
// See http://tools.ietf.org/html/rfc2474 for details.
|
|
||||||
enum DiffServCodePoint {
|
|
||||||
DSCP_NO_CHANGE = -1,
|
|
||||||
DSCP_DEFAULT = 0, // Same as DSCP_CS0
|
|
||||||
DSCP_CS0 = 0, // The default
|
|
||||||
DSCP_CS1 = 8, // Bulk/background traffic
|
|
||||||
DSCP_AF11 = 10,
|
|
||||||
DSCP_AF12 = 12,
|
|
||||||
DSCP_AF13 = 14,
|
|
||||||
DSCP_CS2 = 16,
|
|
||||||
DSCP_AF21 = 18,
|
|
||||||
DSCP_AF22 = 20,
|
|
||||||
DSCP_AF23 = 22,
|
|
||||||
DSCP_CS3 = 24,
|
|
||||||
DSCP_AF31 = 26,
|
|
||||||
DSCP_AF32 = 28,
|
|
||||||
DSCP_AF33 = 30,
|
|
||||||
DSCP_CS4 = 32,
|
|
||||||
DSCP_AF41 = 34, // Video
|
|
||||||
DSCP_AF42 = 36, // Video
|
|
||||||
DSCP_AF43 = 38, // Video
|
|
||||||
DSCP_CS5 = 40, // Video
|
|
||||||
DSCP_EF = 46, // Voice
|
|
||||||
DSCP_CS6 = 48, // Voice
|
|
||||||
DSCP_CS7 = 56, // Control messages
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_DSCP_H_
|
|
@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/event.h"
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#include <windows.h>
|
|
||||||
#elif defined(WEBRTC_POSIX)
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <time.h>
|
|
||||||
#else
|
|
||||||
#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
|
|
||||||
Event::Event(bool manual_reset, bool initially_signaled)
|
|
||||||
: is_manual_reset_(manual_reset),
|
|
||||||
is_initially_signaled_(initially_signaled) {
|
|
||||||
event_handle_ = ::CreateEvent(NULL, // Security attributes.
|
|
||||||
is_manual_reset_,
|
|
||||||
is_initially_signaled_,
|
|
||||||
NULL); // Name.
|
|
||||||
ASSERT(event_handle_ != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::~Event() {
|
|
||||||
CloseHandle(event_handle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Event::Set() {
|
|
||||||
SetEvent(event_handle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Event::Reset() {
|
|
||||||
ResetEvent(event_handle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Event::Wait(int cms) {
|
|
||||||
DWORD ms = (cms == kForever)? INFINITE : cms;
|
|
||||||
return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(WEBRTC_POSIX)
|
|
||||||
|
|
||||||
Event::Event(bool manual_reset, bool initially_signaled)
|
|
||||||
: is_manual_reset_(manual_reset),
|
|
||||||
event_status_(initially_signaled) {
|
|
||||||
VERIFY(pthread_mutex_init(&event_mutex_, NULL) == 0);
|
|
||||||
VERIFY(pthread_cond_init(&event_cond_, NULL) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::~Event() {
|
|
||||||
pthread_mutex_destroy(&event_mutex_);
|
|
||||||
pthread_cond_destroy(&event_cond_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Event::Set() {
|
|
||||||
pthread_mutex_lock(&event_mutex_);
|
|
||||||
event_status_ = true;
|
|
||||||
pthread_cond_broadcast(&event_cond_);
|
|
||||||
pthread_mutex_unlock(&event_mutex_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Event::Reset() {
|
|
||||||
pthread_mutex_lock(&event_mutex_);
|
|
||||||
event_status_ = false;
|
|
||||||
pthread_mutex_unlock(&event_mutex_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Event::Wait(int cms) {
|
|
||||||
pthread_mutex_lock(&event_mutex_);
|
|
||||||
int error = 0;
|
|
||||||
|
|
||||||
if (cms != kForever) {
|
|
||||||
// Converting from seconds and microseconds (1e-6) plus
|
|
||||||
// milliseconds (1e-3) to seconds and nanoseconds (1e-9).
|
|
||||||
|
|
||||||
struct timespec ts;
|
|
||||||
#if HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
|
|
||||||
// Use relative time version, which tends to be more efficient for
|
|
||||||
// pthread implementations where provided (like on Android).
|
|
||||||
ts.tv_sec = cms / 1000;
|
|
||||||
ts.tv_nsec = (cms % 1000) * 1000000;
|
|
||||||
#else
|
|
||||||
struct timeval tv;
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
|
|
||||||
ts.tv_sec = tv.tv_sec + (cms / 1000);
|
|
||||||
ts.tv_nsec = tv.tv_usec * 1000 + (cms % 1000) * 1000000;
|
|
||||||
|
|
||||||
// Handle overflow.
|
|
||||||
if (ts.tv_nsec >= 1000000000) {
|
|
||||||
ts.tv_sec++;
|
|
||||||
ts.tv_nsec -= 1000000000;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while (!event_status_ && error == 0) {
|
|
||||||
#if HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
|
|
||||||
error = pthread_cond_timedwait_relative_np(
|
|
||||||
&event_cond_, &event_mutex_, &ts);
|
|
||||||
#else
|
|
||||||
error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &ts);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (!event_status_ && error == 0)
|
|
||||||
error = pthread_cond_wait(&event_cond_, &event_mutex_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(liulk): Exactly one thread will auto-reset this event. All
|
|
||||||
// the other threads will think it's unsignaled. This seems to be
|
|
||||||
// consistent with auto-reset events in WEBRTC_WIN
|
|
||||||
if (error == 0 && !is_manual_reset_)
|
|
||||||
event_status_ = false;
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&event_mutex_);
|
|
||||||
|
|
||||||
return (error == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_EVENT_H__
|
|
||||||
#define WEBRTC_BASE_EVENT_H__
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#include "webrtc/base/win32.h" // NOLINT: consider this a system header.
|
|
||||||
#elif defined(WEBRTC_POSIX)
|
|
||||||
#include <pthread.h>
|
|
||||||
#else
|
|
||||||
#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class Event {
|
|
||||||
public:
|
|
||||||
Event(bool manual_reset, bool initially_signaled);
|
|
||||||
~Event();
|
|
||||||
|
|
||||||
void Set();
|
|
||||||
void Reset();
|
|
||||||
bool Wait(int cms);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool is_manual_reset_;
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
bool is_initially_signaled_;
|
|
||||||
HANDLE event_handle_;
|
|
||||||
#elif defined(WEBRTC_POSIX)
|
|
||||||
bool event_status_;
|
|
||||||
pthread_mutex_t event_mutex_;
|
|
||||||
pthread_cond_t event_cond_;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_EVENT_H__
|
|
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/event.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
TEST(EventTest, InitiallySignaled) {
|
|
||||||
Event event(false, true);
|
|
||||||
ASSERT_TRUE(event.Wait(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(EventTest, ManualReset) {
|
|
||||||
Event event(true, false);
|
|
||||||
ASSERT_FALSE(event.Wait(0));
|
|
||||||
|
|
||||||
event.Set();
|
|
||||||
ASSERT_TRUE(event.Wait(0));
|
|
||||||
ASSERT_TRUE(event.Wait(0));
|
|
||||||
|
|
||||||
event.Reset();
|
|
||||||
ASSERT_FALSE(event.Wait(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(EventTest, AutoReset) {
|
|
||||||
Event event(false, false);
|
|
||||||
ASSERT_FALSE(event.Wait(0));
|
|
||||||
|
|
||||||
event.Set();
|
|
||||||
ASSERT_TRUE(event.Wait(0));
|
|
||||||
ASSERT_FALSE(event.Wait(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_FAKECPUMONITOR_H_
|
|
||||||
#define WEBRTC_BASE_FAKECPUMONITOR_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/cpumonitor.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class FakeCpuMonitor : public rtc::CpuMonitor {
|
|
||||||
public:
|
|
||||||
explicit FakeCpuMonitor(Thread* thread)
|
|
||||||
: CpuMonitor(thread) {
|
|
||||||
}
|
|
||||||
~FakeCpuMonitor() {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnMessage(rtc::Message* msg) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_FAKECPUMONITOR_H_
|
|
@ -1,119 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_FAKENETWORK_H_
|
|
||||||
#define WEBRTC_BASE_FAKENETWORK_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "webrtc/base/network.h"
|
|
||||||
#include "webrtc/base/messagehandler.h"
|
|
||||||
#include "webrtc/base/socketaddress.h"
|
|
||||||
#include "webrtc/base/stringencode.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
const int kFakeIPv4NetworkPrefixLength = 24;
|
|
||||||
const int kFakeIPv6NetworkPrefixLength = 64;
|
|
||||||
|
|
||||||
// Fake network manager that allows us to manually specify the IPs to use.
|
|
||||||
class FakeNetworkManager : public NetworkManagerBase,
|
|
||||||
public MessageHandler {
|
|
||||||
public:
|
|
||||||
FakeNetworkManager()
|
|
||||||
: thread_(Thread::Current()),
|
|
||||||
next_index_(0),
|
|
||||||
started_(false),
|
|
||||||
sent_first_update_(false) {
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef std::vector<SocketAddress> IfaceList;
|
|
||||||
|
|
||||||
void AddInterface(const SocketAddress& iface) {
|
|
||||||
// ensure a unique name for the interface
|
|
||||||
SocketAddress address("test" + rtc::ToString(next_index_++), 0);
|
|
||||||
address.SetResolvedIP(iface.ipaddr());
|
|
||||||
ifaces_.push_back(address);
|
|
||||||
DoUpdateNetworks();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveInterface(const SocketAddress& iface) {
|
|
||||||
for (IfaceList::iterator it = ifaces_.begin();
|
|
||||||
it != ifaces_.end(); ++it) {
|
|
||||||
if (it->EqualIPs(iface)) {
|
|
||||||
ifaces_.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DoUpdateNetworks();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void StartUpdating() {
|
|
||||||
if (started_) {
|
|
||||||
if (sent_first_update_)
|
|
||||||
SignalNetworksChanged();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
started_ = true;
|
|
||||||
sent_first_update_ = false;
|
|
||||||
thread_->Post(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void StopUpdating() {
|
|
||||||
started_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageHandler interface.
|
|
||||||
virtual void OnMessage(Message* msg) {
|
|
||||||
DoUpdateNetworks();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void DoUpdateNetworks() {
|
|
||||||
if (!started_)
|
|
||||||
return;
|
|
||||||
std::vector<Network*> networks;
|
|
||||||
for (IfaceList::iterator it = ifaces_.begin();
|
|
||||||
it != ifaces_.end(); ++it) {
|
|
||||||
int prefix_length = 0;
|
|
||||||
if (it->ipaddr().family() == AF_INET) {
|
|
||||||
prefix_length = kFakeIPv4NetworkPrefixLength;
|
|
||||||
} else if (it->ipaddr().family() == AF_INET6) {
|
|
||||||
prefix_length = kFakeIPv6NetworkPrefixLength;
|
|
||||||
}
|
|
||||||
IPAddress prefix = TruncateIP(it->ipaddr(), prefix_length);
|
|
||||||
scoped_ptr<Network> net(new Network(it->hostname(),
|
|
||||||
it->hostname(),
|
|
||||||
prefix,
|
|
||||||
prefix_length));
|
|
||||||
net->AddIP(it->ipaddr());
|
|
||||||
networks.push_back(net.release());
|
|
||||||
}
|
|
||||||
bool changed;
|
|
||||||
MergeNetworkList(networks, &changed);
|
|
||||||
if (changed || !sent_first_update_) {
|
|
||||||
SignalNetworksChanged();
|
|
||||||
sent_first_update_ = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread* thread_;
|
|
||||||
IfaceList ifaces_;
|
|
||||||
int next_index_;
|
|
||||||
bool started_;
|
|
||||||
bool sent_first_update_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_FAKENETWORK_H_
|
|
@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_FAKESSLIDENTITY_H_
|
|
||||||
#define WEBRTC_BASE_FAKESSLIDENTITY_H_
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "webrtc/base/messagedigest.h"
|
|
||||||
#include "webrtc/base/sslidentity.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class FakeSSLCertificate : public rtc::SSLCertificate {
|
|
||||||
public:
|
|
||||||
// SHA-1 is the default digest algorithm because it is available in all build
|
|
||||||
// configurations used for unit testing.
|
|
||||||
explicit FakeSSLCertificate(const std::string& data)
|
|
||||||
: data_(data), digest_algorithm_(DIGEST_SHA_1) {}
|
|
||||||
explicit FakeSSLCertificate(const std::vector<std::string>& certs)
|
|
||||||
: data_(certs.front()), digest_algorithm_(DIGEST_SHA_1) {
|
|
||||||
std::vector<std::string>::const_iterator it;
|
|
||||||
// Skip certs[0].
|
|
||||||
for (it = certs.begin() + 1; it != certs.end(); ++it) {
|
|
||||||
certs_.push_back(FakeSSLCertificate(*it));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual FakeSSLCertificate* GetReference() const {
|
|
||||||
return new FakeSSLCertificate(*this);
|
|
||||||
}
|
|
||||||
virtual std::string ToPEMString() const {
|
|
||||||
return data_;
|
|
||||||
}
|
|
||||||
virtual void ToDER(Buffer* der_buffer) const {
|
|
||||||
std::string der_string;
|
|
||||||
VERIFY(SSLIdentity::PemToDer(kPemTypeCertificate, data_, &der_string));
|
|
||||||
der_buffer->SetData(der_string.c_str(), der_string.size());
|
|
||||||
}
|
|
||||||
void set_digest_algorithm(const std::string& algorithm) {
|
|
||||||
digest_algorithm_ = algorithm;
|
|
||||||
}
|
|
||||||
virtual bool GetSignatureDigestAlgorithm(std::string* algorithm) const {
|
|
||||||
*algorithm = digest_algorithm_;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool ComputeDigest(const std::string& algorithm,
|
|
||||||
unsigned char* digest,
|
|
||||||
size_t size,
|
|
||||||
size_t* length) const {
|
|
||||||
*length = rtc::ComputeDigest(algorithm, data_.c_str(), data_.size(),
|
|
||||||
digest, size);
|
|
||||||
return (*length != 0);
|
|
||||||
}
|
|
||||||
virtual bool GetChain(SSLCertChain** chain) const {
|
|
||||||
if (certs_.empty())
|
|
||||||
return false;
|
|
||||||
std::vector<SSLCertificate*> new_certs(certs_.size());
|
|
||||||
std::transform(certs_.begin(), certs_.end(), new_certs.begin(), DupCert);
|
|
||||||
*chain = new SSLCertChain(new_certs);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static FakeSSLCertificate* DupCert(FakeSSLCertificate cert) {
|
|
||||||
return cert.GetReference();
|
|
||||||
}
|
|
||||||
std::string data_;
|
|
||||||
std::vector<FakeSSLCertificate> certs_;
|
|
||||||
std::string digest_algorithm_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FakeSSLIdentity : public rtc::SSLIdentity {
|
|
||||||
public:
|
|
||||||
explicit FakeSSLIdentity(const std::string& data) : cert_(data) {}
|
|
||||||
explicit FakeSSLIdentity(const FakeSSLCertificate& cert) : cert_(cert) {}
|
|
||||||
virtual FakeSSLIdentity* GetReference() const {
|
|
||||||
return new FakeSSLIdentity(*this);
|
|
||||||
}
|
|
||||||
virtual const FakeSSLCertificate& certificate() const { return cert_; }
|
|
||||||
private:
|
|
||||||
FakeSSLCertificate cert_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_FAKESSLIDENTITY_H_
|
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// A fake TaskRunner for use in unit tests.
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_FAKETASKRUNNER_H_
|
|
||||||
#define WEBRTC_BASE_FAKETASKRUNNER_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/taskparent.h"
|
|
||||||
#include "webrtc/base/taskrunner.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class FakeTaskRunner : public TaskRunner {
|
|
||||||
public:
|
|
||||||
FakeTaskRunner() : current_time_(0) {}
|
|
||||||
virtual ~FakeTaskRunner() {}
|
|
||||||
|
|
||||||
virtual void WakeTasks() { RunTasks(); }
|
|
||||||
|
|
||||||
virtual int64 CurrentTime() {
|
|
||||||
// Implement if needed.
|
|
||||||
return current_time_++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64 current_time_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_FAKETASKRUNNER_H_
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 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 "webrtc/base/filelock.h"
|
|
||||||
|
|
||||||
#include "webrtc/base/fileutils.h"
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
#include "webrtc/base/pathutils.h"
|
|
||||||
#include "webrtc/base/stream.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
FileLock::FileLock(const std::string& path, FileStream* file)
|
|
||||||
: path_(path), file_(file) {
|
|
||||||
}
|
|
||||||
|
|
||||||
FileLock::~FileLock() {
|
|
||||||
MaybeUnlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileLock::Unlock() {
|
|
||||||
LOG_F(LS_INFO);
|
|
||||||
MaybeUnlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileLock::MaybeUnlock() {
|
|
||||||
if (file_) {
|
|
||||||
LOG(LS_INFO) << "Unlocking:" << path_;
|
|
||||||
file_->Close();
|
|
||||||
Filesystem::DeleteFile(path_);
|
|
||||||
file_.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileLock* FileLock::TryLock(const std::string& path) {
|
|
||||||
FileStream* stream = new FileStream();
|
|
||||||
bool ok = false;
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
// Open and lock in a single operation.
|
|
||||||
ok = stream->OpenShare(path, "a", _SH_DENYRW, NULL);
|
|
||||||
#else // WEBRTC_LINUX && !WEBRTC_ANDROID and WEBRTC_MAC && !defined(WEBRTC_IOS)
|
|
||||||
ok = stream->Open(path, "a", NULL) && stream->TryLock();
|
|
||||||
#endif
|
|
||||||
if (ok) {
|
|
||||||
return new FileLock(path, stream);
|
|
||||||
} else {
|
|
||||||
// Something failed, either we didn't succeed to open the
|
|
||||||
// file or we failed to lock it. Anyway remove the heap
|
|
||||||
// allocated object and then return NULL to indicate failure.
|
|
||||||
delete stream;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_FILELOCK_H_
|
|
||||||
#define WEBRTC_BASE_FILELOCK_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "webrtc/base/constructormagic.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class FileStream;
|
|
||||||
|
|
||||||
// Implements a very simple cross process lock based on a file.
|
|
||||||
// When Lock(...) is called we try to open/create the file in read/write
|
|
||||||
// mode without any sharing. (Or locking it with flock(...) on Unix)
|
|
||||||
// If the process crash the OS will make sure that the file descriptor
|
|
||||||
// is released and another process can accuire the lock.
|
|
||||||
// This doesn't work on ancient OSX/Linux versions if used on NFS.
|
|
||||||
// (Nfs-client before: ~2.6 and Linux Kernel < 2.6.)
|
|
||||||
class FileLock {
|
|
||||||
public:
|
|
||||||
virtual ~FileLock();
|
|
||||||
|
|
||||||
// Attempts to lock the file. The caller owns the returned
|
|
||||||
// lock object. Returns NULL if the file already was locked.
|
|
||||||
static FileLock* TryLock(const std::string& path);
|
|
||||||
void Unlock();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
FileLock(const std::string& path, FileStream* file);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void MaybeUnlock();
|
|
||||||
|
|
||||||
std::string path_;
|
|
||||||
scoped_ptr<FileStream> file_;
|
|
||||||
|
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(FileLock);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_FILELOCK_H_
|
|
@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 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 <string>
|
|
||||||
|
|
||||||
#include "webrtc/base/event.h"
|
|
||||||
#include "webrtc/base/filelock.h"
|
|
||||||
#include "webrtc/base/fileutils.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/pathutils.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
const static std::string kLockFile = "TestLockFile";
|
|
||||||
const static int kTimeoutMS = 5000;
|
|
||||||
|
|
||||||
class FileLockTest : public testing::Test, public Runnable {
|
|
||||||
public:
|
|
||||||
FileLockTest() : done_(false, false), thread_lock_failed_(false) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void Run(Thread* t) {
|
|
||||||
scoped_ptr<FileLock> lock(FileLock::TryLock(temp_file_.pathname()));
|
|
||||||
// The lock is already owned by the main thread of
|
|
||||||
// this test, therefore the TryLock(...) call should fail.
|
|
||||||
thread_lock_failed_ = lock.get() == NULL;
|
|
||||||
done_.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void SetUp() {
|
|
||||||
thread_lock_failed_ = false;
|
|
||||||
Filesystem::GetAppTempFolder(&temp_dir_);
|
|
||||||
temp_file_ = Pathname(temp_dir_.pathname(), kLockFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LockOnThread() {
|
|
||||||
locker_.Start(this);
|
|
||||||
done_.Wait(kTimeoutMS);
|
|
||||||
}
|
|
||||||
|
|
||||||
Event done_;
|
|
||||||
Thread locker_;
|
|
||||||
bool thread_lock_failed_;
|
|
||||||
Pathname temp_dir_;
|
|
||||||
Pathname temp_file_;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(FileLockTest, TestLockFileDeleted) {
|
|
||||||
scoped_ptr<FileLock> lock(FileLock::TryLock(temp_file_.pathname()));
|
|
||||||
EXPECT_TRUE(lock.get() != NULL);
|
|
||||||
EXPECT_FALSE(Filesystem::IsAbsent(temp_file_.pathname()));
|
|
||||||
lock->Unlock();
|
|
||||||
EXPECT_TRUE(Filesystem::IsAbsent(temp_file_.pathname()));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FileLockTest, TestLock) {
|
|
||||||
scoped_ptr<FileLock> lock(FileLock::TryLock(temp_file_.pathname()));
|
|
||||||
EXPECT_TRUE(lock.get() != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FileLockTest, TestLockX2) {
|
|
||||||
scoped_ptr<FileLock> lock1(FileLock::TryLock(temp_file_.pathname()));
|
|
||||||
EXPECT_TRUE(lock1.get() != NULL);
|
|
||||||
|
|
||||||
scoped_ptr<FileLock> lock2(FileLock::TryLock(temp_file_.pathname()));
|
|
||||||
EXPECT_TRUE(lock2.get() == NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(FileLockTest, TestThreadedLock) {
|
|
||||||
scoped_ptr<FileLock> lock(FileLock::TryLock(temp_file_.pathname()));
|
|
||||||
EXPECT_TRUE(lock.get() != NULL);
|
|
||||||
|
|
||||||
LockOnThread();
|
|
||||||
EXPECT_TRUE(thread_lock_failed_);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,307 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 <assert.h>
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
// TODO(grunell): Remove io.h includes when Chromium has started
|
|
||||||
// to use AEC in each source. http://crbug.com/264611.
|
|
||||||
#include <io.h>
|
|
||||||
#include "webrtc/base/win32.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "webrtc/base/pathutils.h"
|
|
||||||
#include "webrtc/base/fileutils.h"
|
|
||||||
#include "webrtc/base/stringutils.h"
|
|
||||||
#include "webrtc/base/stream.h"
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#include "webrtc/base/win32filesystem.h"
|
|
||||||
#else
|
|
||||||
#include "webrtc/base/unixfilesystem.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(WEBRTC_WIN)
|
|
||||||
#define MAX_PATH 260
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
//////////////////////////
|
|
||||||
// Directory Iterator //
|
|
||||||
//////////////////////////
|
|
||||||
|
|
||||||
// A DirectoryIterator is created with a given directory. It originally points
|
|
||||||
// to the first file in the directory, and can be advanecd with Next(). This
|
|
||||||
// allows you to get information about each file.
|
|
||||||
|
|
||||||
// Constructor
|
|
||||||
DirectoryIterator::DirectoryIterator()
|
|
||||||
#ifdef WEBRTC_WIN
|
|
||||||
: handle_(INVALID_HANDLE_VALUE) {
|
|
||||||
#else
|
|
||||||
: dir_(NULL), dirent_(NULL) {
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
DirectoryIterator::~DirectoryIterator() {
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
if (handle_ != INVALID_HANDLE_VALUE)
|
|
||||||
::FindClose(handle_);
|
|
||||||
#else
|
|
||||||
if (dir_)
|
|
||||||
closedir(dir_);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Starts traversing a directory.
|
|
||||||
// dir is the directory to traverse
|
|
||||||
// returns true if the directory exists and is valid
|
|
||||||
bool DirectoryIterator::Iterate(const Pathname &dir) {
|
|
||||||
directory_ = dir.pathname();
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
if (handle_ != INVALID_HANDLE_VALUE)
|
|
||||||
::FindClose(handle_);
|
|
||||||
std::string d = dir.pathname() + '*';
|
|
||||||
handle_ = ::FindFirstFile(ToUtf16(d).c_str(), &data_);
|
|
||||||
if (handle_ == INVALID_HANDLE_VALUE)
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
if (dir_ != NULL)
|
|
||||||
closedir(dir_);
|
|
||||||
dir_ = ::opendir(directory_.c_str());
|
|
||||||
if (dir_ == NULL)
|
|
||||||
return false;
|
|
||||||
dirent_ = readdir(dir_);
|
|
||||||
if (dirent_ == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (::stat(std::string(directory_ + Name()).c_str(), &stat_) != 0)
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advances to the next file
|
|
||||||
// returns true if there were more files in the directory.
|
|
||||||
bool DirectoryIterator::Next() {
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
return ::FindNextFile(handle_, &data_) == TRUE;
|
|
||||||
#else
|
|
||||||
dirent_ = ::readdir(dir_);
|
|
||||||
if (dirent_ == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return ::stat(std::string(directory_ + Name()).c_str(), &stat_) == 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns true if the file currently pointed to is a directory
|
|
||||||
bool DirectoryIterator::IsDirectory() const {
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
return (data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != FALSE;
|
|
||||||
#else
|
|
||||||
return S_ISDIR(stat_.st_mode);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns the name of the file currently pointed to
|
|
||||||
std::string DirectoryIterator::Name() const {
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
return ToUtf8(data_.cFileName);
|
|
||||||
#else
|
|
||||||
assert(dirent_ != NULL);
|
|
||||||
return dirent_->d_name;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns the size of the file currently pointed to
|
|
||||||
size_t DirectoryIterator::FileSize() const {
|
|
||||||
#if !defined(WEBRTC_WIN)
|
|
||||||
return stat_.st_size;
|
|
||||||
#else
|
|
||||||
return data_.nFileSizeLow;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns the last modified time of this file
|
|
||||||
time_t DirectoryIterator::FileModifyTime() const {
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
time_t val;
|
|
||||||
FileTimeToUnixTime(data_.ftLastWriteTime, &val);
|
|
||||||
return val;
|
|
||||||
#else
|
|
||||||
return stat_.st_mtime;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
FilesystemInterface* Filesystem::default_filesystem_ = NULL;
|
|
||||||
|
|
||||||
FilesystemInterface *Filesystem::EnsureDefaultFilesystem() {
|
|
||||||
if (!default_filesystem_) {
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
default_filesystem_ = new Win32Filesystem();
|
|
||||||
#else
|
|
||||||
default_filesystem_ = new UnixFilesystem();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return default_filesystem_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FilesystemInterface::CopyFolder(const Pathname &old_path,
|
|
||||||
const Pathname &new_path) {
|
|
||||||
bool success = true;
|
|
||||||
VERIFY(IsFolder(old_path));
|
|
||||||
Pathname new_dir;
|
|
||||||
new_dir.SetFolder(new_path.pathname());
|
|
||||||
Pathname old_dir;
|
|
||||||
old_dir.SetFolder(old_path.pathname());
|
|
||||||
if (!CreateFolder(new_dir))
|
|
||||||
return false;
|
|
||||||
DirectoryIterator *di = IterateDirectory();
|
|
||||||
if (!di)
|
|
||||||
return false;
|
|
||||||
if (di->Iterate(old_dir.pathname())) {
|
|
||||||
do {
|
|
||||||
if (di->Name() == "." || di->Name() == "..")
|
|
||||||
continue;
|
|
||||||
Pathname source;
|
|
||||||
Pathname dest;
|
|
||||||
source.SetFolder(old_dir.pathname());
|
|
||||||
dest.SetFolder(new_path.pathname());
|
|
||||||
source.SetFilename(di->Name());
|
|
||||||
dest.SetFilename(di->Name());
|
|
||||||
if (!CopyFileOrFolder(source, dest))
|
|
||||||
success = false;
|
|
||||||
} while (di->Next());
|
|
||||||
}
|
|
||||||
delete di;
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FilesystemInterface::DeleteFolderContents(const Pathname &folder) {
|
|
||||||
bool success = true;
|
|
||||||
VERIFY(IsFolder(folder));
|
|
||||||
DirectoryIterator *di = IterateDirectory();
|
|
||||||
if (!di)
|
|
||||||
return false;
|
|
||||||
if (di->Iterate(folder)) {
|
|
||||||
do {
|
|
||||||
if (di->Name() == "." || di->Name() == "..")
|
|
||||||
continue;
|
|
||||||
Pathname subdir;
|
|
||||||
subdir.SetFolder(folder.pathname());
|
|
||||||
if (di->IsDirectory()) {
|
|
||||||
subdir.AppendFolder(di->Name());
|
|
||||||
if (!DeleteFolderAndContents(subdir)) {
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
subdir.SetFilename(di->Name());
|
|
||||||
if (!DeleteFile(subdir)) {
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (di->Next());
|
|
||||||
}
|
|
||||||
delete di;
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FilesystemInterface::CleanAppTempFolder() {
|
|
||||||
Pathname path;
|
|
||||||
if (!GetAppTempFolder(&path))
|
|
||||||
return false;
|
|
||||||
if (IsAbsent(path))
|
|
||||||
return true;
|
|
||||||
if (!IsTemporaryPath(path)) {
|
|
||||||
ASSERT(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return DeleteFolderContents(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pathname Filesystem::GetCurrentDirectory() {
|
|
||||||
return EnsureDefaultFilesystem()->GetCurrentDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CreateUniqueFile(Pathname& path, bool create_empty) {
|
|
||||||
LOG(LS_INFO) << "Path " << path.pathname() << std::endl;
|
|
||||||
// If no folder is supplied, use the temporary folder
|
|
||||||
if (path.folder().empty()) {
|
|
||||||
Pathname temporary_path;
|
|
||||||
if (!Filesystem::GetTemporaryFolder(temporary_path, true, NULL)) {
|
|
||||||
printf("Get temp failed\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
path.SetFolder(temporary_path.pathname());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no filename is supplied, use a temporary name
|
|
||||||
if (path.filename().empty()) {
|
|
||||||
std::string folder(path.folder());
|
|
||||||
std::string filename = Filesystem::TempFilename(folder, "gt");
|
|
||||||
path.SetPathname(filename);
|
|
||||||
if (!create_empty) {
|
|
||||||
Filesystem::DeleteFile(path.pathname());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, create a unique name based on the given filename
|
|
||||||
// foo.txt -> foo-N.txt
|
|
||||||
const std::string basename = path.basename();
|
|
||||||
const size_t MAX_VERSION = 100;
|
|
||||||
size_t version = 0;
|
|
||||||
while (version < MAX_VERSION) {
|
|
||||||
std::string pathname = path.pathname();
|
|
||||||
|
|
||||||
if (!Filesystem::IsFile(pathname)) {
|
|
||||||
if (create_empty) {
|
|
||||||
FileStream* fs = Filesystem::OpenFile(pathname, "w");
|
|
||||||
delete fs;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
version += 1;
|
|
||||||
char version_base[MAX_PATH];
|
|
||||||
sprintfn(version_base, ARRAY_SIZE(version_base), "%s-%u",
|
|
||||||
basename.c_str(), version);
|
|
||||||
path.SetBasename(version_base);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Taken from Chromium's base/platform_file_*.cc.
|
|
||||||
// TODO(grunell): Remove when Chromium has started to use AEC in each source.
|
|
||||||
// http://crbug.com/264611.
|
|
||||||
FILE* FdopenPlatformFileForWriting(PlatformFile file) {
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
if (file == kInvalidPlatformFileValue)
|
|
||||||
return NULL;
|
|
||||||
int fd = _open_osfhandle(reinterpret_cast<intptr_t>(file), 0);
|
|
||||||
if (fd < 0)
|
|
||||||
return NULL;
|
|
||||||
return _fdopen(fd, "w");
|
|
||||||
#else
|
|
||||||
return fdopen(file, "w");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClosePlatformFile(PlatformFile file) {
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
return CloseHandle(file) != 0;
|
|
||||||
#else
|
|
||||||
return close(file);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,459 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_FILEUTILS_H_
|
|
||||||
#define WEBRTC_BASE_FILEUTILS_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#include "webrtc/base/win32.h"
|
|
||||||
#else
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class FileStream;
|
|
||||||
class Pathname;
|
|
||||||
|
|
||||||
//////////////////////////
|
|
||||||
// Directory Iterator //
|
|
||||||
//////////////////////////
|
|
||||||
|
|
||||||
// A DirectoryIterator is created with a given directory. It originally points
|
|
||||||
// to the first file in the directory, and can be advanecd with Next(). This
|
|
||||||
// allows you to get information about each file.
|
|
||||||
|
|
||||||
class DirectoryIterator {
|
|
||||||
friend class Filesystem;
|
|
||||||
public:
|
|
||||||
// Constructor
|
|
||||||
DirectoryIterator();
|
|
||||||
// Destructor
|
|
||||||
virtual ~DirectoryIterator();
|
|
||||||
|
|
||||||
// Starts traversing a directory
|
|
||||||
// dir is the directory to traverse
|
|
||||||
// returns true if the directory exists and is valid
|
|
||||||
// The iterator will point to the first entry in the directory
|
|
||||||
virtual bool Iterate(const Pathname &path);
|
|
||||||
|
|
||||||
// Advances to the next file
|
|
||||||
// returns true if there were more files in the directory.
|
|
||||||
virtual bool Next();
|
|
||||||
|
|
||||||
// returns true if the file currently pointed to is a directory
|
|
||||||
virtual bool IsDirectory() const;
|
|
||||||
|
|
||||||
// returns the name of the file currently pointed to
|
|
||||||
virtual std::string Name() const;
|
|
||||||
|
|
||||||
// returns the size of the file currently pointed to
|
|
||||||
virtual size_t FileSize() const;
|
|
||||||
|
|
||||||
// returns the last modified time of the file currently pointed to
|
|
||||||
virtual time_t FileModifyTime() const;
|
|
||||||
|
|
||||||
// checks whether current file is a special directory file "." or ".."
|
|
||||||
bool IsDots() const {
|
|
||||||
std::string filename(Name());
|
|
||||||
return (filename.compare(".") == 0) || (filename.compare("..") == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string directory_;
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
WIN32_FIND_DATA data_;
|
|
||||||
HANDLE handle_;
|
|
||||||
#else
|
|
||||||
DIR *dir_;
|
|
||||||
struct dirent *dirent_;
|
|
||||||
struct stat stat_;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
enum FileTimeType { FTT_CREATED, FTT_MODIFIED, FTT_ACCESSED };
|
|
||||||
|
|
||||||
class FilesystemInterface {
|
|
||||||
public:
|
|
||||||
virtual ~FilesystemInterface() {}
|
|
||||||
|
|
||||||
// Returns a DirectoryIterator for a given pathname.
|
|
||||||
// TODO: Do fancy abstracted stuff
|
|
||||||
virtual DirectoryIterator *IterateDirectory() {
|
|
||||||
return new DirectoryIterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Opens a file. Returns an open StreamInterface if function succeeds.
|
|
||||||
// Otherwise, returns NULL.
|
|
||||||
// TODO: Add an error param to indicate failure reason, similar to
|
|
||||||
// FileStream::Open
|
|
||||||
virtual FileStream *OpenFile(const Pathname &filename,
|
|
||||||
const std::string &mode) = 0;
|
|
||||||
|
|
||||||
// Atomically creates an empty file accessible only to the current user if one
|
|
||||||
// does not already exist at the given path, otherwise fails. This is the only
|
|
||||||
// secure way to create a file in a shared temp directory (e.g., C:\Temp on
|
|
||||||
// Windows or /tmp on Linux).
|
|
||||||
// Note that if it is essential that a file be successfully created then the
|
|
||||||
// app must generate random names and retry on failure, or else it will be
|
|
||||||
// vulnerable to a trivial DoS.
|
|
||||||
virtual bool CreatePrivateFile(const Pathname &filename) = 0;
|
|
||||||
|
|
||||||
// This will attempt to delete the path located at filename.
|
|
||||||
// It ASSERTS and returns false if the path points to a folder or a
|
|
||||||
// non-existent file.
|
|
||||||
virtual bool DeleteFile(const Pathname &filename) = 0;
|
|
||||||
|
|
||||||
// This will attempt to delete the empty folder located at 'folder'
|
|
||||||
// It ASSERTS and returns false if the path points to a file or a non-existent
|
|
||||||
// folder. It fails normally if the folder is not empty or can otherwise
|
|
||||||
// not be deleted.
|
|
||||||
virtual bool DeleteEmptyFolder(const Pathname &folder) = 0;
|
|
||||||
|
|
||||||
// This will call IterateDirectory, to get a directory iterator, and then
|
|
||||||
// call DeleteFolderAndContents and DeleteFile on every path contained in this
|
|
||||||
// folder. If the folder is empty, this returns true.
|
|
||||||
virtual bool DeleteFolderContents(const Pathname &folder);
|
|
||||||
|
|
||||||
// This deletes the contents of a folder, recursively, and then deletes
|
|
||||||
// the folder itself.
|
|
||||||
virtual bool DeleteFolderAndContents(const Pathname &folder) {
|
|
||||||
return DeleteFolderContents(folder) && DeleteEmptyFolder(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This will delete whatever is located at path, be it a file or a folder.
|
|
||||||
// If it is a folder, it will delete it recursively by calling
|
|
||||||
// DeleteFolderAndContents
|
|
||||||
bool DeleteFileOrFolder(const Pathname &path) {
|
|
||||||
if (IsFolder(path))
|
|
||||||
return DeleteFolderAndContents(path);
|
|
||||||
else
|
|
||||||
return DeleteFile(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a directory. This will call itself recursively to create /foo/bar
|
|
||||||
// even if /foo does not exist. Returns true if the function succeeds.
|
|
||||||
virtual bool CreateFolder(const Pathname &pathname) = 0;
|
|
||||||
|
|
||||||
// This moves a file from old_path to new_path, where "old_path" is a
|
|
||||||
// plain file. This ASSERTs and returns false if old_path points to a
|
|
||||||
// directory, and returns true if the function succeeds.
|
|
||||||
// If the new path is on a different volume than the old path, this function
|
|
||||||
// will attempt to copy and, if that succeeds, delete the old path.
|
|
||||||
virtual bool MoveFolder(const Pathname &old_path,
|
|
||||||
const Pathname &new_path) = 0;
|
|
||||||
|
|
||||||
// This moves a directory from old_path to new_path, where "old_path" is a
|
|
||||||
// directory. This ASSERTs and returns false if old_path points to a plain
|
|
||||||
// file, and returns true if the function succeeds.
|
|
||||||
// If the new path is on a different volume, this function will attempt to
|
|
||||||
// copy and if that succeeds, delete the old path.
|
|
||||||
virtual bool MoveFile(const Pathname &old_path, const Pathname &new_path) = 0;
|
|
||||||
|
|
||||||
// This attempts to move whatever is located at old_path to new_path,
|
|
||||||
// be it a file or folder.
|
|
||||||
bool MoveFileOrFolder(const Pathname &old_path, const Pathname &new_path) {
|
|
||||||
if (IsFile(old_path)) {
|
|
||||||
return MoveFile(old_path, new_path);
|
|
||||||
} else {
|
|
||||||
return MoveFolder(old_path, new_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This copies a file from old_path to new_path. This method ASSERTs and
|
|
||||||
// returns false if old_path is a folder, and returns true if the copy
|
|
||||||
// succeeds.
|
|
||||||
virtual bool CopyFile(const Pathname &old_path, const Pathname &new_path) = 0;
|
|
||||||
|
|
||||||
// This copies a folder from old_path to new_path.
|
|
||||||
bool CopyFolder(const Pathname &old_path, const Pathname &new_path);
|
|
||||||
|
|
||||||
bool CopyFileOrFolder(const Pathname &old_path, const Pathname &new_path) {
|
|
||||||
if (IsFile(old_path))
|
|
||||||
return CopyFile(old_path, new_path);
|
|
||||||
else
|
|
||||||
return CopyFolder(old_path, new_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if pathname refers to a directory
|
|
||||||
virtual bool IsFolder(const Pathname& pathname) = 0;
|
|
||||||
|
|
||||||
// Returns true if pathname refers to a file
|
|
||||||
virtual bool IsFile(const Pathname& pathname) = 0;
|
|
||||||
|
|
||||||
// Returns true if pathname refers to no filesystem object, every parent
|
|
||||||
// directory either exists, or is also absent.
|
|
||||||
virtual bool IsAbsent(const Pathname& pathname) = 0;
|
|
||||||
|
|
||||||
// Returns true if pathname represents a temporary location on the system.
|
|
||||||
virtual bool IsTemporaryPath(const Pathname& pathname) = 0;
|
|
||||||
|
|
||||||
// A folder appropriate for storing temporary files (Contents are
|
|
||||||
// automatically deleted when the program exits)
|
|
||||||
virtual bool GetTemporaryFolder(Pathname &path, bool create,
|
|
||||||
const std::string *append) = 0;
|
|
||||||
|
|
||||||
virtual std::string TempFilename(const Pathname &dir,
|
|
||||||
const std::string &prefix) = 0;
|
|
||||||
|
|
||||||
// Determines the size of the file indicated by path.
|
|
||||||
virtual bool GetFileSize(const Pathname& path, size_t* size) = 0;
|
|
||||||
|
|
||||||
// Determines a timestamp associated with the file indicated by path.
|
|
||||||
virtual bool GetFileTime(const Pathname& path, FileTimeType which,
|
|
||||||
time_t* time) = 0;
|
|
||||||
|
|
||||||
// Returns the path to the running application.
|
|
||||||
// Note: This is not guaranteed to work on all platforms. Be aware of the
|
|
||||||
// limitations before using it, and robustly handle failure.
|
|
||||||
virtual bool GetAppPathname(Pathname* path) = 0;
|
|
||||||
|
|
||||||
// Get a folder that is unique to the current application, which is suitable
|
|
||||||
// for sharing data between executions of the app. If the per_user arg is
|
|
||||||
// true, the folder is also specific to the current user.
|
|
||||||
virtual bool GetAppDataFolder(Pathname* path, bool per_user) = 0;
|
|
||||||
|
|
||||||
// Get a temporary folder that is unique to the current user and application.
|
|
||||||
// TODO: Re-evaluate the goals of this function. We probably just need any
|
|
||||||
// directory that won't collide with another existing directory, and which
|
|
||||||
// will be cleaned up when the program exits.
|
|
||||||
virtual bool GetAppTempFolder(Pathname* path) = 0;
|
|
||||||
|
|
||||||
// Delete the contents of the folder returned by GetAppTempFolder
|
|
||||||
bool CleanAppTempFolder();
|
|
||||||
|
|
||||||
virtual bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes) = 0;
|
|
||||||
|
|
||||||
// Returns the absolute path of the current directory.
|
|
||||||
virtual Pathname GetCurrentDirectory() = 0;
|
|
||||||
|
|
||||||
// Note: These might go into some shared config section later, but they're
|
|
||||||
// used by some methods in this interface, so we're leaving them here for now.
|
|
||||||
void SetOrganizationName(const std::string& organization) {
|
|
||||||
organization_name_ = organization;
|
|
||||||
}
|
|
||||||
void GetOrganizationName(std::string* organization) {
|
|
||||||
ASSERT(NULL != organization);
|
|
||||||
*organization = organization_name_;
|
|
||||||
}
|
|
||||||
void SetApplicationName(const std::string& application) {
|
|
||||||
application_name_ = application;
|
|
||||||
}
|
|
||||||
void GetApplicationName(std::string* application) {
|
|
||||||
ASSERT(NULL != application);
|
|
||||||
*application = application_name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::string organization_name_;
|
|
||||||
std::string application_name_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Filesystem {
|
|
||||||
public:
|
|
||||||
static FilesystemInterface *default_filesystem() {
|
|
||||||
ASSERT(default_filesystem_ != NULL);
|
|
||||||
return default_filesystem_;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_default_filesystem(FilesystemInterface *filesystem) {
|
|
||||||
default_filesystem_ = filesystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
static FilesystemInterface *swap_default_filesystem(
|
|
||||||
FilesystemInterface *filesystem) {
|
|
||||||
FilesystemInterface *cur = default_filesystem_;
|
|
||||||
default_filesystem_ = filesystem;
|
|
||||||
return cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DirectoryIterator *IterateDirectory() {
|
|
||||||
return EnsureDefaultFilesystem()->IterateDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool CreateFolder(const Pathname &pathname) {
|
|
||||||
return EnsureDefaultFilesystem()->CreateFolder(pathname);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FileStream *OpenFile(const Pathname &filename,
|
|
||||||
const std::string &mode) {
|
|
||||||
return EnsureDefaultFilesystem()->OpenFile(filename, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool CreatePrivateFile(const Pathname &filename) {
|
|
||||||
return EnsureDefaultFilesystem()->CreatePrivateFile(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool DeleteFile(const Pathname &filename) {
|
|
||||||
return EnsureDefaultFilesystem()->DeleteFile(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool DeleteEmptyFolder(const Pathname &folder) {
|
|
||||||
return EnsureDefaultFilesystem()->DeleteEmptyFolder(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool DeleteFolderContents(const Pathname &folder) {
|
|
||||||
return EnsureDefaultFilesystem()->DeleteFolderContents(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool DeleteFolderAndContents(const Pathname &folder) {
|
|
||||||
return EnsureDefaultFilesystem()->DeleteFolderAndContents(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool MoveFolder(const Pathname &old_path, const Pathname &new_path) {
|
|
||||||
return EnsureDefaultFilesystem()->MoveFolder(old_path, new_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool MoveFile(const Pathname &old_path, const Pathname &new_path) {
|
|
||||||
return EnsureDefaultFilesystem()->MoveFile(old_path, new_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool CopyFolder(const Pathname &old_path, const Pathname &new_path) {
|
|
||||||
return EnsureDefaultFilesystem()->CopyFolder(old_path, new_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool CopyFile(const Pathname &old_path, const Pathname &new_path) {
|
|
||||||
return EnsureDefaultFilesystem()->CopyFile(old_path, new_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsFolder(const Pathname& pathname) {
|
|
||||||
return EnsureDefaultFilesystem()->IsFolder(pathname);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsFile(const Pathname &pathname) {
|
|
||||||
return EnsureDefaultFilesystem()->IsFile(pathname);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsAbsent(const Pathname &pathname) {
|
|
||||||
return EnsureDefaultFilesystem()->IsAbsent(pathname);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsTemporaryPath(const Pathname& pathname) {
|
|
||||||
return EnsureDefaultFilesystem()->IsTemporaryPath(pathname);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetTemporaryFolder(Pathname &path, bool create,
|
|
||||||
const std::string *append) {
|
|
||||||
return EnsureDefaultFilesystem()->GetTemporaryFolder(path, create, append);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string TempFilename(const Pathname &dir,
|
|
||||||
const std::string &prefix) {
|
|
||||||
return EnsureDefaultFilesystem()->TempFilename(dir, prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetFileSize(const Pathname& path, size_t* size) {
|
|
||||||
return EnsureDefaultFilesystem()->GetFileSize(path, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetFileTime(const Pathname& path, FileTimeType which,
|
|
||||||
time_t* time) {
|
|
||||||
return EnsureDefaultFilesystem()->GetFileTime(path, which, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetAppPathname(Pathname* path) {
|
|
||||||
return EnsureDefaultFilesystem()->GetAppPathname(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetAppDataFolder(Pathname* path, bool per_user) {
|
|
||||||
return EnsureDefaultFilesystem()->GetAppDataFolder(path, per_user);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetAppTempFolder(Pathname* path) {
|
|
||||||
return EnsureDefaultFilesystem()->GetAppTempFolder(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool CleanAppTempFolder() {
|
|
||||||
return EnsureDefaultFilesystem()->CleanAppTempFolder();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool GetDiskFreeSpace(const Pathname& path, int64 *freebytes) {
|
|
||||||
return EnsureDefaultFilesystem()->GetDiskFreeSpace(path, freebytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Definition has to be in the .cc file due to returning forward-declared
|
|
||||||
// Pathname by value.
|
|
||||||
static Pathname GetCurrentDirectory();
|
|
||||||
|
|
||||||
static void SetOrganizationName(const std::string& organization) {
|
|
||||||
EnsureDefaultFilesystem()->SetOrganizationName(organization);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void GetOrganizationName(std::string* organization) {
|
|
||||||
EnsureDefaultFilesystem()->GetOrganizationName(organization);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SetApplicationName(const std::string& application) {
|
|
||||||
EnsureDefaultFilesystem()->SetApplicationName(application);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void GetApplicationName(std::string* application) {
|
|
||||||
EnsureDefaultFilesystem()->GetApplicationName(application);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static FilesystemInterface* default_filesystem_;
|
|
||||||
|
|
||||||
static FilesystemInterface *EnsureDefaultFilesystem();
|
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Filesystem);
|
|
||||||
};
|
|
||||||
|
|
||||||
class FilesystemScope{
|
|
||||||
public:
|
|
||||||
explicit FilesystemScope(FilesystemInterface *new_fs) {
|
|
||||||
old_fs_ = Filesystem::swap_default_filesystem(new_fs);
|
|
||||||
}
|
|
||||||
~FilesystemScope() {
|
|
||||||
Filesystem::set_default_filesystem(old_fs_);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
FilesystemInterface* old_fs_;
|
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(FilesystemScope);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generates a unique filename based on the input path. If no path component
|
|
||||||
// is specified, it uses the temporary directory. If a filename is provided,
|
|
||||||
// up to 100 variations of form basename-N.extension are tried. When
|
|
||||||
// create_empty is true, an empty file of this name is created (which
|
|
||||||
// decreases the chance of a temporary filename collision with another
|
|
||||||
// process).
|
|
||||||
bool CreateUniqueFile(Pathname& path, bool create_empty);
|
|
||||||
|
|
||||||
// Taken from Chromium's base/platform_file.h.
|
|
||||||
// Don't use ClosePlatformFile to close a file opened with FdopenPlatformFile.
|
|
||||||
// Use fclose instead.
|
|
||||||
// TODO(grunell): Remove when Chromium has started to use AEC in each source.
|
|
||||||
// http://crbug.com/264611.
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
typedef HANDLE PlatformFile;
|
|
||||||
const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
|
|
||||||
#elif defined(WEBRTC_POSIX)
|
|
||||||
typedef int PlatformFile;
|
|
||||||
const PlatformFile kInvalidPlatformFileValue = -1;
|
|
||||||
#else
|
|
||||||
#error Unsupported platform
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FILE* FdopenPlatformFileForWriting(PlatformFile file);
|
|
||||||
bool ClosePlatformFile(PlatformFile file);
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_FILEUTILS_H_
|
|
@ -1,253 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_FILEUTILS_MOCK_H_
|
|
||||||
#define WEBRTC_BASE_FILEUTILS_MOCK_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "webrtc/base/fileutils.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/pathutils.h"
|
|
||||||
#include "webrtc/base/stream.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class FakeFileStream : public FileStream {
|
|
||||||
public:
|
|
||||||
explicit FakeFileStream(const std::string & contents) :
|
|
||||||
string_stream_(contents)
|
|
||||||
{}
|
|
||||||
|
|
||||||
virtual StreamResult Read(void* buffer, size_t buffer_len,
|
|
||||||
size_t* read, int* error) {
|
|
||||||
return string_stream_.Read(buffer, buffer_len, read, error);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void Close() {
|
|
||||||
return string_stream_.Close();
|
|
||||||
}
|
|
||||||
virtual bool GetSize(size_t* size) const {
|
|
||||||
return string_stream_.GetSize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
StringStream string_stream_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FakeDirectoryIterator : public DirectoryIterator {
|
|
||||||
public:
|
|
||||||
typedef std::pair<std::string, std::string> File;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* files should be sorted by directory
|
|
||||||
* put '/' at the end of file if you want it to be a directory
|
|
||||||
*
|
|
||||||
* Sample list:
|
|
||||||
* /var/dir/file1
|
|
||||||
* /var/dir/file2
|
|
||||||
* /var/dir/subdir1/
|
|
||||||
* /var/dir/subdir2/
|
|
||||||
* /var/dir2/file2
|
|
||||||
* /var/dir3/
|
|
||||||
*
|
|
||||||
* you can call Iterate for any path: /var, /var/dir, /var/dir2
|
|
||||||
* unrelated files will be ignored
|
|
||||||
*/
|
|
||||||
explicit FakeDirectoryIterator(const std::vector<File>& all_files) :
|
|
||||||
all_files_(all_files) {}
|
|
||||||
|
|
||||||
virtual bool Iterate(const Pathname& path) {
|
|
||||||
path_iterator_ = all_files_.begin();
|
|
||||||
path_ = path.pathname();
|
|
||||||
|
|
||||||
// make sure path ends end with '/'
|
|
||||||
if (path_.rfind(Pathname::DefaultFolderDelimiter()) != path_.size() - 1)
|
|
||||||
path_ += Pathname::DefaultFolderDelimiter();
|
|
||||||
|
|
||||||
return FakeDirectoryIterator::Search(std::string(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool Next() {
|
|
||||||
std::string current_name = Name();
|
|
||||||
path_iterator_++;
|
|
||||||
return FakeDirectoryIterator::Search(current_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Search(const std::string& current_name) {
|
|
||||||
for (; path_iterator_ != all_files_.end(); path_iterator_++) {
|
|
||||||
if (path_iterator_->first.find(path_) == 0
|
|
||||||
&& Name().compare(current_name) != 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool IsDirectory() const {
|
|
||||||
std::string sub_path = path_iterator_->first;
|
|
||||||
|
|
||||||
return std::string::npos !=
|
|
||||||
sub_path.find(Pathname::DefaultFolderDelimiter(), path_.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::string Name() const {
|
|
||||||
std::string sub_path = path_iterator_->first;
|
|
||||||
|
|
||||||
// path - top level path (ex. /var/lib)
|
|
||||||
// sub_path - subpath under top level path (ex. /var/lib/dir/dir/file )
|
|
||||||
// find shortest non-trivial common path. (ex. /var/lib/dir)
|
|
||||||
size_t start = path_.size();
|
|
||||||
size_t end = sub_path.find(Pathname::DefaultFolderDelimiter(), start);
|
|
||||||
|
|
||||||
if (end != std::string::npos) {
|
|
||||||
return sub_path.substr(start, end - start);
|
|
||||||
} else {
|
|
||||||
return sub_path.substr(start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const std::vector<File> all_files_;
|
|
||||||
|
|
||||||
std::string path_;
|
|
||||||
std::vector<File>::const_iterator path_iterator_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FakeFileSystem : public FilesystemInterface {
|
|
||||||
public:
|
|
||||||
typedef std::pair<std::string, std::string> File;
|
|
||||||
|
|
||||||
explicit FakeFileSystem(const std::vector<File>& all_files) :
|
|
||||||
all_files_(all_files) {}
|
|
||||||
|
|
||||||
virtual DirectoryIterator *IterateDirectory() {
|
|
||||||
return new FakeDirectoryIterator(all_files_);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual FileStream * OpenFile(
|
|
||||||
const Pathname &filename,
|
|
||||||
const std::string &mode) {
|
|
||||||
std::vector<File>::const_iterator i_files = all_files_.begin();
|
|
||||||
std::string path = filename.pathname();
|
|
||||||
|
|
||||||
for (; i_files != all_files_.end(); i_files++) {
|
|
||||||
if (i_files->first.compare(path) == 0) {
|
|
||||||
return new FakeFileStream(i_files->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CreatePrivateFile(const Pathname &filename) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool DeleteFile(const Pathname &filename) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool DeleteEmptyFolder(const Pathname &folder) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool DeleteFolderContents(const Pathname &folder) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool DeleteFolderAndContents(const Pathname &folder) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool CreateFolder(const Pathname &pathname) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool MoveFolder(const Pathname &old_path, const Pathname &new_path) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool MoveFile(const Pathname &old_path, const Pathname &new_path) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool CopyFile(const Pathname &old_path, const Pathname &new_path) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool IsFolder(const Pathname &pathname) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool IsFile(const Pathname &pathname) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool IsAbsent(const Pathname &pathname) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool IsTemporaryPath(const Pathname &pathname) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool GetTemporaryFolder(Pathname &path, bool create,
|
|
||||||
const std::string *append) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
std::string TempFilename(const Pathname &dir, const std::string &prefix) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
bool GetFileSize(const Pathname &path, size_t *size) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool GetFileTime(const Pathname &path, FileTimeType which,
|
|
||||||
time_t* time) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool GetAppPathname(Pathname *path) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool GetAppDataFolder(Pathname *path, bool per_user) {
|
|
||||||
EXPECT_TRUE(per_user) << "Unsupported operation";
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
path->SetPathname("c:\\Users\\test_user", "");
|
|
||||||
#else
|
|
||||||
path->SetPathname("/home/user/test_user", "");
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool GetAppTempFolder(Pathname *path) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool GetDiskFreeSpace(const Pathname &path, int64 *freebytes) {
|
|
||||||
EXPECT_TRUE(false) << "Unsupported operation";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Pathname GetCurrentDirectory() {
|
|
||||||
return Pathname();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const std::vector<File> all_files_;
|
|
||||||
};
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_FILEUTILS_MOCK_H_
|
|
@ -1,131 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/fileutils.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/pathutils.h"
|
|
||||||
#include "webrtc/base/stream.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Make sure we can get a temp folder for the later tests.
|
|
||||||
TEST(FilesystemTest, GetTemporaryFolder) {
|
|
||||||
Pathname path;
|
|
||||||
EXPECT_TRUE(Filesystem::GetTemporaryFolder(path, true, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test creating a temp file, reading it back in, and deleting it.
|
|
||||||
TEST(FilesystemTest, TestOpenFile) {
|
|
||||||
Pathname path;
|
|
||||||
EXPECT_TRUE(Filesystem::GetTemporaryFolder(path, true, NULL));
|
|
||||||
path.SetPathname(Filesystem::TempFilename(path, "ut"));
|
|
||||||
|
|
||||||
FileStream* fs;
|
|
||||||
char buf[256];
|
|
||||||
size_t bytes;
|
|
||||||
|
|
||||||
fs = Filesystem::OpenFile(path, "wb");
|
|
||||||
ASSERT_TRUE(fs != NULL);
|
|
||||||
EXPECT_EQ(SR_SUCCESS, fs->Write("test", 4, &bytes, NULL));
|
|
||||||
EXPECT_EQ(4U, bytes);
|
|
||||||
delete fs;
|
|
||||||
|
|
||||||
EXPECT_TRUE(Filesystem::IsFile(path));
|
|
||||||
|
|
||||||
fs = Filesystem::OpenFile(path, "rb");
|
|
||||||
ASSERT_TRUE(fs != NULL);
|
|
||||||
EXPECT_EQ(SR_SUCCESS, fs->Read(buf, sizeof(buf), &bytes, NULL));
|
|
||||||
EXPECT_EQ(4U, bytes);
|
|
||||||
delete fs;
|
|
||||||
|
|
||||||
EXPECT_TRUE(Filesystem::DeleteFile(path));
|
|
||||||
EXPECT_FALSE(Filesystem::IsFile(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test opening a non-existent file.
|
|
||||||
TEST(FilesystemTest, TestOpenBadFile) {
|
|
||||||
Pathname path;
|
|
||||||
EXPECT_TRUE(Filesystem::GetTemporaryFolder(path, true, NULL));
|
|
||||||
path.SetFilename("not an actual file");
|
|
||||||
|
|
||||||
EXPECT_FALSE(Filesystem::IsFile(path));
|
|
||||||
|
|
||||||
FileStream* fs = Filesystem::OpenFile(path, "rb");
|
|
||||||
EXPECT_FALSE(fs != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that CreatePrivateFile fails for existing files and succeeds for
|
|
||||||
// non-existent ones.
|
|
||||||
TEST(FilesystemTest, TestCreatePrivateFile) {
|
|
||||||
Pathname path;
|
|
||||||
EXPECT_TRUE(Filesystem::GetTemporaryFolder(path, true, NULL));
|
|
||||||
path.SetFilename("private_file_test");
|
|
||||||
|
|
||||||
// First call should succeed because the file doesn't exist yet.
|
|
||||||
EXPECT_TRUE(Filesystem::CreatePrivateFile(path));
|
|
||||||
// Next call should fail, because now it exists.
|
|
||||||
EXPECT_FALSE(Filesystem::CreatePrivateFile(path));
|
|
||||||
|
|
||||||
// Verify that we have permission to open the file for reading and writing.
|
|
||||||
scoped_ptr<FileStream> fs(Filesystem::OpenFile(path, "wb"));
|
|
||||||
EXPECT_TRUE(fs.get() != NULL);
|
|
||||||
// Have to close the file on Windows before it will let us delete it.
|
|
||||||
fs.reset();
|
|
||||||
|
|
||||||
// Verify that we have permission to delete the file.
|
|
||||||
EXPECT_TRUE(Filesystem::DeleteFile(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test checking for free disk space.
|
|
||||||
TEST(FilesystemTest, TestGetDiskFreeSpace) {
|
|
||||||
// Note that we should avoid picking any file/folder which could be located
|
|
||||||
// at the remotely mounted drive/device.
|
|
||||||
Pathname path;
|
|
||||||
ASSERT_TRUE(Filesystem::GetAppDataFolder(&path, true));
|
|
||||||
|
|
||||||
int64 free1 = 0;
|
|
||||||
EXPECT_TRUE(Filesystem::IsFolder(path));
|
|
||||||
EXPECT_FALSE(Filesystem::IsFile(path));
|
|
||||||
EXPECT_TRUE(Filesystem::GetDiskFreeSpace(path, &free1));
|
|
||||||
EXPECT_GT(free1, 0);
|
|
||||||
|
|
||||||
int64 free2 = 0;
|
|
||||||
path.AppendFolder("this_folder_doesnt_exist");
|
|
||||||
EXPECT_FALSE(Filesystem::IsFolder(path));
|
|
||||||
EXPECT_TRUE(Filesystem::IsAbsent(path));
|
|
||||||
EXPECT_TRUE(Filesystem::GetDiskFreeSpace(path, &free2));
|
|
||||||
// These should be the same disk, and disk free space should not have changed
|
|
||||||
// by more than 1% between the two calls.
|
|
||||||
EXPECT_LT(static_cast<int64>(free1 * .9), free2);
|
|
||||||
EXPECT_LT(free2, static_cast<int64>(free1 * 1.1));
|
|
||||||
|
|
||||||
int64 free3 = 0;
|
|
||||||
path.clear();
|
|
||||||
EXPECT_TRUE(path.empty());
|
|
||||||
EXPECT_TRUE(Filesystem::GetDiskFreeSpace(path, &free3));
|
|
||||||
// Current working directory may not be where exe is.
|
|
||||||
// EXPECT_LT(static_cast<int64>(free1 * .9), free3);
|
|
||||||
// EXPECT_LT(free3, static_cast<int64>(free1 * 1.1));
|
|
||||||
EXPECT_GT(free3, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests that GetCurrentDirectory() returns something.
|
|
||||||
TEST(FilesystemTest, TestGetCurrentDirectory) {
|
|
||||||
EXPECT_FALSE(Filesystem::GetCurrentDirectory().empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests that GetAppPathname returns something.
|
|
||||||
TEST(FilesystemTest, TestGetAppPathname) {
|
|
||||||
Pathname path;
|
|
||||||
EXPECT_TRUE(Filesystem::GetAppPathname(&path));
|
|
||||||
EXPECT_FALSE(path.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,239 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/firewallsocketserver.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "webrtc/base/asyncsocket.h"
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class FirewallSocket : public AsyncSocketAdapter {
|
|
||||||
public:
|
|
||||||
FirewallSocket(FirewallSocketServer* server, AsyncSocket* socket, int type)
|
|
||||||
: AsyncSocketAdapter(socket), server_(server), type_(type) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int Connect(const SocketAddress& addr) {
|
|
||||||
if (type_ == SOCK_STREAM) {
|
|
||||||
if (!server_->Check(FP_TCP, GetLocalAddress(), addr)) {
|
|
||||||
LOG(LS_VERBOSE) << "FirewallSocket outbound TCP connection from "
|
|
||||||
<< GetLocalAddress().ToSensitiveString() << " to "
|
|
||||||
<< addr.ToSensitiveString() << " denied";
|
|
||||||
// TODO: Handle this asynchronously.
|
|
||||||
SetError(EHOSTUNREACH);
|
|
||||||
return SOCKET_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return AsyncSocketAdapter::Connect(addr);
|
|
||||||
}
|
|
||||||
virtual int Send(const void* pv, size_t cb) {
|
|
||||||
return SendTo(pv, cb, GetRemoteAddress());
|
|
||||||
}
|
|
||||||
virtual int SendTo(const void* pv, size_t cb, const SocketAddress& addr) {
|
|
||||||
if (type_ == SOCK_DGRAM) {
|
|
||||||
if (!server_->Check(FP_UDP, GetLocalAddress(), addr)) {
|
|
||||||
LOG(LS_VERBOSE) << "FirewallSocket outbound UDP packet from "
|
|
||||||
<< GetLocalAddress().ToSensitiveString() << " to "
|
|
||||||
<< addr.ToSensitiveString() << " dropped";
|
|
||||||
return static_cast<int>(cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return AsyncSocketAdapter::SendTo(pv, cb, addr);
|
|
||||||
}
|
|
||||||
virtual int Recv(void* pv, size_t cb) {
|
|
||||||
SocketAddress addr;
|
|
||||||
return RecvFrom(pv, cb, &addr);
|
|
||||||
}
|
|
||||||
virtual int RecvFrom(void* pv, size_t cb, SocketAddress* paddr) {
|
|
||||||
if (type_ == SOCK_DGRAM) {
|
|
||||||
while (true) {
|
|
||||||
int res = AsyncSocketAdapter::RecvFrom(pv, cb, paddr);
|
|
||||||
if (res <= 0)
|
|
||||||
return res;
|
|
||||||
if (server_->Check(FP_UDP, *paddr, GetLocalAddress()))
|
|
||||||
return res;
|
|
||||||
LOG(LS_VERBOSE) << "FirewallSocket inbound UDP packet from "
|
|
||||||
<< paddr->ToSensitiveString() << " to "
|
|
||||||
<< GetLocalAddress().ToSensitiveString() << " dropped";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return AsyncSocketAdapter::RecvFrom(pv, cb, paddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int Listen(int backlog) {
|
|
||||||
if (!server_->tcp_listen_enabled()) {
|
|
||||||
LOG(LS_VERBOSE) << "FirewallSocket listen attempt denied";
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return AsyncSocketAdapter::Listen(backlog);
|
|
||||||
}
|
|
||||||
virtual AsyncSocket* Accept(SocketAddress* paddr) {
|
|
||||||
SocketAddress addr;
|
|
||||||
while (AsyncSocket* sock = AsyncSocketAdapter::Accept(&addr)) {
|
|
||||||
if (server_->Check(FP_TCP, addr, GetLocalAddress())) {
|
|
||||||
if (paddr)
|
|
||||||
*paddr = addr;
|
|
||||||
return sock;
|
|
||||||
}
|
|
||||||
sock->Close();
|
|
||||||
delete sock;
|
|
||||||
LOG(LS_VERBOSE) << "FirewallSocket inbound TCP connection from "
|
|
||||||
<< addr.ToSensitiveString() << " to "
|
|
||||||
<< GetLocalAddress().ToSensitiveString() << " denied";
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
FirewallSocketServer* server_;
|
|
||||||
int type_;
|
|
||||||
};
|
|
||||||
|
|
||||||
FirewallSocketServer::FirewallSocketServer(SocketServer* server,
|
|
||||||
FirewallManager* manager,
|
|
||||||
bool should_delete_server)
|
|
||||||
: server_(server), manager_(manager),
|
|
||||||
should_delete_server_(should_delete_server),
|
|
||||||
udp_sockets_enabled_(true), tcp_sockets_enabled_(true),
|
|
||||||
tcp_listen_enabled_(true) {
|
|
||||||
if (manager_)
|
|
||||||
manager_->AddServer(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
FirewallSocketServer::~FirewallSocketServer() {
|
|
||||||
if (manager_)
|
|
||||||
manager_->RemoveServer(this);
|
|
||||||
|
|
||||||
if (server_ && should_delete_server_) {
|
|
||||||
delete server_;
|
|
||||||
server_ = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p,
|
|
||||||
FirewallDirection d,
|
|
||||||
const SocketAddress& addr) {
|
|
||||||
SocketAddress src, dst;
|
|
||||||
if (d == FD_IN) {
|
|
||||||
dst = addr;
|
|
||||||
} else {
|
|
||||||
src = addr;
|
|
||||||
}
|
|
||||||
AddRule(allow, p, src, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void FirewallSocketServer::AddRule(bool allow, FirewallProtocol p,
|
|
||||||
const SocketAddress& src,
|
|
||||||
const SocketAddress& dst) {
|
|
||||||
Rule r;
|
|
||||||
r.allow = allow;
|
|
||||||
r.p = p;
|
|
||||||
r.src = src;
|
|
||||||
r.dst = dst;
|
|
||||||
CritScope scope(&crit_);
|
|
||||||
rules_.push_back(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FirewallSocketServer::ClearRules() {
|
|
||||||
CritScope scope(&crit_);
|
|
||||||
rules_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FirewallSocketServer::Check(FirewallProtocol p,
|
|
||||||
const SocketAddress& src,
|
|
||||||
const SocketAddress& dst) {
|
|
||||||
CritScope scope(&crit_);
|
|
||||||
for (size_t i = 0; i < rules_.size(); ++i) {
|
|
||||||
const Rule& r = rules_[i];
|
|
||||||
if ((r.p != p) && (r.p != FP_ANY))
|
|
||||||
continue;
|
|
||||||
if ((r.src.ipaddr() != src.ipaddr()) && !r.src.IsNil())
|
|
||||||
continue;
|
|
||||||
if ((r.src.port() != src.port()) && (r.src.port() != 0))
|
|
||||||
continue;
|
|
||||||
if ((r.dst.ipaddr() != dst.ipaddr()) && !r.dst.IsNil())
|
|
||||||
continue;
|
|
||||||
if ((r.dst.port() != dst.port()) && (r.dst.port() != 0))
|
|
||||||
continue;
|
|
||||||
return r.allow;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Socket* FirewallSocketServer::CreateSocket(int type) {
|
|
||||||
return CreateSocket(AF_INET, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
Socket* FirewallSocketServer::CreateSocket(int family, int type) {
|
|
||||||
return WrapSocket(server_->CreateAsyncSocket(family, type), type);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int type) {
|
|
||||||
return CreateAsyncSocket(AF_INET, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncSocket* FirewallSocketServer::CreateAsyncSocket(int family, int type) {
|
|
||||||
return WrapSocket(server_->CreateAsyncSocket(family, type), type);
|
|
||||||
}
|
|
||||||
|
|
||||||
AsyncSocket* FirewallSocketServer::WrapSocket(AsyncSocket* sock, int type) {
|
|
||||||
if (!sock ||
|
|
||||||
(type == SOCK_STREAM && !tcp_sockets_enabled_) ||
|
|
||||||
(type == SOCK_DGRAM && !udp_sockets_enabled_)) {
|
|
||||||
LOG(LS_VERBOSE) << "FirewallSocketServer socket creation denied";
|
|
||||||
delete sock;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return new FirewallSocket(this, sock, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
FirewallManager::FirewallManager() {
|
|
||||||
}
|
|
||||||
|
|
||||||
FirewallManager::~FirewallManager() {
|
|
||||||
assert(servers_.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FirewallManager::AddServer(FirewallSocketServer* server) {
|
|
||||||
CritScope scope(&crit_);
|
|
||||||
servers_.push_back(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FirewallManager::RemoveServer(FirewallSocketServer* server) {
|
|
||||||
CritScope scope(&crit_);
|
|
||||||
servers_.erase(std::remove(servers_.begin(), servers_.end(), server),
|
|
||||||
servers_.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FirewallManager::AddRule(bool allow, FirewallProtocol p,
|
|
||||||
FirewallDirection d, const SocketAddress& addr) {
|
|
||||||
CritScope scope(&crit_);
|
|
||||||
for (std::vector<FirewallSocketServer*>::const_iterator it =
|
|
||||||
servers_.begin(); it != servers_.end(); ++it) {
|
|
||||||
(*it)->AddRule(allow, p, d, addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FirewallManager::ClearRules() {
|
|
||||||
CritScope scope(&crit_);
|
|
||||||
for (std::vector<FirewallSocketServer*>::const_iterator it =
|
|
||||||
servers_.begin(); it != servers_.end(); ++it) {
|
|
||||||
(*it)->ClearRules();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,120 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_FIREWALLSOCKETSERVER_H_
|
|
||||||
#define WEBRTC_BASE_FIREWALLSOCKETSERVER_H_
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include "webrtc/base/socketserver.h"
|
|
||||||
#include "webrtc/base/criticalsection.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class FirewallManager;
|
|
||||||
|
|
||||||
// This SocketServer shim simulates a rule-based firewall server.
|
|
||||||
|
|
||||||
enum FirewallProtocol { FP_UDP, FP_TCP, FP_ANY };
|
|
||||||
enum FirewallDirection { FD_IN, FD_OUT, FD_ANY };
|
|
||||||
|
|
||||||
class FirewallSocketServer : public SocketServer {
|
|
||||||
public:
|
|
||||||
FirewallSocketServer(SocketServer * server,
|
|
||||||
FirewallManager * manager = NULL,
|
|
||||||
bool should_delete_server = false);
|
|
||||||
virtual ~FirewallSocketServer();
|
|
||||||
|
|
||||||
SocketServer* socketserver() const { return server_; }
|
|
||||||
void set_socketserver(SocketServer* server) {
|
|
||||||
if (server_ && should_delete_server_) {
|
|
||||||
delete server_;
|
|
||||||
server_ = NULL;
|
|
||||||
should_delete_server_ = false;
|
|
||||||
}
|
|
||||||
server_ = server;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Settings to control whether CreateSocket or Socket::Listen succeed.
|
|
||||||
void set_udp_sockets_enabled(bool enabled) { udp_sockets_enabled_ = enabled; }
|
|
||||||
void set_tcp_sockets_enabled(bool enabled) { tcp_sockets_enabled_ = enabled; }
|
|
||||||
bool tcp_listen_enabled() const { return tcp_listen_enabled_; }
|
|
||||||
void set_tcp_listen_enabled(bool enabled) { tcp_listen_enabled_ = enabled; }
|
|
||||||
|
|
||||||
// Rules govern the behavior of Connect/Accept/Send/Recv attempts.
|
|
||||||
void AddRule(bool allow, FirewallProtocol p = FP_ANY,
|
|
||||||
FirewallDirection d = FD_ANY,
|
|
||||||
const SocketAddress& addr = SocketAddress());
|
|
||||||
void AddRule(bool allow, FirewallProtocol p,
|
|
||||||
const SocketAddress& src, const SocketAddress& dst);
|
|
||||||
void ClearRules();
|
|
||||||
|
|
||||||
bool Check(FirewallProtocol p,
|
|
||||||
const SocketAddress& src, const SocketAddress& dst);
|
|
||||||
|
|
||||||
virtual Socket* CreateSocket(int type);
|
|
||||||
virtual Socket* CreateSocket(int family, int type);
|
|
||||||
|
|
||||||
virtual AsyncSocket* CreateAsyncSocket(int type);
|
|
||||||
virtual AsyncSocket* CreateAsyncSocket(int family, int type);
|
|
||||||
|
|
||||||
virtual void SetMessageQueue(MessageQueue* queue) {
|
|
||||||
server_->SetMessageQueue(queue);
|
|
||||||
}
|
|
||||||
virtual bool Wait(int cms, bool process_io) {
|
|
||||||
return server_->Wait(cms, process_io);
|
|
||||||
}
|
|
||||||
virtual void WakeUp() {
|
|
||||||
return server_->WakeUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
Socket * WrapSocket(Socket * sock, int type);
|
|
||||||
AsyncSocket * WrapSocket(AsyncSocket * sock, int type);
|
|
||||||
|
|
||||||
private:
|
|
||||||
SocketServer * server_;
|
|
||||||
FirewallManager * manager_;
|
|
||||||
CriticalSection crit_;
|
|
||||||
struct Rule {
|
|
||||||
bool allow;
|
|
||||||
FirewallProtocol p;
|
|
||||||
FirewallDirection d;
|
|
||||||
SocketAddress src;
|
|
||||||
SocketAddress dst;
|
|
||||||
};
|
|
||||||
std::vector<Rule> rules_;
|
|
||||||
bool should_delete_server_;
|
|
||||||
bool udp_sockets_enabled_;
|
|
||||||
bool tcp_sockets_enabled_;
|
|
||||||
bool tcp_listen_enabled_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// FirewallManager allows you to manage firewalls in multiple threads together
|
|
||||||
|
|
||||||
class FirewallManager {
|
|
||||||
public:
|
|
||||||
FirewallManager();
|
|
||||||
~FirewallManager();
|
|
||||||
|
|
||||||
void AddServer(FirewallSocketServer * server);
|
|
||||||
void RemoveServer(FirewallSocketServer * server);
|
|
||||||
|
|
||||||
void AddRule(bool allow, FirewallProtocol p = FP_ANY,
|
|
||||||
FirewallDirection d = FD_ANY,
|
|
||||||
const SocketAddress& addr = SocketAddress());
|
|
||||||
void ClearRules();
|
|
||||||
|
|
||||||
private:
|
|
||||||
CriticalSection crit_;
|
|
||||||
std::vector<FirewallSocketServer *> servers_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_FIREWALLSOCKETSERVER_H_
|
|
@ -1,298 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006 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 <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#include "webrtc/base/win32.h"
|
|
||||||
#include <shellapi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "webrtc/base/flags.h"
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// Implementation of Flag
|
|
||||||
|
|
||||||
Flag::Flag(const char* file, const char* name, const char* comment,
|
|
||||||
Type type, void* variable, FlagValue default__)
|
|
||||||
: file_(file),
|
|
||||||
name_(name),
|
|
||||||
comment_(comment),
|
|
||||||
type_(type),
|
|
||||||
variable_(reinterpret_cast<FlagValue*>(variable)),
|
|
||||||
default_(default__) {
|
|
||||||
FlagList::Register(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Flag::SetToDefault() {
|
|
||||||
// Note that we cannot simply do '*variable_ = default_;' since
|
|
||||||
// flag variables are not really of type FlagValue and thus may
|
|
||||||
// be smaller! The FlagValue union is simply 'overlayed' on top
|
|
||||||
// of a flag variable for convenient access. Since union members
|
|
||||||
// are guarantee to be aligned at the beginning, this works.
|
|
||||||
switch (type_) {
|
|
||||||
case Flag::BOOL:
|
|
||||||
variable_->b = default_.b;
|
|
||||||
return;
|
|
||||||
case Flag::INT:
|
|
||||||
variable_->i = default_.i;
|
|
||||||
return;
|
|
||||||
case Flag::FLOAT:
|
|
||||||
variable_->f = default_.f;
|
|
||||||
return;
|
|
||||||
case Flag::STRING:
|
|
||||||
variable_->s = default_.s;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const char* Type2String(Flag::Type type) {
|
|
||||||
switch (type) {
|
|
||||||
case Flag::BOOL: return "bool";
|
|
||||||
case Flag::INT: return "int";
|
|
||||||
case Flag::FLOAT: return "float";
|
|
||||||
case Flag::STRING: return "string";
|
|
||||||
}
|
|
||||||
UNREACHABLE();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void PrintFlagValue(Flag::Type type, FlagValue* p) {
|
|
||||||
switch (type) {
|
|
||||||
case Flag::BOOL:
|
|
||||||
printf("%s", (p->b ? "true" : "false"));
|
|
||||||
return;
|
|
||||||
case Flag::INT:
|
|
||||||
printf("%d", p->i);
|
|
||||||
return;
|
|
||||||
case Flag::FLOAT:
|
|
||||||
printf("%f", p->f);
|
|
||||||
return;
|
|
||||||
case Flag::STRING:
|
|
||||||
printf("%s", p->s);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Flag::Print(bool print_current_value) {
|
|
||||||
printf(" --%s (%s) type: %s default: ", name_, comment_,
|
|
||||||
Type2String(type_));
|
|
||||||
PrintFlagValue(type_, &default_);
|
|
||||||
if (print_current_value) {
|
|
||||||
printf(" current value: ");
|
|
||||||
PrintFlagValue(type_, variable_);
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// Implementation of FlagList
|
|
||||||
|
|
||||||
Flag* FlagList::list_ = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
FlagList::FlagList() {
|
|
||||||
list_ = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlagList::Print(const char* file, bool print_current_value) {
|
|
||||||
// Since flag registration is likely by file (= C++ file),
|
|
||||||
// we don't need to sort by file and still get grouped output.
|
|
||||||
const char* current = NULL;
|
|
||||||
for (Flag* f = list_; f != NULL; f = f->next()) {
|
|
||||||
if (file == NULL || file == f->file()) {
|
|
||||||
if (current != f->file()) {
|
|
||||||
printf("Flags from %s:\n", f->file());
|
|
||||||
current = f->file();
|
|
||||||
}
|
|
||||||
f->Print(print_current_value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Flag* FlagList::Lookup(const char* name) {
|
|
||||||
Flag* f = list_;
|
|
||||||
while (f != NULL && strcmp(name, f->name()) != 0)
|
|
||||||
f = f->next();
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void FlagList::SplitArgument(const char* arg,
|
|
||||||
char* buffer, int buffer_size,
|
|
||||||
const char** name, const char** value,
|
|
||||||
bool* is_bool) {
|
|
||||||
*name = NULL;
|
|
||||||
*value = NULL;
|
|
||||||
*is_bool = false;
|
|
||||||
|
|
||||||
if (*arg == '-') {
|
|
||||||
// find the begin of the flag name
|
|
||||||
arg++; // remove 1st '-'
|
|
||||||
if (*arg == '-')
|
|
||||||
arg++; // remove 2nd '-'
|
|
||||||
if (arg[0] == 'n' && arg[1] == 'o') {
|
|
||||||
arg += 2; // remove "no"
|
|
||||||
*is_bool = true;
|
|
||||||
}
|
|
||||||
*name = arg;
|
|
||||||
|
|
||||||
// find the end of the flag name
|
|
||||||
while (*arg != '\0' && *arg != '=')
|
|
||||||
arg++;
|
|
||||||
|
|
||||||
// get the value if any
|
|
||||||
if (*arg == '=') {
|
|
||||||
// make a copy so we can NUL-terminate flag name
|
|
||||||
int n = static_cast<int>(arg - *name);
|
|
||||||
if (n >= buffer_size)
|
|
||||||
Fatal(__FILE__, __LINE__, "CHECK(%s) failed", "n < buffer_size");
|
|
||||||
memcpy(buffer, *name, n * sizeof(char));
|
|
||||||
buffer[n] = '\0';
|
|
||||||
*name = buffer;
|
|
||||||
// get the value
|
|
||||||
*value = arg + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int FlagList::SetFlagsFromCommandLine(int* argc, const char** argv,
|
|
||||||
bool remove_flags) {
|
|
||||||
// parse arguments
|
|
||||||
for (int i = 1; i < *argc; /* see below */) {
|
|
||||||
int j = i; // j > 0
|
|
||||||
const char* arg = argv[i++];
|
|
||||||
|
|
||||||
// split arg into flag components
|
|
||||||
char buffer[1024];
|
|
||||||
const char* name;
|
|
||||||
const char* value;
|
|
||||||
bool is_bool;
|
|
||||||
SplitArgument(arg, buffer, sizeof buffer, &name, &value, &is_bool);
|
|
||||||
|
|
||||||
if (name != NULL) {
|
|
||||||
// lookup the flag
|
|
||||||
Flag* flag = Lookup(name);
|
|
||||||
if (flag == NULL) {
|
|
||||||
fprintf(stderr, "Error: unrecognized flag %s\n", arg);
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we still need a flag value, use the next argument if available
|
|
||||||
if (flag->type() != Flag::BOOL && value == NULL) {
|
|
||||||
if (i < *argc) {
|
|
||||||
value = argv[i++];
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Error: missing value for flag %s of type %s\n",
|
|
||||||
arg, Type2String(flag->type()));
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the flag
|
|
||||||
char empty[] = { '\0' };
|
|
||||||
char* endp = empty;
|
|
||||||
switch (flag->type()) {
|
|
||||||
case Flag::BOOL:
|
|
||||||
*flag->bool_variable() = !is_bool;
|
|
||||||
break;
|
|
||||||
case Flag::INT:
|
|
||||||
*flag->int_variable() = strtol(value, &endp, 10);
|
|
||||||
break;
|
|
||||||
case Flag::FLOAT:
|
|
||||||
*flag->float_variable() = strtod(value, &endp);
|
|
||||||
break;
|
|
||||||
case Flag::STRING:
|
|
||||||
*flag->string_variable() = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle errors
|
|
||||||
if ((flag->type() == Flag::BOOL && value != NULL) ||
|
|
||||||
(flag->type() != Flag::BOOL && is_bool) ||
|
|
||||||
*endp != '\0') {
|
|
||||||
fprintf(stderr, "Error: illegal value for flag %s of type %s\n",
|
|
||||||
arg, Type2String(flag->type()));
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the flag & value from the command
|
|
||||||
if (remove_flags)
|
|
||||||
while (j < i)
|
|
||||||
argv[j++] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// shrink the argument list
|
|
||||||
if (remove_flags) {
|
|
||||||
int j = 1;
|
|
||||||
for (int i = 1; i < *argc; i++) {
|
|
||||||
if (argv[i] != NULL)
|
|
||||||
argv[j++] = argv[i];
|
|
||||||
}
|
|
||||||
*argc = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parsed all flags successfully
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlagList::Register(Flag* flag) {
|
|
||||||
assert(flag != NULL && strlen(flag->name()) > 0);
|
|
||||||
if (Lookup(flag->name()) != NULL)
|
|
||||||
Fatal(flag->file(), 0, "flag %s declared twice", flag->name());
|
|
||||||
flag->next_ = list_;
|
|
||||||
list_ = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
WindowsCommandLineArguments::WindowsCommandLineArguments() {
|
|
||||||
// start by getting the command line.
|
|
||||||
LPTSTR command_line = ::GetCommandLine();
|
|
||||||
// now, convert it to a list of wide char strings.
|
|
||||||
LPWSTR *wide_argv = ::CommandLineToArgvW(command_line, &argc_);
|
|
||||||
// now allocate an array big enough to hold that many string pointers.
|
|
||||||
argv_ = new char*[argc_];
|
|
||||||
|
|
||||||
// iterate over the returned wide strings;
|
|
||||||
for(int i = 0; i < argc_; ++i) {
|
|
||||||
std::string s = rtc::ToUtf8(wide_argv[i], wcslen(wide_argv[i]));
|
|
||||||
char *buffer = new char[s.length() + 1];
|
|
||||||
rtc::strcpyn(buffer, s.length() + 1, s.c_str());
|
|
||||||
|
|
||||||
// make sure the argv array has the right string at this point.
|
|
||||||
argv_[i] = buffer;
|
|
||||||
}
|
|
||||||
LocalFree(wide_argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowsCommandLineArguments::~WindowsCommandLineArguments() {
|
|
||||||
// need to free each string in the array, and then the array.
|
|
||||||
for(int i = 0; i < argc_; i++) {
|
|
||||||
delete[] argv_[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] argv_;
|
|
||||||
}
|
|
||||||
#endif // WEBRTC_WIN
|
|
||||||
|
|
@ -1,267 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// Originally comes from shared/commandlineflags/flags.h
|
|
||||||
|
|
||||||
// Flags are defined and declared using DEFINE_xxx and DECLARE_xxx macros,
|
|
||||||
// where xxx is the flag type. Flags are referred to via FLAG_yyy,
|
|
||||||
// where yyy is the flag name. For intialization and iteration of flags,
|
|
||||||
// see the FlagList class. For full programmatic access to any
|
|
||||||
// flag, see the Flag class.
|
|
||||||
//
|
|
||||||
// The implementation only relies and basic C++ functionality
|
|
||||||
// and needs no special library or STL support.
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_FLAGS_H__
|
|
||||||
#define WEBRTC_BASE_FLAGS_H__
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "webrtc/base/checks.h"
|
|
||||||
#include "webrtc/base/common.h"
|
|
||||||
|
|
||||||
// Internal use only.
|
|
||||||
union FlagValue {
|
|
||||||
// Note: Because in C++ non-bool values are silently converted into
|
|
||||||
// bool values ('bool b = "false";' results in b == true!), we pass
|
|
||||||
// and int argument to New_BOOL as this appears to be safer - sigh.
|
|
||||||
// In particular, it prevents the (not uncommon!) bug where a bool
|
|
||||||
// flag is defined via: DEFINE_bool(flag, "false", "some comment");.
|
|
||||||
static FlagValue New_BOOL(int b) {
|
|
||||||
FlagValue v;
|
|
||||||
v.b = (b != 0);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static FlagValue New_INT(int i) {
|
|
||||||
FlagValue v;
|
|
||||||
v.i = i;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static FlagValue New_FLOAT(float f) {
|
|
||||||
FlagValue v;
|
|
||||||
v.f = f;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static FlagValue New_STRING(const char* s) {
|
|
||||||
FlagValue v;
|
|
||||||
v.s = s;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool b;
|
|
||||||
int i;
|
|
||||||
double f;
|
|
||||||
const char* s;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Each flag can be accessed programmatically via a Flag object.
|
|
||||||
class Flag {
|
|
||||||
public:
|
|
||||||
enum Type { BOOL, INT, FLOAT, STRING };
|
|
||||||
|
|
||||||
// Internal use only.
|
|
||||||
Flag(const char* file, const char* name, const char* comment,
|
|
||||||
Type type, void* variable, FlagValue default_);
|
|
||||||
|
|
||||||
// General flag information
|
|
||||||
const char* file() const { return file_; }
|
|
||||||
const char* name() const { return name_; }
|
|
||||||
const char* comment() const { return comment_; }
|
|
||||||
|
|
||||||
// Flag type
|
|
||||||
Type type() const { return type_; }
|
|
||||||
|
|
||||||
// Flag variables
|
|
||||||
bool* bool_variable() const {
|
|
||||||
assert(type_ == BOOL);
|
|
||||||
return &variable_->b;
|
|
||||||
}
|
|
||||||
|
|
||||||
int* int_variable() const {
|
|
||||||
assert(type_ == INT);
|
|
||||||
return &variable_->i;
|
|
||||||
}
|
|
||||||
|
|
||||||
double* float_variable() const {
|
|
||||||
assert(type_ == FLOAT);
|
|
||||||
return &variable_->f;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char** string_variable() const {
|
|
||||||
assert(type_ == STRING);
|
|
||||||
return &variable_->s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default values
|
|
||||||
bool bool_default() const {
|
|
||||||
assert(type_ == BOOL);
|
|
||||||
return default_.b;
|
|
||||||
}
|
|
||||||
|
|
||||||
int int_default() const {
|
|
||||||
assert(type_ == INT);
|
|
||||||
return default_.i;
|
|
||||||
}
|
|
||||||
|
|
||||||
double float_default() const {
|
|
||||||
assert(type_ == FLOAT);
|
|
||||||
return default_.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* string_default() const {
|
|
||||||
assert(type_ == STRING);
|
|
||||||
return default_.s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resets a flag to its default value
|
|
||||||
void SetToDefault();
|
|
||||||
|
|
||||||
// Iteration support
|
|
||||||
Flag* next() const { return next_; }
|
|
||||||
|
|
||||||
// Prints flag information. The current flag value is only printed
|
|
||||||
// if print_current_value is set.
|
|
||||||
void Print(bool print_current_value);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const char* file_;
|
|
||||||
const char* name_;
|
|
||||||
const char* comment_;
|
|
||||||
|
|
||||||
Type type_;
|
|
||||||
FlagValue* variable_;
|
|
||||||
FlagValue default_;
|
|
||||||
|
|
||||||
Flag* next_;
|
|
||||||
|
|
||||||
friend class FlagList; // accesses next_
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Internal use only.
|
|
||||||
#define DEFINE_FLAG(type, c_type, name, default, comment) \
|
|
||||||
/* define and initialize the flag */ \
|
|
||||||
c_type FLAG_##name = (default); \
|
|
||||||
/* register the flag */ \
|
|
||||||
static Flag Flag_##name(__FILE__, #name, (comment), \
|
|
||||||
Flag::type, &FLAG_##name, \
|
|
||||||
FlagValue::New_##type(default))
|
|
||||||
|
|
||||||
|
|
||||||
// Internal use only.
|
|
||||||
#define DECLARE_FLAG(c_type, name) \
|
|
||||||
/* declare the external flag */ \
|
|
||||||
extern c_type FLAG_##name
|
|
||||||
|
|
||||||
|
|
||||||
// Use the following macros to define a new flag:
|
|
||||||
#define DEFINE_bool(name, default, comment) \
|
|
||||||
DEFINE_FLAG(BOOL, bool, name, default, comment)
|
|
||||||
#define DEFINE_int(name, default, comment) \
|
|
||||||
DEFINE_FLAG(INT, int, name, default, comment)
|
|
||||||
#define DEFINE_float(name, default, comment) \
|
|
||||||
DEFINE_FLAG(FLOAT, double, name, default, comment)
|
|
||||||
#define DEFINE_string(name, default, comment) \
|
|
||||||
DEFINE_FLAG(STRING, const char*, name, default, comment)
|
|
||||||
|
|
||||||
|
|
||||||
// Use the following macros to declare a flag defined elsewhere:
|
|
||||||
#define DECLARE_bool(name) DECLARE_FLAG(bool, name)
|
|
||||||
#define DECLARE_int(name) DECLARE_FLAG(int, name)
|
|
||||||
#define DECLARE_float(name) DECLARE_FLAG(double, name)
|
|
||||||
#define DECLARE_string(name) DECLARE_FLAG(const char*, name)
|
|
||||||
|
|
||||||
|
|
||||||
// The global list of all flags.
|
|
||||||
class FlagList {
|
|
||||||
public:
|
|
||||||
FlagList();
|
|
||||||
|
|
||||||
// The NULL-terminated list of all flags. Traverse with Flag::next().
|
|
||||||
static Flag* list() { return list_; }
|
|
||||||
|
|
||||||
// If file != NULL, prints information for all flags defined in file;
|
|
||||||
// otherwise prints information for all flags in all files. The current
|
|
||||||
// flag value is only printed if print_current_value is set.
|
|
||||||
static void Print(const char* file, bool print_current_value);
|
|
||||||
|
|
||||||
// Lookup a flag by name. Returns the matching flag or NULL.
|
|
||||||
static Flag* Lookup(const char* name);
|
|
||||||
|
|
||||||
// Helper function to parse flags: Takes an argument arg and splits it into
|
|
||||||
// a flag name and flag value (or NULL if they are missing). is_bool is set
|
|
||||||
// if the arg started with "-no" or "--no". The buffer may be used to NUL-
|
|
||||||
// terminate the name, it must be large enough to hold any possible name.
|
|
||||||
static void SplitArgument(const char* arg,
|
|
||||||
char* buffer, int buffer_size,
|
|
||||||
const char** name, const char** value,
|
|
||||||
bool* is_bool);
|
|
||||||
|
|
||||||
// Set the flag values by parsing the command line. If remove_flags
|
|
||||||
// is set, the flags and associated values are removed from (argc,
|
|
||||||
// argv). Returns 0 if no error occurred. Otherwise, returns the
|
|
||||||
// argv index > 0 for the argument where an error occurred. In that
|
|
||||||
// case, (argc, argv) will remain unchanged indepdendent of the
|
|
||||||
// remove_flags value, and no assumptions about flag settings should
|
|
||||||
// be made.
|
|
||||||
//
|
|
||||||
// The following syntax for flags is accepted (both '-' and '--' are ok):
|
|
||||||
//
|
|
||||||
// --flag (bool flags only)
|
|
||||||
// --noflag (bool flags only)
|
|
||||||
// --flag=value (non-bool flags only, no spaces around '=')
|
|
||||||
// --flag value (non-bool flags only)
|
|
||||||
static int SetFlagsFromCommandLine(int* argc,
|
|
||||||
const char** argv,
|
|
||||||
bool remove_flags);
|
|
||||||
static inline int SetFlagsFromCommandLine(int* argc,
|
|
||||||
char** argv,
|
|
||||||
bool remove_flags) {
|
|
||||||
return SetFlagsFromCommandLine(argc, const_cast<const char**>(argv),
|
|
||||||
remove_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Registers a new flag. Called during program initialization. Not
|
|
||||||
// thread-safe.
|
|
||||||
static void Register(Flag* flag);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static Flag* list_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
// A helper class to translate Windows command line arguments into UTF8,
|
|
||||||
// which then allows us to just pass them to the flags system.
|
|
||||||
// This encapsulates all the work of getting the command line and translating
|
|
||||||
// it to an array of 8-bit strings; all you have to do is create one of these,
|
|
||||||
// and then call argc() and argv().
|
|
||||||
class WindowsCommandLineArguments {
|
|
||||||
public:
|
|
||||||
WindowsCommandLineArguments();
|
|
||||||
~WindowsCommandLineArguments();
|
|
||||||
|
|
||||||
int argc() { return argc_; }
|
|
||||||
char **argv() { return argv_; }
|
|
||||||
private:
|
|
||||||
int argc_;
|
|
||||||
char **argv_;
|
|
||||||
|
|
||||||
private:
|
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(WindowsCommandLineArguments);
|
|
||||||
};
|
|
||||||
#endif // WEBRTC_WIN
|
|
||||||
|
|
||||||
|
|
||||||
#endif // SHARED_COMMANDLINEFLAGS_FLAGS_H__
|
|
@ -1,241 +0,0 @@
|
|||||||
// This file was GENERATED by command:
|
|
||||||
// pump.py genericslot.h.pump
|
|
||||||
// DO NOT EDIT BY HAND!!!
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2014 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_GENERICSLOT_H_
|
|
||||||
#define WEBRTC_BASE_GENERICSLOT_H_
|
|
||||||
|
|
||||||
// To generate genericslot.h from genericslot.h.pump, execute:
|
|
||||||
// /home/build/google3/third_party/gtest/scripts/pump.py genericslot.h.pump
|
|
||||||
|
|
||||||
// Generic-slots are pure slots that can be hooked up to signals. They're
|
|
||||||
// mainly intended to be used in tests where we want to check if a signal
|
|
||||||
// was invoked and what arguments were passed. NOTE: They do not do any
|
|
||||||
// lifetime management of the arguments received via callbacks.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// /* Some signal */
|
|
||||||
// sigslot::signal1<int> foo;
|
|
||||||
//
|
|
||||||
// /* We want to monitor foo in some test */
|
|
||||||
// rtc::GenericSlot1<int> slot(&foo, 0);
|
|
||||||
// foo.emit(5);
|
|
||||||
// EXPECT_TRUE(slot.callback_received());
|
|
||||||
// EXPECT_EQ(5, *(slot.arg1()));
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "webrtc/base/constructormagic.h"
|
|
||||||
#include "webrtc/base/sigslot.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
template <class A1>
|
|
||||||
class GenericSlot1 : public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
GenericSlot1(sigslot::signal1<A1>* signal,
|
|
||||||
const A1& arg1_initial)
|
|
||||||
: arg1_initial_(arg1_initial) {
|
|
||||||
Reset();
|
|
||||||
signal->connect(this, &GenericSlot1::OnSignalCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
callback_received_ = false;
|
|
||||||
arg1_ = arg1_initial_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received() const { return callback_received_; }
|
|
||||||
const A1& arg1() const { return arg1_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnSignalCallback(A1 arg1) {
|
|
||||||
callback_received_ = true;
|
|
||||||
arg1_ = arg1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received_;
|
|
||||||
A1 arg1_initial_, arg1_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(GenericSlot1);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class A1, class A2>
|
|
||||||
class GenericSlot2 : public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
GenericSlot2(sigslot::signal2<A1, A2>* signal,
|
|
||||||
const A1& arg1_initial, const A2& arg2_initial)
|
|
||||||
: arg1_initial_(arg1_initial), arg2_initial_(arg2_initial) {
|
|
||||||
Reset();
|
|
||||||
signal->connect(this, &GenericSlot2::OnSignalCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
callback_received_ = false;
|
|
||||||
arg1_ = arg1_initial_;
|
|
||||||
arg2_ = arg2_initial_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received() const { return callback_received_; }
|
|
||||||
const A1& arg1() const { return arg1_; }
|
|
||||||
const A2& arg2() const { return arg2_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnSignalCallback(A1 arg1, A2 arg2) {
|
|
||||||
callback_received_ = true;
|
|
||||||
arg1_ = arg1;
|
|
||||||
arg2_ = arg2;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received_;
|
|
||||||
A1 arg1_initial_, arg1_;
|
|
||||||
A2 arg2_initial_, arg2_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(GenericSlot2);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3>
|
|
||||||
class GenericSlot3 : public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
GenericSlot3(sigslot::signal3<A1, A2, A3>* signal,
|
|
||||||
const A1& arg1_initial, const A2& arg2_initial,
|
|
||||||
const A3& arg3_initial)
|
|
||||||
: arg1_initial_(arg1_initial), arg2_initial_(arg2_initial),
|
|
||||||
arg3_initial_(arg3_initial) {
|
|
||||||
Reset();
|
|
||||||
signal->connect(this, &GenericSlot3::OnSignalCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
callback_received_ = false;
|
|
||||||
arg1_ = arg1_initial_;
|
|
||||||
arg2_ = arg2_initial_;
|
|
||||||
arg3_ = arg3_initial_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received() const { return callback_received_; }
|
|
||||||
const A1& arg1() const { return arg1_; }
|
|
||||||
const A2& arg2() const { return arg2_; }
|
|
||||||
const A3& arg3() const { return arg3_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3) {
|
|
||||||
callback_received_ = true;
|
|
||||||
arg1_ = arg1;
|
|
||||||
arg2_ = arg2;
|
|
||||||
arg3_ = arg3;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received_;
|
|
||||||
A1 arg1_initial_, arg1_;
|
|
||||||
A2 arg2_initial_, arg2_;
|
|
||||||
A3 arg3_initial_, arg3_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(GenericSlot3);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4>
|
|
||||||
class GenericSlot4 : public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
GenericSlot4(sigslot::signal4<A1, A2, A3, A4>* signal,
|
|
||||||
const A1& arg1_initial, const A2& arg2_initial,
|
|
||||||
const A3& arg3_initial, const A4& arg4_initial)
|
|
||||||
: arg1_initial_(arg1_initial), arg2_initial_(arg2_initial),
|
|
||||||
arg3_initial_(arg3_initial), arg4_initial_(arg4_initial) {
|
|
||||||
Reset();
|
|
||||||
signal->connect(this, &GenericSlot4::OnSignalCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
callback_received_ = false;
|
|
||||||
arg1_ = arg1_initial_;
|
|
||||||
arg2_ = arg2_initial_;
|
|
||||||
arg3_ = arg3_initial_;
|
|
||||||
arg4_ = arg4_initial_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received() const { return callback_received_; }
|
|
||||||
const A1& arg1() const { return arg1_; }
|
|
||||||
const A2& arg2() const { return arg2_; }
|
|
||||||
const A3& arg3() const { return arg3_; }
|
|
||||||
const A4& arg4() const { return arg4_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3, A4 arg4) {
|
|
||||||
callback_received_ = true;
|
|
||||||
arg1_ = arg1;
|
|
||||||
arg2_ = arg2;
|
|
||||||
arg3_ = arg3;
|
|
||||||
arg4_ = arg4;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received_;
|
|
||||||
A1 arg1_initial_, arg1_;
|
|
||||||
A2 arg2_initial_, arg2_;
|
|
||||||
A3 arg3_initial_, arg3_;
|
|
||||||
A4 arg4_initial_, arg4_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(GenericSlot4);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class A1, class A2, class A3, class A4, class A5>
|
|
||||||
class GenericSlot5 : public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
GenericSlot5(sigslot::signal5<A1, A2, A3, A4, A5>* signal,
|
|
||||||
const A1& arg1_initial, const A2& arg2_initial,
|
|
||||||
const A3& arg3_initial, const A4& arg4_initial,
|
|
||||||
const A5& arg5_initial)
|
|
||||||
: arg1_initial_(arg1_initial), arg2_initial_(arg2_initial),
|
|
||||||
arg3_initial_(arg3_initial), arg4_initial_(arg4_initial),
|
|
||||||
arg5_initial_(arg5_initial) {
|
|
||||||
Reset();
|
|
||||||
signal->connect(this, &GenericSlot5::OnSignalCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
callback_received_ = false;
|
|
||||||
arg1_ = arg1_initial_;
|
|
||||||
arg2_ = arg2_initial_;
|
|
||||||
arg3_ = arg3_initial_;
|
|
||||||
arg4_ = arg4_initial_;
|
|
||||||
arg5_ = arg5_initial_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received() const { return callback_received_; }
|
|
||||||
const A1& arg1() const { return arg1_; }
|
|
||||||
const A2& arg2() const { return arg2_; }
|
|
||||||
const A3& arg3() const { return arg3_; }
|
|
||||||
const A4& arg4() const { return arg4_; }
|
|
||||||
const A5& arg5() const { return arg5_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnSignalCallback(A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5) {
|
|
||||||
callback_received_ = true;
|
|
||||||
arg1_ = arg1;
|
|
||||||
arg2_ = arg2;
|
|
||||||
arg3_ = arg3;
|
|
||||||
arg4_ = arg4;
|
|
||||||
arg5_ = arg5;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received_;
|
|
||||||
A1 arg1_initial_, arg1_;
|
|
||||||
A2 arg2_initial_, arg2_;
|
|
||||||
A3 arg3_initial_, arg3_;
|
|
||||||
A4 arg4_initial_, arg4_;
|
|
||||||
A5 arg5_initial_, arg5_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(GenericSlot5);
|
|
||||||
};
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_GENERICSLOT_H_
|
|
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_GENERICSLOT_H_
|
|
||||||
#define WEBRTC_BASE_GENERICSLOT_H_
|
|
||||||
|
|
||||||
// To generate genericslot.h from genericslot.h.pump, execute:
|
|
||||||
// /home/build/google3/third_party/gtest/scripts/pump.py genericslot.h.pump
|
|
||||||
|
|
||||||
// Generic-slots are pure slots that can be hooked up to signals. They're
|
|
||||||
// mainly intended to be used in tests where we want to check if a signal
|
|
||||||
// was invoked and what arguments were passed. NOTE: They do not do any
|
|
||||||
// lifetime management of the arguments received via callbacks.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// /* Some signal */
|
|
||||||
// sigslot::signal1<int> foo;
|
|
||||||
//
|
|
||||||
// /* We want to monitor foo in some test */
|
|
||||||
// rtc::GenericSlot1<int> slot(&foo, 0);
|
|
||||||
// foo.emit(5);
|
|
||||||
// EXPECT_TRUE(slot.callback_received());
|
|
||||||
// EXPECT_EQ(5, *(slot.arg1()));
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "webrtc/base/constructormagic.h"
|
|
||||||
#include "webrtc/base/sigslot.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
$var n = 5
|
|
||||||
$range i 1..n
|
|
||||||
$for i [[
|
|
||||||
$range j 1..i
|
|
||||||
|
|
||||||
template <$for j , [[class A$j]]>
|
|
||||||
class GenericSlot$i : public sigslot::has_slots<> {
|
|
||||||
public:
|
|
||||||
GenericSlot$i(sigslot::signal$i<$for j , [[A$j]]>* signal,
|
|
||||||
$for j , [[const A$j& arg$j[[]]_initial]])
|
|
||||||
: $for j , [[arg$j[[]]_initial_(arg$j[[]]_initial)]] {
|
|
||||||
Reset();
|
|
||||||
signal->connect(this, &GenericSlot$i::OnSignalCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Reset() {
|
|
||||||
callback_received_ = false;$for j [[
|
|
||||||
|
|
||||||
arg$j[[]]_ = arg$j[[]]_initial_; ]]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received() const { return callback_received_; }$for j [[
|
|
||||||
|
|
||||||
const A$j& arg$j() const { return arg$j[[]]_; }]]
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
void OnSignalCallback($for j , [[A$j arg$j]]) {
|
|
||||||
callback_received_ = true;$for j [[
|
|
||||||
|
|
||||||
arg$j[[]]_ = arg$j;]]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_received_;$for j [[
|
|
||||||
|
|
||||||
A$j arg$j[[]]_initial_, arg$j[[]]_;]]
|
|
||||||
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(GenericSlot$i);
|
|
||||||
};
|
|
||||||
|
|
||||||
]]
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_GENERICSLOT_H_
|
|
@ -1,37 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2014 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 "webrtc/base/genericslot.h"
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/sigslot.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
TEST(GenericSlotTest, TestSlot1) {
|
|
||||||
sigslot::signal1<int> source1;
|
|
||||||
GenericSlot1<int> slot1(&source1, 1);
|
|
||||||
EXPECT_FALSE(slot1.callback_received());
|
|
||||||
source1.emit(10);
|
|
||||||
EXPECT_TRUE(slot1.callback_received());
|
|
||||||
EXPECT_EQ(10, slot1.arg1());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(GenericSlotTest, TestSlot2) {
|
|
||||||
sigslot::signal2<int, char> source2;
|
|
||||||
GenericSlot2<int, char> slot2(&source2, 1, '0');
|
|
||||||
EXPECT_FALSE(slot2.callback_received());
|
|
||||||
source2.emit(10, 'x');
|
|
||||||
EXPECT_TRUE(slot2.callback_received());
|
|
||||||
EXPECT_EQ(10, slot2.arg1());
|
|
||||||
EXPECT_EQ('x', slot2.arg2());
|
|
||||||
}
|
|
||||||
|
|
||||||
// By induction we assume the rest work too...
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_GUNIT_H_
|
|
||||||
#define WEBRTC_BASE_GUNIT_H_
|
|
||||||
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
#include "webrtc/base/thread.h"
|
|
||||||
#if defined(WEBRTC_ANDROID) || defined(GTEST_RELATIVE_PATH)
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
#else
|
|
||||||
#include "testing/base/public/gunit.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// forward declarations
|
|
||||||
namespace rtc {
|
|
||||||
class Pathname;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until "ex" is true, or "timeout" expires.
|
|
||||||
#define WAIT(ex, timeout) \
|
|
||||||
for (uint32 start = rtc::Time(); \
|
|
||||||
!(ex) && rtc::Time() < start + timeout;) \
|
|
||||||
rtc::Thread::Current()->ProcessMessages(1);
|
|
||||||
|
|
||||||
// This returns the result of the test in res, so that we don't re-evaluate
|
|
||||||
// the expression in the XXXX_WAIT macros below, since that causes problems
|
|
||||||
// when the expression is only true the first time you check it.
|
|
||||||
#define WAIT_(ex, timeout, res) \
|
|
||||||
do { \
|
|
||||||
uint32 start = rtc::Time(); \
|
|
||||||
res = (ex); \
|
|
||||||
while (!res && rtc::Time() < start + timeout) { \
|
|
||||||
rtc::Thread::Current()->ProcessMessages(1); \
|
|
||||||
res = (ex); \
|
|
||||||
} \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
// The typical EXPECT_XXXX and ASSERT_XXXXs, but done until true or a timeout.
|
|
||||||
#define EXPECT_TRUE_WAIT(ex, timeout) \
|
|
||||||
do { \
|
|
||||||
bool res; \
|
|
||||||
WAIT_(ex, timeout, res); \
|
|
||||||
if (!res) EXPECT_TRUE(ex); \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
#define EXPECT_EQ_WAIT(v1, v2, timeout) \
|
|
||||||
do { \
|
|
||||||
bool res; \
|
|
||||||
WAIT_(v1 == v2, timeout, res); \
|
|
||||||
if (!res) EXPECT_EQ(v1, v2); \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
#define ASSERT_TRUE_WAIT(ex, timeout) \
|
|
||||||
do { \
|
|
||||||
bool res; \
|
|
||||||
WAIT_(ex, timeout, res); \
|
|
||||||
if (!res) ASSERT_TRUE(ex); \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
#define ASSERT_EQ_WAIT(v1, v2, timeout) \
|
|
||||||
do { \
|
|
||||||
bool res; \
|
|
||||||
WAIT_(v1 == v2, timeout, res); \
|
|
||||||
if (!res) ASSERT_EQ(v1, v2); \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
// Version with a "soft" timeout and a margin. This logs if the timeout is
|
|
||||||
// exceeded, but it only fails if the expression still isn't true after the
|
|
||||||
// margin time passes.
|
|
||||||
#define EXPECT_TRUE_WAIT_MARGIN(ex, timeout, margin) \
|
|
||||||
do { \
|
|
||||||
bool res; \
|
|
||||||
WAIT_(ex, timeout, res); \
|
|
||||||
if (res) { \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
LOG(LS_WARNING) << "Expression " << #ex << " still not true after " << \
|
|
||||||
timeout << "ms; waiting an additional " << margin << "ms"; \
|
|
||||||
WAIT_(ex, margin, res); \
|
|
||||||
if (!res) { \
|
|
||||||
EXPECT_TRUE(ex); \
|
|
||||||
} \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
rtc::Pathname GetTalkDirectory();
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_GUNIT_H_
|
|
@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_GUNIT_PROD_H_
|
|
||||||
#define WEBRTC_BASE_GUNIT_PROD_H_
|
|
||||||
|
|
||||||
#if defined(WEBRTC_ANDROID)
|
|
||||||
// Android doesn't use gtest at all, so anything that relies on gtest should
|
|
||||||
// check this define first.
|
|
||||||
#define NO_GTEST
|
|
||||||
#elif defined (GTEST_RELATIVE_PATH)
|
|
||||||
#include "gtest/gtest_prod.h"
|
|
||||||
#else
|
|
||||||
#include "testing/base/gunit_prod.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_GUNIT_PROD_H_
|
|
@ -1,296 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 "webrtc/base/helpers.h"
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#if defined(FEATURE_ENABLE_SSL)
|
|
||||||
#include "webrtc/base/sslconfig.h"
|
|
||||||
#if defined(SSL_USE_OPENSSL)
|
|
||||||
#include <openssl/rand.h>
|
|
||||||
#elif defined(SSL_USE_NSS_RNG)
|
|
||||||
#include "pk11func.h"
|
|
||||||
#else
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
#include <ntsecapi.h>
|
|
||||||
#endif // WEBRTC_WIN
|
|
||||||
#endif // else
|
|
||||||
#endif // FEATURE_ENABLED_SSL
|
|
||||||
|
|
||||||
#include "webrtc/base/base64.h"
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
#include "webrtc/base/logging.h"
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
|
||||||
#include "webrtc/base/timeutils.h"
|
|
||||||
|
|
||||||
// Protect against max macro inclusion.
|
|
||||||
#undef max
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// Base class for RNG implementations.
|
|
||||||
class RandomGenerator {
|
|
||||||
public:
|
|
||||||
virtual ~RandomGenerator() {}
|
|
||||||
virtual bool Init(const void* seed, size_t len) = 0;
|
|
||||||
virtual bool Generate(void* buf, size_t len) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(SSL_USE_OPENSSL)
|
|
||||||
// The OpenSSL RNG. Need to make sure it doesn't run out of entropy.
|
|
||||||
class SecureRandomGenerator : public RandomGenerator {
|
|
||||||
public:
|
|
||||||
SecureRandomGenerator() : inited_(false) {
|
|
||||||
}
|
|
||||||
~SecureRandomGenerator() {
|
|
||||||
}
|
|
||||||
virtual bool Init(const void* seed, size_t len) {
|
|
||||||
// By default, seed from the system state.
|
|
||||||
if (!inited_) {
|
|
||||||
if (RAND_poll() <= 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
inited_ = true;
|
|
||||||
}
|
|
||||||
// Allow app data to be mixed in, if provided.
|
|
||||||
if (seed) {
|
|
||||||
RAND_seed(seed, len);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool Generate(void* buf, size_t len) {
|
|
||||||
if (!inited_ && !Init(NULL, 0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool inited_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#elif defined(SSL_USE_NSS_RNG)
|
|
||||||
// The NSS RNG.
|
|
||||||
class SecureRandomGenerator : public RandomGenerator {
|
|
||||||
public:
|
|
||||||
SecureRandomGenerator() {}
|
|
||||||
~SecureRandomGenerator() {}
|
|
||||||
virtual bool Init(const void* seed, size_t len) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool Generate(void* buf, size_t len) {
|
|
||||||
return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
|
|
||||||
static_cast<int>(len)) == SECSuccess);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#else
|
|
||||||
#if defined(WEBRTC_WIN)
|
|
||||||
class SecureRandomGenerator : public RandomGenerator {
|
|
||||||
public:
|
|
||||||
SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
|
|
||||||
~SecureRandomGenerator() {
|
|
||||||
FreeLibrary(advapi32_);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool Init(const void* seed, size_t seed_len) {
|
|
||||||
// We don't do any additional seeding on Win32, we just use the CryptoAPI
|
|
||||||
// RNG (which is exposed as a hidden function off of ADVAPI32 so that we
|
|
||||||
// don't need to drag in all of CryptoAPI)
|
|
||||||
if (rtl_gen_random_) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
advapi32_ = LoadLibrary(L"advapi32.dll");
|
|
||||||
if (!advapi32_) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
|
|
||||||
GetProcAddress(advapi32_, "SystemFunction036"));
|
|
||||||
if (!rtl_gen_random_) {
|
|
||||||
FreeLibrary(advapi32_);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool Generate(void* buf, size_t len) {
|
|
||||||
if (!rtl_gen_random_ && !Init(NULL, 0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
|
|
||||||
HINSTANCE advapi32_;
|
|
||||||
RtlGenRandomProc rtl_gen_random_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#elif !defined(FEATURE_ENABLE_SSL)
|
|
||||||
|
|
||||||
// No SSL implementation -- use rand()
|
|
||||||
class SecureRandomGenerator : public RandomGenerator {
|
|
||||||
public:
|
|
||||||
virtual bool Init(const void* seed, size_t len) {
|
|
||||||
if (len >= 4) {
|
|
||||||
srand(*reinterpret_cast<const int*>(seed));
|
|
||||||
} else {
|
|
||||||
srand(*reinterpret_cast<const char*>(seed));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool Generate(void* buf, size_t len) {
|
|
||||||
char* bytes = reinterpret_cast<char*>(buf);
|
|
||||||
for (size_t i = 0; i < len; ++i) {
|
|
||||||
bytes[i] = static_cast<char>(rand());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#error No SSL implementation has been selected!
|
|
||||||
|
|
||||||
#endif // WEBRTC_WIN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// A test random generator, for predictable output.
|
|
||||||
class TestRandomGenerator : public RandomGenerator {
|
|
||||||
public:
|
|
||||||
TestRandomGenerator() : seed_(7) {
|
|
||||||
}
|
|
||||||
~TestRandomGenerator() {
|
|
||||||
}
|
|
||||||
virtual bool Init(const void* seed, size_t len) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool Generate(void* buf, size_t len) {
|
|
||||||
for (size_t i = 0; i < len; ++i) {
|
|
||||||
static_cast<uint8*>(buf)[i] = static_cast<uint8>(GetRandom());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int GetRandom() {
|
|
||||||
return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
|
|
||||||
}
|
|
||||||
int seed_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Use Base64::Base64Table instead.
|
|
||||||
static const char BASE64[64] = {
|
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
|
||||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
|
||||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// This round about way of creating a global RNG is to safe-guard against
|
|
||||||
// indeterminant static initialization order.
|
|
||||||
scoped_ptr<RandomGenerator>& GetGlobalRng() {
|
|
||||||
LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
|
|
||||||
(new SecureRandomGenerator()));
|
|
||||||
return global_rng;
|
|
||||||
}
|
|
||||||
|
|
||||||
RandomGenerator& Rng() {
|
|
||||||
return *GetGlobalRng();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void SetRandomTestMode(bool test) {
|
|
||||||
if (!test) {
|
|
||||||
GetGlobalRng().reset(new SecureRandomGenerator());
|
|
||||||
} else {
|
|
||||||
GetGlobalRng().reset(new TestRandomGenerator());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InitRandom(int seed) {
|
|
||||||
return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InitRandom(const char* seed, size_t len) {
|
|
||||||
if (!Rng().Init(seed, len)) {
|
|
||||||
LOG(LS_ERROR) << "Failed to init random generator!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CreateRandomString(size_t len) {
|
|
||||||
std::string str;
|
|
||||||
CreateRandomString(len, &str);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CreateRandomString(size_t len,
|
|
||||||
const char* table, int table_size,
|
|
||||||
std::string* str) {
|
|
||||||
str->clear();
|
|
||||||
scoped_ptr<uint8[]> bytes(new uint8[len]);
|
|
||||||
if (!Rng().Generate(bytes.get(), len)) {
|
|
||||||
LOG(LS_ERROR) << "Failed to generate random string!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
str->reserve(len);
|
|
||||||
for (size_t i = 0; i < len; ++i) {
|
|
||||||
str->push_back(table[bytes[i] % table_size]);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CreateRandomString(size_t len, std::string* str) {
|
|
||||||
return CreateRandomString(len, BASE64, 64, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CreateRandomString(size_t len, const std::string& table,
|
|
||||||
std::string* str) {
|
|
||||||
return CreateRandomString(len, table.c_str(),
|
|
||||||
static_cast<int>(table.size()), str);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 CreateRandomId() {
|
|
||||||
uint32 id;
|
|
||||||
if (!Rng().Generate(&id, sizeof(id))) {
|
|
||||||
LOG(LS_ERROR) << "Failed to generate random id!";
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64 CreateRandomId64() {
|
|
||||||
return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 CreateRandomNonZeroId() {
|
|
||||||
uint32 id;
|
|
||||||
do {
|
|
||||||
id = CreateRandomId();
|
|
||||||
} while (id == 0);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
double CreateRandomDouble() {
|
|
||||||
return CreateRandomId() / (std::numeric_limits<uint32>::max() +
|
|
||||||
std::numeric_limits<double>::epsilon());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef WEBRTC_BASE_HELPERS_H_
|
|
||||||
#define WEBRTC_BASE_HELPERS_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "webrtc/base/basictypes.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
// For testing, we can return predictable data.
|
|
||||||
void SetRandomTestMode(bool test);
|
|
||||||
|
|
||||||
// Initializes the RNG, and seeds it with the specified entropy.
|
|
||||||
bool InitRandom(int seed);
|
|
||||||
bool InitRandom(const char* seed, size_t len);
|
|
||||||
|
|
||||||
// Generates a (cryptographically) random string of the given length.
|
|
||||||
// We generate base64 values so that they will be printable.
|
|
||||||
// WARNING: could silently fail. Use the version below instead.
|
|
||||||
std::string CreateRandomString(size_t length);
|
|
||||||
|
|
||||||
// Generates a (cryptographically) random string of the given length.
|
|
||||||
// We generate base64 values so that they will be printable.
|
|
||||||
// Return false if the random number generator failed.
|
|
||||||
bool CreateRandomString(size_t length, std::string* str);
|
|
||||||
|
|
||||||
// Generates a (cryptographically) random string of the given length,
|
|
||||||
// with characters from the given table. Return false if the random
|
|
||||||
// number generator failed.
|
|
||||||
bool CreateRandomString(size_t length, const std::string& table,
|
|
||||||
std::string* str);
|
|
||||||
|
|
||||||
// Generates a random id.
|
|
||||||
uint32 CreateRandomId();
|
|
||||||
|
|
||||||
// Generates a 64 bit random id.
|
|
||||||
uint64 CreateRandomId64();
|
|
||||||
|
|
||||||
// Generates a random id > 0.
|
|
||||||
uint32 CreateRandomNonZeroId();
|
|
||||||
|
|
||||||
// Generates a random double between 0.0 (inclusive) and 1.0 (exclusive).
|
|
||||||
double CreateRandomDouble();
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_BASE_HELPERS_H_
|
|
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2004 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 <string>
|
|
||||||
|
|
||||||
#include "webrtc/base/gunit.h"
|
|
||||||
#include "webrtc/base/helpers.h"
|
|
||||||
#include "webrtc/base/ssladapter.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
|
||||||
|
|
||||||
class RandomTest : public testing::Test {
|
|
||||||
public:
|
|
||||||
static void SetUpTestCase() {
|
|
||||||
rtc::InitializeSSL();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TearDownTestCase() {
|
|
||||||
rtc::CleanupSSL();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(RandomTest, TestCreateRandomId) {
|
|
||||||
CreateRandomId();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RandomTest, TestCreateRandomDouble) {
|
|
||||||
for (int i = 0; i < 100; ++i) {
|
|
||||||
double r = CreateRandomDouble();
|
|
||||||
EXPECT_GE(r, 0.0);
|
|
||||||
EXPECT_LT(r, 1.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RandomTest, TestCreateNonZeroRandomId) {
|
|
||||||
EXPECT_NE(0U, CreateRandomNonZeroId());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RandomTest, TestCreateRandomString) {
|
|
||||||
std::string random = CreateRandomString(256);
|
|
||||||
EXPECT_EQ(256U, random.size());
|
|
||||||
std::string random2;
|
|
||||||
EXPECT_TRUE(CreateRandomString(256, &random2));
|
|
||||||
EXPECT_NE(random, random2);
|
|
||||||
EXPECT_EQ(256U, random2.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(RandomTest, TestCreateRandomForTest) {
|
|
||||||
// Make sure we get the output we expect.
|
|
||||||
SetRandomTestMode(true);
|
|
||||||
EXPECT_EQ(2154761789U, CreateRandomId());
|
|
||||||
EXPECT_EQ("h0ISP4S5SJKH/9EY", CreateRandomString(16));
|
|
||||||
|
|
||||||
// Reset and make sure we get the same output.
|
|
||||||
SetRandomTestMode(true);
|
|
||||||
EXPECT_EQ(2154761789U, CreateRandomId());
|
|
||||||
EXPECT_EQ("h0ISP4S5SJKH/9EY", CreateRandomString(16));
|
|
||||||
|
|
||||||
// Test different character sets.
|
|
||||||
SetRandomTestMode(true);
|
|
||||||
std::string str;
|
|
||||||
EXPECT_TRUE(CreateRandomString(16, "a", &str));
|
|
||||||
EXPECT_EQ("aaaaaaaaaaaaaaaa", str);
|
|
||||||
EXPECT_TRUE(CreateRandomString(16, "abc", &str));
|
|
||||||
EXPECT_EQ("acbccaaaabbaacbb", str);
|
|
||||||
|
|
||||||
// Turn off test mode for other tests.
|
|
||||||
SetRandomTestMode(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rtc
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user