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