| /* |
| * 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 "udp_socket_windows.h" |
| |
| // Disable deprication warning from traffic.h |
| #pragma warning(disable : 4995) |
| |
| #ifndef WIN32_LEAN_AND_MEAN |
| #define WIN32_LEAN_AND_MEAN |
| #endif |
| |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <windows.h> |
| #include <Qos.h> |
| // Don't change include order for these header files. |
| #include <Winsock2.h> |
| #include <Ntddndis.h> |
| #include <traffic.h> |
| |
| #include "traffic_control_windows.h" |
| #include "udp_socket_manager_wrapper.h" |
| |
| namespace webrtc { |
| typedef struct _QOS_DESTADDR |
| { |
| QOS_OBJECT_HDR ObjectHdr; |
| const struct sockaddr* SocketAddress; |
| ULONG SocketAddressLength; |
| } QOS_DESTADDR, *LPQOS_DESTADDR; |
| |
| typedef const QOS_DESTADDR* LPCQOS_DESTADDR; |
| |
| #define QOS_GENERAL_ID_BASE 2000 |
| #define QOS_OBJECT_DESTADDR (0x00000004 + QOS_GENERAL_ID_BASE) |
| |
| #define MAX_PACKET_SIZE 2048 |
| |
| class UDPPacket |
| { |
| public: |
| UDPPacket() |
| { |
| _length = 0; |
| } |
| WebRtc_Word32 Set(const WebRtc_Word8* buf, WebRtc_Word32 length) |
| { |
| if(length > MAX_PACKET_SIZE) |
| return 0; |
| |
| _length = length; |
| memcpy(_buffer,buf,length); |
| return length; |
| } |
| WebRtc_Word32 Set(const WebRtc_Word8* buf, WebRtc_Word32 length, |
| const SocketAddress* addr) |
| { |
| if(length > MAX_PACKET_SIZE) |
| { |
| return 0; |
| } |
| |
| _length = length; |
| memcpy(&_remoteAddr,addr,sizeof(SocketAddress)); |
| memcpy(_buffer,buf,length); |
| return length; |
| } |
| |
| SocketAddress _remoteAddr; |
| WebRtc_Word8 _buffer[MAX_PACKET_SIZE]; |
| WebRtc_Word32 _length; |
| }; |
| |
| UdpSocketWindows::UdpSocketWindows(const WebRtc_Word32 id, |
| UdpSocketManager* mgr, bool ipV6Enable) |
| : _id(id), |
| _qos(true) |
| { |
| _wantsIncoming = false; |
| _error = 0; |
| _mgr = mgr; |
| _addedToMgr = false; |
| |
| _obj = NULL; |
| _incomingCb = NULL; |
| _socket = INVALID_SOCKET; |
| _terminate=false; |
| |
| _clientHandle = INVALID_HANDLE_VALUE; |
| _flowHandle = INVALID_HANDLE_VALUE; |
| _filterHandle = INVALID_HANDLE_VALUE; |
| |
| WEBRTC_TRACE(kTraceMemory, kTraceTransport, _id, |
| "UdpSocketWindows::UdpSocketWindows()"); |
| |
| _gtc = NULL; |
| |
| // Check if QoS is supported. |
| WSAPROTOCOL_INFO pProtocolInfo; |
| DWORD dwBufLen = 0; |
| BOOL bProtocolFound = FALSE; |
| WSAPROTOCOL_INFO* lpProtocolBuf = NULL; |
| |
| // 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); |
| |
| WebRtc_Word32 iProtocol; |
| 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) |
| { |
| _socket = INVALID_SOCKET; |
| _qos = false; |
| free(lpProtocolBuf); |
| _error = SOCKET_ERROR_NO_QOS; |
| }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; |
| _error = SOCKET_ERROR_NO_QOS; |
| } |
| } |
| // QoS not supported. |
| if(ipV6Enable) |
| { |
| _socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); |
| }else |
| { |
| _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| } |
| // Non-blocking mode. |
| WebRtc_Word32 iMode = 1; |
| ioctlsocket(_socket, FIONBIO, (u_long FAR*) &iMode); |
| } |
| |
| UdpSocketWindows::~UdpSocketWindows() |
| { |
| WEBRTC_TRACE(kTraceMemory, kTraceTransport, _id, |
| "UdpSocketWindows::~UdpSocketWindows()"); |
| if (_gtc) |
| { |
| TrafficControlWindows::Release(_gtc); |
| } |
| } |
| |
| WebRtc_Word32 UdpSocketWindows::ChangeUniqueId(const WebRtc_Word32 id) |
| { |
| _id = id; |
| if (_gtc) |
| { |
| _gtc->ChangeUniqueId(id); |
| } |
| return 0; |
| } |
| |
| bool UdpSocketWindows::ValidHandle() |
| { |
| return GetFd() != INVALID_SOCKET; |
| } |
| |
| bool UdpSocketWindows::SetCallback(CallbackObj obj, IncomingSocketCallback cb) |
| { |
| _obj = obj; |
| _incomingCb = cb; |
| |
| if (_mgr->AddSocket(this)) |
| { |
| _addedToMgr = true; |
| return true; |
| } |
| return false; |
| } |
| |
| bool UdpSocketWindows::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 = WSAGetLastError(); |
| return false; |
| } |
| |
| bool UdpSocketWindows::Bind(const SocketAddress& name) |
| { |
| const struct sockaddr* socketName = |
| reinterpret_cast<const struct sockaddr*>(&name); |
| |
| if (0 == bind(_socket, socketName, sizeof(SocketAddress))) |
| { |
| _localAddr = name; |
| return true; |
| } |
| _error = WSAGetLastError(); |
| return false; |
| } |
| |
| WebRtc_Word32 UdpSocketWindows::SendTo(const WebRtc_Word8* buf, |
| WebRtc_Word32 len, |
| const SocketAddress& to) |
| { |
| // Don't try to send this packet if there are older packets queued up. |
| if(!_notSentPackets.Empty()) |
| { |
| UDPPacket* packet = new UDPPacket(); |
| packet->Set(buf, len, &to); |
| if(!_notSentPackets.Empty()) |
| { |
| _notSentPackets.PushBack(packet); |
| return len; |
| }else { |
| // No old packets queued up. Free to try to send. |
| delete packet; |
| } |
| } |
| |
| WebRtc_Word32 retVal; |
| retVal = sendto(_socket, buf, len, 0, |
| reinterpret_cast<const struct sockaddr*>(&to), |
| sizeof(SocketAddress)); |
| |
| if(retVal == SOCKET_ERROR) |
| { |
| _error = WSAGetLastError(); |
| if (_error == WSAEWOULDBLOCK) |
| { |
| UDPPacket* packet = new UDPPacket(); |
| packet->Set(buf,len, &to); |
| _notSentPackets.PushBack(packet); |
| return len; |
| } |
| } |
| return retVal; |
| } |
| |
| void UdpSocketWindows::HasIncoming() |
| { |
| WebRtc_Word8 buf[MAX_PACKET_SIZE]; |
| SocketAddress from; |
| int fromlen = sizeof(from); |
| WebRtc_Word32 retval = recvfrom(_socket,buf, sizeof(buf), 0, |
| reinterpret_cast<struct sockaddr*>(&from), |
| &fromlen); |
| |
| switch(retval) |
| { |
| case 0: |
| // The connection has been gracefully closed. |
| break; |
| case SOCKET_ERROR: |
| _error = WSAGetLastError(); |
| break; |
| default: |
| if(_wantsIncoming && _incomingCb) |
| _incomingCb(_obj,buf, retval, &from); |
| break; |
| } |
| } |
| |
| void UdpSocketWindows::CleanUp() |
| { |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, |
| "UdpSocketWindows::CleanUp()"); |
| _wantsIncoming = false; |
| |
| if(_clientHandle != INVALID_HANDLE_VALUE) |
| { |
| assert(_filterHandle != INVALID_HANDLE_VALUE); |
| assert(_flowHandle != INVALID_HANDLE_VALUE); |
| |
| if (_gtc) |
| { |
| _gtc->TcDeleteFilter(_filterHandle); |
| _gtc->TcDeleteFlow(_flowHandle); |
| _gtc->TcDeregisterClient(_clientHandle); |
| } |
| |
| _clientHandle = INVALID_HANDLE_VALUE; |
| _filterHandle = INVALID_HANDLE_VALUE; |
| _flowHandle = INVALID_HANDLE_VALUE; |
| } |
| |
| while(!_notSentPackets.Empty()) |
| { |
| UDPPacket* packet = (UDPPacket*)_notSentPackets.First()->GetItem(); |
| if(!packet) |
| { |
| break; |
| } |
| delete packet; |
| _notSentPackets.PopFront(); |
| } |
| |
| if (_socket != INVALID_SOCKET) |
| { |
| if (closesocket(_socket) == SOCKET_ERROR) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "closesocket() => error = %d", WSAGetLastError()); |
| } |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, |
| "WinSock::closesocket() done"); |
| |
| if(_addedToMgr) |
| { |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, |
| "calling UdpSocketManager::RemoveSocket()"); |
| _mgr->RemoveSocket(this); |
| } |
| } |
| } |
| |
| void UdpSocketWindows::SetWritable() |
| { |
| // Try to send packets that have been queued up. |
| while(!_notSentPackets.Empty()) |
| { |
| UDPPacket* packet = (UDPPacket*)_notSentPackets.First()->GetItem(); |
| if(!packet) |
| { |
| break; |
| } |
| if(sendto( |
| _socket,packet->_buffer, |
| packet->_length, |
| 0, |
| reinterpret_cast<const struct sockaddr*>( |
| &(packet->_remoteAddr)), |
| sizeof(SocketAddress)) == SOCKET_ERROR) |
| { |
| _error = WSAGetLastError(); |
| if (_error == WSAEWOULDBLOCK) |
| { |
| return; |
| } |
| } else { |
| delete packet; |
| _notSentPackets.PopFront(); |
| } |
| } |
| } |
| |
| bool UdpSocketWindows::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; |
| } |
| QOS Qos; |
| WebRtc_Word32 result; |
| DWORD BytesRet; |
| |
| if(overrideDSCP != 0) |
| { |
| FLOWSPEC f; |
| WebRtc_Word32 err = CreateFlowSpec(serviceType, tokenRate, bucketSize, |
| peekBandwith, minPolicedSize, |
| maxSduSize, &f); |
| if(err == -1) |
| { |
| return false; |
| } |
| return SetTOSByte(overrideDSCP, &f, &f) == 0; |
| } |
| memset(&Qos, QOS_NOT_SPECIFIED, sizeof(QOS)); |
| |
| Qos.SendingFlowspec.ServiceType = serviceType; |
| Qos.SendingFlowspec.TokenRate = tokenRate; |
| Qos.SendingFlowspec.TokenBucketSize = bucketSize; |
| Qos.SendingFlowspec.PeakBandwidth = peekBandwith; |
| Qos.SendingFlowspec.DelayVariation = QOS_NOT_SPECIFIED; |
| Qos.SendingFlowspec.Latency = QOS_NOT_SPECIFIED; |
| Qos.SendingFlowspec.MinimumPolicedSize = minPolicedSize; |
| Qos.SendingFlowspec.MaxSduSize = maxSduSize; |
| |
| // 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; |
| WebRtc_Word8* p = (WebRtc_Word8*)malloc(sizeof(QOS_DESTADDR) + |
| sizeof(QOS_DS_CLASS)); |
| |
| QOS_DESTADDR* QosDestaddr = (QOS_DESTADDR*)p; |
| ZeroMemory((WebRtc_Word8 *)QosDestaddr, sizeof(QOS_DESTADDR)); |
| QosDestaddr->ObjectHdr.ObjectType = QOS_OBJECT_DESTADDR; |
| QosDestaddr->ObjectHdr.ObjectLength = sizeof(QOS_DESTADDR); |
| QosDestaddr->SocketAddress = (SOCKADDR*)&stRemName; |
| QosDestaddr->SocketAddressLength = sizeof(SocketAddress); |
| Qos.ProviderSpecific.len = QosDestaddr->ObjectHdr.ObjectLength; |
| Qos.ProviderSpecific.buf = (WebRtc_Word8*)p; |
| |
| // Socket must be bound for this call to be successfull. If socket is not |
| // bound WSAGetLastError() will return 10022. |
| result = WSAIoctl(GetFd(),SIO_SET_QOS, &Qos,sizeof(QOS),NULL, 0, &BytesRet, |
| NULL,NULL); |
| if (result == SOCKET_ERROR) |
| { |
| _error = WSAGetLastError(); |
| free(p); |
| return false; |
| } |
| free(p); |
| return true; |
| } |
| |
| WebRtc_Word32 UdpSocketWindows::SetTOS(WebRtc_Word32 serviceType) |
| { |
| WebRtc_Word32 res = SetTOSByte(serviceType, NULL, NULL); |
| |
| if (res == -1) |
| { |
| OSVERSIONINFO OsVersion; |
| OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); |
| GetVersionEx (&OsVersion); |
| |
| if ((OsVersion.dwMajorVersion == 4)) |
| { |
| return -1; |
| } |
| } |
| return res; |
| } |
| |
| WebRtc_Word32 UdpSocketWindows::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 = bucketSize; |
| f->PeakBandwidth = peekBandwith; |
| f->DelayVariation = QOS_NOT_SPECIFIED; |
| f->Latency = QOS_NOT_SPECIFIED; |
| f->MinimumPolicedSize = minPolicedSize; |
| f->MaxSduSize = maxSduSize; |
| return 0; |
| } |
| |
| WebRtc_Word32 UdpSocketWindows::SetTOSByte(WebRtc_Word32 serviceType, |
| FLOWSPEC* send, FLOWSPEC* recv) |
| { |
| if(_socket == INVALID_SOCKET) |
| { |
| return -1; |
| } |
| if (!_gtc) |
| { |
| _gtc = TrafficControlWindows::GetInstance(_id); |
| } |
| if (!_gtc) |
| { |
| return -1; |
| } |
| |
| 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) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "TcRegisterClient returned %d", result); |
| return result; |
| } |
| |
| // Find traffic control-enabled network interfaces. |
| ULONG BufferSize = 0; |
| result = _gtc->TcEnumerateInterfaces(ClientHandle, &BufferSize, NULL); |
| |
| if(result != NO_ERROR && result != ERROR_INSUFFICIENT_BUFFER) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "Error enumerating interfaces, %d", result); |
| _gtc->TcDeregisterClient(ClientHandle); |
| return result; |
| } |
| |
| if(result != ERROR_INSUFFICIENT_BUFFER) |
| { |
| // Empty buffer contains all control-enabled network interfaces. I.e. |
| // ToS is not enabled. |
| WEBRTC_TRACE( |
| kTraceError, |
| kTraceTransport, |
| _id, |
| "Error enumerating interfaces: passed in 0 and received\ |
| NO_ERROR when expecting INSUFFICIENT_BUFFER, %d"); |
| _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; |
| |
| const struct sockaddr_in* name; |
| name = reinterpret_cast<const struct sockaddr_in*>(&_localAddr); |
| |
| // 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)) |
| { |
| |
| WebRtc_Word8 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); |
| |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, |
| "Examining Interface %s", interfaceName); |
| if(pIpAddr->in_addr == name->sin_addr.S_un.S_addr) |
| { |
| filterSourceAddress = pIpAddr->in_addr; |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, |
| "Found ip addr: %s", inet_ntoa(name->sin_addr)); |
| addrFound = true; |
| } |
| } |
| if(!addrFound) |
| { |
| continue; |
| } |
| else |
| { |
| break; |
| } |
| } |
| |
| if(!addrFound) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "IP Address 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; |
| } |
| |
| FLOWSPEC defaultSend, defaultRecv; |
| if(send == NULL) |
| { |
| defaultSend.DelayVariation = QOS_NOT_SPECIFIED; |
| defaultSend.Latency = QOS_NOT_SPECIFIED; |
| defaultSend.MaxSduSize = QOS_NOT_SPECIFIED; |
| defaultSend.MinimumPolicedSize = QOS_NOT_SPECIFIED; |
| defaultSend.PeakBandwidth = QOS_NOT_SPECIFIED; |
| defaultSend.ServiceType = SERVICETYPE_BESTEFFORT; |
| defaultSend.TokenBucketSize = QOS_NOT_SPECIFIED; |
| defaultSend.TokenRate = 10000; |
| } |
| else |
| { |
| defaultSend = *send; |
| } |
| if(recv == NULL) |
| { |
| defaultRecv = defaultSend; |
| defaultRecv.ServiceType = SERVICETYPE_CONTROLLEDLOAD; |
| } |
| else |
| { |
| defaultRecv = *recv; |
| } |
| |
| |
| PTC_GEN_FLOW flow = |
| (PTC_GEN_FLOW)malloc(sizeof(TC_GEN_FLOW) + sizeof(QOS_DS_CLASS)); |
| |
| flow->ReceivingFlowspec = defaultRecv; |
| flow->SendingFlowspec = defaultSend; |
| |
| QOS_DS_CLASS dsClass; |
| |
| ZeroMemory((WebRtc_Word8*)&dsClass, sizeof(QOS_DS_CLASS)); |
| |
| dsClass.DSField = serviceType; |
| |
| dsClass.ObjectHdr.ObjectType = QOS_OBJECT_DS_CLASS; |
| dsClass.ObjectHdr.ObjectLength = sizeof(dsClass); |
| |
| memcpy(flow->TcObjects, (void*)&dsClass, sizeof(QOS_DS_CLASS)); |
| flow->TcObjectsLength = sizeof(dsClass); |
| |
| result = _gtc->TcAddFlow(ifcHandle, NULL, 0, flow, &iflowHandle); |
| if(result != NO_ERROR) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "Error adding flow: %d", result); |
| _gtc->TcCloseInterface(ifcHandle); |
| _gtc->TcDeregisterClient(ClientHandle); |
| free(pInterfaceBuffer); |
| return -1; |
| } |
| |
| free(flow); |
| IP_PATTERN filterPattern, mask; |
| |
| ZeroMemory((WebRtc_Word8*)&filterPattern, sizeof(IP_PATTERN)); |
| ZeroMemory((WebRtc_Word8*)&mask, sizeof(IP_PATTERN)); |
| |
| filterPattern.ProtocolId = IPPROTO_UDP; |
| // "name" fields are 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); |
| if(_filterHandle != INVALID_HANDLE_VALUE) |
| { |
| _gtc->TcDeleteFilter(_filterHandle); |
| } |
| |
| result = _gtc->TcAddFilter(iflowHandle, &filter, &iFilterHandle); |
| if(result != NO_ERROR) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "Error adding filter: %d", result); |
| _gtc->TcDeleteFlow(iflowHandle); |
| _gtc->TcCloseInterface(ifcHandle); |
| _gtc->TcDeregisterClient(ClientHandle); |
| free(pInterfaceBuffer); |
| return result; |
| } |
| |
| _flowHandle = iflowHandle; |
| _filterHandle = iFilterHandle; |
| _clientHandle = ClientHandle; |
| |
| _gtc->TcCloseInterface(ifcHandle); |
| free(pInterfaceBuffer); |
| |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, |
| "Successfully created flow and filter."); |
| return 0; |
| } |
| } // namespace webrtc |