Creating a copy of Udp transport under webrtc/test

Adding a test namespace, updating the include paths and renamed folder name.
Review URL: https://webrtc-codereview.appspot.com/1203004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3701 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
pwestin@webrtc.org 2013-03-21 16:38:05 +00:00
parent 2cec0b1670
commit 999e900fb6
24 changed files with 8280 additions and 0 deletions

View File

@ -31,6 +31,7 @@
'dependencies': [
'webrtc/test/metrics.gyp:*',
'webrtc/test/test.gyp:*',
'webrtc/test/channel_transport.gyp:*',
'webrtc/tools/tools.gyp:*',
'tools/e2e_quality/e2e_quality.gyp:*',
],

View File

@ -0,0 +1,67 @@
# 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': 'channel_transport',
'type': 'static_library',
'dependencies': [
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
],
'sources': [
# PLATFORM INDEPENDENT SOURCE FILES
'channel_transport/channel_transport.cc',
'channel_transport/include/channel_transport.h',
'channel_transport/udp_transport.h',
'channel_transport/udp_transport_impl.cc',
'channel_transport/udp_socket_wrapper.cc',
'channel_transport/udp_socket_manager_wrapper.cc',
'channel_transport/udp_transport_impl.h',
'channel_transport/udp_socket_wrapper.h',
'channel_transport/udp_socket_manager_wrapper.h',
# PLATFORM SPECIFIC SOURCE FILES - Will be filtered below
# Posix (Linux/Mac)
'channel_transport/udp_socket_posix.cc',
'channel_transport/udp_socket_posix.h',
'channel_transport/udp_socket_manager_posix.cc',
'channel_transport/udp_socket_manager_posix.h',
# win
'channel_transport/udp_socket2_manager_win.cc',
'channel_transport/udp_socket2_manager_win.h',
'channel_transport/udp_socket2_win.cc',
'channel_transport/udp_socket2_win.h',
'channel_transport/traffic_control_win.cc',
'channel_transport/traffic_control_win.h',
], # source
},
{
'target_name': 'channel_transport_unittests',
'type': 'executable',
'dependencies': [
'channel_transport',
'<(DEPTH)/testing/gtest.gyp:gtest',
'<(DEPTH)/testing/gmock.gyp:gmock',
'<(webrtc_root)/test/test.gyp:test_support_main',
],
'sources': [
'channel_transport/udp_transport_unittest.cc',
'channel_transport/udp_socket_manager_unittest.cc',
'channel_transport/udp_socket_wrapper_unittest.cc',
],
# Disable warnings to enable Win64 build, issue 1323.
'msvs_disabled_warnings': [
4267, # size_t to int truncation.
],
}, # channel_transport_unittests
], # targets
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/test/channel_transport/include/channel_transport.h"
#include <stdio.h>
#include "gtest/gtest.h"
#include "webrtc/test/channel_transport/udp_transport.h"
#include "webrtc/video_engine/include/vie_network.h"
#include "webrtc/voice_engine/include/voe_network.h"
#include "webrtc/video_engine/vie_defines.h"
namespace webrtc {
namespace test {
VoiceChannelTransport::VoiceChannelTransport(VoENetwork* voe_network,
int channel)
: channel_(channel),
voe_network_(voe_network) {
WebRtc_UWord8 socket_threads = 1;
socket_transport_ = UdpTransport::Create(channel, socket_threads);
EXPECT_EQ(0, voe_network_->RegisterExternalTransport(channel,
*socket_transport_));
}
VoiceChannelTransport::~VoiceChannelTransport() {
voe_network_->DeRegisterExternalTransport(channel_);
UdpTransport::Destroy(socket_transport_);
}
void VoiceChannelTransport::IncomingRTPPacket(
const WebRtc_Word8* incoming_rtp_packet,
const WebRtc_Word32 packet_length,
const char* /*from_ip*/,
const WebRtc_UWord16 /*from_port*/) {
voe_network_->ReceivedRTPPacket(channel_, incoming_rtp_packet, packet_length);
}
void VoiceChannelTransport::IncomingRTCPPacket(
const WebRtc_Word8* incoming_rtcp_packet,
const WebRtc_Word32 packet_length,
const char* /*from_ip*/,
const WebRtc_UWord16 /*from_port*/) {
voe_network_->ReceivedRTCPPacket(channel_, incoming_rtcp_packet,
packet_length);
}
int VoiceChannelTransport::SetLocalReceiver(WebRtc_UWord16 rtp_port) {
return socket_transport_->InitializeReceiveSockets(this, rtp_port);
}
int VoiceChannelTransport::SetSendDestination(const char* ip_address,
WebRtc_UWord16 rtp_port) {
return socket_transport_->InitializeSendSockets(ip_address, rtp_port);
}
VideoChannelTransport::VideoChannelTransport(ViENetwork* vie_network,
int channel)
: channel_(channel),
vie_network_(vie_network) {
WebRtc_UWord8 socket_threads = 1;
socket_transport_ = UdpTransport::Create(channel, socket_threads);
EXPECT_EQ(0, vie_network_->RegisterSendTransport(channel,
*socket_transport_));
}
VideoChannelTransport::~VideoChannelTransport() {
vie_network_->DeregisterSendTransport(channel_);
UdpTransport::Destroy(socket_transport_);
}
void VideoChannelTransport::IncomingRTPPacket(
const WebRtc_Word8* incoming_rtp_packet,
const WebRtc_Word32 packet_length,
const char* /*from_ip*/,
const WebRtc_UWord16 /*from_port*/) {
vie_network_->ReceivedRTPPacket(channel_, incoming_rtp_packet, packet_length);
}
void VideoChannelTransport::IncomingRTCPPacket(
const WebRtc_Word8* incoming_rtcp_packet,
const WebRtc_Word32 packet_length,
const char* /*from_ip*/,
const WebRtc_UWord16 /*from_port*/) {
vie_network_->ReceivedRTCPPacket(channel_, incoming_rtcp_packet,
packet_length);
}
int VideoChannelTransport::SetLocalReceiver(WebRtc_UWord16 rtp_port) {
int return_value = socket_transport_->InitializeReceiveSockets(this,
rtp_port);
if (return_value == 0) {
return socket_transport_->StartReceiving(kViENumReceiveSocketBuffers);
}
return return_value;
}
int VideoChannelTransport::SetSendDestination(const char* ip_address,
WebRtc_UWord16 rtp_port) {
return socket_transport_->InitializeSendSockets(ip_address, rtp_port);
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,89 @@
/*
* 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.
*/
#ifndef WEBRTC_TEST_CHANNEL_TRANSPORT_INCLUDE_CHANNEL_TRANSPORT_H_
#define WEBRTC_TEST_CHANNEL_TRANSPORT_INCLUDE_CHANNEL_TRANSPORT_H_
#include "webrtc/test/channel_transport/udp_transport.h"
namespace webrtc {
class ViENetwork;
class VoENetwork;
namespace test {
// Helper class for VoiceEngine tests.
class VoiceChannelTransport : public UdpTransportData {
public:
VoiceChannelTransport(VoENetwork* voe_network, int channel);
virtual ~VoiceChannelTransport();
// Start implementation of UdpTransportData.
void IncomingRTPPacket(const WebRtc_Word8* incoming_rtp_packet,
const WebRtc_Word32 packet_length,
const char* /*from_ip*/,
const WebRtc_UWord16 /*from_port*/);
void IncomingRTCPPacket(const WebRtc_Word8* incoming_rtcp_packet,
const WebRtc_Word32 packet_length,
const char* /*from_ip*/,
const WebRtc_UWord16 /*from_port*/);
// End implementation of UdpTransportData.
// Specifies the ports to receive RTP packets on.
int SetLocalReceiver(WebRtc_UWord16 rtp_port);
// Specifies the destination port and IP address for a specified channel.
int SetSendDestination(const char* ip_address, WebRtc_UWord16 rtp_port);
private:
int channel_;
VoENetwork* voe_network_;
UdpTransport* socket_transport_;
};
// Helper class for VideoEngine tests.
class VideoChannelTransport : public UdpTransportData {
public:
VideoChannelTransport(ViENetwork* vie_network, int channel);
virtual ~VideoChannelTransport();
// Start implementation of UdpTransportData.
void IncomingRTPPacket(const WebRtc_Word8* incoming_rtp_packet,
const WebRtc_Word32 packet_length,
const char* /*from_ip*/,
const WebRtc_UWord16 /*from_port*/);
void IncomingRTCPPacket(const WebRtc_Word8* incoming_rtcp_packet,
const WebRtc_Word32 packet_length,
const char* /*from_ip*/,
const WebRtc_UWord16 /*from_port*/);
// End implementation of UdpTransportData.
// Specifies the ports to receive RTP packets on.
int SetLocalReceiver(WebRtc_UWord16 rtp_port);
// Specifies the destination port and IP address for a specified channel.
int SetSendDestination(const char* ip_address, WebRtc_UWord16 rtp_port);
private:
int channel_;
ViENetwork* vie_network_;
UdpTransport* socket_transport_;
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_CHANNEL_TRANSPORT_INCLUDE_CHANNEL_TRANSPORT_H_

View File

@ -0,0 +1,257 @@
/*
* Copyright (c) 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/test/channel_transport/traffic_control_win.h"
#include <assert.h>
#include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc {
namespace test {
TrafficControlWindows* TrafficControlWindows::instance = NULL;
WebRtc_UWord32 TrafficControlWindows::refCounter = 0;
TrafficControlWindows::TrafficControlWindows(const WebRtc_Word32 id) : _id(id)
{
}
TrafficControlWindows* TrafficControlWindows::GetInstance(
const WebRtc_Word32 id)
{
if(instance != NULL)
{
WEBRTC_TRACE(
kTraceDebug,
kTraceTransport,
id,
"TrafficControlWindows - Returning already created object");
refCounter++;
return instance;
}
WEBRTC_TRACE(kTraceMemory, kTraceTransport, id,
"TrafficControlWindows - Creating new object");
instance = new TrafficControlWindows(id);
if(instance == NULL)
{
WEBRTC_TRACE(kTraceMemory, kTraceTransport, id,
"TrafficControlWindows - Error allocating memory");
return NULL;
}
instance->tcRegister = NULL;
instance->tcDeregister = NULL;
instance->tcEnumerate = NULL;
instance->tcOpenInterface = NULL;
instance->tcCloseInterface = NULL;
instance->tcAddFlow = NULL;
instance->tcDeleteFlow = NULL;
instance->tcAddFilter = NULL;
instance->tcDeleteFilter = NULL;
HMODULE trafficLib = LoadLibrary(TEXT("traffic.dll"));
if(trafficLib == NULL)
{
WEBRTC_TRACE(
kTraceWarning,
kTraceTransport,
id,
"TrafficControlWindows - No QOS support, LoadLibrary returned NULL,\
last error: %d\n",
GetLastError());
delete instance;
instance = NULL;
return NULL;
}
instance->tcRegister = (registerFn)GetProcAddress(trafficLib,
"TcRegisterClient");
instance->tcDeregister = (deregisterFn)GetProcAddress(trafficLib,
"TcDeregisterClient");
instance->tcEnumerate = (enumerateFn)GetProcAddress(
trafficLib,
"TcEnumerateInterfaces");
instance->tcOpenInterface = (openInterfaceFn)GetProcAddress(
trafficLib,
"TcOpenInterfaceW");
instance->tcCloseInterface = (closeInterfaceFn)GetProcAddress(
trafficLib,
"TcCloseInterface");
instance->tcAddFlow = (flowAddFn)GetProcAddress(trafficLib,
"TcAddFlow");
instance->tcDeleteFlow = (flowDeleteFn)GetProcAddress(trafficLib,
"TcDeleteFlow");
instance->tcAddFilter = (filterAddFn)GetProcAddress(trafficLib,
"TcAddFilter");
instance->tcDeleteFilter = (filterDeleteFn)GetProcAddress(trafficLib,
"TcDeleteFilter");
if(instance->tcRegister == NULL ||
instance->tcDeregister == NULL ||
instance->tcEnumerate == NULL ||
instance->tcOpenInterface == NULL ||
instance->tcCloseInterface == NULL ||
instance->tcAddFlow == NULL ||
instance->tcAddFilter == NULL ||
instance->tcDeleteFlow == NULL ||
instance->tcDeleteFilter == NULL)
{
delete instance;
instance = NULL;
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
id,
"TrafficControlWindows - Could not find function pointer for\
traffic control functions");
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
id,
"Tcregister : %x, tcDeregister: %x, tcEnumerate: %x,\
tcOpenInterface: %x, tcCloseInterface: %x, tcAddFlow: %x, tcAddFilter: %x,\
tcDeleteFlow: %x, tcDeleteFilter: %x",
instance->tcRegister,
instance->tcDeregister,
instance->tcEnumerate,
instance->tcOpenInterface,
instance->tcCloseInterface,
instance->tcAddFlow,
instance->tcAddFilter,
instance->tcDeleteFlow,
instance->tcDeleteFilter );
return NULL;
}
refCounter++;
return instance;
}
void TrafficControlWindows::Release(TrafficControlWindows* gtc)
{
if (0 == refCounter)
{
WEBRTC_TRACE(kTraceError, kTraceTransport, -1,
"TrafficControlWindows - Cannot release, refCounter is 0");
return;
}
if (NULL == gtc)
{
WEBRTC_TRACE(kTraceDebug, kTraceTransport, -1,
"TrafficControlWindows - Not releasing, gtc is NULL");
return;
}
WEBRTC_TRACE(kTraceDebug, kTraceTransport, gtc->_id,
"TrafficControlWindows - Releasing object");
refCounter--;
if ((0 == refCounter) && instance)
{
WEBRTC_TRACE(kTraceMemory, kTraceTransport, gtc->_id,
"TrafficControlWindows - Deleting object");
delete instance;
instance = NULL;
}
}
WebRtc_Word32 TrafficControlWindows::ChangeUniqueId(const WebRtc_Word32 id)
{
_id = id;
return 0;
}
ULONG TrafficControlWindows::TcRegisterClient(
ULONG TciVersion,
HANDLE ClRegCtx,
PTCI_CLIENT_FUNC_LIST ClientHandlerList,
PHANDLE pClientHandle)
{
assert(tcRegister != NULL);
return tcRegister(TciVersion, ClRegCtx, ClientHandlerList, pClientHandle);
}
ULONG TrafficControlWindows::TcDeregisterClient(HANDLE clientHandle)
{
assert(tcDeregister != NULL);
return tcDeregister(clientHandle);
}
ULONG TrafficControlWindows::TcEnumerateInterfaces(
HANDLE ClientHandle,
PULONG pBufferSize,
PTC_IFC_DESCRIPTOR interfaceBuffer)
{
assert(tcEnumerate != NULL);
return tcEnumerate(ClientHandle, pBufferSize, interfaceBuffer);
}
ULONG TrafficControlWindows::TcOpenInterfaceW(LPWSTR pInterfaceName,
HANDLE ClientHandle,
HANDLE ClIfcCtx,
PHANDLE pIfcHandle)
{
assert(tcOpenInterface != NULL);
return tcOpenInterface(pInterfaceName, ClientHandle, ClIfcCtx, pIfcHandle);
}
ULONG TrafficControlWindows::TcCloseInterface(HANDLE IfcHandle)
{
assert(tcCloseInterface != NULL);
return tcCloseInterface(IfcHandle);
}
ULONG TrafficControlWindows::TcAddFlow(HANDLE IfcHandle, HANDLE ClFlowCtx,
ULONG Flags, PTC_GEN_FLOW pGenericFlow,
PHANDLE pFlowHandle)
{
assert(tcAddFlow != NULL);
return tcAddFlow(IfcHandle, ClFlowCtx, Flags, pGenericFlow, pFlowHandle);
}
ULONG TrafficControlWindows::TcAddFilter(HANDLE FlowHandle,
PTC_GEN_FILTER pGenericFilter,
PHANDLE pFilterHandle)
{
assert(tcAddFilter != NULL);
return tcAddFilter(FlowHandle, pGenericFilter, pFilterHandle);
}
ULONG TrafficControlWindows::TcDeleteFlow(HANDLE FlowHandle)
{
assert(tcDeleteFlow != NULL);
return tcDeleteFlow(FlowHandle);
}
ULONG TrafficControlWindows::TcDeleteFilter(HANDLE FilterHandle)
{
assert(tcDeleteFilter != NULL);
return tcDeleteFilter(FilterHandle);
}
void MyClNotifyHandler(HANDLE ClRegCtx, HANDLE ClIfcCtx, ULONG Event,
HANDLE SubCode, ULONG BufSize, PVOID Buffer)
{
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 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_TEST_CHANNEL_TRANSPORT_TRAFFIC_CONTROL_WINDOWS_H_
#define WEBRTC_TEST_CHANNEL_TRANSPORT_TRAFFIC_CONTROL_WINDOWS_H_
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
// Disable deprication warning from traffic.h
#pragma warning(disable : 4995)
#include <windows.h>
#include <qos.h>
#include <ntddndis.h>
#include <traffic.h>
#include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc {
namespace test {
void MyClNotifyHandler(HANDLE ClRegCtx, HANDLE ClIfcCtx, ULONG Event,
HANDLE SubCode, ULONG BufSize, PVOID Buffer);
typedef ULONG (WINAPI *registerFn)(ULONG, HANDLE, PTCI_CLIENT_FUNC_LIST,
PHANDLE);
typedef ULONG (WINAPI *deregisterFn)(HANDLE);
typedef ULONG (WINAPI *enumerateFn)(HANDLE, PULONG, PTC_IFC_DESCRIPTOR);
typedef ULONG (WINAPI *openInterfaceFn)(LPWSTR, HANDLE, HANDLE, PHANDLE);
typedef ULONG (WINAPI *closeInterfaceFn)(HANDLE);
typedef ULONG (WINAPI *flowAddFn)(HANDLE, HANDLE, ULONG, PTC_GEN_FLOW, PHANDLE);
typedef ULONG (WINAPI *filterAddFn)(HANDLE, PTC_GEN_FILTER, PHANDLE);
typedef ULONG (WINAPI *flowDeleteFn)(HANDLE);
typedef ULONG (WINAPI *filterDeleteFn)(HANDLE);
class TrafficControlWindows
{
public:
// Factory method. Constructor disabled.
static TrafficControlWindows* GetInstance(const WebRtc_Word32 id);
static void Release(TrafficControlWindows* gtc);
WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
ULONG TcRegisterClient(ULONG TciVersion, HANDLE ClRegCtx,
PTCI_CLIENT_FUNC_LIST ClientHandlerList,
PHANDLE pClientHandle);
ULONG TcDeregisterClient(HANDLE clientHandle);
ULONG TcEnumerateInterfaces(HANDLE ClientHandle, PULONG pBufferSize,
PTC_IFC_DESCRIPTOR interfaceBuffer);
ULONG TcOpenInterfaceW(LPWSTR pInterfaceName, HANDLE ClientHandle,
HANDLE ClIfcCtx, PHANDLE pIfcHandle);
ULONG TcCloseInterface(HANDLE IfcHandle);
ULONG TcAddFlow(HANDLE IfcHandle, HANDLE ClFlowCtx, ULONG Flags,
PTC_GEN_FLOW pGenericFlow, PHANDLE pFlowHandle);
ULONG TcAddFilter(HANDLE FlowHandle, PTC_GEN_FILTER pGenericFilter,
PHANDLE pFilterHandle);
ULONG TcDeleteFlow(HANDLE FlowHandle);
ULONG TcDeleteFilter(HANDLE FilterHandle);
private:
TrafficControlWindows(const WebRtc_Word32 id);
WebRtc_Word32 _id;
TCI_CLIENT_FUNC_LIST QoSFunctions;
static TrafficControlWindows* instance;
registerFn tcRegister;
deregisterFn tcDeregister;
enumerateFn tcEnumerate;
openInterfaceFn tcOpenInterface;
closeInterfaceFn tcCloseInterface;
flowAddFn tcAddFlow;
flowDeleteFn tcDeleteFlow;
filterAddFn tcAddFilter;
filterDeleteFn tcDeleteFilter;
static WebRtc_UWord32 refCounter;
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_CHANNEL_TRANSPORT_TRAFFIC_CONTROL_WINDOWS_H_

View File

@ -0,0 +1,661 @@
/*
* Copyright (c) 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/test/channel_transport/udp_socket2_manager_win.h"
#include <assert.h>
#include <stdio.h>
#include "webrtc/system_wrappers/interface/aligned_malloc.h"
#include "webrtc/test/channel_transport/udp_socket2_win.h"
namespace webrtc {
namespace test {
WebRtc_UWord32 UdpSocket2ManagerWindows::_numOfActiveManagers = 0;
bool UdpSocket2ManagerWindows::_wsaInit = false;
UdpSocket2ManagerWindows::UdpSocket2ManagerWindows()
: UdpSocketManager(),
_id(-1),
_stopped(false),
_init(false),
_pCrit(CriticalSectionWrapper::CreateCriticalSection()),
_ioCompletionHandle(NULL),
_numActiveSockets(0),
_event(EventWrapper::Create())
{
_managerNumber = _numOfActiveManagers++;
if(_numOfActiveManagers == 1)
{
WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA wsaData;
_wsaInit = WSAStartup(wVersionRequested, &wsaData) == 0;
// TODO (hellner): seems safer to use RAII for this. E.g. what happens
// if a UdpSocket2ManagerWindows() created and destroyed
// without being initialized.
}
}
UdpSocket2ManagerWindows::~UdpSocket2ManagerWindows()
{
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocket2ManagerWindows(%d)::~UdpSocket2ManagerWindows()",
_managerNumber);
if(_init)
{
_pCrit->Enter();
if(_numActiveSockets)
{
_pCrit->Leave();
_event->Wait(INFINITE);
}
else
{
_pCrit->Leave();
}
StopWorkerThreads();
// All threads are stopped. Safe to delete them.
ListItem* pItem = NULL;
while((pItem = _workerThreadsList.First()) != NULL)
{
delete static_cast<UdpSocket2WorkerWindows*>(pItem->GetItem());
_workerThreadsList.PopFront();
}
_ioContextPool.Free();
_numOfActiveManagers--;
if(_ioCompletionHandle)
{
CloseHandle(_ioCompletionHandle);
}
if (_numOfActiveManagers == 0)
{
if(_wsaInit)
{
WSACleanup();
}
}
}
if(_pCrit)
{
delete _pCrit;
}
if(_event)
{
delete _event;
}
}
bool UdpSocket2ManagerWindows::Init(WebRtc_Word32 id,
WebRtc_UWord8& numOfWorkThreads) {
CriticalSectionScoped cs(_pCrit);
if ((_id != -1) || (_numOfWorkThreads != 0)) {
assert(_id != -1);
assert(_numOfWorkThreads != 0);
return false;
}
_id = id;
_numOfWorkThreads = numOfWorkThreads;
return true;
}
WebRtc_Word32 UdpSocket2ManagerWindows::ChangeUniqueId(const WebRtc_Word32 id)
{
_id = id;
return 0;
}
bool UdpSocket2ManagerWindows::Start()
{
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocket2ManagerWindows(%d)::Start()",_managerNumber);
if(!_init)
{
StartWorkerThreads();
}
if(!_init)
{
return false;
}
_pCrit->Enter();
// Start worker threads.
_stopped = false;
WebRtc_Word32 error = 0;
ListItem* pItem = _workerThreadsList.First();
UdpSocket2WorkerWindows* pWorker;
while(pItem != NULL && !error)
{
pWorker = (UdpSocket2WorkerWindows*)pItem->GetItem();
if(!pWorker->Start())
error = 1;
pItem = _workerThreadsList.Next(pItem);
}
if(error)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::Start() error starting worker\
threads",
_managerNumber);
_pCrit->Leave();
return false;
}
_pCrit->Leave();
return true;
}
bool UdpSocket2ManagerWindows::StartWorkerThreads()
{
if(!_init)
{
_pCrit->Enter();
_ioCompletionHandle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,
0, 0);
if(_ioCompletionHandle == NULL)
{
WebRtc_Word32 error = GetLastError();
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::StartWorkerThreads()"
"_ioCompletioHandle == NULL: error:%d",
_managerNumber,error);
_pCrit->Leave();
return false;
}
// Create worker threads.
WebRtc_UWord32 i = 0;
bool error = false;
while(i < _numOfWorkThreads && !error)
{
UdpSocket2WorkerWindows* pWorker =
new UdpSocket2WorkerWindows(_ioCompletionHandle);
if(pWorker->Init() != 0)
{
error = true;
delete pWorker;
break;
}
_workerThreadsList.PushFront(pWorker);
i++;
}
if(error)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::StartWorkerThreads() error "
"creating work threads",
_managerNumber);
// Delete worker threads.
ListItem* pItem = NULL;
while((pItem = _workerThreadsList.First()) != NULL)
{
delete static_cast<UdpSocket2WorkerWindows*>(pItem->GetItem());
_workerThreadsList.PopFront();
}
_pCrit->Leave();
return false;
}
if(_ioContextPool.Init())
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::StartWorkerThreads() error "
"initiating _ioContextPool",
_managerNumber);
_pCrit->Leave();
return false;
}
_init = true;
WEBRTC_TRACE(
kTraceDebug,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows::StartWorkerThreads %d number of work "
"threads created and initialized",
_numOfWorkThreads);
_pCrit->Leave();
}
return true;
}
bool UdpSocket2ManagerWindows::Stop()
{
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocket2ManagerWindows(%d)::Stop()",_managerNumber);
if(!_init)
{
return false;
}
_pCrit->Enter();
_stopped = true;
if(_numActiveSockets)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::Stop() there is still active\
sockets",
_managerNumber);
_pCrit->Leave();
return false;
}
// No active sockets. Stop all worker threads.
bool result = StopWorkerThreads();
_pCrit->Leave();
return result;
}
bool UdpSocket2ManagerWindows::StopWorkerThreads()
{
WebRtc_Word32 error = 0;
WEBRTC_TRACE(
kTraceDebug,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::StopWorkerThreads() Worker\
threadsStoped, numActicve Sockets=%d",
_managerNumber,
_numActiveSockets);
UdpSocket2WorkerWindows* pWorker;
ListItem* pItem = _workerThreadsList.First();
// Set worker threads to not alive so that they will stop calling
// UdpSocket2WorkerWindows::Run().
while(pItem != NULL)
{
pWorker = (UdpSocket2WorkerWindows*)pItem->GetItem();
pWorker->SetNotAlive();
pItem = _workerThreadsList.Next(pItem);
}
// Release all threads waiting for GetQueuedCompletionStatus(..).
if(_ioCompletionHandle)
{
WebRtc_UWord32 i = 0;
for(i = 0; i < _workerThreadsList.GetSize(); i++)
{
PostQueuedCompletionStatus(_ioCompletionHandle, 0 ,0 , NULL);
}
}
pItem = _workerThreadsList.First();
while(pItem != NULL)
{
pWorker = (UdpSocket2WorkerWindows*)pItem->GetItem();
if(pWorker->Stop() == false)
{
error = -1;
WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1,
"failed to stop worker thread");
}
pItem = _workerThreadsList.Next(pItem);
}
if(error)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::StopWorkerThreads() error stopping\
worker threads",
_managerNumber);
return false;
}
return true;
}
bool UdpSocket2ManagerWindows::AddSocketPrv(UdpSocket2Windows* s)
{
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocket2ManagerWindows(%d)::AddSocketPrv()",_managerNumber);
if(!_init)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::AddSocketPrv() manager not\
initialized",
_managerNumber);
return false;
}
_pCrit->Enter();
if(s == NULL)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::AddSocketPrv() socket == NULL",
_managerNumber);
_pCrit->Leave();
return false;
}
if(s->GetFd() == NULL || s->GetFd() == INVALID_SOCKET)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::AddSocketPrv() socket->GetFd() ==\
%d",
_managerNumber,
(WebRtc_Word32)s->GetFd());
_pCrit->Leave();
return false;
}
_ioCompletionHandle = CreateIoCompletionPort((HANDLE)s->GetFd(),
_ioCompletionHandle,
(ULONG_PTR)(s), 0);
if(_ioCompletionHandle == NULL)
{
WebRtc_Word32 error = GetLastError();
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::AddSocketPrv() Error adding to IO\
completion: %d",
_managerNumber,
error);
_pCrit->Leave();
return false;
}
_numActiveSockets++;
_pCrit->Leave();
return true;
}
bool UdpSocket2ManagerWindows::RemoveSocketPrv(UdpSocket2Windows* s)
{
if(!_init)
{
return false;
}
_pCrit->Enter();
_numActiveSockets--;
if(_numActiveSockets == 0)
{
_event->Set();
}
_pCrit->Leave();
return true;
}
PerIoContext* UdpSocket2ManagerWindows::PopIoContext()
{
if(!_init)
{
return NULL;
}
PerIoContext* pIoC = NULL;
if(!_stopped)
{
pIoC = _ioContextPool.PopIoContext();
}else
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocket2ManagerWindows(%d)::PopIoContext() Manager Not started",
_managerNumber);
}
return pIoC;
}
WebRtc_Word32 UdpSocket2ManagerWindows::PushIoContext(PerIoContext* pIoContext)
{
return _ioContextPool.PushIoContext(pIoContext);
}
IoContextPool::IoContextPool()
: _pListHead(NULL),
_init(false),
_size(0),
_inUse(0)
{
}
IoContextPool::~IoContextPool()
{
Free();
assert(_size.Value() == 0);
AlignedFree(_pListHead);
}
WebRtc_Word32 IoContextPool::Init(WebRtc_UWord32 /*increaseSize*/)
{
if(_init)
{
return 0;
}
_pListHead = (PSLIST_HEADER)AlignedMalloc(sizeof(SLIST_HEADER),
MEMORY_ALLOCATION_ALIGNMENT);
if(_pListHead == NULL)
{
return -1;
}
InitializeSListHead(_pListHead);
_init = true;
return 0;
}
PerIoContext* IoContextPool::PopIoContext()
{
if(!_init)
{
return NULL;
}
PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(_pListHead);
if(pListEntry == NULL)
{
IoContextPoolItem* item = (IoContextPoolItem*)
AlignedMalloc(
sizeof(IoContextPoolItem),
MEMORY_ALLOCATION_ALIGNMENT);
if(item == NULL)
{
return NULL;
}
memset(&item->payload.ioContext,0,sizeof(PerIoContext));
item->payload.base = item;
pListEntry = &(item->itemEntry);
++_size;
}
++_inUse;
return &((IoContextPoolItem*)pListEntry)->payload.ioContext;
}
WebRtc_Word32 IoContextPool::PushIoContext(PerIoContext* pIoContext)
{
// TODO (hellner): Overlapped IO should be completed at this point. Perhaps
// add an assert?
const bool overlappedIOCompleted = HasOverlappedIoCompleted(
(LPOVERLAPPED)pIoContext);
IoContextPoolItem* item = ((IoContextPoolItemPayload*)pIoContext)->base;
const WebRtc_Word32 usedItems = --_inUse;
const WebRtc_Word32 totalItems = _size.Value();
const WebRtc_Word32 freeItems = totalItems - usedItems;
if(freeItems < 0)
{
assert(false);
AlignedFree(item);
return -1;
}
if((freeItems >= totalItems>>1) &&
overlappedIOCompleted)
{
AlignedFree(item);
--_size;
return 0;
}
InterlockedPushEntrySList(_pListHead, &(item->itemEntry));
return 0;
}
WebRtc_Word32 IoContextPool::Free()
{
if(!_init)
{
return 0;
}
WebRtc_Word32 itemsFreed = 0;
PSLIST_ENTRY pListEntry = InterlockedPopEntrySList(_pListHead);
while(pListEntry != NULL)
{
IoContextPoolItem* item = ((IoContextPoolItem*)pListEntry);
AlignedFree(item);
--_size;
itemsFreed++;
pListEntry = InterlockedPopEntrySList(_pListHead);
}
return itemsFreed;
}
WebRtc_Word32 UdpSocket2WorkerWindows::_numOfWorkers = 0;
UdpSocket2WorkerWindows::UdpSocket2WorkerWindows(HANDLE ioCompletionHandle)
: _ioCompletionHandle(ioCompletionHandle),
_pThread(NULL),
_init(false)
{
_workerNumber = _numOfWorkers++;
WEBRTC_TRACE(kTraceMemory, kTraceTransport, -1,
"UdpSocket2WorkerWindows created");
}
UdpSocket2WorkerWindows::~UdpSocket2WorkerWindows()
{
if(_pThread)
{
delete _pThread;
}
WEBRTC_TRACE(kTraceMemory, kTraceTransport, -1,
"UdpSocket2WorkerWindows deleted");
}
bool UdpSocket2WorkerWindows::Start()
{
unsigned int id = 0;
WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, -1,
"Start UdpSocket2WorkerWindows");
return _pThread->Start(id);
}
bool UdpSocket2WorkerWindows::Stop()
{
WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, -1,
"Stop UdpSocket2WorkerWindows");
return _pThread->Stop();
}
void UdpSocket2WorkerWindows::SetNotAlive()
{
WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, -1,
"SetNotAlive UdpSocket2WorkerWindows");
_pThread->SetNotAlive();
}
WebRtc_Word32 UdpSocket2WorkerWindows::Init()
{
if(!_init)
{
const char* threadName = "UdpSocket2ManagerWindows_thread";
_pThread = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
threadName);
if(_pThread == NULL)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
-1,
"UdpSocket2WorkerWindows(%d)::Init(), error creating thread!",
_workerNumber);
return -1;
}
_init = true;
}
return 0;
}
bool UdpSocket2WorkerWindows::Run(ThreadObj obj)
{
UdpSocket2WorkerWindows* pWorker =
static_cast<UdpSocket2WorkerWindows*>(obj);
return pWorker->Process();
}
// Process should always return true. Stopping the worker threads is done in
// the UdpSocket2ManagerWindows::StopWorkerThreads() function.
bool UdpSocket2WorkerWindows::Process()
{
WebRtc_Word32 success = 0;
DWORD ioSize = 0;
UdpSocket2Windows* pSocket = NULL;
PerIoContext* pIOContext = 0;
OVERLAPPED* pOverlapped = 0;
success = GetQueuedCompletionStatus(_ioCompletionHandle,
&ioSize,
(ULONG_PTR*)&pSocket, &pOverlapped, 200);
WebRtc_UWord32 error = 0;
if(!success)
{
error = GetLastError();
if(error == WAIT_TIMEOUT)
{
return true;
}
// This may happen if e.g. PostQueuedCompletionStatus() has been called.
// The IO context still needs to be reclaimed or re-used which is done
// in UdpSocket2Windows::IOCompleted(..).
}
if(pSocket == NULL)
{
WEBRTC_TRACE(
kTraceDebug,
kTraceTransport,
-1,
"UdpSocket2WorkerWindows(%d)::Process(), pSocket == 0, end thread",
_workerNumber);
return true;
}
pIOContext = (PerIoContext*)pOverlapped;
pSocket->IOCompleted(pIOContext,ioSize,error);
return true;
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 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_TEST_CHANNEL_TRANSPORT_UDP_SOCKET2_MANAGER_WINDOWS_H_
#define WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET2_MANAGER_WINDOWS_H_
#if _MSC_VER > 1000
#pragma once
#endif
#include <winsock2.h>
#include "webrtc/system_wrappers/interface/atomic32.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/list_wrapper.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/test/channel_transport/udp_socket2_win.h"
#include "webrtc/test/channel_transport/udp_socket_manager_wrapper.h"
#define MAX_IO_BUFF_SIZE 1600
namespace webrtc {
namespace test {
enum IO_OPERATION {
OP_READ,
OP_WRITE
};
class UdpSocket2Windows;
// Struct used for all socket I/O operations.
struct PerIoContext {
WSAOVERLAPPED overlapped;
char buffer[MAX_IO_BUFF_SIZE];
WSABUF wsabuf;
int nTotalBytes;
int nSentBytes;
int bytes;
IO_OPERATION ioOperation;
SocketAddress from;
int fromLen;
// Should be set to true if the I/O context was passed to the system by
// a thread not controlled by the socket implementation.
bool ioInitiatedByThreadWrapper;
// TODO (hellner): Not used. Delete it.
PerIoContext* pNextFree;
};
struct IoContextPoolItem;
struct IoContextPoolItemPayload
{
PerIoContext ioContext;
IoContextPoolItem* base;
};
struct IoContextPoolItem
{
// Atomic single linked list entry header.
SLIST_ENTRY itemEntry;
// Atomic single linked list payload
IoContextPoolItemPayload payload;
};
class IoContextPool
{
public:
IoContextPool();
virtual ~IoContextPool();
virtual WebRtc_Word32 Init(WebRtc_UWord32 increaseSize = 128);
// Re-use an old unused IO context or create a new one.
virtual PerIoContext* PopIoContext();
virtual WebRtc_Word32 PushIoContext(PerIoContext* pIoContext);
virtual inline WebRtc_Word32 GetSize(WebRtc_UWord32* inUse = 0)
{return _size.Value();}
virtual WebRtc_Word32 Free();
private:
// Sample code for use of msfts single linked atomic list can be found here:
// http://msdn.microsoft.com/en-us/library/ms686962(VS.85).aspx
// Atomic single linked list head.
PSLIST_HEADER _pListHead;
bool _init;
Atomic32 _size;
Atomic32 _inUse;
};
class UdpSocket2ManagerWindows : public UdpSocketManager
{
public:
UdpSocket2ManagerWindows();
virtual ~UdpSocket2ManagerWindows();
virtual bool Init(WebRtc_Word32 id, WebRtc_UWord8& numOfWorkThreads);
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
virtual bool Start();
virtual bool Stop();
virtual inline bool AddSocket(UdpSocketWrapper* s)
{if(s) return AddSocketPrv(reinterpret_cast<UdpSocket2Windows*>(s));
return false;}
virtual bool RemoveSocket(UdpSocketWrapper* s)
{if(s) return RemoveSocketPrv(reinterpret_cast<UdpSocket2Windows*>(s));
return false;}
PerIoContext* PopIoContext(void);
WebRtc_Word32 PushIoContext(PerIoContext* pIoContext);
private:
bool StopWorkerThreads();
bool StartWorkerThreads();
bool AddSocketPrv(UdpSocket2Windows* s);
bool RemoveSocketPrv(UdpSocket2Windows* s);
static WebRtc_UWord32 _numOfActiveManagers;
static bool _wsaInit;
WebRtc_Word32 _id;
CriticalSectionWrapper* _pCrit;
WebRtc_Word32 _managerNumber;
volatile bool _stopped;
bool _init;
WebRtc_Word32 _numActiveSockets;
ListWrapper _workerThreadsList;
EventWrapper* _event;
HANDLE _ioCompletionHandle;
IoContextPool _ioContextPool;
};
class UdpSocket2WorkerWindows
{
public:
UdpSocket2WorkerWindows(HANDLE ioCompletionHandle);
virtual ~UdpSocket2WorkerWindows();
virtual bool Start();
virtual bool Stop();
virtual WebRtc_Word32 Init();
virtual void SetNotAlive();
protected:
static bool Run(ThreadObj obj);
bool Process();
private:
HANDLE _ioCompletionHandle;
ThreadWrapper*_pThread;
static WebRtc_Word32 _numOfWorkers;
WebRtc_Word32 _workerNumber;
volatile bool _stop;
bool _init;
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET2_MANAGER_WINDOWS_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 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_TEST_CHANNEL_TRANSPORT_UDP_SOCKET2_WINDOWS_H_
#define WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET2_WINDOWS_H_
// Disable deprication warning from traffic.h
#pragma warning(disable : 4995)
// Don't change include order for these header files.
#include <Winsock2.h>
#include <Ntddndis.h>
#include <traffic.h>
#include "webrtc/system_wrappers/interface/atomic32.h"
#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/list_wrapper.h"
#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/test/channel_transport/udp_socket_wrapper.h"
#include "webrtc/test/channel_transport/udp_socket2_manager_win.h"
namespace webrtc {
namespace test {
class UdpSocket2ManagerWindows;
class TrafficControlWindows;
struct PerIoContext;
class UdpSocket2Windows : public UdpSocketWrapper
{
public:
UdpSocket2Windows(const WebRtc_Word32 id, UdpSocketManager* mgr,
bool ipV6Enable = false, bool disableGQOS = false);
virtual ~UdpSocket2Windows();
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
virtual bool ValidHandle();
virtual bool SetCallback(CallbackObj, IncomingSocketCallback);
virtual bool Bind(const SocketAddress& name);
virtual bool SetSockopt(WebRtc_Word32 level, WebRtc_Word32 optname,
const WebRtc_Word8* optval, WebRtc_Word32 optlen);
virtual bool StartReceiving(const WebRtc_UWord32 receiveBuffers);
virtual inline bool StartReceiving() {return StartReceiving(8);}
virtual bool StopReceiving();
virtual WebRtc_Word32 SendTo(const WebRtc_Word8* buf, WebRtc_Word32 len,
const SocketAddress& to);
virtual void CloseBlocking();
virtual SOCKET GetFd() { return _socket;}
virtual bool SetQos(WebRtc_Word32 serviceType, WebRtc_Word32 tokenRate,
WebRtc_Word32 bucketSize, WebRtc_Word32 peekBandwith,
WebRtc_Word32 minPolicedSize, WebRtc_Word32 maxSduSize,
const SocketAddress &stRemName,
WebRtc_Word32 overrideDSCP = 0);
virtual WebRtc_Word32 SetTOS(const WebRtc_Word32 serviceType);
virtual WebRtc_Word32 SetPCP(const WebRtc_Word32 pcp);
virtual WebRtc_UWord32 ReceiveBuffers(){return _receiveBuffers.Value();}
protected:
void IOCompleted(PerIoContext* pIOContext, WebRtc_UWord32 ioSize,
WebRtc_UWord32 error);
WebRtc_Word32 PostRecv();
// Use pIoContext to post a new WSARecvFrom(..).
WebRtc_Word32 PostRecv(PerIoContext* pIoContext);
private:
friend class UdpSocket2WorkerWindows;
// Set traffic control (TC) flow adding it the interface that matches this
// sockets address.
// A filter is created and added to the flow.
// The flow consists of:
// (1) QoS send and receive information (flow specifications).
// (2) A DS object (for specifying exact DSCP value).
// (3) Possibly a traffic object (for specifying exact 802.1p priority (PCP)
// value).
//
// dscp values:
// -1 don't change the current dscp value.
// 0 don't add any flow to TC, unless pcp is specified.
// 1-63 Add a flow to TC with the specified dscp value.
// pcp values:
// -2 Don't add pcp info to the flow, (3) will not be added.
// -1 Don't change the current value.
// 0-7 Add pcp info to the flow with the specified value,
// (3) will be added.
//
// If both dscp and pcp are -1 no flow will be created or added to TC.
// If dscp is 0 and pcp is 0-7 (1), (2) and (3) will be created.
// Note: input parameter values are assumed to be in valid range, checks
// must be done by caller.
WebRtc_Word32 SetTrafficControl(WebRtc_Word32 dscp, WebRtc_Word32 pcp,
const struct sockaddr_in* name,
FLOWSPEC* send = NULL,
FLOWSPEC* recv = NULL);
WebRtc_Word32 CreateFlowSpec(WebRtc_Word32 serviceType,
WebRtc_Word32 tokenRate,
WebRtc_Word32 bucketSize,
WebRtc_Word32 peekBandwith,
WebRtc_Word32 minPolicedSize,
WebRtc_Word32 maxSduSize, FLOWSPEC *f);
WebRtc_Word32 _id;
RWLockWrapper* _ptrCbRWLock;
IncomingSocketCallback _incomingCb;
CallbackObj _obj;
bool _qos;
SocketAddress _remoteAddr;
SOCKET _socket;
WebRtc_Word32 _iProtocol;
UdpSocket2ManagerWindows* _mgr;
CriticalSectionWrapper* _pCrit;
Atomic32 _outstandingCalls;
Atomic32 _outstandingCallComplete;
volatile bool _terminate;
volatile bool _addedToMgr;
CriticalSectionWrapper* _ptrDeleteCrit;
ConditionVariableWrapper* _ptrDeleteCond;
bool _safeTodelete;
RWLockWrapper* _ptrDestRWLock;
bool _outstandingCallsDisabled;
bool NewOutstandingCall();
void OutstandingCallCompleted();
void DisableNewOutstandingCalls();
void WaitForOutstandingCalls();
void RemoveSocketFromManager();
// RWLockWrapper is used as a reference counter for the socket. Write lock
// is used for creating and deleting socket. Read lock is used for
// accessing the socket.
RWLockWrapper* _ptrSocketRWLock;
bool AquireSocket();
void ReleaseSocket();
bool InvalidateSocket();
// Traffic control handles and structure pointers.
HANDLE _clientHandle;
HANDLE _flowHandle;
HANDLE _filterHandle;
PTC_GEN_FLOW _flow;
// TrafficControlWindows implements TOS and PCP.
TrafficControlWindows* _gtc;
// Holds the current pcp value. Can be -2 or 0 - 7.
int _pcp;
Atomic32 _receiveBuffers;
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET2_WINDOWS_H_

View File

@ -0,0 +1,431 @@
/*
* Copyright (c) 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/test/channel_transport/udp_socket_manager_posix.h"
#include <strings.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/test/channel_transport/udp_socket_posix.h"
namespace webrtc {
namespace test {
UdpSocketManagerPosix::UdpSocketManagerPosix()
: UdpSocketManager(),
_id(-1),
_critSect(CriticalSectionWrapper::CreateCriticalSection()),
_numberOfSocketMgr(-1),
_incSocketMgrNextTime(0),
_nextSocketMgrToAssign(0),
_socketMgr()
{
}
bool UdpSocketManagerPosix::Init(WebRtc_Word32 id,
WebRtc_UWord8& numOfWorkThreads) {
CriticalSectionScoped cs(_critSect);
if ((_id != -1) || (_numOfWorkThreads != 0)) {
assert(_id != -1);
assert(_numOfWorkThreads != 0);
return false;
}
_id = id;
_numberOfSocketMgr = numOfWorkThreads;
_numOfWorkThreads = numOfWorkThreads;
if(MAX_NUMBER_OF_SOCKET_MANAGERS_LINUX < _numberOfSocketMgr)
{
_numberOfSocketMgr = MAX_NUMBER_OF_SOCKET_MANAGERS_LINUX;
}
for(int i = 0;i < _numberOfSocketMgr; i++)
{
_socketMgr[i] = new UdpSocketManagerPosixImpl();
}
return true;
}
UdpSocketManagerPosix::~UdpSocketManagerPosix()
{
Stop();
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocketManagerPosix(%d)::UdpSocketManagerPosix()",
_numberOfSocketMgr);
for(int i = 0;i < _numberOfSocketMgr; i++)
{
delete _socketMgr[i];
}
delete _critSect;
}
WebRtc_Word32 UdpSocketManagerPosix::ChangeUniqueId(const WebRtc_Word32 id)
{
_id = id;
return 0;
}
bool UdpSocketManagerPosix::Start()
{
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocketManagerPosix(%d)::Start()",
_numberOfSocketMgr);
_critSect->Enter();
bool retVal = true;
for(int i = 0;i < _numberOfSocketMgr && retVal; i++)
{
retVal = _socketMgr[i]->Start();
}
if(!retVal)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocketManagerPosix(%d)::Start() error starting socket managers",
_numberOfSocketMgr);
}
_critSect->Leave();
return retVal;
}
bool UdpSocketManagerPosix::Stop()
{
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocketManagerPosix(%d)::Stop()",_numberOfSocketMgr);
_critSect->Enter();
bool retVal = true;
for(int i = 0; i < _numberOfSocketMgr && retVal; i++)
{
retVal = _socketMgr[i]->Stop();
}
if(!retVal)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocketManagerPosix(%d)::Stop() there are still active socket "
"managers",
_numberOfSocketMgr);
}
_critSect->Leave();
return retVal;
}
bool UdpSocketManagerPosix::AddSocket(UdpSocketWrapper* s)
{
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocketManagerPosix(%d)::AddSocket()",_numberOfSocketMgr);
_critSect->Enter();
bool retVal = _socketMgr[_nextSocketMgrToAssign]->AddSocket(s);
if(!retVal)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocketManagerPosix(%d)::AddSocket() failed to add socket to\
manager",
_numberOfSocketMgr);
}
// Distribute sockets on UdpSocketManagerPosixImpls in a round-robin
// fashion.
if(_incSocketMgrNextTime == 0)
{
_incSocketMgrNextTime++;
} else {
_incSocketMgrNextTime = 0;
_nextSocketMgrToAssign++;
if(_nextSocketMgrToAssign >= _numberOfSocketMgr)
{
_nextSocketMgrToAssign = 0;
}
}
_critSect->Leave();
return retVal;
}
bool UdpSocketManagerPosix::RemoveSocket(UdpSocketWrapper* s)
{
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocketManagerPosix(%d)::RemoveSocket()",
_numberOfSocketMgr);
_critSect->Enter();
bool retVal = false;
for(int i = 0;i < _numberOfSocketMgr && (retVal == false); i++)
{
retVal = _socketMgr[i]->RemoveSocket(s);
}
if(!retVal)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
_id,
"UdpSocketManagerPosix(%d)::RemoveSocket() failed to remove socket\
from manager",
_numberOfSocketMgr);
}
_critSect->Leave();
return retVal;
}
UdpSocketManagerPosixImpl::UdpSocketManagerPosixImpl()
{
_critSectList = CriticalSectionWrapper::CreateCriticalSection();
_thread = ThreadWrapper::CreateThread(UdpSocketManagerPosixImpl::Run, this,
kRealtimePriority,
"UdpSocketManagerPosixImplThread");
FD_ZERO(&_readFds);
WEBRTC_TRACE(kTraceMemory, kTraceTransport, -1,
"UdpSocketManagerPosix created");
}
UdpSocketManagerPosixImpl::~UdpSocketManagerPosixImpl()
{
if(_thread != NULL)
{
delete _thread;
}
if (_critSectList != NULL)
{
UpdateSocketMap();
_critSectList->Enter();
MapItem* item = _socketMap.First();
while(item)
{
UdpSocketPosix* s = static_cast<UdpSocketPosix*>(item->GetItem());
_socketMap.Erase(item);
item = _socketMap.First();
delete s;
}
_critSectList->Leave();
delete _critSectList;
}
WEBRTC_TRACE(kTraceMemory, kTraceTransport, -1,
"UdpSocketManagerPosix deleted");
}
bool UdpSocketManagerPosixImpl::Start()
{
unsigned int id = 0;
if (_thread == NULL)
{
return false;
}
WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, -1,
"Start UdpSocketManagerPosix");
return _thread->Start(id);
}
bool UdpSocketManagerPosixImpl::Stop()
{
if (_thread == NULL)
{
return true;
}
WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, -1,
"Stop UdpSocketManagerPosix");
return _thread->Stop();
}
bool UdpSocketManagerPosixImpl::Process()
{
bool doSelect = false;
// Timeout = 1 second.
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
MapItem* it;
FD_ZERO(&_readFds);
UpdateSocketMap();
unsigned int maxFd = 0;
for (it = _socketMap.First(); it != NULL; it=_socketMap.Next(it))
{
doSelect = true;
maxFd = maxFd > it->GetUnsignedId() ? maxFd : it->GetUnsignedId();
FD_SET(it->GetUnsignedId(), &_readFds);
}
int num = 0;
if (doSelect)
{
num = select(maxFd+1, &_readFds, NULL, NULL, &timeout);
if (num == SOCKET_ERROR)
{
// Timeout = 10 ms.
timespec t;
t.tv_sec = 0;
t.tv_nsec = 10000*1000;
nanosleep(&t, NULL);
return true;
}
}else
{
// Timeout = 10 ms.
timespec t;
t.tv_sec = 0;
t.tv_nsec = 10000*1000;
nanosleep(&t, NULL);
return true;
}
for (it = _socketMap.First(); it != NULL && num > 0;
it = _socketMap.Next(it))
{
UdpSocketPosix* s = static_cast<UdpSocketPosix*>(it->GetItem());
if (FD_ISSET(it->GetUnsignedId(), &_readFds))
{
s->HasIncoming();
num--;
}
}
return true;
}
bool UdpSocketManagerPosixImpl::Run(ThreadObj obj)
{
UdpSocketManagerPosixImpl* mgr =
static_cast<UdpSocketManagerPosixImpl*>(obj);
return mgr->Process();
}
bool UdpSocketManagerPosixImpl::AddSocket(UdpSocketWrapper* s)
{
UdpSocketPosix* sl = static_cast<UdpSocketPosix*>(s);
if(sl->GetFd() == INVALID_SOCKET || !(sl->GetFd() < FD_SETSIZE))
{
return false;
}
_critSectList->Enter();
_addList.PushBack(s);
_critSectList->Leave();
return true;
}
bool UdpSocketManagerPosixImpl::RemoveSocket(UdpSocketWrapper* s)
{
// Put in remove list if this is the correct UdpSocketManagerPosixImpl.
_critSectList->Enter();
// If the socket is in the add list it's safe to remove and delete it.
ListItem* addListItem = _addList.First();
while(addListItem)
{
UdpSocketPosix* addSocket = (UdpSocketPosix*)addListItem->GetItem();
unsigned int addFD = addSocket->GetFd();
unsigned int removeFD = static_cast<UdpSocketPosix*>(s)->GetFd();
if(removeFD == addFD)
{
_removeList.PushBack(removeFD);
_critSectList->Leave();
return true;
}
addListItem = _addList.Next(addListItem);
}
// Checking the socket map is safe since all Erase and Insert calls to this
// map are also protected by _critSectList.
if(_socketMap.Find(static_cast<UdpSocketPosix*>(s)->GetFd()) != NULL)
{
_removeList.PushBack(static_cast<UdpSocketPosix*>(s)->GetFd());
_critSectList->Leave();
return true;
}
_critSectList->Leave();
return false;
}
void UdpSocketManagerPosixImpl::UpdateSocketMap()
{
// Remove items in remove list.
_critSectList->Enter();
while(!_removeList.Empty())
{
UdpSocketPosix* deleteSocket = NULL;
unsigned int removeFD = _removeList.First()->GetUnsignedItem();
// If the socket is in the add list it hasn't been added to the socket
// map yet. Just remove the socket from the add list.
ListItem* addListItem = _addList.First();
while(addListItem)
{
UdpSocketPosix* addSocket = (UdpSocketPosix*)addListItem->GetItem();
unsigned int addFD = addSocket->GetFd();
if(removeFD == addFD)
{
deleteSocket = addSocket;
_addList.Erase(addListItem);
break;
}
addListItem = _addList.Next(addListItem);
}
// Find and remove socket from _socketMap.
MapItem* it = _socketMap.Find(removeFD);
if(it != NULL)
{
UdpSocketPosix* socket =
static_cast<UdpSocketPosix*>(it->GetItem());
if(socket)
{
deleteSocket = socket;
}
_socketMap.Erase(it);
}
if(deleteSocket)
{
deleteSocket->ReadyForDeletion();
delete deleteSocket;
}
_removeList.PopFront();
}
// Add sockets from add list.
while(!_addList.Empty())
{
UdpSocketPosix* s =
static_cast<UdpSocketPosix*>(_addList.First()->GetItem());
if(s)
{
_socketMap.Insert(s->GetFd(), s);
}
_addList.PopFront();
}
_critSectList->Leave();
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 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_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_MANAGER_POSIX_H_
#define WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_MANAGER_POSIX_H_
#include <sys/types.h>
#include <unistd.h>
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/list_wrapper.h"
#include "webrtc/system_wrappers/interface/map_wrapper.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/test/channel_transport/udp_socket_manager_wrapper.h"
#include "webrtc/test/channel_transport/udp_socket_wrapper.h"
namespace webrtc {
class ConditionVariableWrapper;
namespace test {
class UdpSocketManagerPosixImpl;
#define MAX_NUMBER_OF_SOCKET_MANAGERS_LINUX 8
class UdpSocketManagerPosix : public UdpSocketManager
{
public:
UdpSocketManagerPosix();
virtual ~UdpSocketManagerPosix();
virtual bool Init(WebRtc_Word32 id,
WebRtc_UWord8& numOfWorkThreads);
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
virtual bool Start();
virtual bool Stop();
virtual bool AddSocket(UdpSocketWrapper* s);
virtual bool RemoveSocket(UdpSocketWrapper* s);
private:
WebRtc_Word32 _id;
CriticalSectionWrapper* _critSect;
WebRtc_UWord8 _numberOfSocketMgr;
WebRtc_UWord8 _incSocketMgrNextTime;
WebRtc_UWord8 _nextSocketMgrToAssign;
UdpSocketManagerPosixImpl* _socketMgr[MAX_NUMBER_OF_SOCKET_MANAGERS_LINUX];
};
class UdpSocketManagerPosixImpl
{
public:
UdpSocketManagerPosixImpl();
virtual ~UdpSocketManagerPosixImpl();
virtual bool Start();
virtual bool Stop();
virtual bool AddSocket(UdpSocketWrapper* s);
virtual bool RemoveSocket(UdpSocketWrapper* s);
protected:
static bool Run(ThreadObj obj);
bool Process();
void UpdateSocketMap();
private:
ThreadWrapper* _thread;
CriticalSectionWrapper* _critSectList;
fd_set _readFds;
MapWrapper _socketMap;
ListWrapper _addList;
ListWrapper _removeList;
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_MANAGER_POSIX_H_

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 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.
*/
// Tests for the UdpSocketManager interface.
// Note: This tests UdpSocketManager together with UdpSocketWrapper,
// due to the way the code is full of static-casts to the platform dependent
// subtypes.
// It also uses the static UdpSocketManager object.
// The most important property of these tests is that they do not leak memory.
#include "gtest/gtest.h"
#include "webrtc/test/channel_transport/udp_socket_wrapper.h"
#include "webrtc/test/channel_transport/udp_socket_manager_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc {
namespace test {
TEST(UdpSocketManager, CreateCallsInitAndDoesNotLeakMemory) {
WebRtc_Word32 id = 42;
WebRtc_UWord8 threads = 1;
UdpSocketManager* mgr = UdpSocketManager::Create(id, threads);
// Create is supposed to have called init on the object.
EXPECT_FALSE(mgr->Init(id, threads))
<< "Init should return false since Create is supposed to call it.";
UdpSocketManager::Return();
}
// Creates a socket and adds it to the socket manager, and then removes it
// before destroying the socket manager.
TEST(UdpSocketManager, AddAndRemoveSocketDoesNotLeakMemory) {
WebRtc_Word32 id = 42;
WebRtc_UWord8 threads = 1;
UdpSocketManager* mgr = UdpSocketManager::Create(id, threads);
UdpSocketWrapper* socket =
UdpSocketWrapper::CreateSocket(id,
mgr,
NULL, // CallbackObj
NULL, // IncomingSocketCallback
false, // ipV6Enable
false); // disableGQOS
// The constructor will do AddSocket on the manager.
// RemoveSocket indirectly calls Delete.
EXPECT_EQ(true, mgr->RemoveSocket(socket));
UdpSocketManager::Return();
}
// Creates a socket and add it to the socket manager, but does not remove it
// before destroying the socket manager.
// On Posix, this destroys the socket.
// On Winsock2 Windows, it enters an infinite wait for all the sockets
// to go away.
TEST(UdpSocketManager, UnremovedSocketsGetCollectedAtManagerDeletion) {
#if defined(_WIN32)
// It's hard to test an infinite wait, so we don't.
#else
WebRtc_Word32 id = 42;
WebRtc_UWord8 threads = 1;
UdpSocketManager* mgr = UdpSocketManager::Create(id, threads);
UdpSocketWrapper* unused_socket = UdpSocketWrapper::CreateSocket(
id,
mgr,
NULL, // CallbackObj
NULL, // IncomingSocketCallback
false, // ipV6Enable
false); // disableGQOS
// The constructor will do AddSocket on the manager.
// Call a member funtion to work around "set but not used" compliation
// error on ChromeOS ARM.
unused_socket->SetEventToNull();
unused_socket = NULL;
UdpSocketManager::Return();
#endif
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 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/test/channel_transport/udp_socket_manager_wrapper.h"
#include <cassert>
#ifdef _WIN32
#include "webrtc/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h"
#include "webrtc/test/channel_transport/udp_socket2_manager_win.h"
#else
#include "webrtc/test/channel_transport/udp_socket_manager_posix.h"
#endif
namespace webrtc {
namespace test {
UdpSocketManager* UdpSocketManager::CreateInstance()
{
#if defined(_WIN32)
return static_cast<UdpSocketManager*>(new UdpSocket2ManagerWindows());
#else
return new UdpSocketManagerPosix();
#endif
}
UdpSocketManager* UdpSocketManager::StaticInstance(
CountOperation count_operation,
const WebRtc_Word32 id,
WebRtc_UWord8& numOfWorkThreads)
{
UdpSocketManager* impl =
GetStaticInstance<UdpSocketManager>(count_operation);
if (count_operation == kAddRef && impl != NULL) {
if (impl->Init(id, numOfWorkThreads)) {
impl->Start();
}
}
return impl;
}
UdpSocketManager* UdpSocketManager::Create(const WebRtc_Word32 id,
WebRtc_UWord8& numOfWorkThreads)
{
return UdpSocketManager::StaticInstance(kAddRef, id, numOfWorkThreads);
}
void UdpSocketManager::Return()
{
WebRtc_UWord8 numOfWorkThreads = 0;
UdpSocketManager::StaticInstance(kRelease, -1,
numOfWorkThreads);
}
UdpSocketManager::UdpSocketManager() : _numOfWorkThreads(0)
{
}
WebRtc_UWord8 UdpSocketManager::WorkThreads() const
{
return _numOfWorkThreads;
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 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_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_MANAGER_WRAPPER_H_
#define WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_MANAGER_WRAPPER_H_
#include "webrtc/system_wrappers/interface/static_instance.h"
#include "webrtc/typedefs.h"
namespace webrtc {
namespace test {
class UdpSocketWrapper;
class UdpSocketManager
{
public:
static UdpSocketManager* Create(const WebRtc_Word32 id,
WebRtc_UWord8& numOfWorkThreads);
static void Return();
// Initializes the socket manager. Returns true if the manager wasn't
// already initialized.
virtual bool Init(WebRtc_Word32 id,
WebRtc_UWord8& numOfWorkThreads) = 0;
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id) = 0;
// Start listening to sockets that have been registered via the
// AddSocket(..) API.
virtual bool Start() = 0;
// Stop listening to sockets.
virtual bool Stop() = 0;
virtual WebRtc_UWord8 WorkThreads() const;
// Register a socket with the socket manager.
virtual bool AddSocket(UdpSocketWrapper* s) = 0;
// Unregister a socket from the manager.
virtual bool RemoveSocket(UdpSocketWrapper* s) = 0;
protected:
UdpSocketManager();
virtual ~UdpSocketManager() {}
WebRtc_UWord8 _numOfWorkThreads;
// Factory method.
static UdpSocketManager* CreateInstance();
private:
// Friend function to allow the UDP destructor to be accessed from the
// instance template.
friend UdpSocketManager* webrtc::GetStaticInstance<UdpSocketManager>(
CountOperation count_operation);
static UdpSocketManager* StaticInstance(
CountOperation count_operation,
const WebRtc_Word32 id,
WebRtc_UWord8& numOfWorkThreads);
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_MANAGER_WRAPPER_H_

View File

@ -0,0 +1,281 @@
/*
* Copyright (c) 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/test/channel_transport/udp_socket_posix.h"
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/test/channel_transport/udp_socket_manager_wrapper.h"
#include "webrtc/test/channel_transport/udp_socket_wrapper.h"
namespace webrtc {
namespace test {
UdpSocketPosix::UdpSocketPosix(const WebRtc_Word32 id, UdpSocketManager* mgr,
bool ipV6Enable)
{
WEBRTC_TRACE(kTraceMemory, kTraceTransport, id,
"UdpSocketPosix::UdpSocketPosix()");
_wantsIncoming = false;
_error = 0;
_mgr = mgr;
_id = id;
_obj = NULL;
_incomingCb = NULL;
_readyForDeletionCond = ConditionVariableWrapper::CreateConditionVariable();
_closeBlockingCompletedCond =
ConditionVariableWrapper::CreateConditionVariable();
_cs = CriticalSectionWrapper::CreateCriticalSection();
_readyForDeletion = false;
_closeBlockingActive = false;
_closeBlockingCompleted= false;
if(ipV6Enable)
{
_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
}
else {
_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
// Set socket to nonblocking mode.
int enable_non_blocking = 1;
if(ioctl(_socket, FIONBIO, &enable_non_blocking) == -1)
{
WEBRTC_TRACE(kTraceWarning, kTraceTransport, id,
"Failed to make socket nonblocking");
}
// Enable close on fork for file descriptor so that it will not block until
// forked process terminates.
if(fcntl(_socket, F_SETFD, FD_CLOEXEC) == -1)
{
WEBRTC_TRACE(kTraceWarning, kTraceTransport, id,
"Failed to set FD_CLOEXEC for socket");
}
}
UdpSocketPosix::~UdpSocketPosix()
{
if(_socket != INVALID_SOCKET)
{
close(_socket);
_socket = INVALID_SOCKET;
}
if(_readyForDeletionCond)
{
delete _readyForDeletionCond;
}
if(_closeBlockingCompletedCond)
{
delete _closeBlockingCompletedCond;
}
if(_cs)
{
delete _cs;
}
}
WebRtc_Word32 UdpSocketPosix::ChangeUniqueId(const WebRtc_Word32 id)
{
_id = id;
return 0;
}
bool UdpSocketPosix::SetCallback(CallbackObj obj, IncomingSocketCallback cb)
{
_obj = obj;
_incomingCb = cb;
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocketPosix(%p)::SetCallback", this);
if (_mgr->AddSocket(this))
{
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocketPosix(%p)::SetCallback socket added to manager",
this);
return true; // socket is now ready for action
}
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"UdpSocketPosix(%p)::SetCallback error adding me to mgr",
this);
return false;
}
bool UdpSocketPosix::SetSockopt(WebRtc_Word32 level, WebRtc_Word32 optname,
const WebRtc_Word8* optval, WebRtc_Word32 optlen)
{
if(0 == setsockopt(_socket, level, optname, optval, optlen ))
{
return true;
}
_error = errno;
WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
"UdpSocketPosix::SetSockopt(), error:%d", _error);
return false;
}
WebRtc_Word32 UdpSocketPosix::SetTOS(WebRtc_Word32 serviceType)
{
if (SetSockopt(IPPROTO_IP, IP_TOS ,(WebRtc_Word8*)&serviceType ,4) != 0)
{
return -1;
}
return 0;
}
bool UdpSocketPosix::Bind(const SocketAddress& name)
{
int size = sizeof(sockaddr);
if (0 == bind(_socket, reinterpret_cast<const sockaddr*>(&name),size))
{
return true;
}
_error = errno;
WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
"UdpSocketPosix::Bind() error: %d",_error);
return false;
}
WebRtc_Word32 UdpSocketPosix::SendTo(const WebRtc_Word8* buf, WebRtc_Word32 len,
const SocketAddress& to)
{
int size = sizeof(sockaddr);
int retVal = sendto(_socket,buf, len, 0,
reinterpret_cast<const sockaddr*>(&to), size);
if(retVal == SOCKET_ERROR)
{
_error = errno;
WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
"UdpSocketPosix::SendTo() error: %d", _error);
}
return retVal;
}
bool UdpSocketPosix::ValidHandle()
{
return _socket != INVALID_SOCKET;
}
void UdpSocketPosix::HasIncoming()
{
// replace 2048 with a mcro define and figure out
// where 2048 comes from
WebRtc_Word8 buf[2048];
int retval;
SocketAddress from;
#if defined(WEBRTC_MAC)
sockaddr sockaddrfrom;
memset(&from, 0, sizeof(from));
memset(&sockaddrfrom, 0, sizeof(sockaddrfrom));
socklen_t fromlen = sizeof(sockaddrfrom);
#else
memset(&from, 0, sizeof(from));
socklen_t fromlen = sizeof(from);
#endif
#if defined(WEBRTC_MAC)
retval = recvfrom(_socket,buf, sizeof(buf), 0,
reinterpret_cast<sockaddr*>(&sockaddrfrom), &fromlen);
memcpy(&from, &sockaddrfrom, fromlen);
from._sockaddr_storage.sin_family = sockaddrfrom.sa_family;
#else
retval = recvfrom(_socket,buf, sizeof(buf), 0,
reinterpret_cast<sockaddr*>(&from), &fromlen);
#endif
switch(retval)
{
case 0:
// The peer has performed an orderly shutdown.
break;
case SOCKET_ERROR:
break;
default:
if (_wantsIncoming && _incomingCb)
{
_incomingCb(_obj, buf, retval, &from);
}
break;
}
}
void UdpSocketPosix::CloseBlocking()
{
_cs->Enter();
_closeBlockingActive = true;
if(!CleanUp())
{
_closeBlockingActive = false;
_cs->Leave();
return;
}
while(!_readyForDeletion)
{
_readyForDeletionCond->SleepCS(*_cs);
}
_closeBlockingCompleted = true;
_closeBlockingCompletedCond->Wake();
_cs->Leave();
}
void UdpSocketPosix::ReadyForDeletion()
{
_cs->Enter();
if(!_closeBlockingActive)
{
_cs->Leave();
return;
}
close(_socket);
_socket = INVALID_SOCKET;
_readyForDeletion = true;
_readyForDeletionCond->Wake();
while(!_closeBlockingCompleted)
{
_closeBlockingCompletedCond->SleepCS(*_cs);
}
_cs->Leave();
}
bool UdpSocketPosix::CleanUp()
{
_wantsIncoming = false;
if (_socket == INVALID_SOCKET)
{
return false;
}
WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
"calling UdpSocketManager::RemoveSocket()...");
_mgr->RemoveSocket(this);
// After this, the socket should may be or will be as deleted. Return
// immediately.
return true;
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 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_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_POSIX_H_
#define WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_POSIX_H_
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/test/channel_transport/udp_socket_wrapper.h"
namespace webrtc {
namespace test {
#define SOCKET_ERROR -1
class UdpSocketPosix : public UdpSocketWrapper
{
public:
UdpSocketPosix(const WebRtc_Word32 id, UdpSocketManager* mgr,
bool ipV6Enable = false);
virtual ~UdpSocketPosix();
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
virtual bool SetCallback(CallbackObj obj, IncomingSocketCallback cb);
virtual bool Bind(const SocketAddress& name);
virtual bool SetSockopt(WebRtc_Word32 level, WebRtc_Word32 optname,
const WebRtc_Word8* optval, WebRtc_Word32 optlen);
virtual WebRtc_Word32 SetTOS(const WebRtc_Word32 serviceType);
virtual WebRtc_Word32 SendTo(const WebRtc_Word8* buf, WebRtc_Word32 len,
const SocketAddress& to);
// Deletes socket in addition to closing it.
// TODO (hellner): make destructor protected.
virtual void CloseBlocking();
virtual SOCKET GetFd() {return _socket;}
virtual WebRtc_Word32 GetError() {return _error;}
virtual bool ValidHandle();
virtual bool SetQos(WebRtc_Word32 /*serviceType*/,
WebRtc_Word32 /*tokenRate*/,
WebRtc_Word32 /*bucketSize*/,
WebRtc_Word32 /*peekBandwith*/,
WebRtc_Word32 /*minPolicedSize*/,
WebRtc_Word32 /*maxSduSize*/,
const SocketAddress& /*stRemName*/,
WebRtc_Word32 /*overrideDSCP*/) {return false;}
bool CleanUp();
void HasIncoming();
bool WantsIncoming() {return _wantsIncoming;}
void ReadyForDeletion();
private:
friend class UdpSocketManagerPosix;
WebRtc_Word32 _id;
IncomingSocketCallback _incomingCb;
CallbackObj _obj;
WebRtc_Word32 _error;
SOCKET _socket;
UdpSocketManager* _mgr;
ConditionVariableWrapper* _closeBlockingCompletedCond;
ConditionVariableWrapper* _readyForDeletionCond;
bool _closeBlockingActive;
bool _closeBlockingCompleted;
bool _readyForDeletion;
CriticalSectionWrapper* _cs;
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_POSIX_H_

View File

@ -0,0 +1,151 @@
/*
* Copyright (c) 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/test/channel_transport/udp_socket_wrapper.h"
#include <stdlib.h>
#include <string.h>
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/test/channel_transport/udp_socket_manager_wrapper.h"
#if defined(_WIN32)
#include "webrtc/test/channel_transport/udp_socket2_win.h"
#else
#include "webrtc/test/channel_transport/udp_socket_posix.h"
#endif
namespace webrtc {
namespace test {
bool UdpSocketWrapper::_initiated = false;
// Temporary Android hack. The value 1024 is taken from
// <ndk>/build/platforms/android-1.5/arch-arm/usr/include/linux/posix_types.h
// TODO (tomasl): can we remove this now?
#ifndef FD_SETSIZE
#define FD_SETSIZE 1024
#endif
UdpSocketWrapper::UdpSocketWrapper()
: _wantsIncoming(false),
_deleteEvent(NULL)
{
}
UdpSocketWrapper::~UdpSocketWrapper()
{
if(_deleteEvent)
{
_deleteEvent->Set();
_deleteEvent = NULL;
}
}
void UdpSocketWrapper::SetEventToNull()
{
if (_deleteEvent)
{
_deleteEvent = NULL;
}
}
UdpSocketWrapper* UdpSocketWrapper::CreateSocket(const WebRtc_Word32 id,
UdpSocketManager* mgr,
CallbackObj obj,
IncomingSocketCallback cb,
bool ipV6Enable,
bool disableGQOS)
{
WEBRTC_TRACE(kTraceMemory, kTraceTransport, id,
"UdpSocketWrapper::CreateSocket");
UdpSocketWrapper* s = 0;
#ifdef _WIN32
if (!_initiated)
{
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD( 2, 2 );
WebRtc_Word32 err = WSAStartup( wVersionRequested, &wsaData);
if (err != 0)
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
id,
"UdpSocketWrapper::CreateSocket failed to initialize sockets\
WSAStartup error:%d",
err);
return NULL;
}
_initiated = true;
}
s = new UdpSocket2Windows(id, mgr, ipV6Enable, disableGQOS);
#else
if (!_initiated)
{
_initiated = true;
}
s = new UdpSocketPosix(id, mgr, ipV6Enable);
if (s)
{
UdpSocketPosix* sl = static_cast<UdpSocketPosix*>(s);
if (sl->GetFd() != INVALID_SOCKET && sl->GetFd() < FD_SETSIZE)
{
// ok
} else
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
id,
"UdpSocketWrapper::CreateSocket failed to initialize socket");
delete s;
s = NULL;
}
}
#endif
if (s)
{
s->_deleteEvent = NULL;
if (!s->SetCallback(obj, cb))
{
WEBRTC_TRACE(
kTraceError,
kTraceTransport,
id,
"UdpSocketWrapper::CreateSocket failed to ser callback");
return(NULL);
}
}
return s;
}
bool UdpSocketWrapper::StartReceiving()
{
_wantsIncoming = true;
return true;
}
bool UdpSocketWrapper::StopReceiving()
{
_wantsIncoming = false;
return true;
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 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_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_WRAPPER_H_
#define WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_WRAPPER_H_
#include "webrtc/test/channel_transport/udp_transport.h"
namespace webrtc {
class EventWrapper;
namespace test {
class UdpSocketManager;
#define SOCKET_ERROR_NO_QOS -1000
#ifndef _WIN32
typedef int SOCKET;
#endif
#ifndef INVALID_SOCKET
#define INVALID_SOCKET (SOCKET)(~0)
#ifndef AF_INET
#define AF_INET 2
#endif
#endif
typedef void* CallbackObj;
typedef void(*IncomingSocketCallback)(CallbackObj obj, const WebRtc_Word8* buf,
WebRtc_Word32 len,
const SocketAddress* from);
class UdpSocketWrapper
{
public:
static UdpSocketWrapper* CreateSocket(const WebRtc_Word32 id,
UdpSocketManager* mgr,
CallbackObj obj,
IncomingSocketCallback cb,
bool ipV6Enable = false,
bool disableGQOS = false);
// Set the unique identifier of this class to id.
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id) = 0;
// Register cb for receiving callbacks when there are incoming packets.
// Register obj so that it will be passed in calls to cb.
virtual bool SetCallback(CallbackObj obj, IncomingSocketCallback cb) = 0;
// Socket to local address specified by name.
virtual bool Bind(const SocketAddress& name) = 0;
// Start receiving UDP data.
virtual bool StartReceiving();
virtual inline bool StartReceiving(const WebRtc_UWord32 /*receiveBuffers*/)
{return StartReceiving();}
// Stop receiving UDP data.
virtual bool StopReceiving();
virtual bool ValidHandle() = 0;
// Set socket options.
virtual bool SetSockopt(WebRtc_Word32 level, WebRtc_Word32 optname,
const WebRtc_Word8* optval,
WebRtc_Word32 optlen) = 0;
// Set TOS for outgoing packets.
virtual WebRtc_Word32 SetTOS(const WebRtc_Word32 serviceType) = 0;
// Set 802.1Q PCP field (802.1p) for outgoing VLAN traffic.
virtual WebRtc_Word32 SetPCP(const WebRtc_Word32 /*pcp*/) {return -1;}
// Send buf of length len to the address specified by to.
virtual WebRtc_Word32 SendTo(const WebRtc_Word8* buf, WebRtc_Word32 len,
const SocketAddress& to) = 0;
virtual void SetEventToNull();
// Close socket and don't return until completed.
virtual void CloseBlocking() {}
// tokenRate is in bit/s. peakBandwidt is in byte/s
virtual bool SetQos(WebRtc_Word32 serviceType, WebRtc_Word32 tokenRate,
WebRtc_Word32 bucketSize, WebRtc_Word32 peekBandwith,
WebRtc_Word32 minPolicedSize, WebRtc_Word32 maxSduSize,
const SocketAddress &stRemName,
WebRtc_Word32 overrideDSCP = 0) = 0;
virtual WebRtc_UWord32 ReceiveBuffers() {return 0;};
protected:
// Creating the socket is done via CreateSocket().
UdpSocketWrapper();
// Destroying the socket is done via CloseBlocking().
virtual ~UdpSocketWrapper();
bool _wantsIncoming;
EventWrapper* _deleteEvent;
private:
static bool _initiated;
};
} // namespac test
} // namespace webrtc
#endif // WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_SOCKET_WRAPPER_H_

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 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.
*/
// Tests for the UdpSocketWrapper interface.
// This will test the UdpSocket implementations on various platforms.
// Note that this test is using a real SocketManager, which starts up
// an extra worker thread, making the testing more complex than it
// should be.
// This is because on Posix, the CloseBlocking function waits for the
// ReadyForDeletion function to be called, which has to be called after
// CloseBlocking, and thus has to be called from another thread.
// The manager is the one actually doing the deleting.
// This is done differently in the Winsock2 code, but that code
// will also hang if the destructor is called directly.
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "webrtc/test/channel_transport/udp_socket_wrapper.h"
#include "webrtc/test/channel_transport/udp_socket_manager_wrapper.h"
using ::testing::_;
using ::testing::Return;
namespace webrtc {
namespace test {
class MockSocketManager : public UdpSocketManager {
public:
MockSocketManager() {}
// Access to protected destructor.
void Destroy() {
delete this;
}
MOCK_METHOD2(Init, bool(WebRtc_Word32, WebRtc_UWord8&));
MOCK_METHOD1(ChangeUniqueId, WebRtc_Word32(const WebRtc_Word32));
MOCK_METHOD0(Start, bool());
MOCK_METHOD0(Stop, bool());
MOCK_METHOD1(AddSocket, bool(UdpSocketWrapper*));
MOCK_METHOD1(RemoveSocket, bool(UdpSocketWrapper*));
};
// Creates a socket using the static constructor method and verifies that
// it's added to the socket manager.
TEST(UdpSocketWrapper, CreateSocket) {
WebRtc_Word32 id = 42;
// We can't test deletion of sockets without a socket manager.
WebRtc_UWord8 threads = 1;
UdpSocketManager* mgr = UdpSocketManager::Create(id, threads);
UdpSocketWrapper* socket =
UdpSocketWrapper::CreateSocket(id,
mgr,
NULL, // CallbackObj
NULL, // IncomingSocketCallback
false, // ipV6Enable
false); // disableGQOS
socket->CloseBlocking();
UdpSocketManager::Return();
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,386 @@
/*
* Copyright (c) 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_TEST_CHANNEL_TRANSPORT_UDP_TRANSPORT_H_
#define WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_TRANSPORT_H_
#include "webrtc/common_types.h"
#include "webrtc/typedefs.h"
/*
* WARNING
* This code is not use in production/testing and might have security issues
* for example: http://code.google.com/p/webrtc/issues/detail?id=1028
*
*/
#define SS_MAXSIZE 128
#define SS_ALIGNSIZE (sizeof (WebRtc_UWord64))
#define SS_PAD1SIZE (SS_ALIGNSIZE - sizeof(WebRtc_Word16))
#define SS_PAD2SIZE (SS_MAXSIZE - (sizeof(WebRtc_Word16) + SS_PAD1SIZE +\
SS_ALIGNSIZE))
// BSD requires use of HAVE_STRUCT_SOCKADDR_SA_LEN
namespace webrtc {
namespace test {
struct SocketAddressIn {
// sin_family should be either AF_INET (IPv4) or AF_INET6 (IPv6)
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
WebRtc_Word8 sin_length;
WebRtc_Word8 sin_family;
#else
WebRtc_Word16 sin_family;
#endif
WebRtc_UWord16 sin_port;
WebRtc_UWord32 sin_addr;
WebRtc_Word8 sin_zero[8];
};
struct Version6InAddress {
union {
WebRtc_UWord8 _s6_u8[16];
WebRtc_UWord32 _s6_u32[4];
WebRtc_UWord64 _s6_u64[2];
} Version6AddressUnion;
};
struct SocketAddressInVersion6 {
// sin_family should be either AF_INET (IPv4) or AF_INET6 (IPv6)
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
WebRtc_Word8 sin_length;
WebRtc_Word8 sin_family;
#else
WebRtc_Word16 sin_family;
#endif
// Transport layer port number.
WebRtc_UWord16 sin6_port;
// IPv6 traffic class and flow info or ip4 address.
WebRtc_UWord32 sin6_flowinfo;
// IPv6 address
struct Version6InAddress sin6_addr;
// Set of interfaces for a scope.
WebRtc_UWord32 sin6_scope_id;
};
struct SocketAddressStorage {
// sin_family should be either AF_INET (IPv4) or AF_INET6 (IPv6)
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
WebRtc_Word8 sin_length;
WebRtc_Word8 sin_family;
#else
WebRtc_Word16 sin_family;
#endif
WebRtc_Word8 __ss_pad1[SS_PAD1SIZE];
WebRtc_UWord64 __ss_align;
WebRtc_Word8 __ss_pad2[SS_PAD2SIZE];
};
struct SocketAddress {
union {
struct SocketAddressIn _sockaddr_in;
struct SocketAddressInVersion6 _sockaddr_in6;
struct SocketAddressStorage _sockaddr_storage;
};
};
// Callback class that receives packets from UdpTransport.
class UdpTransportData {
public:
virtual ~UdpTransportData() {};
virtual void IncomingRTPPacket(const WebRtc_Word8* incomingRtpPacket,
const WebRtc_Word32 rtpPacketLength,
const char* fromIP,
const WebRtc_UWord16 fromPort) = 0;
virtual void IncomingRTCPPacket(const WebRtc_Word8* incomingRtcpPacket,
const WebRtc_Word32 rtcpPacketLength,
const char* fromIP,
const WebRtc_UWord16 fromPort) = 0;
};
class UdpTransport : public Transport {
public:
enum
{
kIpAddressVersion6Length = 64,
kIpAddressVersion4Length = 16
};
enum ErrorCode
{
kNoSocketError = 0,
kFailedToBindPort = 1,
kIpAddressInvalid = 2,
kAddressInvalid = 3,
kSocketInvalid = 4,
kPortInvalid = 5,
kTosInvalid = 6,
kMulticastAddressInvalid = 7,
kQosError = 8,
kSocketAlreadyInitialized = 9,
kIpVersion6Error = 10,
FILTER_ERROR = 11,
kStartReceiveError = 12,
kStopReceiveError = 13,
kCannotFindLocalIp = 14,
kTosError = 16,
kNotInitialized = 17,
kPcpError = 18
};
// Factory method. Constructor disabled.
static UdpTransport* Create(const WebRtc_Word32 id,
WebRtc_UWord8& numSocketThreads);
static void Destroy(UdpTransport* module);
// Prepares the class for sending RTP packets to ipAddr:rtpPort and RTCP
// packets to ipAddr:rtpPort+1 if rtcpPort is zero. Otherwise to
// ipAddr:rtcpPort.
virtual WebRtc_Word32 InitializeSendSockets(
const char* ipAddr,
const WebRtc_UWord16 rtpPort,
const WebRtc_UWord16 rtcpPort = 0) = 0;
// Register packetCallback for receiving incoming packets. Set the local
// RTP port to rtpPort. Bind local IP address to ipAddr. If ipAddr is NULL
// bind to local IP ANY. Set the local rtcp port to rtcpPort or rtpPort + 1
// if rtcpPort is 0.
virtual WebRtc_Word32 InitializeReceiveSockets(
UdpTransportData* const packetCallback,
const WebRtc_UWord16 rtpPort,
const char* ipAddr = NULL,
const char* multicastIpAddr = NULL,
const WebRtc_UWord16 rtcpPort = 0) = 0;
// Set local RTP port to rtpPort and RTCP port to rtcpPort or rtpPort + 1 if
// rtcpPort is 0. These ports will be used for sending instead of the local
// ports set by InitializeReceiveSockets(..).
virtual WebRtc_Word32 InitializeSourcePorts(
const WebRtc_UWord16 rtpPort,
const WebRtc_UWord16 rtcpPort = 0) = 0;
// Retrieve local ports used for sending if other than the ports specified
// by InitializeReceiveSockets(..). rtpPort is set to the RTP port.
// rtcpPort is set to the RTCP port.
virtual WebRtc_Word32 SourcePorts(WebRtc_UWord16& rtpPort,
WebRtc_UWord16& rtcpPort) const = 0;
// Set ipAddr to the IP address that is currently being listened on. rtpPort
// to the RTP port listened to. rtcpPort to the RTCP port listened on.
// multicastIpAddr to the multicast IP address group joined (the address
// is NULL terminated).
virtual WebRtc_Word32 ReceiveSocketInformation(
char ipAddr[kIpAddressVersion6Length],
WebRtc_UWord16& rtpPort,
WebRtc_UWord16& rtcpPort,
char multicastIpAddr[kIpAddressVersion6Length]) const = 0;
// Set ipAddr to the IP address being sent from. rtpPort to the local RTP
// port used for sending and rtcpPort to the local RTCP port used for
// sending.
virtual WebRtc_Word32 SendSocketInformation(
char ipAddr[kIpAddressVersion6Length],
WebRtc_UWord16& rtpPort,
WebRtc_UWord16& rtcpPort) const = 0;
// Put the IP address, RTP port and RTCP port from the last received packet
// into ipAddr, rtpPort and rtcpPort respectively.
virtual WebRtc_Word32 RemoteSocketInformation(
char ipAddr[kIpAddressVersion6Length],
WebRtc_UWord16& rtpPort,
WebRtc_UWord16& rtcpPort) const = 0;
// Enable/disable quality of service if QoS is true or false respectively.
// Set the type of service to serviceType, max bitrate in kbit/s to
// maxBitrate and override DSCP if overrideDSCP is not 0.
// Note: Must be called both InitializeSendSockets() and
// InitializeReceiveSockets() has been called.
virtual WebRtc_Word32 SetQoS(const bool QoS,
const WebRtc_Word32 serviceType,
const WebRtc_UWord32 maxBitrate = 0,
const WebRtc_Word32 overrideDSCP = 0,
const bool audio = false) = 0;
// Set QoS to true if quality of service has been turned on. If QoS is true,
// also set serviceType to type of service and overrideDSCP to override
// DSCP.
virtual WebRtc_Word32 QoS(bool& QoS,
WebRtc_Word32& serviceType,
WebRtc_Word32& overrideDSCP) const = 0;
// Set type of service.
virtual WebRtc_Word32 SetToS(const WebRtc_Word32 DSCP,
const bool useSetSockOpt = false) = 0;
// Get type of service configuration.
virtual WebRtc_Word32 ToS(WebRtc_Word32& DSCP,
bool& useSetSockOpt) const = 0;
// Set Priority Code Point (IEEE 802.1Q)
// Note: for Linux this function will set the priority for the socket,
// which then can be mapped to a PCP value with vconfig.
virtual WebRtc_Word32 SetPCP(const WebRtc_Word32 PCP) = 0;
// Get Priority Code Point
virtual WebRtc_Word32 PCP(WebRtc_Word32& PCP) const = 0;
// Enable IPv6.
// Note: this API must be called before any call to
// InitializeReceiveSockets() or InitializeSendSockets(). It is not
// possible to go back to IPv4 (default) after this call.
virtual WebRtc_Word32 EnableIpV6() = 0;
// Return true if IPv6 has been enabled.
virtual bool IpV6Enabled() const = 0;
// Only allow packets received from filterIPAddress to be processed.
// Note: must be called after EnableIPv6(), if IPv6 is used.
virtual WebRtc_Word32 SetFilterIP(
const char filterIPAddress[kIpAddressVersion6Length]) = 0;
// Write the filter IP address (if any) to filterIPAddress.
virtual WebRtc_Word32 FilterIP(
char filterIPAddress[kIpAddressVersion6Length]) const = 0;
// Only allow RTP packets from rtpFilterPort and RTCP packets from
// rtcpFilterPort be processed.
// Note: must be called after EnableIPv6(), if IPv6 is used.
virtual WebRtc_Word32 SetFilterPorts(
const WebRtc_UWord16 rtpFilterPort,
const WebRtc_UWord16 rtcpFilterPort) = 0;
// Set rtpFilterPort to the filter RTP port and rtcpFilterPort to the
// filter RTCP port (if filtering based on port is enabled).
virtual WebRtc_Word32 FilterPorts(WebRtc_UWord16& rtpFilterPort,
WebRtc_UWord16& rtcpFilterPort) const = 0;
// Set the number of buffers that the socket implementation may use for
// receiving packets to numberOfSocketBuffers. I.e. the number of packets
// that can be received in parallell.
// Note: this API only has effect on Windows.
virtual WebRtc_Word32 StartReceiving(
const WebRtc_UWord32 numberOfSocketBuffers) = 0;
// Stop receive incoming packets.
virtual WebRtc_Word32 StopReceiving() = 0;
// Return true incoming packets are received.
virtual bool Receiving() const = 0;
// Return true if send sockets have been initialized.
virtual bool SendSocketsInitialized() const = 0;
// Return true if local ports for sending has been set.
virtual bool SourcePortsInitialized() const = 0;
// Return true if receive sockets have been initialized.
virtual bool ReceiveSocketsInitialized() const = 0;
// Send data with size length to ip:portnr. The same port as the set
// with InitializeSendSockets(..) is used if portnr is 0. The same IP
// address as set with InitializeSendSockets(..) is used if ip is NULL.
// If isRTCP is true the port used will be the RTCP port.
virtual WebRtc_Word32 SendRaw(const WebRtc_Word8* data,
WebRtc_UWord32 length,
WebRtc_Word32 isRTCP,
WebRtc_UWord16 portnr = 0,
const char* ip = NULL) = 0;
// Send RTP data with size length to the address specified by to.
virtual WebRtc_Word32 SendRTPPacketTo(const WebRtc_Word8* data,
WebRtc_UWord32 length,
const SocketAddress& to) = 0;
// Send RTCP data with size length to the address specified by to.
virtual WebRtc_Word32 SendRTCPPacketTo(const WebRtc_Word8* data,
WebRtc_UWord32 length,
const SocketAddress& to) = 0;
// Send RTP data with size length to ip:rtpPort where ip is the ip set by
// the InitializeSendSockets(..) call.
virtual WebRtc_Word32 SendRTPPacketTo(const WebRtc_Word8* data,
WebRtc_UWord32 length,
WebRtc_UWord16 rtpPort) = 0;
// Send RTCP data with size length to ip:rtcpPort where ip is the ip set by
// the InitializeSendSockets(..) call.
virtual WebRtc_Word32 SendRTCPPacketTo(const WebRtc_Word8* data,
WebRtc_UWord32 length,
WebRtc_UWord16 rtcpPort) = 0;
// Set the IP address to which packets are sent to ipaddr.
virtual WebRtc_Word32 SetSendIP(
const char ipaddr[kIpAddressVersion6Length]) = 0;
// Set the send RTP and RTCP port to rtpPort and rtcpPort respectively.
virtual WebRtc_Word32 SetSendPorts(const WebRtc_UWord16 rtpPort,
const WebRtc_UWord16 rtcpPort = 0) = 0;
// Retreive the last registered error code.
virtual ErrorCode LastError() const = 0;
// Put the local IPv4 address in localIP.
// Note: this API is for IPv4 only.
static WebRtc_Word32 LocalHostAddress(WebRtc_UWord32& localIP);
// Put the local IP6 address in localIP.
// Note: this API is for IPv6 only.
static WebRtc_Word32 LocalHostAddressIPV6(char localIP[16]);
// Return a copy of hostOrder (host order) in network order.
static WebRtc_UWord16 Htons(WebRtc_UWord16 hostOrder);
// Return a copy of hostOrder (host order) in network order.
static WebRtc_UWord32 Htonl(WebRtc_UWord32 hostOrder);
// Return IPv4 address in ip as 32 bit integer.
static WebRtc_UWord32 InetAddrIPV4(const char* ip);
// Convert the character string src into a network address structure in
// the af address family and put it in dst.
// Note: same functionality as inet_pton(..)
static WebRtc_Word32 InetPresentationToNumeric(WebRtc_Word32 af,
const char* src,
void* dst);
// Set ip and sourcePort according to address. As input parameter ipSize
// is the length of ip. As output parameter it's the number of characters
// written to ip (not counting the '\0' character).
// Note: this API is only implemented on Windows and Linux.
static WebRtc_Word32 IPAddress(const SocketAddress& address,
char* ip,
WebRtc_UWord32& ipSize,
WebRtc_UWord16& sourcePort);
// Set ip and sourcePort according to address. As input parameter ipSize
// is the length of ip. As output parameter it's the number of characters
// written to ip (not counting the '\0' character).
// Note: this API is only implemented on Windows and Linux.
// Additional note: this API caches the address of the last call to it. If
// address is likley to be the same for multiple calls it may be beneficial
// to call this API instead of IPAddress().
virtual WebRtc_Word32 IPAddressCached(const SocketAddress& address,
char* ip,
WebRtc_UWord32& ipSize,
WebRtc_UWord16& sourcePort) = 0;
// Return true if ipaddr is a valid IP address.
// If ipV6 is false ipaddr is interpreted as an IPv4 address otherwise it
// is interptreted as IPv6.
static bool IsIpAddressValid(const char* ipaddr, const bool ipV6);
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_TRANSPORT_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,264 @@
/*
* Copyright (c) 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_TEST_CHANNEL_TRANSPORT_UDP_TRANSPORT_IMPL_H_
#define WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_TRANSPORT_IMPL_H_
#include "webrtc/test/channel_transport/udp_transport.h"
#include "webrtc/test/channel_transport/udp_socket_wrapper.h"
namespace webrtc {
class CriticalSectionWrapper;
class RWLockWrapper;
namespace test {
class UdpSocketManager;
class UdpTransportImpl : public UdpTransport
{
public:
// A factory that returns a wrapped UDP socket or equivalent.
class SocketFactoryInterface {
public:
virtual ~SocketFactoryInterface() {}
virtual UdpSocketWrapper* CreateSocket(const WebRtc_Word32 id,
UdpSocketManager* mgr,
CallbackObj obj,
IncomingSocketCallback cb,
bool ipV6Enable,
bool disableGQOS) = 0;
};
// Constructor, only called by UdpTransport::Create and tests.
// The constructor takes ownership of the "maker".
// The constructor does not take ownership of socket_manager.
UdpTransportImpl(const WebRtc_Word32 id,
SocketFactoryInterface* maker,
UdpSocketManager* socket_manager);
virtual ~UdpTransportImpl();
// UdpTransport functions
virtual WebRtc_Word32 InitializeSendSockets(
const char* ipAddr,
const WebRtc_UWord16 rtpPort,
const WebRtc_UWord16 rtcpPort = 0);
virtual WebRtc_Word32 InitializeReceiveSockets(
UdpTransportData* const packetCallback,
const WebRtc_UWord16 rtpPort,
const char* ipAddr = NULL,
const char* multicastIpAddr = NULL,
const WebRtc_UWord16 rtcpPort = 0);
virtual WebRtc_Word32 InitializeSourcePorts(
const WebRtc_UWord16 rtpPort,
const WebRtc_UWord16 rtcpPort = 0);
virtual WebRtc_Word32 SourcePorts(WebRtc_UWord16& rtpPort,
WebRtc_UWord16& rtcpPort) const;
virtual WebRtc_Word32 ReceiveSocketInformation(
char ipAddr[kIpAddressVersion6Length],
WebRtc_UWord16& rtpPort,
WebRtc_UWord16& rtcpPort,
char multicastIpAddr[kIpAddressVersion6Length]) const;
virtual WebRtc_Word32 SendSocketInformation(
char ipAddr[kIpAddressVersion6Length],
WebRtc_UWord16& rtpPort,
WebRtc_UWord16& rtcpPort) const;
virtual WebRtc_Word32 RemoteSocketInformation(
char ipAddr[kIpAddressVersion6Length],
WebRtc_UWord16& rtpPort,
WebRtc_UWord16& rtcpPort) const;
virtual WebRtc_Word32 SetQoS(const bool QoS,
const WebRtc_Word32 serviceType,
const WebRtc_UWord32 maxBitrate = 0,
const WebRtc_Word32 overrideDSCP = 0,
const bool audio = false);
virtual WebRtc_Word32 QoS(bool& QoS, WebRtc_Word32& serviceType,
WebRtc_Word32& overrideDSCP) const;
virtual WebRtc_Word32 SetToS(const WebRtc_Word32 DSCP,
const bool useSetSockOpt = false);
virtual WebRtc_Word32 ToS(WebRtc_Word32& DSCP,
bool& useSetSockOpt) const;
virtual WebRtc_Word32 SetPCP(const WebRtc_Word32 PCP);
virtual WebRtc_Word32 PCP(WebRtc_Word32& PCP) const;
virtual WebRtc_Word32 EnableIpV6();
virtual bool IpV6Enabled() const;
virtual WebRtc_Word32 SetFilterIP(
const char filterIPAddress[kIpAddressVersion6Length]);
virtual WebRtc_Word32 FilterIP(
char filterIPAddress[kIpAddressVersion6Length]) const;
virtual WebRtc_Word32 SetFilterPorts(const WebRtc_UWord16 rtpFilterPort,
const WebRtc_UWord16 rtcpFilterPort);
virtual WebRtc_Word32 FilterPorts(WebRtc_UWord16& rtpFilterPort,
WebRtc_UWord16& rtcpFilterPort) const;
virtual WebRtc_Word32 StartReceiving(
const WebRtc_UWord32 numberOfSocketBuffers);
virtual WebRtc_Word32 StopReceiving();
virtual bool Receiving() const;
virtual bool SendSocketsInitialized() const;
virtual bool SourcePortsInitialized() const;
virtual bool ReceiveSocketsInitialized() const;
virtual WebRtc_Word32 SendRaw(const WebRtc_Word8* data,
WebRtc_UWord32 length, WebRtc_Word32 isRTCP,
WebRtc_UWord16 portnr = 0,
const char* ip = NULL);
virtual WebRtc_Word32 SendRTPPacketTo(const WebRtc_Word8 *data,
WebRtc_UWord32 length,
const SocketAddress& to);
virtual WebRtc_Word32 SendRTCPPacketTo(const WebRtc_Word8 *data,
WebRtc_UWord32 length,
const SocketAddress& to);
virtual WebRtc_Word32 SendRTPPacketTo(const WebRtc_Word8 *data,
WebRtc_UWord32 length,
WebRtc_UWord16 rtpPort);
virtual WebRtc_Word32 SendRTCPPacketTo(const WebRtc_Word8 *data,
WebRtc_UWord32 length,
WebRtc_UWord16 rtcpPort);
// Transport functions
virtual int SendPacket(int channel, const void* data, int length);
virtual int SendRTCPPacket(int channel, const void* data, int length);
// UdpTransport functions continue.
virtual WebRtc_Word32 SetSendIP(const char* ipaddr);
virtual WebRtc_Word32 SetSendPorts(const WebRtc_UWord16 rtpPort,
const WebRtc_UWord16 rtcpPort = 0);
virtual ErrorCode LastError() const;
virtual WebRtc_Word32 IPAddressCached(const SocketAddress& address,
char* ip,
WebRtc_UWord32& ipSize,
WebRtc_UWord16& sourcePort);
WebRtc_Word32 Id() const {return _id;}
protected:
// IncomingSocketCallback signature functions for receiving callbacks from
// UdpSocketWrapper.
static void IncomingRTPCallback(CallbackObj obj,
const WebRtc_Word8* rtpPacket,
WebRtc_Word32 rtpPacketLength,
const SocketAddress* from);
static void IncomingRTCPCallback(CallbackObj obj,
const WebRtc_Word8* rtcpPacket,
WebRtc_Word32 rtcpPacketLength,
const SocketAddress* from);
void CloseSendSockets();
void CloseReceiveSockets();
// Update _remoteRTPAddr according to _destPort and _destIP
void BuildRemoteRTPAddr();
// Update _remoteRTCPAddr according to _destPortRTCP and _destIP
void BuildRemoteRTCPAddr();
void BuildSockaddrIn(WebRtc_UWord16 portnr, const char* ip,
SocketAddress& remoteAddr) const;
ErrorCode BindLocalRTPSocket();
ErrorCode BindLocalRTCPSocket();
ErrorCode BindRTPSendSocket();
ErrorCode BindRTCPSendSocket();
void IncomingRTPFunction(const WebRtc_Word8* rtpPacket,
WebRtc_Word32 rtpPacketLength,
const SocketAddress* from);
void IncomingRTCPFunction(const WebRtc_Word8* rtcpPacket,
WebRtc_Word32 rtcpPacketLength,
const SocketAddress* from);
bool FilterIPAddress(const SocketAddress* fromAddress);
bool SetSockOptUsed();
WebRtc_Word32 EnableQoS(WebRtc_Word32 serviceType, bool audio,
WebRtc_UWord32 maxBitrate,
WebRtc_Word32 overrideDSCP);
WebRtc_Word32 DisableQoS();
private:
void GetCachedAddress(char* ip, WebRtc_UWord32& ipSize,
WebRtc_UWord16& sourcePort);
WebRtc_Word32 _id;
SocketFactoryInterface* _socket_creator;
// Protects the sockets from being re-configured while receiving packets.
CriticalSectionWrapper* _crit;
CriticalSectionWrapper* _critFilter;
// _packetCallback's critical section.
CriticalSectionWrapper* _critPacketCallback;
UdpSocketManager* _mgr;
ErrorCode _lastError;
// Remote RTP and RTCP ports.
WebRtc_UWord16 _destPort;
WebRtc_UWord16 _destPortRTCP;
// Local RTP and RTCP ports.
WebRtc_UWord16 _localPort;
WebRtc_UWord16 _localPortRTCP;
// Local port number when the local port for receiving and local port number
// for sending are not the same.
WebRtc_UWord16 _srcPort;
WebRtc_UWord16 _srcPortRTCP;
// Remote port from which last received packet was sent.
WebRtc_UWord16 _fromPort;
WebRtc_UWord16 _fromPortRTCP;
char _fromIP[kIpAddressVersion6Length];
char _destIP[kIpAddressVersion6Length];
char _localIP[kIpAddressVersion6Length];
char _localMulticastIP[kIpAddressVersion6Length];
UdpSocketWrapper* _ptrRtpSocket;
UdpSocketWrapper* _ptrRtcpSocket;
// Local port when the local port for receiving and local port for sending
// are not the same.
UdpSocketWrapper* _ptrSendRtpSocket;
UdpSocketWrapper* _ptrSendRtcpSocket;
SocketAddress _remoteRTPAddr;
SocketAddress _remoteRTCPAddr;
SocketAddress _localRTPAddr;
SocketAddress _localRTCPAddr;
WebRtc_Word32 _tos;
bool _receiving;
bool _useSetSockOpt;
bool _qos;
WebRtc_Word32 _pcp;
bool _ipV6Enabled;
WebRtc_Word32 _serviceType;
WebRtc_Word32 _overrideDSCP;
WebRtc_UWord32 _maxBitrate;
// Cache used by GetCachedAddress(..).
RWLockWrapper* _cachLock;
SocketAddress _previousAddress;
char _previousIP[kIpAddressVersion6Length];
WebRtc_UWord32 _previousIPSize;
WebRtc_UWord16 _previousSourcePort;
SocketAddress _filterIPAddress;
WebRtc_UWord16 _rtpFilterPort;
WebRtc_UWord16 _rtcpFilterPort;
UdpTransportData* _packetCallback;
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_CHANNEL_TRANSPORT_UDP_TRANSPORT_IMPL_H_

View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 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 <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "webrtc/test/channel_transport/udp_transport.h"
// We include the implementation header file to get at the dependency-injecting
// constructor.
#include "webrtc/test/channel_transport/udp_transport_impl.h"
// We must mock the socket manager, for which we need its definition.
#include "webrtc/test/channel_transport/udp_socket_manager_wrapper.h"
using ::testing::_;
using ::testing::Return;
namespace webrtc {
namespace test {
class MockUdpSocketWrapper : public UdpSocketWrapper {
public:
// The following methods have to be mocked because they are pure.
MOCK_METHOD1(ChangeUniqueId, WebRtc_Word32(WebRtc_Word32));
MOCK_METHOD2(SetCallback, bool(CallbackObj, IncomingSocketCallback));
MOCK_METHOD1(Bind, bool(const SocketAddress&));
MOCK_METHOD0(ValidHandle, bool());
MOCK_METHOD4(SetSockopt, bool(WebRtc_Word32, WebRtc_Word32,
const WebRtc_Word8*,
WebRtc_Word32));
MOCK_METHOD1(SetTOS, WebRtc_Word32(WebRtc_Word32));
MOCK_METHOD3(SendTo, WebRtc_Word32(const WebRtc_Word8*, WebRtc_Word32,
const SocketAddress&));
MOCK_METHOD8(SetQos, bool(WebRtc_Word32, WebRtc_Word32,
WebRtc_Word32, WebRtc_Word32,
WebRtc_Word32, WebRtc_Word32,
const SocketAddress &,
WebRtc_Word32));
};
class MockUdpSocketManager : public UdpSocketManager {
public:
// Access to protected destructor.
void Destroy() {
delete this;
}
MOCK_METHOD2(Init, bool(WebRtc_Word32, WebRtc_UWord8&));
MOCK_METHOD1(ChangeUniqueId, WebRtc_Word32(const WebRtc_Word32));
MOCK_METHOD0(Start, bool());
MOCK_METHOD0(Stop, bool());
MOCK_METHOD1(AddSocket, bool(UdpSocketWrapper*));
MOCK_METHOD1(RemoveSocket, bool(UdpSocketWrapper*));
};
class MockSocketFactory :
public UdpTransportImpl::SocketFactoryInterface {
public:
MockSocketFactory(std::vector<MockUdpSocketWrapper*>* socket_counter)
: socket_counter_(socket_counter) {
}
UdpSocketWrapper* CreateSocket(const WebRtc_Word32 id,
UdpSocketManager* mgr,
CallbackObj obj,
IncomingSocketCallback cb,
bool ipV6Enable,
bool disableGQOS) {
MockUdpSocketWrapper* socket = new MockUdpSocketWrapper();
// We instrument the socket with calls that are expected, but do
// not matter for any specific test, in order to avoid warning messages.
EXPECT_CALL(*socket, ValidHandle()).WillRepeatedly(Return(true));
EXPECT_CALL(*socket, Bind(_)).WillOnce(Return(true));
socket_counter_->push_back(socket);
return socket;
}
std::vector<MockUdpSocketWrapper*>* socket_counter_;
};
class UDPTransportTest : public ::testing::Test {
public:
UDPTransportTest()
: sockets_created_(0) {
}
~UDPTransportTest() {
// In production, sockets register themselves at creation time with
// an UdpSocketManager, and the UdpSocketManager is responsible for
// deleting them. In this test, we just delete them after the test.
while (!sockets_created_.empty()) {
delete sockets_created_.back();
sockets_created_.pop_back();
}
}
int NumSocketsCreated() {
return sockets_created_.size();
}
std::vector<MockUdpSocketWrapper*>* sockets_created() {
return &sockets_created_;
}
private:
std::vector<MockUdpSocketWrapper*> sockets_created_;
};
TEST_F(UDPTransportTest, CreateTransport) {
WebRtc_Word32 id = 0;
WebRtc_UWord8 threads = 1;
UdpTransport* transport = UdpTransport::Create(id, threads);
UdpTransport::Destroy(transport);
}
// This test verifies that the mock_socket is not called from the constructor.
TEST_F(UDPTransportTest, ConstructorDoesNotCreateSocket) {
WebRtc_Word32 id = 0;
UdpTransportImpl::SocketFactoryInterface* null_maker = NULL;
UdpSocketManager* null_manager = NULL;
UdpTransport* transport = new UdpTransportImpl(id,
null_maker,
null_manager);
delete transport;
}
TEST_F(UDPTransportTest, InitializeSourcePorts) {
WebRtc_Word32 id = 0;
UdpTransportImpl::SocketFactoryInterface* mock_maker
= new MockSocketFactory(sockets_created());
MockUdpSocketManager* mock_manager = new MockUdpSocketManager();
UdpTransport* transport = new UdpTransportImpl(id,
mock_maker,
mock_manager);
EXPECT_EQ(0, transport->InitializeSourcePorts(4711, 4712));
EXPECT_EQ(2, NumSocketsCreated());
delete transport;
mock_manager->Destroy();
}
} // namespace test
} // namespace webrtc