Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Unified Diff: webrtc/test/channel_transport/udp_socket2_win.cc

Issue 2336123002: Revert of Moved webrtc/test/channel_transport/ into webrtc/voice_engine/test/ (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/test/channel_transport/udp_socket2_win.cc
diff --git a/webrtc/test/channel_transport/udp_socket2_win.cc b/webrtc/test/channel_transport/udp_socket2_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2858c2d002d0795237fa04ffb67aa04daa4c1cd5
--- /dev/null
+++ b/webrtc/test/channel_transport/udp_socket2_win.cc
@@ -0,0 +1,1353 @@
+/*
+ * 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/base/format_macros.h"
+#include "webrtc/system_wrappers/include/sleep.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 int32_t id,
+ UdpSocketManager* mgr, bool ipV6Enable,
+ bool disableGQOS)
+ : _id(id),
+ _qos(true),
+ _iProtocol(0),
+ _outstandingCalls(0),
+ _outstandingCallComplete(0),
+ _terminate(false),
+ _addedToMgr(false),
+ delete_event_(true, 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;
+ _ptrCbRWLock = RWLockWrapper::CreateRWLock();
+ _ptrDestRWLock = RWLockWrapper::CreateRWLock();
+ _ptrSocketRWLock = RWLockWrapper::CreateRWLock();
+
+ // 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.
+ int32_t 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 (int32_t 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.
+ int32_t nZero = 0;
+ int32_t 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()");
+
+ delete_event_.Wait(rtc::Event::kForever);
+
+
+ delete _ptrCbRWLock;
+ delete _ptrDestRWLock;
+ delete _ptrSocketRWLock;
+
+ if (_flow)
+ {
+ free(_flow);
+ _flow = NULL;
+ }
+
+ if (_gtc)
+ {
+ if(_filterHandle)
+ {
+ _gtc->TcDeleteFilter(_filterHandle);
+ }
+ if(_flowHandle)
+ {
+ _gtc->TcDeleteFlow(_flowHandle);
+ }
+ TrafficControlWindows::Release( _gtc);
+ }
+}
+
+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 ",(int32_t)this);
+ if(_addedToMgr)
+ {
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::SetCallback alreadey added",
+ (int32_t) this);
+ return false;
+
+ }
+ if (_mgr->AddSocket(this))
+ {
+ WEBRTC_TRACE(
+ kTraceDebug, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::SetCallback socket added to manager",
+ (int32_t)this);
+ _addedToMgr = true;
+ return true;
+ }
+
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::SetCallback error adding me to mgr",
+ (int32_t) this);
+ return false;
+}
+
+bool UdpSocket2Windows::SetSockopt(int32_t level, int32_t optname,
+ const int8_t* optval, int32_t 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(uint32_t receiveBuffers)
+{
+ WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::StartReceiving(%d)", (int32_t)this,
+ receiveBuffers);
+
+ _wantsIncoming = true;
+
+ int32_t numberOfReceiveBuffersToCreate =
+ receiveBuffers - _receiveBuffers.Value();
+ numberOfReceiveBuffersToCreate = (numberOfReceiveBuffersToCreate < 0) ?
+ 0 : numberOfReceiveBuffersToCreate;
+
+ int32_t error = 0;
+ for(int32_t 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;
+}
+
+int32_t UdpSocket2Windows::SendTo(const int8_t* buf, size_t len,
+ const SocketAddress& to)
+{
+ int32_t retVal = 0;
+ int32_t error = 0;
+ PerIoContext* pIoContext = _mgr->PopIoContext();
+ if(pIoContext == 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::SendTo(), pIoContext==0",
+ (int32_t) this);
+ return -1;
+ }
+ // sizeof(pIoContext->buffer) is smaller than the highest number that
+ // can be represented by a size_t.
+ if(len >= sizeof(pIoContext->buffer))
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows(%d)::SendTo(), len= %" PRIuS
+ " > buffer_size = %d",
+ (int32_t) this,
+ len,sizeof(pIoContext->buffer));
+ len = sizeof(pIoContext->buffer);
+ }
+
+ memcpy(pIoContext->buffer,buf,len);
+ pIoContext->wsabuf.buf = pIoContext->buffer;
+ pIoContext->wsabuf.len = static_cast<ULONG>(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 static_cast<int32_t>(len);
+ }
+ error = _mgr->PushIoContext(pIoContext);
+ if(error)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows(%d)::SendTo(), error:%d pushing ioContext",
+ (int32_t)this, error);
+ }
+
+ // Roll back.
+ OutstandingCallCompleted();
+ return -1;
+}
+
+void UdpSocket2Windows::IOCompleted(PerIoContext* pIOContext,
+ uint32_t ioSize, uint32_t error)
+{
+ if(pIOContext == NULL || error == ERROR_OPERATION_ABORTED)
+ {
+ if ((pIOContext != NULL) &&
+ !pIOContext->ioInitiatedByPlatformThread &&
+ (error == ERROR_OPERATION_ABORTED) &&
+ (pIOContext->ioOperation == OP_READ) &&
+ _outstandingCallsDisabled)
+ {
+ // !pIOContext->initiatedIOByPlatformThread indicate that the I/O
+ // was not initiated by a PlatformThread 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",
+ (int32_t)pIOContext,
+ ioSize,
+ error,
+ pIOContext ? (int32_t)pIOContext->ioOperation : -1);
+ } else {
+ WEBRTC_TRACE(
+ kTraceDebug,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows::IOCompleted() Operation aborted");
+ }
+ if(pIOContext)
+ {
+ int32_t remainingReceiveBuffers = --_receiveBuffers;
+ if(remainingReceiveBuffers < 0)
+ {
+ assert(false);
+ }
+ int32_t err = _mgr->PushIoContext(pIOContext);
+ if(err)
+ {
+ 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 int8_t*>(
+ pIOContext->wsabuf.buf),
+ ioSize,
+ &pIOContext->from);
+ }
+ _ptrCbRWLock->ReleaseLockShared();
+ }
+ int32_t err = PostRecv(pIOContext);
+ if(err == 0)
+ {
+ // The PerIoContext was posted by a thread controlled by the socket
+ // implementation.
+ pIOContext->ioInitiatedByPlatformThread = 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.
+}
+
+int32_t UdpSocket2Windows::PostRecv()
+{
+ PerIoContext* pIoContext=_mgr->PopIoContext();
+ if(pIoContext == 0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::PostRecv(), pIoContext == 0",
+ (int32_t)this);
+ return -1;
+ }
+ // This function may have been called by thread not controlled by the socket
+ // implementation.
+ pIoContext->ioInitiatedByPlatformThread = false;
+ return PostRecv(pIoContext);
+}
+
+int32_t UdpSocket2Windows::PostRecv(PerIoContext* pIoContext)
+{
+ if(pIoContext==0)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows(%d)::PostRecv(?), pIoContext==0",
+ (int32_t)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;
+ int32_t rxError = 0;
+ int32_t nRet = 0;
+ int32_t 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(int32_t 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",
+ (int32_t)this,
+ rxError,
+ tries);
+ // Tell the OS that this is a good place to context switch if
+ // it wants to.
+ SleepMs(0);
+ }
+ }
+ if((rxError == ERROR_IO_PENDING) || (nRet == 0))
+ {
+ postingSucessfull = true;
+ break;
+ }
+ }
+ ReleaseSocket();
+
+ if(postingSucessfull)
+ {
+ return 0;
+ }
+ int32_t remainingReceiveBuffers = --_receiveBuffers;
+ if(remainingReceiveBuffers < 0)
+ {
+ assert(false);
+ }
+ int32_t error = _mgr->PushIoContext(pIoContext);
+ if(error)
+ {
+ WEBRTC_TRACE(
+ kTraceError,
+ kTraceTransport,
+ _id,
+ "UdpSocket2Windows(%d)::PostRecv(?), error:%d when PushIoContext",
+ (int32_t)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();
+ delete this;
+}
+
+bool UdpSocket2Windows::SetQos(int32_t serviceType,
+ int32_t tokenRate,
+ int32_t bucketSize,
+ int32_t peekBandwith,
+ int32_t minPolicedSize,
+ int32_t maxSduSize,
+ const SocketAddress &stRemName,
+ int32_t overrideDSCP)
+{
+ if(_qos == false)
+ {
+ WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
+ "UdpSocket2Windows::SetQos(), socket not capable of QOS");
+ return false;
+ }
+ if(overrideDSCP != 0)
+ {
+ FLOWSPEC f;
+ int32_t 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((int8_t *)&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.
+ int32_t 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;
+}
+
+int32_t UdpSocket2Windows::SetTOS(int32_t 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();
+ }
+
+ int32_t 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 ,
+ (int8_t*)&serviceType, 4) != 0)
+ {
+ return -1;
+ }
+ }
+ }
+ return res;
+}
+
+int32_t UdpSocket2Windows::SetPCP(int32_t 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);
+}
+
+int32_t UdpSocket2Windows::SetTrafficControl(
+ int32_t dscp,
+ int32_t 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)
+ (((int8_t*)pInterfaceBuffer) + BufferSize);
+ oneinterface = (PTC_IFC_DESCRIPTOR)
+ ((int8_t *)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((int8_t*)&filterPattern, sizeof(IP_PATTERN));
+ ZeroMemory((int8_t*)&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;
+}
+
+int32_t UdpSocket2Windows::CreateFlowSpec(int32_t serviceType,
+ int32_t tokenRate,
+ int32_t bucketSize,
+ int32_t peekBandwith,
+ int32_t minPolicedSize,
+ int32_t 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.
+ delete_event_.Set();
+ }
+}
+
+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)
+ {
+ delete_event_.Set();
+ }
+}
+
+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",
+ (int32_t)this, WSAGetLastError());
+ }
+ _socket = INVALID_SOCKET;
+ _ptrSocketRWLock->ReleaseLockExclusive();
+ return true;
+}
+
+} // namespace test
+} // namespace webrtc
« no previous file with comments | « webrtc/test/channel_transport/udp_socket2_win.h ('k') | webrtc/test/channel_transport/udp_socket_manager_posix.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698