3098 lines
92 KiB
C++
3098 lines
92 KiB
C++
/*
|
|
* 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_transport_impl.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#if defined(_WIN32)
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
// Disable warning for default initialized arrays on VS2005
|
|
#pragma warning(disable:4351)
|
|
#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 MAC_IPHONE
|
|
#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 "common_types.h"
|
|
#include "critical_section_wrapper.h"
|
|
#include "rw_lock_wrapper.h"
|
|
#include "trace.h"
|
|
#include "typedefs.h"
|
|
#include "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))
|
|
|
|
WebRtc_UWord32 timeGetTime()
|
|
{
|
|
struct timeval tv;
|
|
struct timezone tz;
|
|
WebRtc_UWord32 val;
|
|
gettimeofday(&tv, &tz);
|
|
val= tv.tv_sec*1000+ tv.tv_usec/1000;
|
|
return(val);
|
|
}
|
|
#endif // defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
|
|
|
|
namespace webrtc {
|
|
UdpTransport* UdpTransport::Create(const WebRtc_Word32 id,
|
|
WebRtc_UWord8& numSocketThreads)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, id,
|
|
"Create(numSocketThreads:%d)",numSocketThreads);
|
|
return new UdpTransportImpl(id, numSocketThreads);
|
|
}
|
|
|
|
void UdpTransport::Destroy(UdpTransport* module)
|
|
{
|
|
if(module)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport,
|
|
static_cast<UdpTransportImpl*>(module)->Id(), "Destroy");
|
|
delete module;
|
|
}
|
|
}
|
|
|
|
UdpTransportImpl::UdpTransportImpl(const WebRtc_Word32 id,
|
|
WebRtc_UWord8& numSocketThreads)
|
|
: _id(id),
|
|
_crit(CriticalSectionWrapper::CreateCriticalSection()),
|
|
_critFilter(CriticalSectionWrapper::CreateCriticalSection()),
|
|
_critPacketCallback(CriticalSectionWrapper::CreateCriticalSection()),
|
|
_mgr(UdpSocketManager::Create(id, numSocketThreads)),
|
|
_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),
|
|
_IpV6EnabledRead(false),
|
|
_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));
|
|
if(_mgr == NULL)
|
|
{
|
|
_mgr = UdpSocketManager::Create(id, numSocketThreads);
|
|
}
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceTransport, id, "%s created", __FUNCTION__);
|
|
}
|
|
|
|
UdpTransportImpl::~UdpTransportImpl()
|
|
{
|
|
CloseSendSockets();
|
|
CloseReceiveSockets();
|
|
delete _crit;
|
|
delete _critFilter;
|
|
delete _critPacketCallback;
|
|
delete _cachLock;
|
|
|
|
UdpSocketManager::Return();
|
|
WEBRTC_TRACE(kTraceMemory, kTraceTransport, _id, "%s deleted",
|
|
__FUNCTION__);
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransportImpl::ChangeUniqueId(const WebRtc_Word32 id)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id,
|
|
"ChangeUniqueId(new id:%d)", id);
|
|
|
|
CriticalSectionScoped cs(*_crit);
|
|
_id = id;
|
|
if(_mgr)
|
|
{
|
|
_mgr->ChangeUniqueId(id);
|
|
}
|
|
if(_ptrRtpSocket)
|
|
{
|
|
_ptrRtpSocket->ChangeUniqueId(id);
|
|
}
|
|
if(_ptrRtcpSocket)
|
|
{
|
|
_ptrRtcpSocket->ChangeUniqueId(id);
|
|
}
|
|
if(_ptrSendRtpSocket)
|
|
{
|
|
_ptrSendRtpSocket->ChangeUniqueId(id);
|
|
}
|
|
if(_ptrSendRtcpSocket)
|
|
{
|
|
_ptrSendRtcpSocket->ChangeUniqueId(id);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransportImpl::Version(WebRtc_Word8* version,
|
|
WebRtc_UWord32& remainingBufferInBytes,
|
|
WebRtc_UWord32& position) const
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
if(version == NULL)
|
|
{
|
|
WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
|
|
"Version pointer is NULL");
|
|
return -1;
|
|
}
|
|
WebRtc_Word8 ourVersion[256] = "UdpTransport 1.1.0";
|
|
WebRtc_Word32 ourLength = (WebRtc_Word32)strlen(ourVersion);
|
|
if((WebRtc_Word32)remainingBufferInBytes < ourLength +1)
|
|
{
|
|
WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id,
|
|
"Version buffer not long enough");
|
|
return -1;
|
|
}
|
|
memcpy(version, ourVersion, ourLength);
|
|
version[ourLength] = 0;
|
|
position += ourLength;
|
|
return 0;
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransportImpl::TimeUntilNextProcess()
|
|
{
|
|
return 100;
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransportImpl::Process()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
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(WebRtc_Word8* 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,
|
|
WebRtc_Word8* 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 WebRtc_Word8* ip,
|
|
const WebRtc_Word8* multicastIpAddr,
|
|
const WebRtc_UWord16 rtcpPort)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
|
|
{
|
|
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 = UdpSocketWrapper::CreateSocket(_id, _mgr, this,
|
|
IncomingRTPCallback,
|
|
IpV6Enabled());
|
|
|
|
_ptrRtcpSocket = UdpSocketWrapper::CreateSocket(_id, _mgr, this,
|
|
IncomingRTCPCallback,
|
|
IpV6Enabled());
|
|
|
|
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(
|
|
WebRtc_Word8 ipAddr[kIpAddressVersion6Length],
|
|
WebRtc_UWord16& rtpPort,
|
|
WebRtc_UWord16& rtcpPort,
|
|
WebRtc_Word8 multicastIpAddr[kIpAddressVersion6Length]) const
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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(
|
|
WebRtc_Word8 ipAddr[kIpAddressVersion6Length],
|
|
WebRtc_UWord16& rtpPort,
|
|
WebRtc_UWord16& rtcpPort) const
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
CriticalSectionScoped cs(*_crit);
|
|
rtpPort = _destPort;
|
|
rtcpPort = _destPortRTCP;
|
|
strncpy(ipAddr, _destIP, IpV6Enabled() ?
|
|
UdpTransport::kIpAddressVersion6Length :
|
|
UdpTransport::kIpAddressVersion4Length);
|
|
return 0;
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransportImpl::RemoteSocketInformation(
|
|
WebRtc_Word8 ipAddr[kIpAddressVersion6Length],
|
|
WebRtc_UWord16& rtpPort,
|
|
WebRtc_UWord16& rtcpPort) const
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
CriticalSectionScoped cs(*_crit);
|
|
QoS = _qos;
|
|
serviceType = _serviceType;
|
|
overrideDSCP = _overrideDSCP;
|
|
return 0;
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransportImpl::SetToS(WebRtc_Word32 DSCP, bool useSetSockOpt)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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 =
|
|
UdpSocketWrapper::CreateSocket(_id, _mgr, NULL,
|
|
NULL, IpV6Enabled(),
|
|
true);
|
|
_ptrSendRtcpSocket =
|
|
UdpSocketWrapper::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 = UdpSocketWrapper::CreateSocket(
|
|
_id, _mgr, this, IncomingRTPCallback,
|
|
IpV6Enabled(), true);
|
|
_ptrRtcpSocket = UdpSocketWrapper::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
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
CriticalSectionScoped cs(*_crit);
|
|
DSCP = _tos;
|
|
useSetSockOpt = _useSetSockOpt;
|
|
return 0;
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransportImpl::SetPCP(WebRtc_Word32 PCP)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
|
|
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
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
CriticalSectionScoped cs(*_crit);
|
|
PCP = _pcp;
|
|
return 0;
|
|
}
|
|
|
|
bool UdpTransportImpl::SetSockOptUsed()
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
return _useSetSockOpt;
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransportImpl::EnableIpV6()
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
CriticalSectionScoped cs(*_crit);
|
|
if(_IpV6EnabledRead)
|
|
{
|
|
if(_ipV6Enabled)
|
|
{
|
|
return 0;
|
|
}else {
|
|
_lastError = kIpVersion6Error;
|
|
return -1;
|
|
}
|
|
}
|
|
_ipV6Enabled=true;
|
|
return 0;
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransportImpl::FilterIP(
|
|
WebRtc_Word8 filterIPAddress[kIpAddressVersion6Length]) const
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
|
|
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 WebRtc_Word8 filterIPAddress[kIpAddressVersion6Length])
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
CriticalSectionScoped cs(*_critFilter);
|
|
_rtpFilterPort = rtpFilterPort;
|
|
_rtcpFilterPort = rtcpFilterPort;
|
|
return 0;
|
|
}
|
|
|
|
bool UdpTransportImpl::SendSocketsInitialized() const
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
CriticalSectionScoped cs(*_crit);
|
|
if(_ptrSendRtpSocket)
|
|
{
|
|
return true;
|
|
}
|
|
if(_destPort !=0)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool UdpTransportImpl::ReceiveSocketsInitialized() const
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
if(_ptrRtpSocket)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool UdpTransportImpl::SourcePortsInitialized() const
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
if(_ptrSendRtpSocket)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool UdpTransportImpl::IpV6Enabled() const
|
|
{
|
|
WEBRTC_TRACE(kTraceStream, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
_IpV6EnabledRead=true;
|
|
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)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
|
|
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 = UdpSocketWrapper::CreateSocket(_id, _mgr, NULL, NULL,
|
|
IpV6Enabled());
|
|
_ptrSendRtcpSocket = UdpSocketWrapper::CreateSocket(_id, _mgr, NULL, NULL,
|
|
IpV6Enabled());
|
|
|
|
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
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
return _receiving;
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransportImpl::StopReceiving()
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
|
|
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 WebRtc_Word8* ipaddr,
|
|
const WebRtc_UWord16 rtpPort,
|
|
const WebRtc_UWord16 rtcpPort)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
{
|
|
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 WebRtc_Word8* 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<WebRtc_Word8*>(ip));
|
|
}
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransportImpl::SendRaw(const WebRtc_Word8 *data,
|
|
WebRtc_UWord32 length,
|
|
WebRtc_Word32 isRTCP,
|
|
WebRtc_UWord16 portnr,
|
|
const WebRtc_Word8 *ip)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
|
|
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)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
|
|
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)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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 = UdpSocketWrapper::CreateSocket(_id, _mgr, this,
|
|
IncomingRTPCallback,
|
|
IpV6Enabled());
|
|
|
|
// 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)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
|
|
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 = UdpSocketWrapper::CreateSocket(_id, _mgr, this,
|
|
IncomingRTCPCallback,
|
|
IpV6Enabled());
|
|
|
|
// 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 WebRtc_Word8* ipaddr)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, _id, "%s", __FUNCTION__);
|
|
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)
|
|
{
|
|
WebRtc_Word8 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
|
|
{
|
|
strncpy(_fromIP, ipAddress, kIpAddressVersion6Length);
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
WebRtc_Word8 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 {
|
|
strncpy(_fromIP, ipAddress, kIpAddressVersion6Length);
|
|
}
|
|
|
|
// 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 WebRtc_Word8* ip)
|
|
{
|
|
return ::inet_addr(ip);
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransport::InetPresentationToNumeric(WebRtc_Word32 af,
|
|
const WebRtc_Word8* 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(WebRtc_UWord8 localIP[16])
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, -1, "%s", __FUNCTION__);
|
|
|
|
#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++)
|
|
{
|
|
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(localIP[n] != 0)
|
|
{
|
|
islocalIP = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(islocalIP && localIP[15] != 1)
|
|
{
|
|
islocalIP = false;
|
|
}
|
|
|
|
if(islocalIP && ptr->ai_next)
|
|
{
|
|
continue;
|
|
}
|
|
if(localIP[0] == 0xfe && 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)
|
|
{
|
|
bool islocalIP = true;
|
|
for(int n = 2; n< 15; n++)
|
|
{
|
|
if(ptrIfAddrs->ifa_addr->sa_data[n+6] != 0)
|
|
{
|
|
islocalIP = false;
|
|
break;
|
|
}
|
|
}
|
|
if(islocalIP && ptrIfAddrs->ifa_addr->sa_data[15+6] != 1)
|
|
{
|
|
islocalIP = false;
|
|
}
|
|
|
|
if(!islocalIP)
|
|
{
|
|
for(int i = 0; i< 16; i++)
|
|
{
|
|
localIP[i] = ptrIfAddrs->ifa_addr->sa_data[i+6];
|
|
}
|
|
if(localIP[0] == 0xfe && localIP[1] == 0x80 &&
|
|
ptrIfAddrs->ifa_next)
|
|
{
|
|
ptrIfAddrs = ptrIfAddrs->ifa_next;
|
|
continue;
|
|
}
|
|
freeifaddrs(ptrIfAddrsStart);
|
|
return 0;
|
|
}
|
|
}
|
|
ptrIfAddrs = ptrIfAddrs->ifa_next;
|
|
}
|
|
freeifaddrs(ptrIfAddrsStart);
|
|
return -1;
|
|
#elif defined(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);
|
|
|
|
// 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++)
|
|
{
|
|
localIP[i] = in6p->s6_addr[i];
|
|
}
|
|
if(localIP[0] == 0xfe && localIP[1] == 0x80)
|
|
{
|
|
// Auto configured IP.
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransport::LocalHostAddress(WebRtc_UWord32& localIP)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, -1, "%s", __FUNCTION__);
|
|
#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))
|
|
{
|
|
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);
|
|
return 0;
|
|
}
|
|
}
|
|
close(sockfd);
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
WebRtc_Word32 UdpTransport::IPAddress(const SocketAddress& address,
|
|
WebRtc_Word8* 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".
|
|
WebRtc_Word8* 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".
|
|
WebRtc_Word8* 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 WebRtc_Word8* ipadr, const bool ipV6)
|
|
{
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceTransport, -1, "%s", __FUNCTION__);
|
|
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;
|
|
WebRtc_Word8 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] == (WebRtc_Word8)'.')
|
|
{
|
|
// 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)
|
|
{
|
|
WebRtc_Word8 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)
|
|
{
|
|
WebRtc_Word8 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)
|
|
{
|
|
WebRtc_Word8 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 webrtc
|