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/webrtc@3701 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/test/channel_transport.gyp b/test/channel_transport.gyp
new file mode 100644
index 0000000..10808db
--- /dev/null
+++ b/test/channel_transport.gyp
@@ -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
+}
diff --git a/test/channel_transport/channel_transport.cc b/test/channel_transport/channel_transport.cc
new file mode 100644
index 0000000..877a601
--- /dev/null
+++ b/test/channel_transport/channel_transport.cc
@@ -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
diff --git a/test/channel_transport/include/channel_transport.h b/test/channel_transport/include/channel_transport.h
new file mode 100644
index 0000000..ba71829
--- /dev/null
+++ b/test/channel_transport/include/channel_transport.h
@@ -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_
+
diff --git a/test/channel_transport/traffic_control_win.cc b/test/channel_transport/traffic_control_win.cc
new file mode 100644
index 0000000..1833586
--- /dev/null
+++ b/test/channel_transport/traffic_control_win.cc
@@ -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
diff --git a/test/channel_transport/traffic_control_win.h b/test/channel_transport/traffic_control_win.h
new file mode 100644
index 0000000..7286ed5
--- /dev/null
+++ b/test/channel_transport/traffic_control_win.h
@@ -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_
diff --git a/test/channel_transport/udp_socket2_manager_win.cc b/test/channel_transport/udp_socket2_manager_win.cc
new file mode 100644
index 0000000..7d49081
--- /dev/null
+++ b/test/channel_transport/udp_socket2_manager_win.cc
@@ -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
diff --git a/test/channel_transport/udp_socket2_manager_win.h b/test/channel_transport/udp_socket2_manager_win.h
new file mode 100644
index 0000000..d77c792
--- /dev/null
+++ b/test/channel_transport/udp_socket2_manager_win.h
@@ -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_
diff --git a/test/channel_transport/udp_socket2_win.cc b/test/channel_transport/udp_socket2_win.cc
new file mode 100644
index 0000000..03a823e
--- /dev/null
+++ b/test/channel_transport/udp_socket2_win.cc
@@ -0,0 +1,1390 @@
+/*
+ * 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_win.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <winsock2.h>
+
+#include "webrtc/test/channel_transport/traffic_control_win.h"
+#include "webrtc/test/channel_transport/udp_socket2_manager_win.h"
+
+#pragma warning(disable : 4311)
+
+namespace webrtc {
+namespace test {
+
+typedef struct _QOS_DESTADDR
+{
+ QOS_OBJECT_HDR ObjectHdr;
+ const struct sockaddr* SocketAddress;
+ ULONG SocketAddressLength;
+} QOS_DESTADDR, *LPQOS_DESTADDR;
+
+typedef const QOS_DESTADDR* LPCQOS_DESTADDR;
+
+// TODO (patrikw): seems to be defined in ws2ipdef.h as 3. How come it's
+// redefined here (as a different value)?
+#define IP_TOS 8
+
+#define QOS_GENERAL_ID_BASE 2000
+#define QOS_OBJECT_DESTADDR (0x00000004 + QOS_GENERAL_ID_BASE)
+
+UdpSocket2Windows::UdpSocket2Windows(const WebRtc_Word32 id,
+ UdpSocketManager* mgr, bool ipV6Enable,
+ bool disableGQOS)
+ : _id(id),
+ _qos(true),
+ _iProtocol(0),
+ _outstandingCalls(0),
+ _outstandingCallComplete(0),
+ _terminate(false),
+ _addedToMgr(false),
+ _safeTodelete(false),
+ _outstandingCallsDisabled(false),
+ _clientHandle(NULL),
+ _flowHandle(NULL),
+ _filterHandle(NULL),
+ _flow(NULL),
+ _gtc(NULL),
+ _pcp(-2),
+ _receiveBuffers(0)
+{
+ WEBRTC_TRACE(kTraceMemory, kTraceTransport, _id,
+ "UdpSocket2Windows::UdpSocket2Windows()");
+
+ _wantsIncoming = false;
+ _mgr = static_cast<UdpSocket2ManagerWindows *>(mgr);
+
+ _obj = NULL;
+ _incomingCb = NULL;
+ _socket = INVALID_SOCKET;
+ _pCrit = CriticalSectionWrapper::CreateCriticalSection();
+ _ptrCbRWLock = RWLockWrapper::CreateRWLock();
+ _ptrDestRWLock = RWLockWrapper::CreateRWLock();
+ _ptrSocketRWLock = RWLockWrapper::CreateRWLock();
+ _ptrDeleteCrit = CriticalSectionWrapper::CreateCriticalSection();
+ _ptrDeleteCond = ConditionVariableWrapper::CreateConditionVariable();
+
+ // Check if QoS is supported.
+ BOOL bProtocolFound = FALSE;
+ WSAPROTOCOL_INFO *lpProtocolBuf = NULL;
+ WSAPROTOCOL_INFO pProtocolInfo;
+
+ if(!disableGQOS)
+ {
+ DWORD dwBufLen = 0;
+ // Set dwBufLen to the size needed to retreive all the requested
+ // information from WSAEnumProtocols.
+ WebRtc_Word32 nRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen);
+ lpProtocolBuf = (WSAPROTOCOL_INFO*)malloc(dwBufLen);
+ nRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen);
+
+ if (ipV6Enable)
+ {
+ _iProtocol=AF_INET6;
+ } else {
+ _iProtocol=AF_INET;
+ }
+
+ for (WebRtc_Word32 i=0; i<nRet; i++)
+ {
+ if (_iProtocol == lpProtocolBuf[i].iAddressFamily &&
+ IPPROTO_UDP == lpProtocolBuf[i].iProtocol)
+ {
+ if ((XP1_QOS_SUPPORTED ==
+ (XP1_QOS_SUPPORTED & lpProtocolBuf[i].dwServiceFlags1)))
+ {
+ pProtocolInfo = lpProtocolBuf[i];
+ bProtocolFound = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ if(!bProtocolFound)
+ {
+ free(lpProtocolBuf);
+ _qos=false;
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows::UdpSocket2Windows(), SOCKET_ERROR_NO_QOS,\
+ !bProtocolFound");
+ } else {
+
+ _socket = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,&pProtocolInfo, 0,
+ WSA_FLAG_OVERLAPPED);
+ free(lpProtocolBuf);
+
+ if (_socket != INVALID_SOCKET)
+ {
+ return;
+ } else {
+ _qos = false;
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows::UdpSocket2Windows(), SOCKET_ERROR_NO_QOS");
+ }
+ }
+ // QoS not supported.
+ if(ipV6Enable)
+ {
+ _socket = WSASocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, 0 , 0,
+ WSA_FLAG_OVERLAPPED);
+ }else
+ {
+ _socket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0 , 0,
+ WSA_FLAG_OVERLAPPED);
+ }
+ if (_socket == INVALID_SOCKET)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows::UdpSocket2Windows(), INVALID_SOCKET,\
+ WSAerror: %d",
+ WSAGetLastError());
+ }
+
+ // Disable send buffering on the socket to improve CPU usage.
+ // This is done by setting SO_SNDBUF to 0.
+ WebRtc_Word32 nZero = 0;
+ WebRtc_Word32 nRet = setsockopt(_socket, SOL_SOCKET, SO_SNDBUF,
+ (char*)&nZero, sizeof(nZero));
+ if( nRet == SOCKET_ERROR )
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows::UdpSocket2Windows(), SOCKET_ERROR,\
+ WSAerror: %d",
+ WSAGetLastError());
+ }
+}
+
+UdpSocket2Windows::~UdpSocket2Windows()
+{
+ WEBRTC_TRACE(kTraceMemory, kTraceTransport, _id,
+ "UdpSocket2Windows::~UdpSocket2Windows()");
+
+ WaitForOutstandingCalls();
+
+ delete _ptrCbRWLock;
+ delete _ptrDeleteCrit;
+ delete _ptrDeleteCond;
+ delete _ptrDestRWLock;
+ delete _ptrSocketRWLock;
+
+ if(_pCrit)
+ delete _pCrit;
+
+ if (_flow)
+ {
+ free(_flow);
+ _flow = NULL;
+ }
+
+ if (_gtc)
+ {
+ if(_filterHandle)
+ {
+ _gtc->TcDeleteFilter(_filterHandle);
+ }
+ if(_flowHandle)
+ {
+ _gtc->TcDeleteFlow(_flowHandle);
+ }
+ TrafficControlWindows::Release( _gtc);
+ }
+}
+
+WebRtc_Word32 UdpSocket2Windows::ChangeUniqueId(const WebRtc_Word32 id)
+{
+ _id = id;
+ if (_gtc)
+ {
+ _gtc->ChangeUniqueId(id);
+ }
+ return 0;
+}
+
+bool UdpSocket2Windows::ValidHandle()
+{
+ return GetFd() != INVALID_SOCKET;
+}
+
+bool UdpSocket2Windows::SetCallback(CallbackObj obj, IncomingSocketCallback cb)
+{
+ _ptrCbRWLock->AcquireLockExclusive();
+ _obj = obj;
+ _incomingCb = cb;
+ _ptrCbRWLock->ReleaseLockExclusive();
+
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::SetCallback ",(WebRtc_Word32)this);
+ if(_addedToMgr)
+ {
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::SetCallback alreadey added",
+ (WebRtc_Word32) this);
+ return false;
+
+ }
+ if (_mgr->AddSocket(this))
+ {
+ WEBRTC_TRACE(
+ kTraceDebug, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::SetCallback socket added to manager",
+ (WebRtc_Word32)this);
+ _addedToMgr = true;
+ return true;
+ }
+
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::SetCallback error adding me to mgr",
+ (WebRtc_Word32) this);
+ return false;
+}
+
+bool UdpSocket2Windows::SetSockopt(WebRtc_Word32 level, WebRtc_Word32 optname,
+ const WebRtc_Word8* optval,
+ WebRtc_Word32 optlen)
+{
+ bool returnValue = true;
+ if(!AquireSocket())
+ {
+ return false;
+ }
+ if(0 != setsockopt(_socket, level, optname,
+ reinterpret_cast<const char*>(optval), optlen ))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows::SetSockopt(), WSAerror:%d",
+ WSAGetLastError());
+ returnValue = false;
+ }
+ ReleaseSocket();
+ return returnValue;
+}
+
+bool UdpSocket2Windows::StartReceiving(WebRtc_UWord32 receiveBuffers)
+{
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::StartReceiving(%d)",
+ (WebRtc_Word32)this, receiveBuffers);
+
+ _wantsIncoming = true;
+
+ WebRtc_Word32 numberOfReceiveBuffersToCreate =
+ receiveBuffers - _receiveBuffers.Value();
+ numberOfReceiveBuffersToCreate = (numberOfReceiveBuffersToCreate < 0) ?
+ 0 : numberOfReceiveBuffersToCreate;
+
+ WebRtc_Word32 error = 0;
+ for(WebRtc_Word32 i = 0;
+ i < numberOfReceiveBuffersToCreate;
+ i++)
+ {
+ if(PostRecv())
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows::StartReceiving() i=%d", i);
+ error = -1;
+ break;
+ }
+ ++_receiveBuffers;
+ }
+ if(error == -1)
+ {
+ return false;
+ }
+
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "Socket receiving using:%d number of buffers",
+ _receiveBuffers.Value());
+ return true;
+}
+
+bool UdpSocket2Windows::StopReceiving()
+{
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "UdpSocket2Windows::StopReceiving()");
+ _wantsIncoming = false;
+ return true;
+}
+
+bool UdpSocket2Windows::Bind(const SocketAddress& name)
+{
+ const struct sockaddr* addr =
+ reinterpret_cast<const struct sockaddr*>(&name);
+ bool returnValue = true;
+ if(!AquireSocket())
+ {
+ return false;
+ }
+ if (0 != bind(_socket, addr, sizeof(SocketAddress)))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows::Bind() WSAerror: %d",
+ WSAGetLastError());
+ returnValue = false;
+ }
+ ReleaseSocket();
+ return returnValue;
+}
+
+WebRtc_Word32 UdpSocket2Windows::SendTo(const WebRtc_Word8* buf,
+ WebRtc_Word32 len,
+ const SocketAddress& to)
+{
+ WebRtc_Word32 retVal = 0;
+ WebRtc_Word32 error = 0;
+ if(len < 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::SendTo(), len= %d < 0",
+ (WebRtc_Word32)this, len);
+ return -1;
+ }
+
+ PerIoContext* pIoContext = _mgr->PopIoContext();
+ if(pIoContext == 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::SendTo(), pIoContext==0",
+ (WebRtc_Word32) this);
+ return -1;
+ }
+ // sizeof(pIoContext->buffer) is smaller than the highest number that
+ // can be represented by a WebRtc_Word32.
+ if(len >= (WebRtc_Word32) sizeof(pIoContext->buffer))
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows(%d)::SendTo(), len= %d > buffer_size = %d",
+ (WebRtc_Word32) this,
+ len,sizeof(pIoContext->buffer));
+ len = sizeof(pIoContext->buffer);
+ }
+
+ memcpy(pIoContext->buffer,buf,len);
+ pIoContext->wsabuf.buf = pIoContext->buffer;
+ pIoContext->wsabuf.len = len;
+ pIoContext->fromLen=sizeof(SocketAddress);
+ pIoContext->ioOperation = OP_WRITE;
+ pIoContext->nTotalBytes = len;
+ pIoContext->nSentBytes=0;
+
+ DWORD numOfbytesSent = 0;
+ const struct sockaddr* addr = reinterpret_cast<const struct sockaddr*>(&to);
+
+ if(!AquireSocket())
+ {
+ _mgr->PushIoContext(pIoContext);
+ return -1;
+ }
+ // Assume that the WSASendTo call will be successfull to make sure that
+ // _outstandingCalls is positive. Roll back if WSASendTo failed.
+ if(!NewOutstandingCall())
+ {
+ _mgr->PushIoContext(pIoContext);
+ ReleaseSocket();
+ return -1;
+ }
+ retVal = WSASendTo(_socket, &pIoContext->wsabuf, 1, &numOfbytesSent,
+ 0, addr, sizeof(SocketAddress),
+ &(pIoContext->overlapped), 0);
+ ReleaseSocket();
+
+ if( retVal == SOCKET_ERROR )
+ {
+ error = WSAGetLastError();
+ if(error != ERROR_IO_PENDING)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows::SendTo() WSAerror: %d",error);
+ }
+ }
+ if(retVal == 0 || (retVal == SOCKET_ERROR && error == ERROR_IO_PENDING))
+ {
+ return len;
+ }
+ if((error = _mgr->PushIoContext(pIoContext)))
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows(%d)::SendTo(), error:%d pushing ioContext",
+ (WebRtc_Word32)this, error);
+ }
+
+ // Roll back.
+ OutstandingCallCompleted();
+ return -1;
+}
+
+void UdpSocket2Windows::IOCompleted(PerIoContext* pIOContext,
+ WebRtc_UWord32 ioSize, WebRtc_UWord32 error)
+{
+ if(pIOContext == NULL || error == ERROR_OPERATION_ABORTED)
+ {
+ if ((pIOContext != NULL) &&
+ !pIOContext->ioInitiatedByThreadWrapper &&
+ (error == ERROR_OPERATION_ABORTED) &&
+ (pIOContext->ioOperation == OP_READ) &&
+ _outstandingCallsDisabled)
+ {
+ // !pIOContext->initiatedIOByThreadWrapper indicate that the I/O
+ // was not initiated by a ThreadWrapper thread.
+ // This may happen if the thread that initiated receiving (e.g.
+ // by calling StartListen())) is deleted before any packets have
+ // been received.
+ // In this case there is no packet in the PerIoContext. Re-use it
+ // to post a new PostRecv(..).
+ // Note 1: the PerIoContext will henceforth be posted by a thread
+ // that is controlled by the socket implementation.
+ // Note 2: This is more likely to happen to RTCP packets as
+ // they are less frequent than RTP packets.
+ // Note 3: _outstandingCallsDisabled being false indicates
+ // that the socket isn't being shut down.
+ // Note 4: This should only happen buffers set to receive packets
+ // (OP_READ).
+ } else {
+ if(pIOContext == NULL)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows::IOCompleted(%d,%d,%d), %d",
+ (WebRtc_Word32)pIOContext,
+ ioSize,
+ error,
+ pIOContext ? (WebRtc_Word32)pIOContext->ioOperation : -1);
+ } else {
+ WEBRTC_TRACE(
+ kTraceDebug,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows::IOCompleted() Operation aborted");
+ }
+ if(pIOContext)
+ {
+ WebRtc_Word32 remainingReceiveBuffers = --_receiveBuffers;
+ if(remainingReceiveBuffers < 0)
+ {
+ assert(false);
+ }
+ WebRtc_Word32 err = 0;
+ if((err = _mgr->PushIoContext(pIOContext)))
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows::IOCompleted(), err = %d, when\
+ pushing ioContext after error",
+ err);
+ }
+ }
+ OutstandingCallCompleted();
+ return;
+ }
+ } // if (pIOContext == NULL || error == ERROR_OPERATION_ABORTED)
+
+ if(pIOContext->ioOperation == OP_WRITE)
+ {
+ _mgr->PushIoContext(pIOContext);
+ }
+ else if(pIOContext->ioOperation == OP_READ)
+ {
+ if(!error && ioSize != 0)
+ {
+ _ptrCbRWLock->AcquireLockShared();
+ if(_wantsIncoming && _incomingCb)
+ {
+ _incomingCb(_obj,
+ reinterpret_cast<const WebRtc_Word8*>(
+ pIOContext->wsabuf.buf),
+ ioSize,
+ &pIOContext->from);
+ }
+ _ptrCbRWLock->ReleaseLockShared();
+ }
+ WebRtc_Word32 err = PostRecv(pIOContext);
+ if(err == 0)
+ {
+ // The PerIoContext was posted by a thread controlled by the socket
+ // implementation.
+ pIOContext->ioInitiatedByThreadWrapper = true;
+ }
+ OutstandingCallCompleted();
+ return;
+ } else {
+ // Unknown operation. Should not happen. Return pIOContext to avoid
+ // memory leak.
+ assert(false);
+ _mgr->PushIoContext(pIOContext);
+ }
+ OutstandingCallCompleted();
+ // Don't touch any members after OutstandingCallCompleted() since the socket
+ // may be deleted at this point.
+}
+
+WebRtc_Word32 UdpSocket2Windows::PostRecv()
+{
+ PerIoContext* pIoContext=_mgr->PopIoContext();
+ if(pIoContext == 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::PostRecv(), pIoContext == 0",
+ (WebRtc_Word32)this);
+ return -1;
+ }
+ // This function may have been called by thread not controlled by the socket
+ // implementation.
+ pIoContext->ioInitiatedByThreadWrapper = false;
+ return PostRecv(pIoContext);
+}
+
+WebRtc_Word32 UdpSocket2Windows::PostRecv(PerIoContext* pIoContext)
+{
+ if(pIoContext==0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::PostRecv(?), pIoContext==0",
+ (WebRtc_Word32)this);
+ return -1;
+ }
+
+ DWORD numOfRecivedBytes = 0;
+ DWORD flags = 0;
+ pIoContext->wsabuf.buf = pIoContext->buffer;
+ pIoContext->wsabuf.len = sizeof(pIoContext->buffer);
+ pIoContext->fromLen = sizeof(SocketAddress);
+ pIoContext->ioOperation = OP_READ;
+ WebRtc_Word32 rxError = 0;
+ WebRtc_Word32 nRet = 0;
+ WebRtc_Word32 postingSucessfull = false;
+
+ if(!AquireSocket())
+ {
+ _mgr->PushIoContext(pIoContext);
+ return -1;
+ }
+
+ // Assume that the WSARecvFrom() call will be successfull to make sure that
+ // _outstandingCalls is positive. Roll back if WSARecvFrom() failed.
+ if(!NewOutstandingCall())
+ {
+ _mgr->PushIoContext(pIoContext);
+ ReleaseSocket();
+ return -1;
+ }
+ for(WebRtc_Word32 tries = 0; tries < 10; tries++)
+ {
+ nRet = WSARecvFrom(
+ _socket,
+ &(pIoContext->wsabuf),
+ 1,
+ &numOfRecivedBytes,
+ &flags,
+ reinterpret_cast<struct sockaddr*>(&(pIoContext->from)),
+ &(pIoContext->fromLen),
+ &(pIoContext->overlapped),
+ 0);
+
+ if( nRet == SOCKET_ERROR)
+ {
+ rxError = WSAGetLastError();
+ if(rxError != ERROR_IO_PENDING)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows(%d)::PostRecv(?), WSAerror:%d when\
+ posting new recieve,trie:%d",
+ (WebRtc_Word32)this,
+ rxError,
+ tries);
+ // Tell the OS that this is a good place to context switch if
+ // it wants to.
+ Sleep(0);
+ }
+ }
+ if((rxError == ERROR_IO_PENDING) || (nRet == 0))
+ {
+ postingSucessfull = true;
+ break;
+ }
+ }
+ ReleaseSocket();
+
+ if(postingSucessfull)
+ {
+ return 0;
+ }
+ WebRtc_Word32 remainingReceiveBuffers = --_receiveBuffers;
+ if(remainingReceiveBuffers < 0)
+ {
+ assert(false);
+ }
+ WebRtc_Word32 error = 0;
+ if((error = _mgr->PushIoContext(pIoContext)))
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows(%d)::PostRecv(?), error:%d when PushIoContext",
+ (WebRtc_Word32)this,
+ error);
+ }
+ // Roll back.
+ OutstandingCallCompleted();
+ return -1;
+}
+
+void UdpSocket2Windows::CloseBlocking()
+{
+ LINGER lingerStruct;
+
+ lingerStruct.l_onoff = 1;
+ lingerStruct.l_linger = 0;
+ if(AquireSocket())
+ {
+ setsockopt(_socket, SOL_SOCKET, SO_LINGER,
+ reinterpret_cast<const char*>(&lingerStruct),
+ sizeof(lingerStruct));
+ ReleaseSocket();
+ }
+
+ _wantsIncoming = false;
+ // Reclaims the socket and prevents it from being used again.
+ InvalidateSocket();
+ DisableNewOutstandingCalls();
+ WaitForOutstandingCalls();
+ delete this;
+}
+
+bool UdpSocket2Windows::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)
+{
+ if(_qos == false)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows::SetQos(), socket not capable of QOS");
+ return false;
+ }
+ if(overrideDSCP != 0)
+ {
+ FLOWSPEC f;
+ WebRtc_Word32 err = CreateFlowSpec(serviceType, tokenRate, bucketSize,
+ peekBandwith, minPolicedSize,
+ maxSduSize, &f);
+ if(err == -1)
+ {
+ return false;
+ }
+
+ SocketAddress socketName;
+ struct sockaddr_in* name =
+ reinterpret_cast<struct sockaddr_in*>(&socketName);
+ int nameLength = sizeof(SocketAddress);
+ if(AquireSocket())
+ {
+ getsockname(_socket, (struct sockaddr*)name, &nameLength);
+ ReleaseSocket();
+ }
+
+ if(serviceType == 0)
+ {
+ // Disable TOS byte setting.
+ return SetTrafficControl(0, -1, name, &f, &f) == 0;
+ }
+ return SetTrafficControl(overrideDSCP, -1, name, &f, &f) == 0;
+ }
+
+ QOS Qos;
+ DWORD BytesRet;
+ QOS_DESTADDR QosDestaddr;
+
+ memset (&Qos, QOS_NOT_SPECIFIED, sizeof(QOS));
+
+ Qos.SendingFlowspec.ServiceType = serviceType;
+ Qos.SendingFlowspec.TokenRate = tokenRate;
+ Qos.SendingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED;
+ Qos.SendingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED;
+ Qos.SendingFlowspec.DelayVariation = QOS_NOT_SPECIFIED;
+ Qos.SendingFlowspec.Latency = QOS_NOT_SPECIFIED;
+ Qos.SendingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED;
+ Qos.SendingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED;
+
+ // Only ServiceType is needed for receiving.
+ Qos.ReceivingFlowspec.ServiceType = serviceType;
+ Qos.ReceivingFlowspec.TokenRate = QOS_NOT_SPECIFIED;
+ Qos.ReceivingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED;
+ Qos.ReceivingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED;
+ Qos.ReceivingFlowspec.Latency = QOS_NOT_SPECIFIED;
+ Qos.ReceivingFlowspec.DelayVariation = QOS_NOT_SPECIFIED;
+ Qos.ReceivingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED;
+ Qos.ReceivingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED;
+
+ Qos.ProviderSpecific.len = 0;
+
+ Qos.ProviderSpecific.buf = NULL;
+
+ ZeroMemory((WebRtc_Word8 *)&QosDestaddr, sizeof(QosDestaddr));
+
+ OSVERSIONINFOEX osvie;
+ osvie.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ GetVersionEx((LPOSVERSIONINFO)&osvie);
+
+// Operating system Version number dwMajorVersion dwMinorVersion
+// Windows 7 6.1 6 1
+// Windows Server 2008 R2 6.1 6 1
+// Windows Server 2008 6.0 6 0
+// Windows Vista 6.0 6 0
+// Windows Server 2003 R2 5.2 5 2
+// Windows Server 2003 5.2 5 2
+// Windows XP 5.1 5 1
+// Windows 2000 5.0 5 0
+
+ // SERVICE_NO_QOS_SIGNALING and QOS_DESTADDR should not be used if version
+ // is 6.0 or greater.
+ if(osvie.dwMajorVersion >= 6)
+ {
+ Qos.SendingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED;
+ Qos.ReceivingFlowspec.ServiceType = serviceType;
+
+ } else {
+ Qos.SendingFlowspec.MinimumPolicedSize =
+ QOS_NOT_SPECIFIED | SERVICE_NO_QOS_SIGNALING;
+ Qos.ReceivingFlowspec.ServiceType =
+ serviceType | SERVICE_NO_QOS_SIGNALING;
+
+ QosDestaddr.ObjectHdr.ObjectType = QOS_OBJECT_DESTADDR;
+ QosDestaddr.ObjectHdr.ObjectLength = sizeof(QosDestaddr);
+ QosDestaddr.SocketAddress = (SOCKADDR *)&stRemName;
+ if (AF_INET6 == _iProtocol)
+ {
+ QosDestaddr.SocketAddressLength = sizeof(SocketAddressInVersion6);
+ } else {
+ QosDestaddr.SocketAddressLength = sizeof(SocketAddressIn);
+ }
+
+ Qos.ProviderSpecific.len = QosDestaddr.ObjectHdr.ObjectLength;
+ Qos.ProviderSpecific.buf = (char*)&QosDestaddr;
+ }
+
+ if(!AquireSocket()) {
+ return false;
+ }
+ // To set QoS with SIO_SET_QOS the socket must be locally bound first
+ // or the call will fail with error code 10022.
+ WebRtc_Word32 result = WSAIoctl(GetFd(), SIO_SET_QOS, &Qos, sizeof(QOS),
+ NULL, 0, &BytesRet, NULL,NULL);
+ ReleaseSocket();
+ if (result == SOCKET_ERROR)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows::SetQos() WSAerror : %d",
+ WSAGetLastError());
+ return false;
+ }
+ return true;
+}
+
+WebRtc_Word32 UdpSocket2Windows::SetTOS(WebRtc_Word32 serviceType)
+{
+ SocketAddress socketName;
+
+ struct sockaddr_in* name =
+ reinterpret_cast<struct sockaddr_in*>(&socketName);
+ int nameLength = sizeof(SocketAddress);
+ if(AquireSocket())
+ {
+ getsockname(_socket, (struct sockaddr*)name, &nameLength);
+ ReleaseSocket();
+ }
+
+ WebRtc_Word32 res = SetTrafficControl(serviceType, -1, name);
+ if (res == -1)
+ {
+ OSVERSIONINFO OsVersion;
+ OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx (&OsVersion);
+
+ if ((OsVersion.dwMajorVersion == 4)) // NT 4.0
+ {
+ if(SetSockopt(IPPROTO_IP,IP_TOS ,
+ (WebRtc_Word8*)&serviceType, 4) != 0)
+ {
+ return -1;
+ }
+ }
+ }
+ return res;
+}
+
+WebRtc_Word32 UdpSocket2Windows::SetPCP(WebRtc_Word32 pcp)
+{
+ SocketAddress socketName;
+ struct sockaddr_in* name =
+ reinterpret_cast<struct sockaddr_in*>(&socketName);
+ int nameLength = sizeof(SocketAddress);
+ if(AquireSocket())
+ {
+ getsockname(_socket, (struct sockaddr*)name, &nameLength);
+ ReleaseSocket();
+ }
+ return SetTrafficControl(-1, pcp, name);
+}
+
+WebRtc_Word32 UdpSocket2Windows::SetTrafficControl(
+ WebRtc_Word32 dscp,
+ WebRtc_Word32 pcp,
+ const struct sockaddr_in* name,
+ FLOWSPEC* send, FLOWSPEC* recv)
+{
+ if (pcp == _pcp)
+ {
+ // No change.
+ pcp = -1;
+ }
+ if ((-1 == pcp) && (-1 == dscp))
+ {
+ return 0;
+ }
+ if (!_gtc)
+ {
+ _gtc = TrafficControlWindows::GetInstance(_id);
+ }
+ if (!_gtc)
+ {
+ return -1;
+ }
+ if(_filterHandle)
+ {
+ _gtc->TcDeleteFilter(_filterHandle);
+ _filterHandle = NULL;
+ }
+ if(_flowHandle)
+ {
+ _gtc->TcDeleteFlow(_flowHandle);
+ _flowHandle = NULL;
+ }
+ if(_clientHandle)
+ {
+ _gtc->TcDeregisterClient(_clientHandle);
+ _clientHandle = NULL;
+ }
+ if ((0 == dscp) && (-2 == _pcp) && (-1 == pcp))
+ {
+ // TODO (pwestin): why is this not done before deleting old filter and
+ // flow? This scenario should probably be documented in
+ // the function declaration.
+ return 0;
+ }
+
+ TCI_CLIENT_FUNC_LIST QoSFunctions;
+ QoSFunctions.ClAddFlowCompleteHandler = NULL;
+ QoSFunctions.ClDeleteFlowCompleteHandler = NULL;
+ QoSFunctions.ClModifyFlowCompleteHandler = NULL;
+ QoSFunctions.ClNotifyHandler = (TCI_NOTIFY_HANDLER)MyClNotifyHandler;
+ // Register the client with Traffic control interface.
+ HANDLE ClientHandle;
+ ULONG result = _gtc->TcRegisterClient(CURRENT_TCI_VERSION, NULL,
+ &QoSFunctions,&ClientHandle);
+ if(result != NO_ERROR)
+ {
+ // This is likely caused by the application not being run as
+ // administrator.
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "TcRegisterClient returned %d", result);
+ return result;
+ }
+
+ // Find traffic control-enabled network interfaces that matches this
+ // socket's IP address.
+ ULONG BufferSize = 0;
+ result = _gtc->TcEnumerateInterfaces(ClientHandle, &BufferSize, NULL);
+
+ if(result != NO_ERROR && result != ERROR_INSUFFICIENT_BUFFER)
+ {
+ _gtc->TcDeregisterClient(ClientHandle);
+ return result;
+ }
+
+ if(result != ERROR_INSUFFICIENT_BUFFER)
+ {
+ // Empty buffer contains all control-enabled network interfaces. I.e.
+ // QoS is not enabled.
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "QOS faild since QOS is not installed on the interface");
+
+ _gtc->TcDeregisterClient(ClientHandle);
+ return -1;
+ }
+
+ PTC_IFC_DESCRIPTOR pInterfaceBuffer =
+ (PTC_IFC_DESCRIPTOR)malloc(BufferSize);
+ if(pInterfaceBuffer == NULL)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Out ot memory failure");
+ _gtc->TcDeregisterClient(ClientHandle);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ result = _gtc->TcEnumerateInterfaces(ClientHandle, &BufferSize,
+ pInterfaceBuffer);
+
+ if(result != NO_ERROR)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "Critical: error enumerating interfaces when passing in correct\
+ buffer size: %d", result);
+ _gtc->TcDeregisterClient(ClientHandle);
+ free(pInterfaceBuffer);
+ return result;
+ }
+
+ PTC_IFC_DESCRIPTOR oneinterface;
+ HANDLE ifcHandle, iFilterHandle, iflowHandle;
+ bool addrFound = false;
+ ULONG filterSourceAddress = ULONG_MAX;
+
+ // Find the interface corresponding to the local address.
+ for(oneinterface = pInterfaceBuffer;
+ oneinterface != (PTC_IFC_DESCRIPTOR)
+ (((WebRtc_Word8*)pInterfaceBuffer) + BufferSize);
+ oneinterface = (PTC_IFC_DESCRIPTOR)
+ ((WebRtc_Word8 *)oneinterface + oneinterface->Length))
+ {
+
+ char interfaceName[500];
+ WideCharToMultiByte(CP_ACP, 0, oneinterface->pInterfaceName, -1,
+ interfaceName, sizeof(interfaceName), 0, 0 );
+
+ PNETWORK_ADDRESS_LIST addresses =
+ &(oneinterface->AddressListDesc.AddressList);
+ for(LONG i = 0; i < addresses->AddressCount ; i++)
+ {
+ // Only look at TCP/IP addresses.
+ if(addresses->Address[i].AddressType != NDIS_PROTOCOL_ID_TCP_IP)
+ {
+ continue;
+ }
+
+ NETWORK_ADDRESS_IP* pIpAddr =
+ (NETWORK_ADDRESS_IP*)&(addresses->Address[i].Address);
+ struct in_addr in;
+ in.S_un.S_addr = pIpAddr->in_addr;
+ if(pIpAddr->in_addr == name->sin_addr.S_un.S_addr)
+ {
+ filterSourceAddress = pIpAddr->in_addr;
+ addrFound = true;
+ }
+ }
+ if(!addrFound)
+ {
+ continue;
+ } else
+ {
+ break;
+ }
+ }
+ if(!addrFound)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "QOS faild since address is not found");
+ _gtc->TcDeregisterClient(ClientHandle);
+ free(pInterfaceBuffer);
+ return -1;
+ }
+ result = _gtc->TcOpenInterfaceW(oneinterface->pInterfaceName, ClientHandle,
+ NULL, &ifcHandle);
+ if(result != NO_ERROR)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Error opening interface: %d", result);
+ _gtc->TcDeregisterClient(ClientHandle);
+ free(pInterfaceBuffer);
+ return result;
+ }
+
+ // Create flow if one doesn't exist.
+ if (!_flow)
+ {
+ bool addPCP = ((pcp >= 0) || ((-1 == pcp) && (_pcp >= 0)));
+ int allocSize = sizeof(TC_GEN_FLOW) + sizeof(QOS_DS_CLASS) +
+ (addPCP ? sizeof(QOS_TRAFFIC_CLASS) : 0);
+ _flow = (PTC_GEN_FLOW)malloc(allocSize);
+
+ _flow->SendingFlowspec.DelayVariation = QOS_NOT_SPECIFIED;
+ _flow->SendingFlowspec.Latency = QOS_NOT_SPECIFIED;
+ _flow->SendingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED;
+ _flow->SendingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED;
+ _flow->SendingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED;
+ _flow->SendingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT;
+ _flow->SendingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED;
+ _flow->SendingFlowspec.TokenRate = QOS_NOT_SPECIFIED;
+
+ _flow->ReceivingFlowspec.DelayVariation = QOS_NOT_SPECIFIED;
+ _flow->ReceivingFlowspec.Latency = QOS_NOT_SPECIFIED;
+ _flow->ReceivingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED;
+ _flow->ReceivingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED;
+ _flow->ReceivingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED;
+ _flow->ReceivingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT;
+ _flow->ReceivingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED;
+ _flow->ReceivingFlowspec.TokenRate = QOS_NOT_SPECIFIED;
+
+ QOS_DS_CLASS* dsClass = (QOS_DS_CLASS*)_flow->TcObjects;
+ dsClass->DSField = 0;
+ dsClass->ObjectHdr.ObjectType = QOS_OBJECT_DS_CLASS;
+ dsClass->ObjectHdr.ObjectLength = sizeof(QOS_DS_CLASS);
+
+ if (addPCP)
+ {
+ QOS_TRAFFIC_CLASS* trafficClass = (QOS_TRAFFIC_CLASS*)(dsClass + 1);
+ trafficClass->TrafficClass = 0;
+ trafficClass->ObjectHdr.ObjectType = QOS_OBJECT_TRAFFIC_CLASS;
+ trafficClass->ObjectHdr.ObjectLength = sizeof(QOS_TRAFFIC_CLASS);
+ }
+
+ _flow->TcObjectsLength = sizeof(QOS_DS_CLASS) +
+ (addPCP ? sizeof(QOS_TRAFFIC_CLASS) : 0);
+ } else if (-1 != pcp) {
+ // Reallocate memory since pcp has changed.
+ PTC_GEN_FLOW oldFlow = _flow;
+ bool addPCP = (pcp >= 0);
+ int allocSize = sizeof(TC_GEN_FLOW) + sizeof(QOS_DS_CLASS) +
+ (addPCP ? sizeof(QOS_TRAFFIC_CLASS) : 0);
+ _flow = (PTC_GEN_FLOW)malloc(allocSize);
+
+ // Copy old flow.
+ _flow->ReceivingFlowspec = oldFlow->ReceivingFlowspec;
+ _flow->SendingFlowspec = oldFlow->SendingFlowspec;
+ // The DS info is always the first object.
+ QOS_DS_CLASS* dsClass = (QOS_DS_CLASS*)_flow->TcObjects;
+ QOS_DS_CLASS* oldDsClass = (QOS_DS_CLASS*)oldFlow->TcObjects;
+ dsClass->DSField = oldDsClass->DSField;
+ dsClass->ObjectHdr.ObjectType = oldDsClass->ObjectHdr.ObjectType;
+ dsClass->ObjectHdr.ObjectLength = oldDsClass->ObjectHdr.ObjectLength;
+
+ if (addPCP)
+ {
+ QOS_TRAFFIC_CLASS* trafficClass = (QOS_TRAFFIC_CLASS*)(dsClass + 1);
+ trafficClass->TrafficClass = 0;
+ trafficClass->ObjectHdr.ObjectType = QOS_OBJECT_TRAFFIC_CLASS;
+ trafficClass->ObjectHdr.ObjectLength = sizeof(QOS_TRAFFIC_CLASS);
+ }
+
+ _flow->TcObjectsLength = sizeof(QOS_DS_CLASS) +
+ (addPCP ? sizeof(QOS_TRAFFIC_CLASS) : 0);
+ free(oldFlow);
+ }
+
+ // Setup send and receive flow and DS object.
+ if (dscp >= 0)
+ {
+ if (!send || (0 == dscp))
+ {
+ _flow->SendingFlowspec.DelayVariation = QOS_NOT_SPECIFIED;
+ _flow->SendingFlowspec.Latency = QOS_NOT_SPECIFIED;
+ _flow->SendingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED;
+ _flow->SendingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED;
+ _flow->SendingFlowspec.PeakBandwidth =
+ (0 == dscp ? QOS_NOT_SPECIFIED : POSITIVE_INFINITY_RATE);
+ _flow->SendingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT;
+ _flow->SendingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED;
+ // 128000 * 10 is 10mbit/s.
+ _flow->SendingFlowspec.TokenRate =
+ (0 == dscp ? QOS_NOT_SPECIFIED : 128000 * 10);
+ }
+ else
+ {
+ _flow->SendingFlowspec.DelayVariation = send->DelayVariation;
+ _flow->SendingFlowspec.Latency = send->Latency;
+ _flow->SendingFlowspec.MaxSduSize = send->MaxSduSize;
+ _flow->SendingFlowspec.MinimumPolicedSize =
+ send->MinimumPolicedSize;
+ _flow->SendingFlowspec.PeakBandwidth = send->PeakBandwidth;
+ _flow->SendingFlowspec.PeakBandwidth = POSITIVE_INFINITY_RATE;
+ _flow->SendingFlowspec.ServiceType = send->ServiceType;
+ _flow->SendingFlowspec.TokenBucketSize = send->TokenBucketSize;
+ _flow->SendingFlowspec.TokenRate = send->TokenRate;
+ }
+
+ if (!recv || (0 == dscp))
+ {
+ _flow->ReceivingFlowspec.DelayVariation =
+ _flow->SendingFlowspec.DelayVariation;
+ _flow->ReceivingFlowspec.Latency = _flow->SendingFlowspec.Latency;
+ _flow->ReceivingFlowspec.MaxSduSize =
+ _flow->SendingFlowspec.MaxSduSize;
+ _flow->ReceivingFlowspec.MinimumPolicedSize =
+ _flow->SendingFlowspec.MinimumPolicedSize;
+ _flow->ReceivingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED;
+ _flow->ReceivingFlowspec.ServiceType =
+ 0 == dscp ? SERVICETYPE_BESTEFFORT : SERVICETYPE_CONTROLLEDLOAD;
+ _flow->ReceivingFlowspec.TokenBucketSize =
+ _flow->SendingFlowspec.TokenBucketSize;
+ _flow->ReceivingFlowspec.TokenRate =
+ _flow->SendingFlowspec.TokenRate;
+ } else {
+ _flow->ReceivingFlowspec.DelayVariation = recv->DelayVariation;
+ _flow->ReceivingFlowspec.Latency = recv->Latency;
+ _flow->ReceivingFlowspec.MaxSduSize = recv->MaxSduSize;
+ _flow->ReceivingFlowspec.MinimumPolicedSize =
+ recv->MinimumPolicedSize;
+ _flow->ReceivingFlowspec.PeakBandwidth = recv->PeakBandwidth;
+ _flow->ReceivingFlowspec.ServiceType = recv->ServiceType;
+ _flow->ReceivingFlowspec.TokenBucketSize = recv->TokenBucketSize;
+ _flow->ReceivingFlowspec.TokenRate = QOS_NOT_SPECIFIED;
+ }
+
+ // Setup DS (for DSCP value).
+ // DS is always the first object.
+ QOS_DS_CLASS* dsClass = (QOS_DS_CLASS*)_flow->TcObjects;
+ dsClass->DSField = dscp;
+ }
+
+ // Setup PCP (802.1p priority in 802.1Q/VLAN tagging)
+ if (pcp >= 0)
+ {
+ // DS is always first object.
+ QOS_DS_CLASS* dsClass = (QOS_DS_CLASS*)_flow->TcObjects;
+ QOS_TRAFFIC_CLASS* trafficClass = (QOS_TRAFFIC_CLASS*)(dsClass + 1);
+ trafficClass->TrafficClass = pcp;
+ }
+
+ result = _gtc->TcAddFlow(ifcHandle, NULL, 0, _flow, &iflowHandle);
+ if(result != NO_ERROR)
+ {
+ _gtc->TcCloseInterface(ifcHandle);
+ _gtc->TcDeregisterClient(ClientHandle);
+ free(pInterfaceBuffer);
+ return -1;
+ }
+
+ IP_PATTERN filterPattern, mask;
+
+ ZeroMemory((WebRtc_Word8*)&filterPattern, sizeof(IP_PATTERN));
+ ZeroMemory((WebRtc_Word8*)&mask, sizeof(IP_PATTERN));
+
+ filterPattern.ProtocolId = IPPROTO_UDP;
+ // "name" fields already in network order.
+ filterPattern.S_un.S_un_ports.s_srcport = name->sin_port;
+ filterPattern.SrcAddr = filterSourceAddress;
+
+ // Unsigned max of a type corresponds to a bitmask with all bits set to 1.
+ // I.e. the filter should allow all ProtocolIds, any source port and any
+ // IP address
+ mask.ProtocolId = UCHAR_MAX;
+ mask.S_un.S_un_ports.s_srcport = USHRT_MAX;
+ mask.SrcAddr = ULONG_MAX;
+
+ TC_GEN_FILTER filter;
+
+ filter.AddressType = NDIS_PROTOCOL_ID_TCP_IP;
+ filter.Mask = (LPVOID)&mask;
+ filter.Pattern = (LPVOID)&filterPattern;
+ filter.PatternSize = sizeof(IP_PATTERN);
+
+ result = _gtc->TcAddFilter(iflowHandle, &filter, &iFilterHandle);
+ if(result != NO_ERROR)
+ {
+ _gtc->TcDeleteFlow(iflowHandle);
+ _gtc->TcCloseInterface(ifcHandle);
+ _gtc->TcDeregisterClient(ClientHandle);
+ free(pInterfaceBuffer);
+ return result;
+ }
+
+ _flowHandle = iflowHandle;
+ _filterHandle = iFilterHandle;
+ _clientHandle = ClientHandle;
+ if (-1 != pcp)
+ {
+ _pcp = pcp;
+ }
+
+ _gtc->TcCloseInterface(ifcHandle);
+ free(pInterfaceBuffer);
+
+ return 0;
+}
+
+WebRtc_Word32 UdpSocket2Windows::CreateFlowSpec(WebRtc_Word32 serviceType,
+ WebRtc_Word32 tokenRate,
+ WebRtc_Word32 bucketSize,
+ WebRtc_Word32 peekBandwith,
+ WebRtc_Word32 minPolicedSize,
+ WebRtc_Word32 maxSduSize,
+ FLOWSPEC* f)
+{
+ if (!f)
+ {
+ return -1;
+ }
+
+ f->ServiceType = serviceType;
+ f->TokenRate = tokenRate;
+ f->TokenBucketSize = QOS_NOT_SPECIFIED;
+ f->PeakBandwidth = QOS_NOT_SPECIFIED;
+ f->DelayVariation = QOS_NOT_SPECIFIED;
+ f->Latency = QOS_NOT_SPECIFIED;
+ f->MaxSduSize = QOS_NOT_SPECIFIED;
+ f->MinimumPolicedSize = QOS_NOT_SPECIFIED;
+ return 0;
+}
+
+bool UdpSocket2Windows::NewOutstandingCall()
+{
+ assert(!_outstandingCallsDisabled);
+
+ ++_outstandingCalls;
+ return true;
+}
+
+void UdpSocket2Windows::OutstandingCallCompleted()
+{
+ _ptrDestRWLock->AcquireLockShared();
+ ++_outstandingCallComplete;
+ if((--_outstandingCalls == 0) && _outstandingCallsDisabled)
+ {
+ // When there are no outstanding calls and new outstanding calls are
+ // disabled it is time to terminate.
+ _terminate = true;
+ }
+ _ptrDestRWLock->ReleaseLockShared();
+
+ if((--_outstandingCallComplete == 0) &&
+ (_terminate))
+ {
+ // Only one thread will enter here. The thread with the last outstanding
+ // call.
+ CriticalSectionScoped cs(_ptrDeleteCrit);
+ _safeTodelete = true;
+ _ptrDeleteCond->Wake();
+ }
+}
+
+void UdpSocket2Windows::DisableNewOutstandingCalls()
+{
+ _ptrDestRWLock->AcquireLockExclusive();
+ if(_outstandingCallsDisabled)
+ {
+ // Outstandning calls are already disabled.
+ _ptrDestRWLock->ReleaseLockExclusive();
+ return;
+ }
+ _outstandingCallsDisabled = true;
+ const bool noOutstandingCalls = (_outstandingCalls.Value() == 0);
+ _ptrDestRWLock->ReleaseLockExclusive();
+
+ RemoveSocketFromManager();
+
+ if(noOutstandingCalls)
+ {
+ CriticalSectionScoped cs(_ptrDeleteCrit);
+ _safeTodelete = true;
+ _ptrDeleteCond->Wake();
+ }
+}
+
+void UdpSocket2Windows::WaitForOutstandingCalls()
+{
+ CriticalSectionScoped cs(_ptrDeleteCrit);
+ while(!_safeTodelete)
+ {
+ _ptrDeleteCond->SleepCS(*_ptrDeleteCrit);
+ }
+}
+
+void UdpSocket2Windows::RemoveSocketFromManager()
+{
+ // New outstanding calls should be disabled at this point.
+ assert(_outstandingCallsDisabled);
+
+ if(_addedToMgr)
+ {
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "calling UdpSocketManager::RemoveSocket()");
+ if(_mgr->RemoveSocket(this))
+ {
+ _addedToMgr=false;
+ }
+ }
+}
+
+bool UdpSocket2Windows::AquireSocket()
+{
+ _ptrSocketRWLock->AcquireLockShared();
+ const bool returnValue = _socket != INVALID_SOCKET;
+ if(!returnValue)
+ {
+ _ptrSocketRWLock->ReleaseLockShared();
+ }
+ return returnValue;
+}
+
+void UdpSocket2Windows::ReleaseSocket()
+{
+ _ptrSocketRWLock->ReleaseLockShared();
+}
+
+bool UdpSocket2Windows::InvalidateSocket()
+{
+ _ptrSocketRWLock->AcquireLockExclusive();
+ if(_socket == INVALID_SOCKET)
+ {
+ _ptrSocketRWLock->ReleaseLockExclusive();
+ return true;
+ }
+ // Give the socket back to the system. All socket calls will fail from now
+ // on.
+ if(closesocket(_socket) == SOCKET_ERROR)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::InvalidateSocket() WSAerror: %d",
+ (WebRtc_Word32)this, WSAGetLastError());
+ }
+ _socket = INVALID_SOCKET;
+ _ptrSocketRWLock->ReleaseLockExclusive();
+ return true;
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/test/channel_transport/udp_socket2_win.h b/test/channel_transport/udp_socket2_win.h
new file mode 100644
index 0000000..624db9b
--- /dev/null
+++ b/test/channel_transport/udp_socket2_win.h
@@ -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_
diff --git a/test/channel_transport/udp_socket_manager_posix.cc b/test/channel_transport/udp_socket_manager_posix.cc
new file mode 100644
index 0000000..8741641
--- /dev/null
+++ b/test/channel_transport/udp_socket_manager_posix.cc
@@ -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
diff --git a/test/channel_transport/udp_socket_manager_posix.h b/test/channel_transport/udp_socket_manager_posix.h
new file mode 100644
index 0000000..e6df98e
--- /dev/null
+++ b/test/channel_transport/udp_socket_manager_posix.h
@@ -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_
diff --git a/test/channel_transport/udp_socket_manager_unittest.cc b/test/channel_transport/udp_socket_manager_unittest.cc
new file mode 100644
index 0000000..8045dfe
--- /dev/null
+++ b/test/channel_transport/udp_socket_manager_unittest.cc
@@ -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
diff --git a/test/channel_transport/udp_socket_manager_wrapper.cc b/test/channel_transport/udp_socket_manager_wrapper.cc
new file mode 100644
index 0000000..e26e649
--- /dev/null
+++ b/test/channel_transport/udp_socket_manager_wrapper.cc
@@ -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
diff --git a/test/channel_transport/udp_socket_manager_wrapper.h b/test/channel_transport/udp_socket_manager_wrapper.h
new file mode 100644
index 0000000..2cad1cb
--- /dev/null
+++ b/test/channel_transport/udp_socket_manager_wrapper.h
@@ -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_
diff --git a/test/channel_transport/udp_socket_posix.cc b/test/channel_transport/udp_socket_posix.cc
new file mode 100644
index 0000000..016526c
--- /dev/null
+++ b/test/channel_transport/udp_socket_posix.cc
@@ -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
diff --git a/test/channel_transport/udp_socket_posix.h b/test/channel_transport/udp_socket_posix.h
new file mode 100644
index 0000000..b77d663
--- /dev/null
+++ b/test/channel_transport/udp_socket_posix.h
@@ -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_
diff --git a/test/channel_transport/udp_socket_wrapper.cc b/test/channel_transport/udp_socket_wrapper.cc
new file mode 100644
index 0000000..aae43d4
--- /dev/null
+++ b/test/channel_transport/udp_socket_wrapper.cc
@@ -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
diff --git a/test/channel_transport/udp_socket_wrapper.h b/test/channel_transport/udp_socket_wrapper.h
new file mode 100644
index 0000000..39880b7
--- /dev/null
+++ b/test/channel_transport/udp_socket_wrapper.h
@@ -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_
diff --git a/test/channel_transport/udp_socket_wrapper_unittest.cc b/test/channel_transport/udp_socket_wrapper_unittest.cc
new file mode 100644
index 0000000..759a222
--- /dev/null
+++ b/test/channel_transport/udp_socket_wrapper_unittest.cc
@@ -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
diff --git a/test/channel_transport/udp_transport.h b/test/channel_transport/udp_transport.h
new file mode 100644
index 0000000..75859c9
--- /dev/null
+++ b/test/channel_transport/udp_transport.h
@@ -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_
diff --git a/test/channel_transport/udp_transport_impl.cc b/test/channel_transport/udp_transport_impl.cc
new file mode 100644
index 0000000..3c0419a
--- /dev/null
+++ b/test/channel_transport/udp_transport_impl.cc
@@ -0,0 +1,2999 @@
+/*
+ * 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_transport_impl.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#if defined(_WIN32)
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <unistd.h>
+#ifndef WEBRTC_IOS
+#include <net/if_arp.h>
+#endif
+#endif // defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
+
+#if defined(WEBRTC_MAC)
+#include <ifaddrs.h>
+#include <machine/types.h>
+#endif
+#if defined(WEBRTC_LINUX)
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#endif
+
+#include "webrtc/common_types.h"
+#include "webrtc/typedefs.h"
+#include "webrtc/system_wrappers/interface/critical_section_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_manager_wrapper.h"
+
+#if defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
+#define GetLastError() errno
+
+#define IFRSIZE ((int)(size * sizeof (struct ifreq)))
+
+#define NLMSG_OK_NO_WARNING(nlh,len) \
+ ((len) >= (int)sizeof(struct nlmsghdr) && \
+ (int)(nlh)->nlmsg_len >= (int)sizeof(struct nlmsghdr) && \
+ (int)(nlh)->nlmsg_len <= (len))
+
+#endif // defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
+
+namespace webrtc {
+namespace test {
+
+class SocketFactory : public UdpTransportImpl::SocketFactoryInterface {
+ public:
+ UdpSocketWrapper* CreateSocket(const WebRtc_Word32 id,
+ UdpSocketManager* mgr,
+ CallbackObj obj,
+ IncomingSocketCallback cb,
+ bool ipV6Enable,
+ bool disableGQOS) {
+ return UdpSocketWrapper::CreateSocket(id, mgr, obj, cb, ipV6Enable,
+ disableGQOS);
+ }
+};
+
+// Creates an UdpTransport using the definition of SocketFactory above,
+// and passes (creating if needed) a pointer to the static singleton
+// UdpSocketManager.
+UdpTransport* UdpTransport::Create(const WebRtc_Word32 id,
+ WebRtc_UWord8& numSocketThreads)
+{
+ return new UdpTransportImpl(id,
+ new SocketFactory(),
+ UdpSocketManager::Create(id, numSocketThreads));
+}
+
+// Deletes the UdpTransport and decrements the refcount of the
+// static singleton UdpSocketManager, possibly destroying it.
+// Should only be used on UdpTransports that are created using Create.
+void UdpTransport::Destroy(UdpTransport* module)
+{
+ if(module)
+ {
+ delete module;
+ UdpSocketManager::Return();
+ }
+}
+
+UdpTransportImpl::UdpTransportImpl(const WebRtc_Word32 id,
+ SocketFactoryInterface* maker,
+ UdpSocketManager* socket_manager)
+ : _id(id),
+ _socket_creator(maker),
+ _crit(CriticalSectionWrapper::CreateCriticalSection()),
+ _critFilter(CriticalSectionWrapper::CreateCriticalSection()),
+ _critPacketCallback(CriticalSectionWrapper::CreateCriticalSection()),
+ _mgr(socket_manager),
+ _lastError(kNoSocketError),
+ _destPort(0),
+ _destPortRTCP(0),
+ _localPort(0),
+ _localPortRTCP(0),
+ _srcPort(0),
+ _srcPortRTCP(0),
+ _fromPort(0),
+ _fromPortRTCP(0),
+ _fromIP(),
+ _destIP(),
+ _localIP(),
+ _localMulticastIP(),
+ _ptrRtpSocket(NULL),
+ _ptrRtcpSocket(NULL),
+ _ptrSendRtpSocket(NULL),
+ _ptrSendRtcpSocket(NULL),
+ _remoteRTPAddr(),
+ _remoteRTCPAddr(),
+ _localRTPAddr(),
+ _localRTCPAddr(),
+ _tos(0),
+ _receiving(false),
+ _useSetSockOpt(false),
+ _qos(false),
+ _pcp(0),
+ _ipV6Enabled(false),
+ _serviceType(0),
+ _overrideDSCP(0),
+ _maxBitrate(0),
+ _cachLock(RWLockWrapper::CreateRWLock()),
+ _previousAddress(),
+ _previousIP(),
+ _previousIPSize(0),
+ _previousSourcePort(0),
+ _filterIPAddress(),
+ _rtpFilterPort(0),
+ _rtcpFilterPort(0),
+ _packetCallback(0)
+{
+ memset(&_remoteRTPAddr, 0, sizeof(_remoteRTPAddr));
+ memset(&_remoteRTCPAddr, 0, sizeof(_remoteRTCPAddr));
+ memset(&_localRTPAddr, 0, sizeof(_localRTPAddr));
+ memset(&_localRTCPAddr, 0, sizeof(_localRTCPAddr));
+
+ memset(_fromIP, 0, sizeof(_fromIP));
+ memset(_destIP, 0, sizeof(_destIP));
+ memset(_localIP, 0, sizeof(_localIP));
+ memset(_localMulticastIP, 0, sizeof(_localMulticastIP));
+
+ memset(&_filterIPAddress, 0, sizeof(_filterIPAddress));
+
+ WEBRTC_TRACE(kTraceMemory, kTraceTransport, id, "%s created", __FUNCTION__);
+}
+
+UdpTransportImpl::~UdpTransportImpl()
+{
+ CloseSendSockets();
+ CloseReceiveSockets();
+ delete _crit;
+ delete _critFilter;
+ delete _critPacketCallback;
+ delete _cachLock;
+ delete _socket_creator;
+
+ WEBRTC_TRACE(kTraceMemory, kTraceTransport, _id, "%s deleted",
+ __FUNCTION__);
+}
+
+UdpTransport::ErrorCode UdpTransportImpl::LastError() const
+{
+ return _lastError;
+}
+
+bool SameAddress(const SocketAddress& address1, const SocketAddress& address2)
+{
+ return (memcmp(&address1,&address2,sizeof(address1)) == 0);
+}
+
+void UdpTransportImpl::GetCachedAddress(char* ip,
+ WebRtc_UWord32& ipSize,
+ WebRtc_UWord16& sourcePort)
+{
+ const WebRtc_UWord32 originalIPSize = ipSize;
+ // If the incoming string is too small, fill it as much as there is room
+ // for. Make sure that there is room for the '\0' character.
+ ipSize = (ipSize - 1 < _previousIPSize) ? ipSize - 1 : _previousIPSize;
+ memcpy(ip,_previousIP,sizeof(WebRtc_Word8)*(ipSize + 1));
+ ip[originalIPSize - 1] = '\0';
+ sourcePort = _previousSourcePort;
+}
+
+WebRtc_Word32 UdpTransportImpl::IPAddressCached(const SocketAddress& address,
+ char* ip,
+ WebRtc_UWord32& ipSize,
+ WebRtc_UWord16& sourcePort)
+{
+ {
+ ReadLockScoped rl(*_cachLock);
+ // Check if the old address can be re-used (is the same).
+ if(SameAddress(address,_previousAddress))
+ {
+ GetCachedAddress(ip,ipSize,sourcePort);
+ return 0;
+ }
+ }
+ // Get the new address and store it.
+ WriteLockScoped wl(*_cachLock);
+ ipSize = kIpAddressVersion6Length;
+ if(IPAddress(address,_previousIP,ipSize,_previousSourcePort) != 0)
+ {
+ return -1;
+ }
+ _previousIPSize = ipSize;
+ memcpy(&_previousAddress, &address, sizeof(address));
+ // Address has been cached at this point.
+ GetCachedAddress(ip,ipSize,sourcePort);
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::InitializeReceiveSockets(
+ UdpTransportData* const packetCallback,
+ const WebRtc_UWord16 portnr,
+ const char* ip,
+ const char* multicastIpAddr,
+ const WebRtc_UWord16 rtcpPort)
+{
+ {
+ CriticalSectionScoped cs(_critPacketCallback);
+ _packetCallback = packetCallback;
+
+ if(packetCallback == NULL)
+ {
+ WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, _id,
+ "Closing down receive sockets");
+ return 0;
+ }
+ }
+
+ CriticalSectionScoped cs(_crit);
+ CloseReceiveSockets();
+
+ if(portnr == 0)
+ {
+ // TODO (hellner): why not just fail here?
+ if(_destPort == 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "InitializeReceiveSockets port 0 not allowed");
+ _lastError = kPortInvalid;
+ return -1;
+ }
+ _localPort = _destPort;
+ } else {
+ _localPort = portnr;
+ }
+ if(rtcpPort)
+ {
+ _localPortRTCP = rtcpPort;
+ }else {
+ _localPortRTCP = _localPort + 1;
+ WEBRTC_TRACE(
+ kTraceStateInfo,
+ kTraceTransport,
+ _id,
+ "InitializeReceiveSockets RTCP port not configured using RTP\
+ port+1=%d",
+ _localPortRTCP);
+ }
+
+ if(ip)
+ {
+ if(IsIpAddressValid(ip,IpV6Enabled()))
+ {
+ strncpy(_localIP, ip,kIpAddressVersion6Length);
+ } else
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "InitializeReceiveSockets invalid IP address");
+ _lastError = kIpAddressInvalid;
+ return -1;
+ }
+ }else
+ {
+ // Don't bind to a specific IP address.
+ if(! IpV6Enabled())
+ {
+ strncpy(_localIP, "0.0.0.0",16);
+ } else
+ {
+ strncpy(_localIP, "0000:0000:0000:0000:0000:0000:0000:0000",
+ kIpAddressVersion6Length);
+ }
+ }
+ if(multicastIpAddr && !IpV6Enabled())
+ {
+ if(IsIpAddressValid(multicastIpAddr,IpV6Enabled()))
+ {
+ strncpy(_localMulticastIP, multicastIpAddr,
+ kIpAddressVersion6Length);
+ } else
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "InitializeReceiveSockets invalid IP address");
+ _lastError = kIpAddressInvalid;
+ return -1;
+ }
+ }
+ if(_mgr == NULL)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "InitializeReceiveSockets no socket manager");
+ return -1;
+ }
+
+ _useSetSockOpt=false;
+ _tos=0;
+ _pcp=0;
+
+ _ptrRtpSocket = _socket_creator->CreateSocket(_id, _mgr, this,
+ IncomingRTPCallback,
+ IpV6Enabled(), false);
+
+ _ptrRtcpSocket = _socket_creator->CreateSocket(_id, _mgr, this,
+ IncomingRTCPCallback,
+ IpV6Enabled(), false);
+
+ ErrorCode retVal = BindLocalRTPSocket();
+ if(retVal != kNoSocketError)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "InitializeReceiveSockets faild to bind RTP socket");
+ _lastError = retVal;
+ CloseReceiveSockets();
+ return -1;
+ }
+ retVal = BindLocalRTCPSocket();
+ if(retVal != kNoSocketError)
+ {
+ _lastError = retVal;
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "InitializeReceiveSockets faild to bind RTCP socket");
+ CloseReceiveSockets();
+ return -1;
+ }
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::ReceiveSocketInformation(
+ char ipAddr[kIpAddressVersion6Length],
+ WebRtc_UWord16& rtpPort,
+ WebRtc_UWord16& rtcpPort,
+ char multicastIpAddr[kIpAddressVersion6Length]) const
+{
+ CriticalSectionScoped cs(_crit);
+ rtpPort = _localPort;
+ rtcpPort = _localPortRTCP;
+ if (ipAddr)
+ {
+ strncpy(ipAddr, _localIP, IpV6Enabled() ?
+ UdpTransport::kIpAddressVersion6Length :
+ UdpTransport::kIpAddressVersion4Length);
+ }
+ if (multicastIpAddr)
+ {
+ strncpy(multicastIpAddr, _localMulticastIP, IpV6Enabled() ?
+ UdpTransport::kIpAddressVersion6Length :
+ UdpTransport::kIpAddressVersion4Length);
+ }
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::SendSocketInformation(
+ char ipAddr[kIpAddressVersion6Length],
+ WebRtc_UWord16& rtpPort,
+ WebRtc_UWord16& rtcpPort) const
+{
+ CriticalSectionScoped cs(_crit);
+ rtpPort = _destPort;
+ rtcpPort = _destPortRTCP;
+ strncpy(ipAddr, _destIP, IpV6Enabled() ?
+ UdpTransport::kIpAddressVersion6Length :
+ UdpTransport::kIpAddressVersion4Length);
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::RemoteSocketInformation(
+ char ipAddr[kIpAddressVersion6Length],
+ WebRtc_UWord16& rtpPort,
+ WebRtc_UWord16& rtcpPort) const
+{
+ CriticalSectionScoped cs(_crit);
+ rtpPort = _fromPort;
+ rtcpPort = _fromPortRTCP;
+ if(ipAddr)
+ {
+ strncpy(ipAddr, _fromIP, IpV6Enabled() ?
+ kIpAddressVersion6Length :
+ kIpAddressVersion4Length);
+ }
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::FilterPorts(
+ WebRtc_UWord16& rtpFilterPort,
+ WebRtc_UWord16& rtcpFilterPort) const
+{
+ CriticalSectionScoped cs(_critFilter);
+ rtpFilterPort = _rtpFilterPort;
+ rtcpFilterPort = _rtcpFilterPort;
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::SetQoS(bool QoS, WebRtc_Word32 serviceType,
+ WebRtc_UWord32 maxBitrate,
+ WebRtc_Word32 overrideDSCP, bool audio)
+{
+ if(QoS)
+ {
+ return EnableQoS(serviceType, audio, maxBitrate, overrideDSCP);
+ }else
+ {
+ return DisableQoS();
+ }
+}
+
+WebRtc_Word32 UdpTransportImpl::EnableQoS(WebRtc_Word32 serviceType,
+ bool audio, WebRtc_UWord32 maxBitrate,
+ WebRtc_Word32 overrideDSCP)
+{
+ if (_ipV6Enabled)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "QOS is enabled but will be ignored since IPv6 is enabled");
+ _lastError = kQosError;
+ return -1;
+ }
+ if (_tos)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "TOS already enabled, can't use TOS and QoS at the same time");
+ _lastError = kQosError;
+ return -1;
+ }
+ if (_pcp)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "PCP already enabled, can't use PCP and QoS at the same time");
+ _lastError = kQosError;
+ return -1;
+ }
+ if(_destPort == 0)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "QOS is enabled but not started since we have not yet configured\
+ the send destination");
+ return -1;
+ }
+ if(_qos)
+ {
+ if(_overrideDSCP == 0 && overrideDSCP != 0)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "QOS is already enabled and overrideDSCP differs, not allowed");
+ return -1;
+ }
+ }
+ CriticalSectionScoped cs(_crit);
+
+ UdpSocketWrapper* rtpSock = _ptrSendRtpSocket ?
+ _ptrSendRtpSocket :
+ _ptrRtpSocket;
+ if (!rtpSock || !rtpSock->ValidHandle())
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "QOS is enabled but not started since we have not yet created the\
+ RTP socket");
+ return -1;
+ }
+ UdpSocketWrapper* rtcpSock = _ptrSendRtcpSocket ?
+ _ptrSendRtcpSocket :
+ _ptrRtcpSocket;
+ if (!rtcpSock || !rtcpSock->ValidHandle())
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "QOS is enabled but not started since we have not yet created the\
+ RTCP socket");
+ return -1;
+ }
+
+ // Minimum packet size in bytes for which the requested quality of service
+ // will be provided. The smallest RTP header is 12 byte.
+ const WebRtc_Word32 min_policed_size = 12;
+ // Max SDU, maximum packet size permitted or used in the traffic flow, in
+ // bytes.
+ const WebRtc_Word32 max_sdu_size = 1500;
+
+ // Enable QoS for RTP sockets.
+ if(maxBitrate)
+ {
+ // Note: 1 kbit is 125 bytes.
+ // Token Rate is typically set to the average bit rate from peak to
+ // peak.
+ // Bucket size is normally set to the largest average frame size.
+ if(audio)
+ {
+ WEBRTC_TRACE(kTraceStateInfo,
+ kTraceTransport,
+ _id,
+ "Enable QOS for audio with max bitrate:%d",
+ maxBitrate);
+
+ const WebRtc_Word32 token_rate = maxBitrate*125;
+ // The largest audio packets are 60ms frames. This is a fraction
+ // more than 16 packets/second. These 16 frames are sent, at max,
+ // at a bitrate of maxBitrate*125 -> 1 frame is maxBitrate*125/16 ~
+ // maxBitrate * 8.
+ const WebRtc_Word32 bucket_size = maxBitrate * 8;
+ const WebRtc_Word32 peek_bandwith = maxBitrate * 125;
+ if (!rtpSock->SetQos(serviceType, token_rate, bucket_size,
+ peek_bandwith, min_policed_size,
+ max_sdu_size, _remoteRTPAddr, overrideDSCP))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "QOS failed on the RTP socket");
+ _lastError = kQosError;
+ return -1;
+ }
+ }else
+ {
+ WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, _id,
+ "Enable QOS for video with max bitrate:%d",
+ maxBitrate);
+
+ // Allow for a token rate that is twice that of the maximum bitrate
+ // (in bytes).
+ const WebRtc_Word32 token_rate = maxBitrate*250;
+ // largest average frame size (key frame size). Assuming that a
+ // keyframe is 25% of the bitrate during the second its sent
+ // Assume that a key frame is 25% of the bitrate the second that it
+ // is sent. The largest frame size is then maxBitrate* 125 * 0.25 ~
+ // 31.
+ const WebRtc_Word32 bucket_size = maxBitrate*31;
+ const WebRtc_Word32 peek_bandwith = maxBitrate*125;
+ if (!rtpSock->SetQos(serviceType, token_rate, bucket_size,
+ peek_bandwith, min_policed_size, max_sdu_size,
+ _remoteRTPAddr, overrideDSCP))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "QOS failed on the RTP socket");
+ _lastError = kQosError;
+ return -1;
+ }
+ }
+ } else if(audio)
+ {
+ // No max bitrate set. Audio.
+ WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, _id,
+ "Enable QOS for audio with default max bitrate");
+
+ // Let max bitrate be 240kbit/s.
+ const WebRtc_Word32 token_rate = 30000;
+ const WebRtc_Word32 bucket_size = 2000;
+ const WebRtc_Word32 peek_bandwith = 30000;
+ if (!rtpSock->SetQos(serviceType, token_rate, bucket_size,
+ peek_bandwith, min_policed_size, max_sdu_size,
+ _remoteRTPAddr, overrideDSCP))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "QOS failed on the RTP socket");
+ _lastError = kQosError;
+ return -1;
+ }
+ }else
+ {
+ // No max bitrate set. Video.
+ WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, _id,
+ "Enable QOS for video with default max bitrate");
+
+ // Let max bitrate be 10mbit/s.
+ const WebRtc_Word32 token_rate = 128000*10;
+ const WebRtc_Word32 bucket_size = 32000;
+ const WebRtc_Word32 peek_bandwith = 256000;
+ if (!rtpSock->SetQos(serviceType, token_rate, bucket_size,
+ peek_bandwith, min_policed_size, max_sdu_size,
+ _remoteRTPAddr, overrideDSCP))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "QOS failed on the RTP socket");
+ _lastError = kQosError;
+ return -1;
+ }
+ }
+
+ // Enable QoS for RTCP sockets.
+ // TODO (hellner): shouldn't RTCP be based on 5% of the maximum bandwidth?
+ if(audio)
+ {
+ const WebRtc_Word32 token_rate = 200;
+ const WebRtc_Word32 bucket_size = 200;
+ const WebRtc_Word32 peek_bandwith = 400;
+ if (!rtcpSock->SetQos(serviceType, token_rate, bucket_size,
+ peek_bandwith, min_policed_size, max_sdu_size,
+ _remoteRTCPAddr, overrideDSCP))
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id,
+ "QOS failed on the RTCP socket");
+ _lastError = kQosError;
+ }
+ }else
+ {
+ const WebRtc_Word32 token_rate = 5000;
+ const WebRtc_Word32 bucket_size = 100;
+ const WebRtc_Word32 peek_bandwith = 10000;
+ if (!rtcpSock->SetQos(serviceType, token_rate, bucket_size,
+ peek_bandwith, min_policed_size, max_sdu_size,
+ _remoteRTCPAddr, _overrideDSCP))
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id,
+ "QOS failed on the RTCP socket");
+ _lastError = kQosError;
+ }
+ }
+ _qos = true;
+ _serviceType = serviceType;
+ _maxBitrate = maxBitrate;
+ _overrideDSCP = overrideDSCP;
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::DisableQoS()
+{
+ if(_qos == false)
+ {
+ return 0;
+ }
+ CriticalSectionScoped cs(_crit);
+
+ UdpSocketWrapper* rtpSock = (_ptrSendRtpSocket ?
+ _ptrSendRtpSocket : _ptrRtpSocket);
+ if (!rtpSock || !rtpSock->ValidHandle())
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "QOS is enabled but not started since we have not yet created the\
+ RTP socket");
+ return -1;
+ }
+ UdpSocketWrapper* rtcpSock = (_ptrSendRtcpSocket ?
+ _ptrSendRtcpSocket : _ptrRtcpSocket);
+ if (!rtcpSock || !rtcpSock->ValidHandle())
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "QOS is enabled but not started since we have not yet created the\
+ RTCP socket");
+ return -1;
+ }
+
+ const WebRtc_Word32 service_type = 0; // = SERVICETYPE_NOTRAFFIC
+ const WebRtc_Word32 not_specified = -1;
+ if (!rtpSock->SetQos(service_type, not_specified, not_specified,
+ not_specified, not_specified, not_specified,
+ _remoteRTPAddr, _overrideDSCP))
+ {
+ _lastError = kQosError;
+ return -1;
+ }
+ if (!rtcpSock->SetQos(service_type, not_specified, not_specified,
+ not_specified, not_specified, not_specified,
+ _remoteRTCPAddr,_overrideDSCP))
+ {
+ _lastError = kQosError;
+ }
+ _qos = false;
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::QoS(bool& QoS, WebRtc_Word32& serviceType,
+ WebRtc_Word32& overrideDSCP) const
+{
+ CriticalSectionScoped cs(_crit);
+ QoS = _qos;
+ serviceType = _serviceType;
+ overrideDSCP = _overrideDSCP;
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::SetToS(WebRtc_Word32 DSCP, bool useSetSockOpt)
+{
+ if (_qos)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "QoS already enabled");
+ _lastError = kQosError;
+ return -1;
+ }
+ if (DSCP < 0 || DSCP > 63)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "Invalid DSCP");
+ _lastError = kTosInvalid;
+ return -1;
+ }
+ if(_tos)
+ {
+ if(useSetSockOpt != _useSetSockOpt)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "Can't switch SetSockOpt method without disabling TOS first");
+ _lastError = kTosInvalid;
+ return -1;
+ }
+ }
+ CriticalSectionScoped cs(_crit);
+ UdpSocketWrapper* rtpSock = NULL;
+ UdpSocketWrapper* rtcpSock = NULL;
+ if(_ptrSendRtpSocket)
+ {
+ rtpSock = _ptrSendRtpSocket;
+ }else
+ {
+ rtpSock = _ptrRtpSocket;
+ }
+ if (rtpSock == NULL)
+ {
+ _lastError = kSocketInvalid;
+ return -1;
+ }
+ if(!rtpSock->ValidHandle())
+ {
+ _lastError = kSocketInvalid;
+ return -1;
+ }
+ if(_ptrSendRtcpSocket)
+ {
+ rtcpSock = _ptrSendRtcpSocket;
+ }else
+ {
+ rtcpSock = _ptrRtcpSocket;
+ }
+ if (rtcpSock == NULL)
+ {
+ _lastError = kSocketInvalid;
+ return -1;
+ }
+ if(!rtcpSock->ValidHandle())
+ {
+ _lastError = kSocketInvalid;
+ return -1;
+ }
+
+ if (useSetSockOpt)
+ {
+#ifdef _WIN32
+ OSVERSIONINFO OsVersion;
+ OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&OsVersion);
+ // Disable QoS before setting ToS on Windows XP. This is done by closing
+ // and re-opening the sockets.
+ // TODO (hellner): why not just fail here and force the user to
+ // re-initialize sockets? Doing this may trick the user
+ // into thinking that the sockets are in a state which
+ // they aren't.
+ if (OsVersion.dwMajorVersion == 5 &&
+ OsVersion.dwMinorVersion == 1)
+ {
+ if(!_useSetSockOpt)
+ {
+ if(_ptrSendRtpSocket)
+ {
+ CloseSendSockets();
+ _ptrSendRtpSocket =
+ _socket_creator->CreateSocket(_id, _mgr, NULL,
+ NULL, IpV6Enabled(),
+ true);
+ _ptrSendRtcpSocket =
+ _socket_creator->CreateSocket(_id, _mgr, NULL,
+ NULL, IpV6Enabled(),
+ true);
+ rtpSock=_ptrSendRtpSocket;
+ rtcpSock=_ptrSendRtcpSocket;
+ ErrorCode retVal = BindRTPSendSocket();
+ if(retVal != kNoSocketError)
+ {
+ _lastError = retVal;
+ return -1;
+ }
+ retVal = BindRTCPSendSocket();
+ if(retVal != kNoSocketError)
+ {
+ _lastError = retVal;
+ return -1;
+ }
+ }
+ else
+ {
+ bool receiving=_receiving;
+ WebRtc_UWord32 noOfReceiveBuffers = 0;
+ if(receiving)
+ {
+ noOfReceiveBuffers=_ptrRtpSocket->ReceiveBuffers();
+ if(StopReceiving()!=0)
+ {
+ return -1;
+ }
+ }
+ CloseReceiveSockets();
+ _ptrRtpSocket = _socket_creator->CreateSocket(
+ _id, _mgr, this, IncomingRTPCallback, IpV6Enabled(),
+ true);
+ _ptrRtcpSocket = _socket_creator->CreateSocket(
+ _id, _mgr, this, IncomingRTCPCallback, IpV6Enabled(),
+ true);
+ rtpSock=_ptrRtpSocket;
+ rtcpSock=_ptrRtcpSocket;
+ ErrorCode retVal = BindLocalRTPSocket();
+ if(retVal != kNoSocketError)
+ {
+ _lastError = retVal;
+ return -1;
+ }
+ retVal = BindLocalRTCPSocket();
+ if(retVal != kNoSocketError)
+ {
+ _lastError = retVal;
+ return -1;
+ }
+ if(receiving)
+ {
+ if(StartReceiving(noOfReceiveBuffers) !=
+ kNoSocketError)
+ {
+ return -1;
+ }
+ }
+ }
+ }
+ }
+#endif // #ifdef _WIN32
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "Setting TOS using SetSockopt");
+ WebRtc_Word32 TOSShifted = DSCP << 2;
+ if (!rtpSock->SetSockopt(IPPROTO_IP, IP_TOS,
+ (WebRtc_Word8*) &TOSShifted, 4))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Could not SetSockopt tos value on RTP socket");
+ _lastError = kTosInvalid;
+ return -1;
+ }
+ if (!rtcpSock->SetSockopt(IPPROTO_IP, IP_TOS,
+ (WebRtc_Word8*) &TOSShifted, 4))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Could not sSetSockopt tos value on RTCP socket");
+ _lastError = kTosInvalid;
+ return -1;
+ }
+ } else
+ {
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "Setting TOS NOT using SetSockopt");
+ if (rtpSock->SetTOS(DSCP) != 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Could not set tos value on RTP socket");
+ _lastError = kTosError;
+ return -1;
+ }
+ if (rtcpSock->SetTOS(DSCP) != 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Could not set tos value on RTCP socket");
+ _lastError = kTosError;
+ return -1;
+ }
+ }
+ _useSetSockOpt = useSetSockOpt;
+ _tos = DSCP;
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::ToS(WebRtc_Word32& DSCP,
+ bool& useSetSockOpt) const
+{
+ CriticalSectionScoped cs(_crit);
+ DSCP = _tos;
+ useSetSockOpt = _useSetSockOpt;
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::SetPCP(WebRtc_Word32 PCP)
+{
+
+ if (_qos)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "QoS already enabled");
+ _lastError = kQosError;
+ return -1;
+ }
+ if ((PCP < 0) || (PCP > 7))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "Invalid PCP");
+ _lastError = kPcpError;
+ return -1;
+ }
+
+ CriticalSectionScoped cs(_crit);
+ UdpSocketWrapper* rtpSock = NULL;
+ UdpSocketWrapper* rtcpSock = NULL;
+ if(_ptrSendRtpSocket)
+ {
+ rtpSock = _ptrSendRtpSocket;
+ }else
+ {
+ rtpSock = _ptrRtpSocket;
+ }
+ if (rtpSock == NULL)
+ {
+ _lastError = kSocketInvalid;
+ return -1;
+ }
+ if(!rtpSock->ValidHandle())
+ {
+ _lastError = kSocketInvalid;
+ return -1;
+ }
+ if(_ptrSendRtcpSocket)
+ {
+ rtcpSock = _ptrSendRtcpSocket;
+ }else
+ {
+ rtcpSock = _ptrRtcpSocket;
+ }
+ if (rtcpSock == NULL)
+ {
+ _lastError = kSocketInvalid;
+ return -1;
+ }
+ if(!rtcpSock->ValidHandle())
+ {
+ _lastError = kSocketInvalid;
+ return -1;
+ }
+
+#if defined(_WIN32)
+ if (rtpSock->SetPCP(PCP) != 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Could not set PCP value on RTP socket");
+ _lastError = kPcpError;
+ return -1;
+ }
+ if (rtcpSock->SetPCP(PCP) != 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Could not set PCP value on RTCP socket");
+ _lastError = kPcpError;
+ return -1;
+ }
+
+#elif defined(WEBRTC_LINUX)
+ if (!rtpSock->SetSockopt(SOL_SOCKET, SO_PRIORITY, (WebRtc_Word8*) &PCP,
+ sizeof(PCP)))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Could not SetSockopt PCP value on RTP socket");
+ _lastError = kPcpError;
+ return -1;
+ }
+ if (!rtcpSock->SetSockopt(SOL_SOCKET, SO_PRIORITY, (WebRtc_Word8*) &PCP,
+ sizeof(PCP)))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Could not SetSockopt PCP value on RTCP socket");
+ _lastError = kPcpError;
+ return -1;
+ }
+#else
+ // Not supported on other platforms (WEBRTC_MAC)
+ _lastError = kPcpError;
+ return -1;
+#endif
+ _pcp = PCP;
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::PCP(WebRtc_Word32& PCP) const
+{
+ CriticalSectionScoped cs(_crit);
+ PCP = _pcp;
+ return 0;
+}
+
+bool UdpTransportImpl::SetSockOptUsed()
+{
+ return _useSetSockOpt;
+}
+
+WebRtc_Word32 UdpTransportImpl::EnableIpV6() {
+
+ CriticalSectionScoped cs(_crit);
+ const bool initialized = (_ptrSendRtpSocket || _ptrRtpSocket);
+
+ if (_ipV6Enabled) {
+ return 0;
+ }
+ if (initialized) {
+ _lastError = kIpVersion6Error;
+ return -1;
+ }
+ _ipV6Enabled = true;
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::FilterIP(
+ char filterIPAddress[kIpAddressVersion6Length]) const
+{
+
+ if(filterIPAddress == NULL)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "FilterIP: Invalid argument");
+ return -1;
+ }
+ if(_filterIPAddress._sockaddr_storage.sin_family == 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "No Filter configured");
+ return -1;
+ }
+ CriticalSectionScoped cs(_critFilter);
+ WebRtc_UWord32 ipSize = kIpAddressVersion6Length;
+ WebRtc_UWord16 sourcePort;
+ return IPAddress(_filterIPAddress, filterIPAddress, ipSize, sourcePort);
+}
+
+WebRtc_Word32 UdpTransportImpl::SetFilterIP(
+ const char filterIPAddress[kIpAddressVersion6Length])
+{
+ if(filterIPAddress == NULL)
+ {
+ memset(&_filterIPAddress, 0, sizeof(_filterIPAddress));
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, "Filter IP reset");
+ return 0;
+ }
+ CriticalSectionScoped cs(_critFilter);
+ if (_ipV6Enabled)
+ {
+ _filterIPAddress._sockaddr_storage.sin_family = AF_INET6;
+
+ if (InetPresentationToNumeric(
+ AF_INET6,
+ filterIPAddress,
+ &_filterIPAddress._sockaddr_in6.sin6_addr) < 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "Failed to set\
+ filter IP for IPv6");
+ _lastError = FILTER_ERROR;
+ return -1;
+ }
+ }
+ else
+ {
+ _filterIPAddress._sockaddr_storage.sin_family = AF_INET;
+
+ if(InetPresentationToNumeric(
+ AF_INET,
+ filterIPAddress,
+ &_filterIPAddress._sockaddr_in.sin_addr) < 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Failed to set filter IP for IPv4");
+ _lastError = FILTER_ERROR;
+ return -1;
+ }
+ }
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, "Filter IP set");
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::SetFilterPorts(WebRtc_UWord16 rtpFilterPort,
+ WebRtc_UWord16 rtcpFilterPort)
+{
+ CriticalSectionScoped cs(_critFilter);
+ _rtpFilterPort = rtpFilterPort;
+ _rtcpFilterPort = rtcpFilterPort;
+ return 0;
+}
+
+bool UdpTransportImpl::SendSocketsInitialized() const
+{
+ CriticalSectionScoped cs(_crit);
+ if(_ptrSendRtpSocket)
+ {
+ return true;
+ }
+ if(_destPort !=0)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool UdpTransportImpl::ReceiveSocketsInitialized() const
+{
+ if(_ptrRtpSocket)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool UdpTransportImpl::SourcePortsInitialized() const
+{
+ if(_ptrSendRtpSocket)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool UdpTransportImpl::IpV6Enabled() const
+{
+ WEBRTC_TRACE(kTraceStream, kTraceTransport, _id, "%s", __FUNCTION__);
+ return _ipV6Enabled;
+}
+
+void UdpTransportImpl::BuildRemoteRTPAddr()
+{
+ if(_ipV6Enabled)
+ {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ _remoteRTPAddr.sin_length = 0;
+ _remoteRTPAddr.sin_family = PF_INET6;
+#else
+ _remoteRTPAddr._sockaddr_storage.sin_family = PF_INET6;
+#endif
+
+ _remoteRTPAddr._sockaddr_in6.sin6_flowinfo=0;
+ _remoteRTPAddr._sockaddr_in6.sin6_scope_id=0;
+ _remoteRTPAddr._sockaddr_in6.sin6_port = Htons(_destPort);
+ InetPresentationToNumeric(AF_INET6,_destIP,
+ &_remoteRTPAddr._sockaddr_in6.sin6_addr);
+ } else
+ {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ _remoteRTPAddr.sin_length = 0;
+ _remoteRTPAddr.sin_family = PF_INET;
+#else
+ _remoteRTPAddr._sockaddr_storage.sin_family = PF_INET;
+#endif
+ _remoteRTPAddr._sockaddr_in.sin_port = Htons(_destPort);
+ _remoteRTPAddr._sockaddr_in.sin_addr = InetAddrIPV4(_destIP);
+ }
+}
+
+void UdpTransportImpl::BuildRemoteRTCPAddr()
+{
+ if(_ipV6Enabled)
+ {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ _remoteRTCPAddr.sin_length = 0;
+ _remoteRTCPAddr.sin_family = PF_INET6;
+#else
+ _remoteRTCPAddr._sockaddr_storage.sin_family = PF_INET6;
+#endif
+
+ _remoteRTCPAddr._sockaddr_in6.sin6_flowinfo=0;
+ _remoteRTCPAddr._sockaddr_in6.sin6_scope_id=0;
+ _remoteRTCPAddr._sockaddr_in6.sin6_port = Htons(_destPortRTCP);
+ InetPresentationToNumeric(AF_INET6,_destIP,
+ &_remoteRTCPAddr._sockaddr_in6.sin6_addr);
+
+ } else
+ {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ _remoteRTCPAddr.sin_length = 0;
+ _remoteRTCPAddr.sin_family = PF_INET;
+#else
+ _remoteRTCPAddr._sockaddr_storage.sin_family = PF_INET;
+#endif
+ _remoteRTCPAddr._sockaddr_in.sin_port = Htons(_destPortRTCP);
+ _remoteRTCPAddr._sockaddr_in.sin_addr= InetAddrIPV4(_destIP);
+ }
+}
+
+UdpTransportImpl::ErrorCode UdpTransportImpl::BindRTPSendSocket()
+{
+ if(!_ptrSendRtpSocket)
+ {
+ return kSocketInvalid;
+ }
+ if(!_ptrSendRtpSocket->ValidHandle())
+ {
+ return kIpAddressInvalid;
+ }
+ if(_ipV6Enabled)
+ {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ _localRTPAddr.sin_length = 0;
+ _localRTPAddr.sin_family = PF_INET6;
+#else
+ _localRTPAddr._sockaddr_storage.sin_family = PF_INET6;
+#endif
+ _localRTPAddr._sockaddr_in6.sin6_flowinfo=0;
+ _localRTPAddr._sockaddr_in6.sin6_scope_id=0;
+ _localRTPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[0] =
+ 0; // = INADDR_ANY
+ _localRTPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[1] =
+ 0;
+ _localRTPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[2] =
+ 0;
+ _localRTPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[3] =
+ 0;
+ _localRTPAddr._sockaddr_in6.sin6_port = Htons(_srcPort);
+ if(_ptrSendRtpSocket->Bind(_localRTPAddr) == false)
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id,
+ "Failed to bind to port:%d ", _srcPort);
+ return kFailedToBindPort;
+ }
+
+ } else {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ _localRTPAddr.sin_length = 0;
+ _localRTPAddr.sin_family = PF_INET;
+#else
+ _localRTPAddr._sockaddr_storage.sin_family = PF_INET;
+#endif
+ _localRTPAddr._sockaddr_in.sin_addr = 0;
+ _localRTPAddr._sockaddr_in.sin_port = Htons(_srcPort);
+ if(_ptrSendRtpSocket->Bind(_localRTPAddr) == false)
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id,
+ "Failed to bind to port:%d ", _srcPort);
+ return kFailedToBindPort;
+ }
+ }
+ return kNoSocketError;
+}
+
+UdpTransportImpl::ErrorCode UdpTransportImpl::BindRTCPSendSocket()
+{
+ if(!_ptrSendRtcpSocket)
+ {
+ return kSocketInvalid;
+ }
+
+ if(_ipV6Enabled)
+ {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ _localRTCPAddr.sin_length = 0;
+ _localRTCPAddr.sin_family = PF_INET6;
+#else
+ _localRTCPAddr._sockaddr_storage.sin_family = PF_INET6;
+#endif
+ _localRTCPAddr._sockaddr_in6.sin6_flowinfo=0;
+ _localRTCPAddr._sockaddr_in6.sin6_scope_id=0;
+ _localRTCPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[0] =
+ 0; // = INADDR_ANY
+ _localRTCPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[1] =
+ 0;
+ _localRTCPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[2] =
+ 0;
+ _localRTCPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[3] =
+ 0;
+ _localRTCPAddr._sockaddr_in6.sin6_port = Htons(_srcPortRTCP);
+ if(_ptrSendRtcpSocket->Bind(_localRTCPAddr) == false)
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id,
+ "Failed to bind to port:%d ", _srcPortRTCP);
+ return kFailedToBindPort;
+ }
+ } else {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ _localRTCPAddr.sin_length = 0;
+ _localRTCPAddr.sin_family = PF_INET;
+#else
+ _localRTCPAddr._sockaddr_storage.sin_family = PF_INET;
+#endif
+ _localRTCPAddr._sockaddr_in.sin_addr= 0;
+ _localRTCPAddr._sockaddr_in.sin_port = Htons(_srcPortRTCP);
+ if(_ptrSendRtcpSocket->Bind(_localRTCPAddr) == false)
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id,
+ "Failed to bind to port:%d ", _srcPortRTCP);
+ return kFailedToBindPort;
+ }
+ }
+ return kNoSocketError;
+}
+
+UdpTransportImpl::ErrorCode UdpTransportImpl::BindLocalRTPSocket()
+{
+ if(!_ptrRtpSocket)
+ {
+ return kSocketInvalid;
+ }
+ if(!IpV6Enabled())
+ {
+ SocketAddress recAddr;
+ memset(&recAddr, 0, sizeof(SocketAddress));
+ recAddr._sockaddr_storage.sin_family = AF_INET;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ recAddr.sin_length = 0;
+ recAddr.sin_family = PF_INET;
+#else
+ recAddr._sockaddr_storage.sin_family = PF_INET;
+#endif
+ recAddr._sockaddr_in.sin_addr = InetAddrIPV4(_localIP);
+ recAddr._sockaddr_in.sin_port = Htons(_localPort);
+
+ if (!_ptrRtpSocket->Bind(recAddr))
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id,
+ "Failed to bind to port:%d ", _localPort);
+ return kFailedToBindPort;
+ }
+ }
+ else
+ {
+ SocketAddress stLclName;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ stLclName.sin_lenght = 0;
+ stLclName.sin_family = PF_INET6;
+#else
+ stLclName._sockaddr_storage.sin_family = PF_INET6;
+#endif
+ InetPresentationToNumeric(AF_INET6,_localIP,
+ &stLclName._sockaddr_in6.sin6_addr);
+ stLclName._sockaddr_in6.sin6_port = Htons(_localPort);
+ stLclName._sockaddr_in6.sin6_flowinfo = 0;
+ stLclName._sockaddr_in6.sin6_scope_id = 0;
+
+ if (!_ptrRtpSocket->Bind(stLclName))
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id,
+ "Failed to bind to port:%d ", _localPort);
+ return kFailedToBindPort;
+ }
+ }
+
+ if(_localMulticastIP[0] != 0)
+ {
+ // Join the multicast group from which to receive datagrams.
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = InetAddrIPV4(_localMulticastIP);
+ mreq.imr_interface.s_addr = INADDR_ANY;
+
+ if (!_ptrRtpSocket->SetSockopt(IPPROTO_IP,IP_ADD_MEMBERSHIP,
+ (WebRtc_Word8*)&mreq,sizeof (mreq)))
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "setsockopt() for multicast failed, not closing socket");
+ }else
+ {
+ WEBRTC_TRACE(kTraceInfo, kTraceTransport, _id,
+ "multicast group successfully joined");
+ }
+ }
+ return kNoSocketError;
+}
+
+UdpTransportImpl::ErrorCode UdpTransportImpl::BindLocalRTCPSocket()
+{
+ if(!_ptrRtcpSocket)
+ {
+ return kSocketInvalid;
+ }
+ if(! IpV6Enabled())
+ {
+ SocketAddress recAddr;
+ memset(&recAddr, 0, sizeof(SocketAddress));
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ recAddr.sin_length = 0;
+ recAddr.sin_family = AF_INET;
+#else
+ recAddr._sockaddr_storage.sin_family = AF_INET;
+#endif
+ recAddr._sockaddr_in.sin_addr = InetAddrIPV4(_localIP);
+ recAddr._sockaddr_in.sin_port = Htons(_localPortRTCP);
+
+ if (!_ptrRtcpSocket->Bind(recAddr))
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id,
+ "Failed to bind to port:%d ", _localPortRTCP);
+ return kFailedToBindPort;
+ }
+ }
+ else
+ {
+ SocketAddress stLclName;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ stLclName.sin_length = 0;
+ stLclName.sin_family = PF_INET6;
+#else
+ stLclName._sockaddr_storage.sin_family = PF_INET6;
+#endif
+ stLclName._sockaddr_in6.sin6_flowinfo = 0;
+ stLclName._sockaddr_in6.sin6_scope_id = 0;
+ stLclName._sockaddr_in6.sin6_port = Htons(_localPortRTCP);
+
+ InetPresentationToNumeric(AF_INET6,_localIP,
+ &stLclName._sockaddr_in6.sin6_addr);
+ if (!_ptrRtcpSocket->Bind(stLclName))
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id,
+ "Failed to bind to port:%d ", _localPortRTCP);
+ return kFailedToBindPort;
+ }
+ }
+ if(_localMulticastIP[0] != 0)
+ {
+ // Join the multicast group from which to receive datagrams.
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr.s_addr = InetAddrIPV4(_localMulticastIP);
+ mreq.imr_interface.s_addr = INADDR_ANY;
+
+ if (!_ptrRtcpSocket->SetSockopt(IPPROTO_IP,IP_ADD_MEMBERSHIP,
+ (WebRtc_Word8*)&mreq,sizeof (mreq)))
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "setsockopt() for multicast failed, not closing socket");
+ }else
+ {
+ WEBRTC_TRACE(kTraceInfo, kTraceTransport, _id,
+ "multicast group successfully joined");
+ }
+ }
+ return kNoSocketError;
+}
+
+WebRtc_Word32 UdpTransportImpl::InitializeSourcePorts(WebRtc_UWord16 rtpPort,
+ WebRtc_UWord16 rtcpPort)
+{
+
+ if(rtpPort == 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "InitializeSourcePorts port 0 not allowed");
+ _lastError = kPortInvalid;
+ return -1;
+ }
+
+ CriticalSectionScoped cs(_crit);
+
+ CloseSendSockets();
+
+ if(_mgr == NULL)
+ {
+ return -1;
+ }
+
+ _srcPort = rtpPort;
+ if(rtcpPort == 0)
+ {
+ _srcPortRTCP = rtpPort+1;
+ } else
+ {
+ _srcPortRTCP = rtcpPort;
+ }
+ _useSetSockOpt =false;
+ _tos=0;
+ _pcp=0;
+
+ _ptrSendRtpSocket = _socket_creator->CreateSocket(_id, _mgr, NULL, NULL,
+ IpV6Enabled(), false);
+ _ptrSendRtcpSocket = _socket_creator->CreateSocket(_id, _mgr, NULL, NULL,
+ IpV6Enabled(), false);
+
+ ErrorCode retVal = BindRTPSendSocket();
+ if(retVal != kNoSocketError)
+ {
+ _lastError = retVal;
+ return -1;
+ }
+ retVal = BindRTCPSendSocket();
+ if(retVal != kNoSocketError)
+ {
+ _lastError = retVal;
+ return -1;
+ }
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::SourcePorts(WebRtc_UWord16& rtpPort,
+ WebRtc_UWord16& rtcpPort) const
+{
+ CriticalSectionScoped cs(_crit);
+
+ rtpPort = (_srcPort != 0) ? _srcPort : _localPort;
+ rtcpPort = (_srcPortRTCP != 0) ? _srcPortRTCP : _localPortRTCP;
+ return 0;
+}
+
+
+#ifdef _WIN32
+WebRtc_Word32 UdpTransportImpl::StartReceiving(
+ WebRtc_UWord32 numberOfSocketBuffers)
+#else
+WebRtc_Word32 UdpTransportImpl::StartReceiving(
+ WebRtc_UWord32 /*numberOfSocketBuffers*/)
+#endif
+{
+ CriticalSectionScoped cs(_crit);
+ if(_receiving)
+ {
+ return 0;
+ }
+ if(_ptrRtpSocket)
+ {
+#ifdef _WIN32
+ if(!_ptrRtpSocket->StartReceiving(numberOfSocketBuffers))
+#else
+ if(!_ptrRtpSocket->StartReceiving())
+#endif
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Failed to start receive on RTP socket");
+ _lastError = kStartReceiveError;
+ return -1;
+ }
+ }
+ if(_ptrRtcpSocket)
+ {
+ if(!_ptrRtcpSocket->StartReceiving())
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Failed to start receive on RTCP socket");
+ _lastError = kStartReceiveError;
+ return -1;
+ }
+ }
+ if( _ptrRtpSocket == NULL &&
+ _ptrRtcpSocket == NULL)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Failed to StartReceiving, no socket initialized");
+ _lastError = kStartReceiveError;
+ return -1;
+ }
+ _receiving = true;
+ return 0;
+}
+
+bool UdpTransportImpl::Receiving() const
+{
+ return _receiving;
+}
+
+WebRtc_Word32 UdpTransportImpl::StopReceiving()
+{
+
+ CriticalSectionScoped cs(_crit);
+
+ _receiving = false;
+
+ if (_ptrRtpSocket)
+ {
+ if (!_ptrRtpSocket->StopReceiving())
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Failed to stop receiving on RTP socket");
+ _lastError = kStopReceiveError;
+ return -1;
+ }
+ }
+ if (_ptrRtcpSocket)
+ {
+ if (!_ptrRtcpSocket->StopReceiving())
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "Failed to stop receiving on RTCP socket");
+ _lastError = kStopReceiveError;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::InitializeSendSockets(
+ const char* ipaddr,
+ const WebRtc_UWord16 rtpPort,
+ const WebRtc_UWord16 rtcpPort)
+{
+ {
+ CriticalSectionScoped cs(_crit);
+ _destPort = rtpPort;
+ if(rtcpPort == 0)
+ {
+ _destPortRTCP = _destPort+1;
+ } else
+ {
+ _destPortRTCP = rtcpPort;
+ }
+
+ if(ipaddr == NULL)
+ {
+ if (!IsIpAddressValid(_destIP, IpV6Enabled()))
+ {
+ _destPort = 0;
+ _destPortRTCP = 0;
+ _lastError = kIpAddressInvalid;
+ return -1;
+ }
+ } else
+ {
+ if (IsIpAddressValid(ipaddr, IpV6Enabled()))
+ {
+ strncpy(
+ _destIP,
+ ipaddr,
+ IpV6Enabled() ? kIpAddressVersion6Length :
+ kIpAddressVersion4Length);
+ } else {
+ _destPort = 0;
+ _destPortRTCP = 0;
+ _lastError = kIpAddressInvalid;
+ return -1;
+ }
+ }
+ BuildRemoteRTPAddr();
+ BuildRemoteRTCPAddr();
+ }
+
+ if (_ipV6Enabled)
+ {
+ if (_qos)
+ {
+ WEBRTC_TRACE(
+ kTraceWarning,
+ kTraceTransport,
+ _id,
+ "QOS is enabled but will be ignored since IPv6 is enabled");
+ }
+ }else
+ {
+ // TODO (grunell): Multicast support is experimantal.
+
+ // Put the first digit of the remote address in val.
+ WebRtc_Word32 val = ntohl(_remoteRTPAddr._sockaddr_in.sin_addr)>> 24;
+
+ if((val > 223) && (val < 240))
+ {
+ // Multicast address.
+ CriticalSectionScoped cs(_crit);
+
+ UdpSocketWrapper* rtpSock = (_ptrSendRtpSocket ?
+ _ptrSendRtpSocket : _ptrRtpSocket);
+ if (!rtpSock || !rtpSock->ValidHandle())
+ {
+ _lastError = kSocketInvalid;
+ return -1;
+ }
+ UdpSocketWrapper* rtcpSock = (_ptrSendRtcpSocket ?
+ _ptrSendRtcpSocket : _ptrRtcpSocket);
+ if (!rtcpSock || !rtcpSock->ValidHandle())
+ {
+ _lastError = kSocketInvalid;
+ return -1;
+ }
+
+ // Set Time To Live to same region
+ WebRtc_Word32 iOptVal = 64;
+ if (!rtpSock->SetSockopt(IPPROTO_IP, IP_MULTICAST_TTL,
+ (WebRtc_Word8*)&iOptVal,
+ sizeof (WebRtc_Word32)))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "setsockopt for multicast error on RTP socket");
+ _ptrRtpSocket->CloseBlocking();
+ _ptrRtpSocket = NULL;
+ _lastError = kMulticastAddressInvalid;
+ return -1;
+ }
+ if (!rtcpSock->SetSockopt(IPPROTO_IP, IP_MULTICAST_TTL,
+ (WebRtc_Word8*)&iOptVal,
+ sizeof (WebRtc_Word32)))
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "setsockopt for multicast error on RTCP socket");
+ _ptrRtpSocket->CloseBlocking();
+ _ptrRtpSocket = NULL;
+ _lastError = kMulticastAddressInvalid;
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+void UdpTransportImpl::BuildSockaddrIn(WebRtc_UWord16 portnr,
+ const char* ip,
+ SocketAddress& remoteAddr) const
+{
+ if(_ipV6Enabled)
+ {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ remoteAddr.sin_length = 0;
+ remoteAddr.sin_family = PF_INET6;
+#else
+ remoteAddr._sockaddr_storage.sin_family = PF_INET6;
+#endif
+ remoteAddr._sockaddr_in6.sin6_port = Htons(portnr);
+ InetPresentationToNumeric(AF_INET6, ip,
+ &remoteAddr._sockaddr_in6.sin6_addr);
+ remoteAddr._sockaddr_in6.sin6_flowinfo=0;
+ remoteAddr._sockaddr_in6.sin6_scope_id=0;
+ } else
+ {
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ remoteAddr.sin_length = 0;
+ remoteAddr.sin_family = PF_INET;
+#else
+ remoteAddr._sockaddr_storage.sin_family = PF_INET;
+#endif
+ remoteAddr._sockaddr_in.sin_port = Htons(portnr);
+ remoteAddr._sockaddr_in.sin_addr= InetAddrIPV4(
+ const_cast<char*>(ip));
+ }
+}
+
+WebRtc_Word32 UdpTransportImpl::SendRaw(const WebRtc_Word8 *data,
+ WebRtc_UWord32 length,
+ WebRtc_Word32 isRTCP,
+ WebRtc_UWord16 portnr,
+ const char* ip)
+{
+ CriticalSectionScoped cs(_crit);
+ if(isRTCP)
+ {
+ UdpSocketWrapper* rtcpSock = NULL;
+ if(_ptrSendRtcpSocket)
+ {
+ rtcpSock = _ptrSendRtcpSocket;
+ } else if(_ptrRtcpSocket)
+ {
+ rtcpSock = _ptrRtcpSocket;
+ } else
+ {
+ return -1;
+ }
+ if(portnr == 0 && ip == NULL)
+ {
+ return rtcpSock->SendTo(data,length,_remoteRTCPAddr);
+
+ } else if(portnr != 0 && ip != NULL)
+ {
+ SocketAddress remoteAddr;
+ BuildSockaddrIn(portnr, ip, remoteAddr);
+ return rtcpSock->SendTo(data,length,remoteAddr);
+ } else if(ip != NULL)
+ {
+ SocketAddress remoteAddr;
+ BuildSockaddrIn(_destPortRTCP, ip, remoteAddr);
+ return rtcpSock->SendTo(data,length,remoteAddr);
+ } else
+ {
+ SocketAddress remoteAddr;
+ BuildSockaddrIn(portnr, _destIP, remoteAddr);
+ return rtcpSock->SendTo(data,length,remoteAddr);
+ }
+ } else {
+ UdpSocketWrapper* rtpSock = NULL;
+ if(_ptrSendRtpSocket)
+ {
+ rtpSock = _ptrSendRtpSocket;
+
+ } else if(_ptrRtpSocket)
+ {
+ rtpSock = _ptrRtpSocket;
+ } else
+ {
+ return -1;
+ }
+ if(portnr == 0 && ip == NULL)
+ {
+ return rtpSock->SendTo(data,length,_remoteRTPAddr);
+
+ } else if(portnr != 0 && ip != NULL)
+ {
+ SocketAddress remoteAddr;
+ BuildSockaddrIn(portnr, ip, remoteAddr);
+ return rtpSock->SendTo(data,length,remoteAddr);
+ } else if(ip != NULL)
+ {
+ SocketAddress remoteAddr;
+ BuildSockaddrIn(_destPort, ip, remoteAddr);
+ return rtpSock->SendTo(data,length,remoteAddr);
+ } else
+ {
+ SocketAddress remoteAddr;
+ BuildSockaddrIn(portnr, _destIP, remoteAddr);
+ return rtpSock->SendTo(data,length,remoteAddr);
+ }
+ }
+}
+
+WebRtc_Word32 UdpTransportImpl::SendRTPPacketTo(const WebRtc_Word8* data,
+ WebRtc_UWord32 length,
+ const SocketAddress& to)
+{
+ CriticalSectionScoped cs(_crit);
+ if(_ptrSendRtpSocket)
+ {
+ return _ptrSendRtpSocket->SendTo(data,length,to);
+
+ } else if(_ptrRtpSocket)
+ {
+ return _ptrRtpSocket->SendTo(data,length,to);
+ }
+ return -1;
+}
+
+WebRtc_Word32 UdpTransportImpl::SendRTCPPacketTo(const WebRtc_Word8* data,
+ WebRtc_UWord32 length,
+ const SocketAddress& to)
+{
+
+ CriticalSectionScoped cs(_crit);
+
+ if(_ptrSendRtcpSocket)
+ {
+ return _ptrSendRtcpSocket->SendTo(data,length,to);
+
+ } else if(_ptrRtcpSocket)
+ {
+ return _ptrRtcpSocket->SendTo(data,length,to);
+ }
+ return -1;
+}
+
+WebRtc_Word32 UdpTransportImpl::SendRTPPacketTo(const WebRtc_Word8* data,
+ WebRtc_UWord32 length,
+ const WebRtc_UWord16 rtpPort)
+{
+ CriticalSectionScoped cs(_crit);
+ // Use the current SocketAdress but update it with rtpPort.
+ SocketAddress to;
+ memcpy(&to, &_remoteRTPAddr, sizeof(SocketAddress));
+
+ if(_ipV6Enabled)
+ {
+ to._sockaddr_in6.sin6_port = Htons(rtpPort);
+ } else
+ {
+ to._sockaddr_in.sin_port = Htons(rtpPort);
+ }
+
+ if(_ptrSendRtpSocket)
+ {
+ return _ptrSendRtpSocket->SendTo(data,length,to);
+
+ } else if(_ptrRtpSocket)
+ {
+ return _ptrRtpSocket->SendTo(data,length,to);
+ }
+ return -1;
+}
+
+WebRtc_Word32 UdpTransportImpl::SendRTCPPacketTo(const WebRtc_Word8* data,
+ WebRtc_UWord32 length,
+ const WebRtc_UWord16 rtcpPort)
+{
+ CriticalSectionScoped cs(_crit);
+
+ // Use the current SocketAdress but update it with rtcpPort.
+ SocketAddress to;
+ memcpy(&to, &_remoteRTCPAddr, sizeof(SocketAddress));
+
+ if(_ipV6Enabled)
+ {
+ to._sockaddr_in6.sin6_port = Htons(rtcpPort);
+ } else
+ {
+ to._sockaddr_in.sin_port = Htons(rtcpPort);
+ }
+
+ if(_ptrSendRtcpSocket)
+ {
+ return _ptrSendRtcpSocket->SendTo(data,length,to);
+
+ } else if(_ptrRtcpSocket)
+ {
+ return _ptrRtcpSocket->SendTo(data,length,to);
+ }
+ return -1;
+}
+
+int UdpTransportImpl::SendPacket(int /*channel*/, const void* data, int length)
+{
+ WEBRTC_TRACE(kTraceStream, kTraceTransport, _id, "%s", __FUNCTION__);
+
+ CriticalSectionScoped cs(_crit);
+
+ if(_destIP[0] == 0)
+ {
+ return -1;
+ }
+ if(_destPort == 0)
+ {
+ return -1;
+ }
+
+ // Create socket if it hasn't been set up already.
+ // TODO (hellner): why not fail here instead. Sockets not being initialized
+ // indicates that there is a problem somewhere.
+ if( _ptrSendRtpSocket == NULL &&
+ _ptrRtpSocket == NULL)
+ {
+ WEBRTC_TRACE(
+ kTraceStateInfo,
+ kTraceTransport,
+ _id,
+ "Creating RTP socket since no receive or source socket is\
+ configured");
+
+ _ptrRtpSocket = _socket_creator->CreateSocket(_id, _mgr, this,
+ IncomingRTPCallback,
+ IpV6Enabled(), false);
+
+ // Don't bind to a specific IP address.
+ if(! IpV6Enabled())
+ {
+ strncpy(_localIP, "0.0.0.0",16);
+ } else
+ {
+ strncpy(_localIP, "0000:0000:0000:0000:0000:0000:0000:0000",
+ kIpAddressVersion6Length);
+ }
+ _localPort = _destPort;
+
+ ErrorCode retVal = BindLocalRTPSocket();
+ if(retVal != kNoSocketError)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "SendPacket() failed to bind RTP socket");
+ _lastError = retVal;
+ CloseReceiveSockets();
+ return -1;
+ }
+ }
+
+ if(_ptrSendRtpSocket)
+ {
+ return _ptrSendRtpSocket->SendTo((const WebRtc_Word8*)data, length,
+ _remoteRTPAddr);
+
+ } else if(_ptrRtpSocket)
+ {
+ return _ptrRtpSocket->SendTo((const WebRtc_Word8*)data, length,
+ _remoteRTPAddr);
+ }
+ return -1;
+}
+
+int UdpTransportImpl::SendRTCPPacket(int /*channel*/, const void* data,
+ int length)
+{
+
+ CriticalSectionScoped cs(_crit);
+ if(_destIP[0] == 0)
+ {
+ return -1;
+ }
+ if(_destPortRTCP == 0)
+ {
+ return -1;
+ }
+
+ // Create socket if it hasn't been set up already.
+ // TODO (hellner): why not fail here instead. Sockets not being initialized
+ // indicates that there is a problem somewhere.
+ if( _ptrSendRtcpSocket == NULL &&
+ _ptrRtcpSocket == NULL)
+ {
+ WEBRTC_TRACE(
+ kTraceStateInfo,
+ kTraceTransport,
+ _id,
+ "Creating RTCP socket since no receive or source socket is\
+ configured");
+
+ _ptrRtcpSocket = _socket_creator->CreateSocket(_id, _mgr, this,
+ IncomingRTCPCallback,
+ IpV6Enabled(), false);
+
+ // Don't bind to a specific IP address.
+ if(! IpV6Enabled())
+ {
+ strncpy(_localIP, "0.0.0.0",16);
+ } else
+ {
+ strncpy(_localIP, "0000:0000:0000:0000:0000:0000:0000:0000",
+ kIpAddressVersion6Length);
+ }
+ _localPortRTCP = _destPortRTCP;
+
+ ErrorCode retVal = BindLocalRTCPSocket();
+ if(retVal != kNoSocketError)
+ {
+ _lastError = retVal;
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "SendRTCPPacket() failed to bind RTCP socket");
+ CloseReceiveSockets();
+ return -1;
+ }
+ }
+
+ if(_ptrSendRtcpSocket)
+ {
+ return _ptrSendRtcpSocket->SendTo((const WebRtc_Word8*)data, length,
+ _remoteRTCPAddr);
+ } else if(_ptrRtcpSocket)
+ {
+ return _ptrRtcpSocket->SendTo((const WebRtc_Word8*)data, length,
+ _remoteRTCPAddr);
+ }
+ return -1;
+}
+
+WebRtc_Word32 UdpTransportImpl::SetSendIP(const char* ipaddr)
+{
+ if(!IsIpAddressValid(ipaddr,IpV6Enabled()))
+ {
+ return kIpAddressInvalid;
+ }
+ CriticalSectionScoped cs(_crit);
+ strncpy(_destIP, ipaddr,kIpAddressVersion6Length);
+ BuildRemoteRTPAddr();
+ BuildRemoteRTCPAddr();
+ return 0;
+}
+
+WebRtc_Word32 UdpTransportImpl::SetSendPorts(WebRtc_UWord16 rtpPort,
+ WebRtc_UWord16 rtcpPort)
+{
+ CriticalSectionScoped cs(_crit);
+ _destPort = rtpPort;
+ if(rtcpPort == 0)
+ {
+ _destPortRTCP = _destPort+1;
+ } else
+ {
+ _destPortRTCP = rtcpPort;
+ }
+ BuildRemoteRTPAddr();
+ BuildRemoteRTCPAddr();
+ return 0;
+}
+
+void UdpTransportImpl::IncomingRTPCallback(CallbackObj obj,
+ const WebRtc_Word8* rtpPacket,
+ WebRtc_Word32 rtpPacketLength,
+ const SocketAddress* from)
+{
+ if (rtpPacket && rtpPacketLength > 0)
+ {
+ UdpTransportImpl* socketTransport = (UdpTransportImpl*) obj;
+ socketTransport->IncomingRTPFunction(rtpPacket, rtpPacketLength, from);
+ }
+}
+
+void UdpTransportImpl::IncomingRTCPCallback(CallbackObj obj,
+ const WebRtc_Word8* rtcpPacket,
+ WebRtc_Word32 rtcpPacketLength,
+ const SocketAddress* from)
+{
+ if (rtcpPacket && rtcpPacketLength > 0)
+ {
+ UdpTransportImpl* socketTransport = (UdpTransportImpl*) obj;
+ socketTransport->IncomingRTCPFunction(rtcpPacket, rtcpPacketLength,
+ from);
+ }
+}
+
+void UdpTransportImpl::IncomingRTPFunction(const WebRtc_Word8* rtpPacket,
+ WebRtc_Word32 rtpPacketLength,
+ const SocketAddress* fromSocket)
+{
+ char ipAddress[kIpAddressVersion6Length];
+ WebRtc_UWord32 ipAddressLength = kIpAddressVersion6Length;
+ WebRtc_UWord16 portNr = 0;
+
+ {
+ CriticalSectionScoped cs(_critFilter);
+ if (FilterIPAddress(fromSocket) == false)
+ {
+ // Packet should be filtered out. Drop it.
+ WEBRTC_TRACE(kTraceStream, kTraceTransport, _id,
+ "Incoming RTP packet blocked by IP filter");
+ return;
+ }
+
+ if (IPAddressCached(*fromSocket, ipAddress, ipAddressLength, portNr) <
+ 0)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpTransportImpl::IncomingRTPFunction - Cannot get sender\
+ information");
+ }else
+ {
+ // Make sure ipAddress is null terminated.
+ ipAddress[kIpAddressVersion6Length - 1] = 0;
+ strncpy(_fromIP, ipAddress, kIpAddressVersion6Length - 1);
+ }
+
+ // Filter based on port.
+ if (_rtpFilterPort != 0 &&
+ _rtpFilterPort != portNr)
+ {
+ // Drop packet.
+ memset(_fromIP, 0, sizeof(_fromIP));
+ WEBRTC_TRACE(
+ kTraceStream,
+ kTraceTransport,
+ _id,
+ "Incoming RTP packet blocked by filter incoming from port:%d\
+ allowed port:%d",
+ portNr,
+ _rtpFilterPort);
+ return;
+ }
+ _fromPort = portNr;
+ }
+
+ CriticalSectionScoped cs(_critPacketCallback);
+ if (_packetCallback)
+ {
+ WEBRTC_TRACE(kTraceStream, kTraceTransport, _id,
+ "Incoming RTP packet from ip:%s port:%d", ipAddress, portNr);
+ _packetCallback->IncomingRTPPacket(rtpPacket, rtpPacketLength,
+ ipAddress, portNr);
+ }
+}
+
+void UdpTransportImpl::IncomingRTCPFunction(const WebRtc_Word8* rtcpPacket,
+ WebRtc_Word32 rtcpPacketLength,
+ const SocketAddress* fromSocket)
+{
+ char ipAddress[kIpAddressVersion6Length];
+ WebRtc_UWord32 ipAddressLength = kIpAddressVersion6Length;
+ WebRtc_UWord16 portNr = 0;
+
+ {
+ CriticalSectionScoped cs(_critFilter);
+ if (FilterIPAddress(fromSocket) == false)
+ {
+ // Packet should be filtered out. Drop it.
+ WEBRTC_TRACE(kTraceStream, kTraceTransport, _id,
+ "Incoming RTCP packet blocked by IP filter");
+ return;
+ }
+ if (IPAddress(*fromSocket, ipAddress, ipAddressLength, portNr) < 0)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpTransportImpl::IncomingRTCPFunction - Cannot get sender\
+ information");
+ }else {
+ // Make sure ipAddress is null terminated.
+ ipAddress[kIpAddressVersion6Length - 1] = 0;
+ strncpy(_fromIP, ipAddress, kIpAddressVersion6Length - 1);
+ }
+
+ // Filter based on port.
+ if (_rtcpFilterPort != 0 &&
+ _rtcpFilterPort != portNr)
+ {
+ // Drop packet.
+ WEBRTC_TRACE(
+ kTraceStream,
+ kTraceTransport,
+ _id,
+ "Incoming RTCP packet blocked by filter incoming from port:%d\
+ allowed port:%d",
+ portNr,
+ _rtpFilterPort);
+ return;
+ }
+ _fromPortRTCP = portNr;
+ }
+
+ CriticalSectionScoped cs(_critPacketCallback);
+ if (_packetCallback)
+ {
+ WEBRTC_TRACE(kTraceStream, kTraceTransport, _id,
+ "Incoming RTCP packet from ip:%s port:%d", ipAddress,
+ portNr);
+ _packetCallback->IncomingRTCPPacket(rtcpPacket, rtcpPacketLength,
+ ipAddress, portNr);
+ }
+}
+
+bool UdpTransportImpl::FilterIPAddress(const SocketAddress* fromAddress)
+{
+ if(fromAddress->_sockaddr_storage.sin_family == AF_INET)
+ {
+ if (_filterIPAddress._sockaddr_storage.sin_family == AF_INET)
+ {
+ // IP is stored in sin_addr.
+ if (_filterIPAddress._sockaddr_in.sin_addr != 0 &&
+ (_filterIPAddress._sockaddr_in.sin_addr !=
+ fromAddress->_sockaddr_in.sin_addr))
+ {
+ return false;
+ }
+ }
+ }
+ else if(fromAddress->_sockaddr_storage.sin_family == AF_INET6)
+ {
+ if (_filterIPAddress._sockaddr_storage.sin_family == AF_INET6)
+ {
+ // IP is stored in sin_6addr.
+ for (WebRtc_Word32 i = 0; i < 4; i++)
+ {
+ if (_filterIPAddress._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[i] != 0 &&
+ _filterIPAddress._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[i] != fromAddress->_sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[i])
+ {
+ return false;
+ }
+ }
+ }
+ }
+ else
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpTransportImpl::FilterIPAddress() unknown address family");
+ return false;
+ }
+ return true;
+}
+
+void UdpTransportImpl::CloseReceiveSockets()
+{
+ if(_ptrRtpSocket)
+ {
+ _ptrRtpSocket->CloseBlocking();
+ _ptrRtpSocket = NULL;
+ }
+ if(_ptrRtcpSocket)
+ {
+ _ptrRtcpSocket->CloseBlocking();
+ _ptrRtcpSocket = NULL;
+ }
+ _receiving = false;
+}
+
+void UdpTransportImpl::CloseSendSockets()
+{
+ if(_ptrSendRtpSocket)
+ {
+ _ptrSendRtpSocket->CloseBlocking();
+ _ptrSendRtpSocket = 0;
+ }
+ if(_ptrSendRtcpSocket)
+ {
+ _ptrSendRtcpSocket->CloseBlocking();
+ _ptrSendRtcpSocket = 0;
+ }
+}
+
+WebRtc_UWord16 UdpTransport::Htons(const WebRtc_UWord16 port)
+{
+ return htons(port);
+}
+
+WebRtc_UWord32 UdpTransport::Htonl(const WebRtc_UWord32 a)
+{
+ return htonl(a);
+}
+
+WebRtc_UWord32 UdpTransport::InetAddrIPV4(const char* ip)
+{
+ return ::inet_addr(ip);
+}
+
+WebRtc_Word32 UdpTransport::InetPresentationToNumeric(WebRtc_Word32 af,
+ const char* src,
+ void* dst)
+{
+#if defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
+ const WebRtc_Word32 result = inet_pton(af, src, dst);
+ return result > 0 ? 0 : -1;
+
+#elif defined(_WIN32)
+ SocketAddress temp;
+ int length=sizeof(SocketAddress);
+
+ if(af == AF_INET)
+ {
+ WebRtc_Word32 result = WSAStringToAddressA(
+ (const LPSTR)src,
+ af,
+ 0,
+ reinterpret_cast<struct sockaddr*>(&temp),
+ &length);
+ if(result != 0)
+ {
+ return -1;
+ }
+ memcpy(dst,&(temp._sockaddr_in.sin_addr),
+ sizeof(temp._sockaddr_in.sin_addr));
+ return 0;
+ }
+ else if(af == AF_INET6)
+ {
+ WebRtc_Word32 result = WSAStringToAddressA(
+ (const LPSTR)src,
+ af,
+ 0,
+ reinterpret_cast<struct sockaddr*>(&temp),
+ &length);
+ if(result !=0)
+ {
+ return -1;
+ }
+ memcpy(dst,&(temp._sockaddr_in6.sin6_addr),
+ sizeof(temp._sockaddr_in6.sin6_addr));
+ return 0;
+
+ }else
+ {
+ return -1;
+ }
+#else
+ return -1;
+#endif
+}
+
+WebRtc_Word32 UdpTransport::LocalHostAddressIPV6(char n_localIP[16])
+{
+
+#if defined(_WIN32)
+ struct addrinfo *result = NULL;
+ struct addrinfo *ptr = NULL;
+ struct addrinfo hints;
+
+ ZeroMemory(&hints, sizeof(hints));
+ hints.ai_family = AF_INET6;
+
+ char szHostName[256] = "";
+ if(::gethostname(szHostName, sizeof(szHostName) - 1))
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1, "gethostname failed");
+ return -1;
+ }
+
+ DWORD dwRetval = getaddrinfo(szHostName, NULL, &hints, &result);
+ if ( dwRetval != 0 )
+ {
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1,
+ "getaddrinfo failed, error:%d", dwRetval);
+ return -1;
+ }
+ for(ptr=result; ptr != NULL ;ptr=ptr->ai_next)
+ {
+ switch (ptr->ai_family)
+ {
+ case AF_INET6:
+ {
+ for(int i = 0; i< 16; i++)
+ {
+ n_localIP[i] = (*(SocketAddress*)ptr->ai_addr).
+ _sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u8[i];
+ }
+ bool islocalIP = true;
+
+ for(int n = 0; n< 15; n++)
+ {
+ if(n_localIP[n] != 0)
+ {
+ islocalIP = false;
+ break;
+ }
+ }
+
+ if(islocalIP && n_localIP[15] != 1)
+ {
+ islocalIP = false;
+ }
+
+ if(islocalIP && ptr->ai_next)
+ {
+ continue;
+ }
+ if(n_localIP[0] == 0xfe &&
+ n_localIP[1] == 0x80 && ptr->ai_next)
+ {
+ continue;
+ }
+ freeaddrinfo(result);
+ }
+ return 0;
+ default:
+ break;
+ };
+ }
+ freeaddrinfo(result);
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1,
+ "getaddrinfo failed to find address");
+ return -1;
+
+#elif defined(WEBRTC_MAC)
+ struct ifaddrs* ptrIfAddrs = NULL;
+ struct ifaddrs* ptrIfAddrsStart = NULL;
+
+ getifaddrs(&ptrIfAddrsStart);
+ ptrIfAddrs = ptrIfAddrsStart;
+ while(ptrIfAddrs)
+ {
+ if(ptrIfAddrs->ifa_addr->sa_family == AF_INET6)
+ {
+ const struct sockaddr_in6* sock_in6 =
+ reinterpret_cast<struct sockaddr_in6*>(ptrIfAddrs->ifa_addr);
+ const struct in6_addr* sin6_addr = &sock_in6->sin6_addr;
+
+ if (IN6_IS_ADDR_LOOPBACK(sin6_addr) ||
+ IN6_IS_ADDR_LINKLOCAL(sin6_addr)) {
+ ptrIfAddrs = ptrIfAddrs->ifa_next;
+ continue;
+ }
+ memcpy(n_localIP, sin6_addr->s6_addr, sizeof(sin6_addr->s6_addr));
+ freeifaddrs(ptrIfAddrsStart);
+ return 0;
+ }
+ ptrIfAddrs = ptrIfAddrs->ifa_next;
+ }
+ freeifaddrs(ptrIfAddrsStart);
+ return -1;
+#elif defined(WEBRTC_ANDROID)
+ return -1;
+#else // WEBRTC_LINUX
+ struct
+ {
+ struct nlmsghdr n;
+ struct ifaddrmsg r;
+ } req;
+
+ struct rtattr* rta = NULL;
+ int status;
+ char buf[16384]; // = 16 * 1024 (16 kB)
+ struct nlmsghdr* nlmp;
+ struct ifaddrmsg* rtmp;
+ struct rtattr* rtatp;
+ int rtattrlen;
+ struct in6_addr* in6p;
+
+ int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (fd == -1)
+ {
+ return -1;
+ }
+
+ // RTM_GETADDR is used to fetch the ip address from the kernel interface
+ // table. Populate the msg structure (req) the size of the message buffer
+ // is specified to netlinkmessage header, and flags values are set as
+ // NLM_F_ROOT | NLM_F_REQUEST.
+ // The request flag must be set for all messages requesting the data from
+ // kernel. The root flag is used to notify the kernel to return the full
+ // tabel. Another flag (not used) is NLM_F_MATCH. This is used to get only
+ // specified entries in the table. At the time of writing this program this
+ // flag is not implemented in kernel
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
+ req.n.nlmsg_type = RTM_GETADDR;
+ req.r.ifa_family = AF_INET6;
+
+ // Fill up all the attributes for the rtnetlink header.
+ // The lenght is very important. 16 signifies the ipv6 address.
+ rta = (struct rtattr*)(((char*)&req) + NLMSG_ALIGN(req.n.nlmsg_len));
+ rta->rta_len = RTA_LENGTH(16);
+
+ status = send(fd, &req, req.n.nlmsg_len, 0);
+ if (status < 0)
+ {
+ close(fd);
+ return -1;
+ }
+ status = recv(fd, buf, sizeof(buf), 0);
+ if (status < 0)
+ {
+ close(fd);
+ return -1;
+ }
+ if(status == 0)
+ {
+ close(fd);
+ return -1;
+ }
+ close(fd);
+
+ // The message is stored in buff. Parse the message to get the requested
+ // data.
+ {
+ nlmp = (struct nlmsghdr*)buf;
+ int len = nlmp->nlmsg_len;
+ int req_len = len - sizeof(*nlmp);
+
+ if (req_len < 0 || len > status)
+ {
+ return -1;
+ }
+ if (!NLMSG_OK_NO_WARNING(nlmp, status))
+ {
+ return -1;
+ }
+ rtmp = (struct ifaddrmsg*)NLMSG_DATA(nlmp);
+ rtatp = (struct rtattr*)IFA_RTA(rtmp);
+
+ rtattrlen = IFA_PAYLOAD(nlmp);
+
+ for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen))
+ {
+
+ // Here we hit the fist chunk of the message. Time to validate the
+ // type. For more info on the different types see
+ // "man(7) rtnetlink" The table below is taken from man pages.
+ // Attributes
+ // rta_type value type description
+ // -------------------------------------------------------------
+ // IFA_UNSPEC - unspecified.
+ // IFA_ADDRESS raw protocol address interface address
+ // IFA_LOCAL raw protocol address local address
+ // IFA_LABEL asciiz string name of the interface
+ // IFA_BROADCAST raw protocol address broadcast address.
+ // IFA_ANYCAST raw protocol address anycast address
+ // IFA_CACHEINFO struct ifa_cacheinfo Address information.
+
+ if(rtatp->rta_type == IFA_ADDRESS)
+ {
+ bool islocalIP = true;
+ in6p = (struct in6_addr*)RTA_DATA(rtatp);
+ for(int n = 0; n< 15; n++)
+ {
+ if(in6p->s6_addr[n] != 0)
+ {
+ islocalIP = false;
+ break;
+ }
+ }
+ if(islocalIP && in6p->s6_addr[15] != 1)
+ {
+ islocalIP = false;
+ }
+ if(!islocalIP)
+ {
+ for(int i = 0; i< 16; i++)
+ {
+ n_localIP[i] = in6p->s6_addr[i];
+ }
+ if(n_localIP[0] == static_cast<char> (0xfe)
+ && n_localIP[1] == static_cast<char>(0x80) )
+ {
+ // Auto configured IP.
+ continue;
+ }
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+#endif
+}
+
+WebRtc_Word32 UdpTransport::LocalHostAddress(WebRtc_UWord32& localIP)
+{
+ #if defined(_WIN32)
+ hostent* localHost;
+ localHost = gethostbyname( "" );
+ if(localHost)
+ {
+ if(localHost->h_addrtype != AF_INET)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ -1,
+ "LocalHostAddress can only get local IP for IP Version 4");
+ return -1;
+ }
+ localIP= Htonl(
+ (*(struct in_addr *)localHost->h_addr_list[0]).S_un.S_addr);
+ return 0;
+ }
+ else
+ {
+ WebRtc_Word32 error = WSAGetLastError();
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1,
+ "gethostbyname failed, error:%d", error);
+ return -1;
+ }
+#elif (defined(WEBRTC_MAC))
+ char localname[255];
+ if (gethostname(localname, 255) != -1)
+ {
+ hostent* localHost;
+ localHost = gethostbyname(localname);
+ if(localHost)
+ {
+ if(localHost->h_addrtype != AF_INET)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ -1,
+ "LocalHostAddress can only get local IP for IP Version 4");
+ return -1;
+ }
+ localIP = Htonl((*(struct in_addr*)*localHost->h_addr_list).s_addr);
+ return 0;
+ }
+ }
+ WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1, "gethostname failed");
+ return -1;
+#else // WEBRTC_LINUX
+ int sockfd, size = 1;
+ struct ifreq* ifr;
+ struct ifconf ifc;
+
+ if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
+ {
+ return -1;
+ }
+ ifc.ifc_len = IFRSIZE;
+ ifc.ifc_req = NULL;
+ do
+ {
+ ++size;
+ // Buffer size needed is unknown. Try increasing it until no overflow
+ // occurs.
+ if (NULL == (ifc.ifc_req = (ifreq*)realloc(ifc.ifc_req, IFRSIZE))) {
+ fprintf(stderr, "Out of memory.\n");
+ exit(EXIT_FAILURE);
+ }
+ ifc.ifc_len = IFRSIZE;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc))
+ {
+ free(ifc.ifc_req);
+ close(sockfd);
+ return -1;
+ }
+ } while (IFRSIZE <= ifc.ifc_len);
+
+ ifr = ifc.ifc_req;
+ for (;(char *) ifr < (char *) ifc.ifc_req + ifc.ifc_len; ++ifr)
+ {
+ if (ifr->ifr_addr.sa_data == (ifr+1)->ifr_addr.sa_data)
+ {
+ continue; // duplicate, skip it
+ }
+ if (ioctl(sockfd, SIOCGIFFLAGS, ifr))
+ {
+ continue; // failed to get flags, skip it
+ }
+ if(strncmp(ifr->ifr_name, "lo",3) == 0)
+ {
+ continue;
+ }else
+ {
+ struct sockaddr* saddr = &(ifr->ifr_addr);
+ SocketAddress* socket_addess = reinterpret_cast<SocketAddress*>(
+ saddr);
+ localIP = Htonl(socket_addess->_sockaddr_in.sin_addr);
+ close(sockfd);
+ free(ifc.ifc_req);
+ return 0;
+ }
+ }
+ free(ifc.ifc_req);
+ close(sockfd);
+ return -1;
+#endif
+}
+
+WebRtc_Word32 UdpTransport::IPAddress(const SocketAddress& address,
+ char* ip,
+ WebRtc_UWord32& ipSize,
+ WebRtc_UWord16& sourcePort)
+{
+ #if defined(_WIN32)
+ DWORD dwIPSize = ipSize;
+ WebRtc_Word32 returnvalue = WSAAddressToStringA((LPSOCKADDR)(&address),
+ sizeof(SocketAddress),
+ NULL,
+ ip,
+ &dwIPSize);
+ if(returnvalue == -1)
+ {
+ return -1;
+ }
+
+ WebRtc_UWord16 source_port = 0;
+ if(address._sockaddr_storage.sin_family == AF_INET)
+ {
+ // Parse IP assuming format "a.b.c.d:port".
+ char* ipEnd = strchr(ip,':');
+ if(ipEnd != NULL)
+ {
+ *ipEnd = '\0';
+ }
+ ipSize = (WebRtc_Word32)strlen(ip);
+ if(ipSize == 0)
+ {
+ return -1;
+ }
+ source_port = address._sockaddr_in.sin_port;
+ }
+ else
+ {
+ // Parse IP assuming format "[address]:port".
+ char* ipEnd = strchr(ip,']');
+ if(ipEnd != NULL)
+ {
+ // Calculate length
+ WebRtc_Word32 adrSize = WebRtc_Word32(ipEnd - ip) - 1;
+ memmove(ip, &ip[1], adrSize); // Remove '['
+ *(ipEnd - 1) = '\0';
+ }
+ ipSize = (WebRtc_Word32)strlen(ip);
+ if(ipSize == 0)
+ {
+ return -1;
+ }
+
+ source_port = address._sockaddr_in6.sin6_port;
+ }
+ // Convert port number to network byte order.
+ sourcePort = htons(source_port);
+ return 0;
+
+ #elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
+ WebRtc_Word32 ipFamily = address._sockaddr_storage.sin_family;
+ const void* ptrNumericIP = NULL;
+
+ if(ipFamily == AF_INET)
+ {
+ ptrNumericIP = &(address._sockaddr_in.sin_addr);
+ }
+ else if(ipFamily == AF_INET6)
+ {
+ ptrNumericIP = &(address._sockaddr_in6.sin6_addr);
+ }
+ else
+ {
+ return -1;
+ }
+ if(inet_ntop(ipFamily, ptrNumericIP, ip, ipSize) == NULL)
+ {
+ return -1;
+ }
+ WebRtc_UWord16 source_port;
+ if(ipFamily == AF_INET)
+ {
+ source_port = address._sockaddr_in.sin_port;
+ } else
+ {
+ source_port = address._sockaddr_in6.sin6_port;
+ }
+ // Convert port number to network byte order.
+ sourcePort = htons(source_port);
+ return 0;
+ #else
+ return -1;
+ #endif
+}
+
+bool UdpTransport::IsIpAddressValid(const char* ipadr, const bool ipV6)
+{
+ if(ipV6)
+ {
+ WebRtc_Word32 len = (WebRtc_Word32)strlen(ipadr);
+ if( len>39 || len == 0)
+ {
+ return false;
+ }
+
+ WebRtc_Word32 i;
+ WebRtc_Word32 colonPos[7] = {0,0,0,0,0,0,0};
+ WebRtc_Word32 lastColonPos = -2;
+ WebRtc_Word32 nColons = 0;
+ WebRtc_Word32 nDubbleColons = 0;
+ WebRtc_Word32 nDots = 0;
+ WebRtc_Word32 error = 0;
+ char c;
+ for(i = 0; i < len ; i++)
+ {
+ c=ipadr[i];
+ if(isxdigit(c))
+ ;
+ else if(c == ':')
+ {
+ if(nColons < 7)
+ colonPos[nColons] = i;
+ if((i-lastColonPos)==1)
+ nDubbleColons++;
+ lastColonPos=i;
+ if(nDots != 0)
+ {
+ error = 1;
+ }
+ nColons++;
+ }
+ else if(c == '.')
+ {
+ nDots++;
+ }
+ else
+ {
+ error = 1;
+ }
+
+ }
+ if(error)
+ {
+ return false;
+ }
+ if(nDubbleColons > 1)
+ {
+ return false;
+ }
+ if(nColons > 7 || nColons < 2)
+ {
+ return false;
+ }
+ if(!(nDots == 3 || nDots == 0))
+ {
+ return false;
+ }
+ lastColonPos = -1;
+ WebRtc_Word32 charsBeforeColon = 0;
+ for(i = 0; i < nColons; i++)
+ {
+ charsBeforeColon=colonPos[i]-lastColonPos-1;
+ if(charsBeforeColon > 4)
+ {
+ return false;
+ }
+ lastColonPos=colonPos[i];
+ }
+ WebRtc_Word32 lengthAfterLastColon = len - lastColonPos - 1;
+ if(nDots == 0)
+ {
+ if(lengthAfterLastColon > 4)
+ return false;
+ }
+ if(nDots == 3 && lengthAfterLastColon > 0)
+ {
+ return IsIpAddressValid((ipadr+lastColonPos+1),false);
+ }
+
+ }
+ else
+ {
+ WebRtc_Word32 len = (WebRtc_Word32)strlen(ipadr);
+ if((len>15)||(len==0))
+ {
+ return false;
+ }
+
+ // IPv4 should be [0-255].[0-255].[0-255].[0-255]
+ WebRtc_Word32 i;
+ WebRtc_Word32 nDots = 0;
+ WebRtc_Word32 iDotPos[4] = {0,0,0,0};
+
+ for (i = 0; (i < len) && (nDots < 4); i++)
+ {
+ if (ipadr[i] == (char)'.')
+ {
+ // Store index of dots and count number of dots.
+ iDotPos[nDots++] = i;
+ }
+ }
+
+ bool allUnder256 = false;
+ // TODO (hellner): while loop seems to be abused here to get
+ // label like functionality. Fix later to avoid introducing bugs now.
+
+ // Check that all numbers are smaller than 256.
+ do
+ {
+ if (nDots != 3 )
+ {
+ break;
+ }
+
+ if (iDotPos[0] <= 3)
+ {
+ char nr[4];
+ memset(nr,0,4);
+ strncpy(nr,&ipadr[0],iDotPos[0]);
+ WebRtc_Word32 num = atoi(nr);
+ if (num > 255)
+ {
+ break;
+ }
+ } else {
+ break;
+ }
+
+ if (iDotPos[1] - iDotPos[0] <= 4)
+ {
+ char nr[4];
+ memset(nr,0,4);
+ strncpy(nr,&ipadr[iDotPos[0]+1], iDotPos[1] - iDotPos[0] - 1);
+ WebRtc_Word32 num = atoi(nr);
+ if (num > 255)
+ break;
+ } else {
+ break;
+ }
+
+ if (iDotPos[2] - iDotPos[1] <= 4)
+ {
+ char nr[4];
+ memset(nr,0,4);
+ strncpy(nr,&ipadr[iDotPos[1]+1], iDotPos[1] - iDotPos[0] - 1);
+ WebRtc_Word32 num = atoi(nr);
+ if (num > 255)
+ break;
+
+ memset(nr,0,4);
+ strncpy(nr,&ipadr[iDotPos[2]+1], len - iDotPos[2] -1);
+ num = atoi(nr);
+ if (num > 255)
+ break;
+ else
+ allUnder256 = true;
+ } else
+ break;
+ } while(false);
+
+ if (nDots != 3 || !allUnder256)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace test
+} // namespace webrtc
diff --git a/test/channel_transport/udp_transport_impl.h b/test/channel_transport/udp_transport_impl.h
new file mode 100644
index 0000000..644b716
--- /dev/null
+++ b/test/channel_transport/udp_transport_impl.h
@@ -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_
diff --git a/test/channel_transport/udp_transport_unittest.cc b/test/channel_transport/udp_transport_unittest.cc
new file mode 100644
index 0000000..7408e4b
--- /dev/null
+++ b/test/channel_transport/udp_transport_unittest.cc
@@ -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