| /* |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "webrtc/test/channel_transport/udp_transport_impl.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| |
| #if defined(_WIN32) |
| #include <winsock2.h> |
| #include <ws2tcpip.h> |
| #elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) |
| #include <arpa/inet.h> |
| #include <ctype.h> |
| #include <fcntl.h> |
| #include <net/if.h> |
| #include <netdb.h> |
| #include <netinet/in.h> |
| #include <stdlib.h> |
| #include <sys/ioctl.h> |
| #include <sys/socket.h> |
| #include <sys/time.h> |
| #include <unistd.h> |
| #ifndef WEBRTC_IOS |
| #include <net/if_arp.h> |
| #endif |
| #endif // defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) |
| |
| #if defined(WEBRTC_MAC) |
| #include <ifaddrs.h> |
| #include <machine/types.h> |
| #endif |
| #if defined(WEBRTC_LINUX) |
| #include <linux/netlink.h> |
| #include <linux/rtnetlink.h> |
| #endif |
| |
| #include "webrtc/common_types.h" |
| #include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
| #include "webrtc/system_wrappers/include/rw_lock_wrapper.h" |
| #include "webrtc/system_wrappers/include/trace.h" |
| #include "webrtc/test/channel_transport/udp_socket_manager_wrapper.h" |
| #include "webrtc/typedefs.h" |
| |
| #if defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) |
| #define GetLastError() errno |
| |
| #define IFRSIZE ((int)(size * sizeof (struct ifreq))) |
| |
| #define NLMSG_OK_NO_WARNING(nlh,len) \ |
| ((len) >= (int)sizeof(struct nlmsghdr) && \ |
| (int)(nlh)->nlmsg_len >= (int)sizeof(struct nlmsghdr) && \ |
| (int)(nlh)->nlmsg_len <= (len)) |
| |
| #endif // defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) |
| |
| namespace webrtc { |
| namespace test { |
| |
| class SocketFactory : public UdpTransportImpl::SocketFactoryInterface { |
| public: |
| UdpSocketWrapper* CreateSocket(const int32_t id, |
| UdpSocketManager* mgr, |
| CallbackObj obj, |
| IncomingSocketCallback cb, |
| bool ipV6Enable, |
| bool disableGQOS) override { |
| return UdpSocketWrapper::CreateSocket(id, mgr, obj, cb, ipV6Enable, |
| disableGQOS); |
| } |
| }; |
| |
| // Creates an UdpTransport using the definition of SocketFactory above, |
| // and passes (creating if needed) a pointer to the static singleton |
| // UdpSocketManager. |
| UdpTransport* UdpTransport::Create(const int32_t id, |
| uint8_t& numSocketThreads) |
| { |
| return new UdpTransportImpl(id, |
| new SocketFactory(), |
| UdpSocketManager::Create(id, numSocketThreads)); |
| } |
| |
| // Deletes the UdpTransport and decrements the refcount of the |
| // static singleton UdpSocketManager, possibly destroying it. |
| // Should only be used on UdpTransports that are created using Create. |
| void UdpTransport::Destroy(UdpTransport* module) |
| { |
| if(module) |
| { |
| delete module; |
| UdpSocketManager::Return(); |
| } |
| } |
| |
| UdpTransportImpl::UdpTransportImpl(const int32_t id, |
| SocketFactoryInterface* maker, |
| UdpSocketManager* socket_manager) |
| : _id(id), |
| _socket_creator(maker), |
| _crit(CriticalSectionWrapper::CreateCriticalSection()), |
| _critFilter(CriticalSectionWrapper::CreateCriticalSection()), |
| _critPacketCallback(CriticalSectionWrapper::CreateCriticalSection()), |
| _mgr(socket_manager), |
| _lastError(kNoSocketError), |
| _destPort(0), |
| _destPortRTCP(0), |
| _localPort(0), |
| _localPortRTCP(0), |
| _srcPort(0), |
| _srcPortRTCP(0), |
| _fromPort(0), |
| _fromPortRTCP(0), |
| _fromIP(), |
| _destIP(), |
| _localIP(), |
| _localMulticastIP(), |
| _ptrRtpSocket(NULL), |
| _ptrRtcpSocket(NULL), |
| _ptrSendRtpSocket(NULL), |
| _ptrSendRtcpSocket(NULL), |
| _remoteRTPAddr(), |
| _remoteRTCPAddr(), |
| _localRTPAddr(), |
| _localRTCPAddr(), |
| _tos(0), |
| _receiving(false), |
| _useSetSockOpt(false), |
| _qos(false), |
| _pcp(0), |
| _ipV6Enabled(false), |
| _serviceType(0), |
| _overrideDSCP(0), |
| _maxBitrate(0), |
| _cachLock(RWLockWrapper::CreateRWLock()), |
| _previousAddress(), |
| _previousIP(), |
| _previousIPSize(0), |
| _previousSourcePort(0), |
| _filterIPAddress(), |
| _rtpFilterPort(0), |
| _rtcpFilterPort(0), |
| _packetCallback(0) |
| { |
| memset(&_remoteRTPAddr, 0, sizeof(_remoteRTPAddr)); |
| memset(&_remoteRTCPAddr, 0, sizeof(_remoteRTCPAddr)); |
| memset(&_localRTPAddr, 0, sizeof(_localRTPAddr)); |
| memset(&_localRTCPAddr, 0, sizeof(_localRTCPAddr)); |
| |
| memset(_fromIP, 0, sizeof(_fromIP)); |
| memset(_destIP, 0, sizeof(_destIP)); |
| memset(_localIP, 0, sizeof(_localIP)); |
| memset(_localMulticastIP, 0, sizeof(_localMulticastIP)); |
| |
| memset(&_filterIPAddress, 0, sizeof(_filterIPAddress)); |
| |
| WEBRTC_TRACE(kTraceMemory, kTraceTransport, id, "%s created", __FUNCTION__); |
| } |
| |
| UdpTransportImpl::~UdpTransportImpl() |
| { |
| CloseSendSockets(); |
| CloseReceiveSockets(); |
| delete _crit; |
| delete _critFilter; |
| delete _critPacketCallback; |
| delete _cachLock; |
| delete _socket_creator; |
| |
| WEBRTC_TRACE(kTraceMemory, kTraceTransport, _id, "%s deleted", |
| __FUNCTION__); |
| } |
| |
| UdpTransport::ErrorCode UdpTransportImpl::LastError() const |
| { |
| return _lastError; |
| } |
| |
| bool SameAddress(const SocketAddress& address1, const SocketAddress& address2) |
| { |
| return (memcmp(&address1,&address2,sizeof(address1)) == 0); |
| } |
| |
| void UdpTransportImpl::GetCachedAddress(char* ip, |
| uint32_t& ipSize, |
| uint16_t& sourcePort) |
| { |
| const uint32_t 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(int8_t)*(ipSize + 1)); |
| ip[originalIPSize - 1] = '\0'; |
| sourcePort = _previousSourcePort; |
| } |
| |
| int32_t UdpTransportImpl::IPAddressCached(const SocketAddress& address, |
| char* ip, |
| uint32_t& ipSize, |
| uint16_t& 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; |
| } |
| |
| int32_t UdpTransportImpl::InitializeReceiveSockets( |
| UdpTransportData* const packetCallback, |
| const uint16_t portnr, |
| const char* ip, |
| const char* multicastIpAddr, |
| const uint16_t rtcpPort) |
| { |
| { |
| CriticalSectionScoped cs(_critPacketCallback); |
| _packetCallback = packetCallback; |
| |
| if(packetCallback == NULL) |
| { |
| WEBRTC_TRACE(kTraceStateInfo, kTraceTransport, _id, |
| "Closing down receive sockets"); |
| return 0; |
| } |
| } |
| |
| CriticalSectionScoped cs(_crit); |
| CloseReceiveSockets(); |
| |
| if(portnr == 0) |
| { |
| // TODO (hellner): why not just fail here? |
| if(_destPort == 0) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "InitializeReceiveSockets port 0 not allowed"); |
| _lastError = kPortInvalid; |
| return -1; |
| } |
| _localPort = _destPort; |
| } else { |
| _localPort = portnr; |
| } |
| if(rtcpPort) |
| { |
| _localPortRTCP = rtcpPort; |
| }else { |
| _localPortRTCP = _localPort + 1; |
| WEBRTC_TRACE( |
| kTraceStateInfo, |
| kTraceTransport, |
| _id, |
| "InitializeReceiveSockets RTCP port not configured using RTP\ |
| port+1=%d", |
| _localPortRTCP); |
| } |
| |
| if(ip) |
| { |
| if(IsIpAddressValid(ip,IpV6Enabled())) |
| { |
| strncpy(_localIP, ip,kIpAddressVersion6Length); |
| } else |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "InitializeReceiveSockets invalid IP address"); |
| _lastError = kIpAddressInvalid; |
| return -1; |
| } |
| }else |
| { |
| // Don't bind to a specific IP address. |
| if(! IpV6Enabled()) |
| { |
| strncpy(_localIP, "0.0.0.0",16); |
| } else |
| { |
| strncpy(_localIP, "0000:0000:0000:0000:0000:0000:0000:0000", |
| kIpAddressVersion6Length); |
| } |
| } |
| if(multicastIpAddr && !IpV6Enabled()) |
| { |
| if(IsIpAddressValid(multicastIpAddr,IpV6Enabled())) |
| { |
| strncpy(_localMulticastIP, multicastIpAddr, |
| kIpAddressVersion6Length); |
| } else |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "InitializeReceiveSockets invalid IP address"); |
| _lastError = kIpAddressInvalid; |
| return -1; |
| } |
| } |
| if(_mgr == NULL) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "InitializeReceiveSockets no socket manager"); |
| return -1; |
| } |
| |
| _useSetSockOpt=false; |
| _tos=0; |
| _pcp=0; |
| |
| _ptrRtpSocket = _socket_creator->CreateSocket(_id, _mgr, this, |
| IncomingRTPCallback, |
| IpV6Enabled(), false); |
| |
| _ptrRtcpSocket = _socket_creator->CreateSocket(_id, _mgr, this, |
| IncomingRTCPCallback, |
| IpV6Enabled(), false); |
| |
| ErrorCode retVal = BindLocalRTPSocket(); |
| if(retVal != kNoSocketError) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "InitializeReceiveSockets faild to bind RTP socket"); |
| _lastError = retVal; |
| CloseReceiveSockets(); |
| return -1; |
| } |
| retVal = BindLocalRTCPSocket(); |
| if(retVal != kNoSocketError) |
| { |
| _lastError = retVal; |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "InitializeReceiveSockets faild to bind RTCP socket"); |
| CloseReceiveSockets(); |
| return -1; |
| } |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::ReceiveSocketInformation( |
| char ipAddr[kIpAddressVersion6Length], |
| uint16_t& rtpPort, |
| uint16_t& rtcpPort, |
| char multicastIpAddr[kIpAddressVersion6Length]) const |
| { |
| CriticalSectionScoped cs(_crit); |
| rtpPort = _localPort; |
| rtcpPort = _localPortRTCP; |
| if (ipAddr) |
| { |
| strncpy(ipAddr, _localIP, IpV6Enabled() ? |
| UdpTransport::kIpAddressVersion6Length : |
| UdpTransport::kIpAddressVersion4Length); |
| } |
| if (multicastIpAddr) |
| { |
| strncpy(multicastIpAddr, _localMulticastIP, IpV6Enabled() ? |
| UdpTransport::kIpAddressVersion6Length : |
| UdpTransport::kIpAddressVersion4Length); |
| } |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::SendSocketInformation( |
| char ipAddr[kIpAddressVersion6Length], |
| uint16_t& rtpPort, |
| uint16_t& rtcpPort) const |
| { |
| CriticalSectionScoped cs(_crit); |
| rtpPort = _destPort; |
| rtcpPort = _destPortRTCP; |
| strncpy(ipAddr, _destIP, IpV6Enabled() ? |
| UdpTransport::kIpAddressVersion6Length : |
| UdpTransport::kIpAddressVersion4Length); |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::RemoteSocketInformation( |
| char ipAddr[kIpAddressVersion6Length], |
| uint16_t& rtpPort, |
| uint16_t& rtcpPort) const |
| { |
| CriticalSectionScoped cs(_crit); |
| rtpPort = _fromPort; |
| rtcpPort = _fromPortRTCP; |
| if(ipAddr) |
| { |
| strncpy(ipAddr, _fromIP, IpV6Enabled() ? |
| kIpAddressVersion6Length : |
| kIpAddressVersion4Length); |
| } |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::FilterPorts( |
| uint16_t& rtpFilterPort, |
| uint16_t& rtcpFilterPort) const |
| { |
| CriticalSectionScoped cs(_critFilter); |
| rtpFilterPort = _rtpFilterPort; |
| rtcpFilterPort = _rtcpFilterPort; |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::SetQoS(bool QoS, int32_t serviceType, |
| uint32_t maxBitrate, |
| int32_t overrideDSCP, bool audio) |
| { |
| if(QoS) |
| { |
| return EnableQoS(serviceType, audio, maxBitrate, overrideDSCP); |
| }else |
| { |
| return DisableQoS(); |
| } |
| } |
| |
| int32_t UdpTransportImpl::EnableQoS(int32_t serviceType, |
| bool audio, uint32_t maxBitrate, |
| int32_t 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 int32_t min_policed_size = 12; |
| // Max SDU, maximum packet size permitted or used in the traffic flow, in |
| // bytes. |
| const int32_t 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 int32_t 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 int32_t bucket_size = maxBitrate * 8; |
| const int32_t 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 int32_t 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 int32_t bucket_size = maxBitrate*31; |
| const int32_t 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 int32_t token_rate = 30000; |
| const int32_t bucket_size = 2000; |
| const int32_t 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 int32_t token_rate = 128000*10; |
| const int32_t bucket_size = 32000; |
| const int32_t 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 int32_t token_rate = 200; |
| const int32_t bucket_size = 200; |
| const int32_t 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 int32_t token_rate = 5000; |
| const int32_t bucket_size = 100; |
| const int32_t 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; |
| } |
| |
| int32_t 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 int32_t service_type = 0; // = SERVICETYPE_NOTRAFFIC |
| const int32_t 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; |
| } |
| |
| int32_t UdpTransportImpl::QoS(bool& QoS, int32_t& serviceType, |
| int32_t& overrideDSCP) const |
| { |
| CriticalSectionScoped cs(_crit); |
| QoS = _qos; |
| serviceType = _serviceType; |
| overrideDSCP = _overrideDSCP; |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::SetToS(int32_t DSCP, bool useSetSockOpt) |
| { |
| if (_qos) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "QoS already enabled"); |
| _lastError = kQosError; |
| return -1; |
| } |
| if (DSCP < 0 || DSCP > 63) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "Invalid DSCP"); |
| _lastError = kTosInvalid; |
| return -1; |
| } |
| if(_tos) |
| { |
| if(useSetSockOpt != _useSetSockOpt) |
| { |
| WEBRTC_TRACE( |
| kTraceError, |
| kTraceTransport, |
| _id, |
| "Can't switch SetSockOpt method without disabling TOS first"); |
| _lastError = kTosInvalid; |
| return -1; |
| } |
| } |
| CriticalSectionScoped cs(_crit); |
| UdpSocketWrapper* rtpSock = NULL; |
| UdpSocketWrapper* rtcpSock = NULL; |
| if(_ptrSendRtpSocket) |
| { |
| rtpSock = _ptrSendRtpSocket; |
| }else |
| { |
| rtpSock = _ptrRtpSocket; |
| } |
| if (rtpSock == NULL) |
| { |
| _lastError = kSocketInvalid; |
| return -1; |
| } |
| if(!rtpSock->ValidHandle()) |
| { |
| _lastError = kSocketInvalid; |
| return -1; |
| } |
| if(_ptrSendRtcpSocket) |
| { |
| rtcpSock = _ptrSendRtcpSocket; |
| }else |
| { |
| rtcpSock = _ptrRtcpSocket; |
| } |
| if (rtcpSock == NULL) |
| { |
| _lastError = kSocketInvalid; |
| return -1; |
| } |
| if(!rtcpSock->ValidHandle()) |
| { |
| _lastError = kSocketInvalid; |
| return -1; |
| } |
| |
| if (useSetSockOpt) |
| { |
| #ifdef _WIN32 |
| OSVERSIONINFO OsVersion; |
| OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); |
| GetVersionEx(&OsVersion); |
| // Disable QoS before setting ToS on Windows XP. This is done by closing |
| // and re-opening the sockets. |
| // TODO (hellner): why not just fail here and force the user to |
| // re-initialize sockets? Doing this may trick the user |
| // into thinking that the sockets are in a state which |
| // they aren't. |
| if (OsVersion.dwMajorVersion == 5 && |
| OsVersion.dwMinorVersion == 1) |
| { |
| if(!_useSetSockOpt) |
| { |
| if(_ptrSendRtpSocket) |
| { |
| CloseSendSockets(); |
| _ptrSendRtpSocket = |
| _socket_creator->CreateSocket(_id, _mgr, NULL, |
| NULL, IpV6Enabled(), |
| true); |
| _ptrSendRtcpSocket = |
| _socket_creator->CreateSocket(_id, _mgr, NULL, |
| NULL, IpV6Enabled(), |
| true); |
| rtpSock=_ptrSendRtpSocket; |
| rtcpSock=_ptrSendRtcpSocket; |
| ErrorCode retVal = BindRTPSendSocket(); |
| if(retVal != kNoSocketError) |
| { |
| _lastError = retVal; |
| return -1; |
| } |
| retVal = BindRTCPSendSocket(); |
| if(retVal != kNoSocketError) |
| { |
| _lastError = retVal; |
| return -1; |
| } |
| } |
| else |
| { |
| bool receiving=_receiving; |
| uint32_t noOfReceiveBuffers = 0; |
| if(receiving) |
| { |
| noOfReceiveBuffers=_ptrRtpSocket->ReceiveBuffers(); |
| if(StopReceiving()!=0) |
| { |
| return -1; |
| } |
| } |
| CloseReceiveSockets(); |
| _ptrRtpSocket = _socket_creator->CreateSocket( |
| _id, _mgr, this, IncomingRTPCallback, IpV6Enabled(), |
| true); |
| _ptrRtcpSocket = _socket_creator->CreateSocket( |
| _id, _mgr, this, IncomingRTCPCallback, IpV6Enabled(), |
| true); |
| rtpSock=_ptrRtpSocket; |
| rtcpSock=_ptrRtcpSocket; |
| ErrorCode retVal = BindLocalRTPSocket(); |
| if(retVal != kNoSocketError) |
| { |
| _lastError = retVal; |
| return -1; |
| } |
| retVal = BindLocalRTCPSocket(); |
| if(retVal != kNoSocketError) |
| { |
| _lastError = retVal; |
| return -1; |
| } |
| if(receiving) |
| { |
| if(StartReceiving(noOfReceiveBuffers) != |
| kNoSocketError) |
| { |
| return -1; |
| } |
| } |
| } |
| } |
| } |
| #endif // #ifdef _WIN32 |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, |
| "Setting TOS using SetSockopt"); |
| int32_t TOSShifted = DSCP << 2; |
| if (!rtpSock->SetSockopt(IPPROTO_IP, IP_TOS, |
| (int8_t*) &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, |
| (int8_t*) &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; |
| } |
| |
| int32_t UdpTransportImpl::ToS(int32_t& DSCP, |
| bool& useSetSockOpt) const |
| { |
| CriticalSectionScoped cs(_crit); |
| DSCP = _tos; |
| useSetSockOpt = _useSetSockOpt; |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::SetPCP(int32_t PCP) |
| { |
| |
| if (_qos) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "QoS already enabled"); |
| _lastError = kQosError; |
| return -1; |
| } |
| if ((PCP < 0) || (PCP > 7)) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "Invalid PCP"); |
| _lastError = kPcpError; |
| return -1; |
| } |
| |
| CriticalSectionScoped cs(_crit); |
| UdpSocketWrapper* rtpSock = NULL; |
| UdpSocketWrapper* rtcpSock = NULL; |
| if(_ptrSendRtpSocket) |
| { |
| rtpSock = _ptrSendRtpSocket; |
| }else |
| { |
| rtpSock = _ptrRtpSocket; |
| } |
| if (rtpSock == NULL) |
| { |
| _lastError = kSocketInvalid; |
| return -1; |
| } |
| if(!rtpSock->ValidHandle()) |
| { |
| _lastError = kSocketInvalid; |
| return -1; |
| } |
| if(_ptrSendRtcpSocket) |
| { |
| rtcpSock = _ptrSendRtcpSocket; |
| }else |
| { |
| rtcpSock = _ptrRtcpSocket; |
| } |
| if (rtcpSock == NULL) |
| { |
| _lastError = kSocketInvalid; |
| return -1; |
| } |
| if(!rtcpSock->ValidHandle()) |
| { |
| _lastError = kSocketInvalid; |
| return -1; |
| } |
| |
| #if defined(_WIN32) |
| if (rtpSock->SetPCP(PCP) != 0) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "Could not set PCP value on RTP socket"); |
| _lastError = kPcpError; |
| return -1; |
| } |
| if (rtcpSock->SetPCP(PCP) != 0) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "Could not set PCP value on RTCP socket"); |
| _lastError = kPcpError; |
| return -1; |
| } |
| |
| #elif defined(WEBRTC_LINUX) |
| if (!rtpSock->SetSockopt(SOL_SOCKET, SO_PRIORITY, (int8_t*) &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, (int8_t*) &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; |
| } |
| |
| int32_t UdpTransportImpl::PCP(int32_t& PCP) const |
| { |
| CriticalSectionScoped cs(_crit); |
| PCP = _pcp; |
| return 0; |
| } |
| |
| bool UdpTransportImpl::SetSockOptUsed() |
| { |
| return _useSetSockOpt; |
| } |
| |
| int32_t UdpTransportImpl::EnableIpV6() { |
| |
| CriticalSectionScoped cs(_crit); |
| const bool initialized = (_ptrSendRtpSocket || _ptrRtpSocket); |
| |
| if (_ipV6Enabled) { |
| return 0; |
| } |
| if (initialized) { |
| _lastError = kIpVersion6Error; |
| return -1; |
| } |
| _ipV6Enabled = true; |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::FilterIP( |
| char filterIPAddress[kIpAddressVersion6Length]) const |
| { |
| |
| if(filterIPAddress == NULL) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "FilterIP: Invalid argument"); |
| return -1; |
| } |
| if(_filterIPAddress._sockaddr_storage.sin_family == 0) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "No Filter configured"); |
| return -1; |
| } |
| CriticalSectionScoped cs(_critFilter); |
| uint32_t ipSize = kIpAddressVersion6Length; |
| uint16_t sourcePort; |
| return IPAddress(_filterIPAddress, filterIPAddress, ipSize, sourcePort); |
| } |
| |
| int32_t UdpTransportImpl::SetFilterIP( |
| const char filterIPAddress[kIpAddressVersion6Length]) |
| { |
| if(filterIPAddress == NULL) |
| { |
| memset(&_filterIPAddress, 0, sizeof(_filterIPAddress)); |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, "Filter IP reset"); |
| return 0; |
| } |
| CriticalSectionScoped cs(_critFilter); |
| if (_ipV6Enabled) |
| { |
| _filterIPAddress._sockaddr_storage.sin_family = AF_INET6; |
| |
| if (InetPresentationToNumeric( |
| AF_INET6, |
| filterIPAddress, |
| &_filterIPAddress._sockaddr_in6.sin6_addr) < 0) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, "Failed to set\ |
| filter IP for IPv6"); |
| _lastError = FILTER_ERROR; |
| return -1; |
| } |
| } |
| else |
| { |
| _filterIPAddress._sockaddr_storage.sin_family = AF_INET; |
| |
| if(InetPresentationToNumeric( |
| AF_INET, |
| filterIPAddress, |
| &_filterIPAddress._sockaddr_in.sin_addr) < 0) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "Failed to set filter IP for IPv4"); |
| _lastError = FILTER_ERROR; |
| return -1; |
| } |
| } |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, "Filter IP set"); |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::SetFilterPorts(uint16_t rtpFilterPort, |
| uint16_t rtcpFilterPort) |
| { |
| CriticalSectionScoped cs(_critFilter); |
| _rtpFilterPort = rtpFilterPort; |
| _rtcpFilterPort = rtcpFilterPort; |
| return 0; |
| } |
| |
| bool UdpTransportImpl::SendSocketsInitialized() const |
| { |
| CriticalSectionScoped cs(_crit); |
| if(_ptrSendRtpSocket) |
| { |
| return true; |
| } |
| if(_destPort !=0) |
| { |
| return true; |
| } |
| return false; |
| } |
| |
| bool UdpTransportImpl::ReceiveSocketsInitialized() const |
| { |
| if(_ptrRtpSocket) |
| { |
| return true; |
| } |
| return false; |
| } |
| |
| bool UdpTransportImpl::SourcePortsInitialized() const |
| { |
| if(_ptrSendRtpSocket) |
| { |
| return true; |
| } |
| return false; |
| } |
| |
| bool UdpTransportImpl::IpV6Enabled() const |
| { |
| WEBRTC_TRACE(kTraceStream, kTraceTransport, _id, "%s", __FUNCTION__); |
| return _ipV6Enabled; |
| } |
| |
| void UdpTransportImpl::BuildRemoteRTPAddr() |
| { |
| if(_ipV6Enabled) |
| { |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| _remoteRTPAddr.sin_length = 0; |
| _remoteRTPAddr.sin_family = PF_INET6; |
| #else |
| _remoteRTPAddr._sockaddr_storage.sin_family = PF_INET6; |
| #endif |
| |
| _remoteRTPAddr._sockaddr_in6.sin6_flowinfo=0; |
| _remoteRTPAddr._sockaddr_in6.sin6_scope_id=0; |
| _remoteRTPAddr._sockaddr_in6.sin6_port = Htons(_destPort); |
| InetPresentationToNumeric(AF_INET6,_destIP, |
| &_remoteRTPAddr._sockaddr_in6.sin6_addr); |
| } else |
| { |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| _remoteRTPAddr.sin_length = 0; |
| _remoteRTPAddr.sin_family = PF_INET; |
| #else |
| _remoteRTPAddr._sockaddr_storage.sin_family = PF_INET; |
| #endif |
| _remoteRTPAddr._sockaddr_in.sin_port = Htons(_destPort); |
| _remoteRTPAddr._sockaddr_in.sin_addr = InetAddrIPV4(_destIP); |
| } |
| } |
| |
| void UdpTransportImpl::BuildRemoteRTCPAddr() |
| { |
| if(_ipV6Enabled) |
| { |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| _remoteRTCPAddr.sin_length = 0; |
| _remoteRTCPAddr.sin_family = PF_INET6; |
| #else |
| _remoteRTCPAddr._sockaddr_storage.sin_family = PF_INET6; |
| #endif |
| |
| _remoteRTCPAddr._sockaddr_in6.sin6_flowinfo=0; |
| _remoteRTCPAddr._sockaddr_in6.sin6_scope_id=0; |
| _remoteRTCPAddr._sockaddr_in6.sin6_port = Htons(_destPortRTCP); |
| InetPresentationToNumeric(AF_INET6,_destIP, |
| &_remoteRTCPAddr._sockaddr_in6.sin6_addr); |
| |
| } else |
| { |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| _remoteRTCPAddr.sin_length = 0; |
| _remoteRTCPAddr.sin_family = PF_INET; |
| #else |
| _remoteRTCPAddr._sockaddr_storage.sin_family = PF_INET; |
| #endif |
| _remoteRTCPAddr._sockaddr_in.sin_port = Htons(_destPortRTCP); |
| _remoteRTCPAddr._sockaddr_in.sin_addr= InetAddrIPV4(_destIP); |
| } |
| } |
| |
| UdpTransportImpl::ErrorCode UdpTransportImpl::BindRTPSendSocket() |
| { |
| if(!_ptrSendRtpSocket) |
| { |
| return kSocketInvalid; |
| } |
| if(!_ptrSendRtpSocket->ValidHandle()) |
| { |
| return kIpAddressInvalid; |
| } |
| if(_ipV6Enabled) |
| { |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| _localRTPAddr.sin_length = 0; |
| _localRTPAddr.sin_family = PF_INET6; |
| #else |
| _localRTPAddr._sockaddr_storage.sin_family = PF_INET6; |
| #endif |
| _localRTPAddr._sockaddr_in6.sin6_flowinfo=0; |
| _localRTPAddr._sockaddr_in6.sin6_scope_id=0; |
| _localRTPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[0] = |
| 0; // = INADDR_ANY |
| _localRTPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[1] = |
| 0; |
| _localRTPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[2] = |
| 0; |
| _localRTPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[3] = |
| 0; |
| _localRTPAddr._sockaddr_in6.sin6_port = Htons(_srcPort); |
| if(_ptrSendRtpSocket->Bind(_localRTPAddr) == false) |
| { |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id, |
| "Failed to bind to port:%d ", _srcPort); |
| return kFailedToBindPort; |
| } |
| |
| } else { |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| _localRTPAddr.sin_length = 0; |
| _localRTPAddr.sin_family = PF_INET; |
| #else |
| _localRTPAddr._sockaddr_storage.sin_family = PF_INET; |
| #endif |
| _localRTPAddr._sockaddr_in.sin_addr = 0; |
| _localRTPAddr._sockaddr_in.sin_port = Htons(_srcPort); |
| if(_ptrSendRtpSocket->Bind(_localRTPAddr) == false) |
| { |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id, |
| "Failed to bind to port:%d ", _srcPort); |
| return kFailedToBindPort; |
| } |
| } |
| return kNoSocketError; |
| } |
| |
| UdpTransportImpl::ErrorCode UdpTransportImpl::BindRTCPSendSocket() |
| { |
| if(!_ptrSendRtcpSocket) |
| { |
| return kSocketInvalid; |
| } |
| |
| if(_ipV6Enabled) |
| { |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| _localRTCPAddr.sin_length = 0; |
| _localRTCPAddr.sin_family = PF_INET6; |
| #else |
| _localRTCPAddr._sockaddr_storage.sin_family = PF_INET6; |
| #endif |
| _localRTCPAddr._sockaddr_in6.sin6_flowinfo=0; |
| _localRTCPAddr._sockaddr_in6.sin6_scope_id=0; |
| _localRTCPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[0] = |
| 0; // = INADDR_ANY |
| _localRTCPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[1] = |
| 0; |
| _localRTCPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[2] = |
| 0; |
| _localRTCPAddr._sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u32[3] = |
| 0; |
| _localRTCPAddr._sockaddr_in6.sin6_port = Htons(_srcPortRTCP); |
| if(_ptrSendRtcpSocket->Bind(_localRTCPAddr) == false) |
| { |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id, |
| "Failed to bind to port:%d ", _srcPortRTCP); |
| return kFailedToBindPort; |
| } |
| } else { |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| _localRTCPAddr.sin_length = 0; |
| _localRTCPAddr.sin_family = PF_INET; |
| #else |
| _localRTCPAddr._sockaddr_storage.sin_family = PF_INET; |
| #endif |
| _localRTCPAddr._sockaddr_in.sin_addr= 0; |
| _localRTCPAddr._sockaddr_in.sin_port = Htons(_srcPortRTCP); |
| if(_ptrSendRtcpSocket->Bind(_localRTCPAddr) == false) |
| { |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id, |
| "Failed to bind to port:%d ", _srcPortRTCP); |
| return kFailedToBindPort; |
| } |
| } |
| return kNoSocketError; |
| } |
| |
| UdpTransportImpl::ErrorCode UdpTransportImpl::BindLocalRTPSocket() |
| { |
| if(!_ptrRtpSocket) |
| { |
| return kSocketInvalid; |
| } |
| if(!IpV6Enabled()) |
| { |
| SocketAddress recAddr; |
| memset(&recAddr, 0, sizeof(SocketAddress)); |
| recAddr._sockaddr_storage.sin_family = AF_INET; |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| recAddr.sin_length = 0; |
| recAddr.sin_family = PF_INET; |
| #else |
| recAddr._sockaddr_storage.sin_family = PF_INET; |
| #endif |
| recAddr._sockaddr_in.sin_addr = InetAddrIPV4(_localIP); |
| recAddr._sockaddr_in.sin_port = Htons(_localPort); |
| |
| if (!_ptrRtpSocket->Bind(recAddr)) |
| { |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id, |
| "Failed to bind to port:%d ", _localPort); |
| return kFailedToBindPort; |
| } |
| } |
| else |
| { |
| SocketAddress stLclName; |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| stLclName.sin_lenght = 0; |
| stLclName.sin_family = PF_INET6; |
| #else |
| stLclName._sockaddr_storage.sin_family = PF_INET6; |
| #endif |
| InetPresentationToNumeric(AF_INET6,_localIP, |
| &stLclName._sockaddr_in6.sin6_addr); |
| stLclName._sockaddr_in6.sin6_port = Htons(_localPort); |
| stLclName._sockaddr_in6.sin6_flowinfo = 0; |
| stLclName._sockaddr_in6.sin6_scope_id = 0; |
| |
| if (!_ptrRtpSocket->Bind(stLclName)) |
| { |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, _id, |
| "Failed to bind to port:%d ", _localPort); |
| return kFailedToBindPort; |
| } |
| } |
| |
| if(_localMulticastIP[0] != 0) |
| { |
| // Join the multicast group from which to receive datagrams. |
| struct ip_mreq mreq; |
| mreq.imr_multiaddr.s_addr = InetAddrIPV4(_localMulticastIP); |
| mreq.imr_interface.s_addr = INADDR_ANY; |
| |
| if (!_ptrRtpSocket->SetSockopt(IPPROTO_IP,IP_ADD_MEMBERSHIP, |
| (int8_t*)&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, |
| (int8_t*)&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; |
| } |
| |
| int32_t UdpTransportImpl::InitializeSourcePorts(uint16_t rtpPort, |
| uint16_t rtcpPort) |
| { |
| |
| if(rtpPort == 0) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "InitializeSourcePorts port 0 not allowed"); |
| _lastError = kPortInvalid; |
| return -1; |
| } |
| |
| CriticalSectionScoped cs(_crit); |
| |
| CloseSendSockets(); |
| |
| if(_mgr == NULL) |
| { |
| return -1; |
| } |
| |
| _srcPort = rtpPort; |
| if(rtcpPort == 0) |
| { |
| _srcPortRTCP = rtpPort+1; |
| } else |
| { |
| _srcPortRTCP = rtcpPort; |
| } |
| _useSetSockOpt =false; |
| _tos=0; |
| _pcp=0; |
| |
| _ptrSendRtpSocket = _socket_creator->CreateSocket(_id, _mgr, NULL, NULL, |
| IpV6Enabled(), false); |
| _ptrSendRtcpSocket = _socket_creator->CreateSocket(_id, _mgr, NULL, NULL, |
| IpV6Enabled(), false); |
| |
| ErrorCode retVal = BindRTPSendSocket(); |
| if(retVal != kNoSocketError) |
| { |
| _lastError = retVal; |
| return -1; |
| } |
| retVal = BindRTCPSendSocket(); |
| if(retVal != kNoSocketError) |
| { |
| _lastError = retVal; |
| return -1; |
| } |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::SourcePorts(uint16_t& rtpPort, |
| uint16_t& rtcpPort) const |
| { |
| CriticalSectionScoped cs(_crit); |
| |
| rtpPort = (_srcPort != 0) ? _srcPort : _localPort; |
| rtcpPort = (_srcPortRTCP != 0) ? _srcPortRTCP : _localPortRTCP; |
| return 0; |
| } |
| |
| |
| #ifdef _WIN32 |
| int32_t UdpTransportImpl::StartReceiving(uint32_t numberOfSocketBuffers) |
| #else |
| int32_t UdpTransportImpl::StartReceiving(uint32_t /*numberOfSocketBuffers*/) |
| #endif |
| { |
| CriticalSectionScoped cs(_crit); |
| if(_receiving) |
| { |
| return 0; |
| } |
| if(_ptrRtpSocket) |
| { |
| #ifdef _WIN32 |
| if(!_ptrRtpSocket->StartReceiving(numberOfSocketBuffers)) |
| #else |
| if(!_ptrRtpSocket->StartReceiving()) |
| #endif |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "Failed to start receive on RTP socket"); |
| _lastError = kStartReceiveError; |
| return -1; |
| } |
| } |
| if(_ptrRtcpSocket) |
| { |
| if(!_ptrRtcpSocket->StartReceiving()) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "Failed to start receive on RTCP socket"); |
| _lastError = kStartReceiveError; |
| return -1; |
| } |
| } |
| if( _ptrRtpSocket == NULL && |
| _ptrRtcpSocket == NULL) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "Failed to StartReceiving, no socket initialized"); |
| _lastError = kStartReceiveError; |
| return -1; |
| } |
| _receiving = true; |
| return 0; |
| } |
| |
| bool UdpTransportImpl::Receiving() const |
| { |
| return _receiving; |
| } |
| |
| int32_t UdpTransportImpl::StopReceiving() |
| { |
| |
| CriticalSectionScoped cs(_crit); |
| |
| _receiving = false; |
| |
| if (_ptrRtpSocket) |
| { |
| if (!_ptrRtpSocket->StopReceiving()) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "Failed to stop receiving on RTP socket"); |
| _lastError = kStopReceiveError; |
| return -1; |
| } |
| } |
| if (_ptrRtcpSocket) |
| { |
| if (!_ptrRtcpSocket->StopReceiving()) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "Failed to stop receiving on RTCP socket"); |
| _lastError = kStopReceiveError; |
| return -1; |
| } |
| } |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::InitializeSendSockets( |
| const char* ipaddr, |
| const uint16_t rtpPort, |
| const uint16_t rtcpPort) |
| { |
| { |
| CriticalSectionScoped cs(_crit); |
| _destPort = rtpPort; |
| if(rtcpPort == 0) |
| { |
| _destPortRTCP = _destPort+1; |
| } else |
| { |
| _destPortRTCP = rtcpPort; |
| } |
| |
| if(ipaddr == NULL) |
| { |
| if (!IsIpAddressValid(_destIP, IpV6Enabled())) |
| { |
| _destPort = 0; |
| _destPortRTCP = 0; |
| _lastError = kIpAddressInvalid; |
| return -1; |
| } |
| } else |
| { |
| if (IsIpAddressValid(ipaddr, IpV6Enabled())) |
| { |
| strncpy( |
| _destIP, |
| ipaddr, |
| IpV6Enabled() ? kIpAddressVersion6Length : |
| kIpAddressVersion4Length); |
| } else { |
| _destPort = 0; |
| _destPortRTCP = 0; |
| _lastError = kIpAddressInvalid; |
| return -1; |
| } |
| } |
| BuildRemoteRTPAddr(); |
| BuildRemoteRTCPAddr(); |
| } |
| |
| if (_ipV6Enabled) |
| { |
| if (_qos) |
| { |
| WEBRTC_TRACE( |
| kTraceWarning, |
| kTraceTransport, |
| _id, |
| "QOS is enabled but will be ignored since IPv6 is enabled"); |
| } |
| }else |
| { |
| // TODO (grunell): Multicast support is experimantal. |
| |
| // Put the first digit of the remote address in val. |
| int32_t 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 |
| int32_t iOptVal = 64; |
| if (!rtpSock->SetSockopt(IPPROTO_IP, IP_MULTICAST_TTL, |
| (int8_t*)&iOptVal, |
| sizeof (int32_t))) |
| { |
| 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, |
| (int8_t*)&iOptVal, |
| sizeof (int32_t))) |
| { |
| 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(uint16_t portnr, |
| const char* ip, |
| SocketAddress& remoteAddr) const |
| { |
| if(_ipV6Enabled) |
| { |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| remoteAddr.sin_length = 0; |
| remoteAddr.sin_family = PF_INET6; |
| #else |
| remoteAddr._sockaddr_storage.sin_family = PF_INET6; |
| #endif |
| remoteAddr._sockaddr_in6.sin6_port = Htons(portnr); |
| InetPresentationToNumeric(AF_INET6, ip, |
| &remoteAddr._sockaddr_in6.sin6_addr); |
| remoteAddr._sockaddr_in6.sin6_flowinfo=0; |
| remoteAddr._sockaddr_in6.sin6_scope_id=0; |
| } else |
| { |
| #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
| remoteAddr.sin_length = 0; |
| remoteAddr.sin_family = PF_INET; |
| #else |
| remoteAddr._sockaddr_storage.sin_family = PF_INET; |
| #endif |
| remoteAddr._sockaddr_in.sin_port = Htons(portnr); |
| remoteAddr._sockaddr_in.sin_addr= InetAddrIPV4( |
| const_cast<char*>(ip)); |
| } |
| } |
| |
| int32_t UdpTransportImpl::SendRaw(const int8_t *data, |
| size_t length, |
| int32_t isRTCP, |
| uint16_t portnr, |
| const char* ip) |
| { |
| CriticalSectionScoped cs(_crit); |
| if(isRTCP) |
| { |
| UdpSocketWrapper* rtcpSock = NULL; |
| if(_ptrSendRtcpSocket) |
| { |
| rtcpSock = _ptrSendRtcpSocket; |
| } else if(_ptrRtcpSocket) |
| { |
| rtcpSock = _ptrRtcpSocket; |
| } else |
| { |
| return -1; |
| } |
| if(portnr == 0 && ip == NULL) |
| { |
| return rtcpSock->SendTo(data,length,_remoteRTCPAddr); |
| |
| } else if(portnr != 0 && ip != NULL) |
| { |
| SocketAddress remoteAddr; |
| BuildSockaddrIn(portnr, ip, remoteAddr); |
| return rtcpSock->SendTo(data,length,remoteAddr); |
| } else if(ip != NULL) |
| { |
| SocketAddress remoteAddr; |
| BuildSockaddrIn(_destPortRTCP, ip, remoteAddr); |
| return rtcpSock->SendTo(data,length,remoteAddr); |
| } else |
| { |
| SocketAddress remoteAddr; |
| BuildSockaddrIn(portnr, _destIP, remoteAddr); |
| return rtcpSock->SendTo(data,length,remoteAddr); |
| } |
| } else { |
| UdpSocketWrapper* rtpSock = NULL; |
| if(_ptrSendRtpSocket) |
| { |
| rtpSock = _ptrSendRtpSocket; |
| |
| } else if(_ptrRtpSocket) |
| { |
| rtpSock = _ptrRtpSocket; |
| } else |
| { |
| return -1; |
| } |
| if(portnr == 0 && ip == NULL) |
| { |
| return rtpSock->SendTo(data,length,_remoteRTPAddr); |
| |
| } else if(portnr != 0 && ip != NULL) |
| { |
| SocketAddress remoteAddr; |
| BuildSockaddrIn(portnr, ip, remoteAddr); |
| return rtpSock->SendTo(data,length,remoteAddr); |
| } else if(ip != NULL) |
| { |
| SocketAddress remoteAddr; |
| BuildSockaddrIn(_destPort, ip, remoteAddr); |
| return rtpSock->SendTo(data,length,remoteAddr); |
| } else |
| { |
| SocketAddress remoteAddr; |
| BuildSockaddrIn(portnr, _destIP, remoteAddr); |
| return rtpSock->SendTo(data,length,remoteAddr); |
| } |
| } |
| } |
| |
| int32_t UdpTransportImpl::SendRTPPacketTo(const int8_t* data, |
| size_t length, |
| const SocketAddress& to) |
| { |
| CriticalSectionScoped cs(_crit); |
| if(_ptrSendRtpSocket) |
| { |
| return _ptrSendRtpSocket->SendTo(data,length,to); |
| |
| } else if(_ptrRtpSocket) |
| { |
| return _ptrRtpSocket->SendTo(data,length,to); |
| } |
| return -1; |
| } |
| |
| int32_t UdpTransportImpl::SendRTCPPacketTo(const int8_t* data, |
| size_t length, |
| const SocketAddress& to) |
| { |
| |
| CriticalSectionScoped cs(_crit); |
| |
| if(_ptrSendRtcpSocket) |
| { |
| return _ptrSendRtcpSocket->SendTo(data,length,to); |
| |
| } else if(_ptrRtcpSocket) |
| { |
| return _ptrRtcpSocket->SendTo(data,length,to); |
| } |
| return -1; |
| } |
| |
| int32_t UdpTransportImpl::SendRTPPacketTo(const int8_t* data, |
| size_t length, |
| const uint16_t rtpPort) |
| { |
| CriticalSectionScoped cs(_crit); |
| // Use the current SocketAdress but update it with rtpPort. |
| SocketAddress to; |
| memcpy(&to, &_remoteRTPAddr, sizeof(SocketAddress)); |
| |
| if(_ipV6Enabled) |
| { |
| to._sockaddr_in6.sin6_port = Htons(rtpPort); |
| } else |
| { |
| to._sockaddr_in.sin_port = Htons(rtpPort); |
| } |
| |
| if(_ptrSendRtpSocket) |
| { |
| return _ptrSendRtpSocket->SendTo(data,length,to); |
| |
| } else if(_ptrRtpSocket) |
| { |
| return _ptrRtpSocket->SendTo(data,length,to); |
| } |
| return -1; |
| } |
| |
| int32_t UdpTransportImpl::SendRTCPPacketTo(const int8_t* data, |
| size_t length, |
| const uint16_t rtcpPort) |
| { |
| CriticalSectionScoped cs(_crit); |
| |
| // Use the current SocketAdress but update it with rtcpPort. |
| SocketAddress to; |
| memcpy(&to, &_remoteRTCPAddr, sizeof(SocketAddress)); |
| |
| if(_ipV6Enabled) |
| { |
| to._sockaddr_in6.sin6_port = Htons(rtcpPort); |
| } else |
| { |
| to._sockaddr_in.sin_port = Htons(rtcpPort); |
| } |
| |
| if(_ptrSendRtcpSocket) |
| { |
| return _ptrSendRtcpSocket->SendTo(data,length,to); |
| |
| } else if(_ptrRtcpSocket) |
| { |
| return _ptrRtcpSocket->SendTo(data,length,to); |
| } |
| return -1; |
| } |
| |
| bool UdpTransportImpl::SendRtp(const uint8_t* data, |
| size_t length, |
| const PacketOptions& packet_options) { |
| WEBRTC_TRACE(kTraceStream, kTraceTransport, _id, "%s", __FUNCTION__); |
| |
| CriticalSectionScoped cs(_crit); |
| |
| if(_destIP[0] == 0) |
| { |
| return false; |
| } |
| if(_destPort == 0) |
| { |
| return false; |
| } |
| |
| // Create socket if it hasn't been set up already. |
| // TODO (hellner): why not fail here instead. Sockets not being initialized |
| // indicates that there is a problem somewhere. |
| if( _ptrSendRtpSocket == NULL && |
| _ptrRtpSocket == NULL) |
| { |
| WEBRTC_TRACE( |
| kTraceStateInfo, |
| kTraceTransport, |
| _id, |
| "Creating RTP socket since no receive or source socket is\ |
| configured"); |
| |
| _ptrRtpSocket = _socket_creator->CreateSocket(_id, _mgr, this, |
| IncomingRTPCallback, |
| IpV6Enabled(), false); |
| |
| // Don't bind to a specific IP address. |
| if(! IpV6Enabled()) |
| { |
| strncpy(_localIP, "0.0.0.0",16); |
| } else |
| { |
| strncpy(_localIP, "0000:0000:0000:0000:0000:0000:0000:0000", |
| kIpAddressVersion6Length); |
| } |
| _localPort = _destPort; |
| |
| ErrorCode retVal = BindLocalRTPSocket(); |
| if(retVal != kNoSocketError) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "SendPacket() failed to bind RTP socket"); |
| _lastError = retVal; |
| CloseReceiveSockets(); |
| return false; |
| } |
| } |
| |
| if(_ptrSendRtpSocket) |
| { |
| return _ptrSendRtpSocket->SendTo((const int8_t*)data, length, |
| _remoteRTPAddr) >= 0; |
| |
| } else if(_ptrRtpSocket) |
| { |
| return _ptrRtpSocket->SendTo((const int8_t*)data, length, |
| _remoteRTPAddr) >= 0; |
| } |
| return false; |
| } |
| |
| bool UdpTransportImpl::SendRtcp(const uint8_t* data, size_t length) { |
| CriticalSectionScoped cs(_crit); |
| if(_destIP[0] == 0) |
| { |
| return false; |
| } |
| if(_destPortRTCP == 0) |
| { |
| return false; |
| } |
| |
| // Create socket if it hasn't been set up already. |
| // TODO (hellner): why not fail here instead. Sockets not being initialized |
| // indicates that there is a problem somewhere. |
| if( _ptrSendRtcpSocket == NULL && |
| _ptrRtcpSocket == NULL) |
| { |
| WEBRTC_TRACE( |
| kTraceStateInfo, |
| kTraceTransport, |
| _id, |
| "Creating RTCP socket since no receive or source socket is\ |
| configured"); |
| |
| _ptrRtcpSocket = _socket_creator->CreateSocket(_id, _mgr, this, |
| IncomingRTCPCallback, |
| IpV6Enabled(), false); |
| |
| // Don't bind to a specific IP address. |
| if(! IpV6Enabled()) |
| { |
| strncpy(_localIP, "0.0.0.0",16); |
| } else |
| { |
| strncpy(_localIP, "0000:0000:0000:0000:0000:0000:0000:0000", |
| kIpAddressVersion6Length); |
| } |
| _localPortRTCP = _destPortRTCP; |
| |
| ErrorCode retVal = BindLocalRTCPSocket(); |
| if(retVal != kNoSocketError) |
| { |
| _lastError = retVal; |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "SendRtcp() failed to bind RTCP socket"); |
| CloseReceiveSockets(); |
| return false; |
| } |
| } |
| |
| if(_ptrSendRtcpSocket) |
| { |
| return _ptrSendRtcpSocket->SendTo((const int8_t*)data, length, |
| _remoteRTCPAddr) >= 0; |
| } else if(_ptrRtcpSocket) |
| { |
| return _ptrRtcpSocket->SendTo((const int8_t*)data, length, |
| _remoteRTCPAddr) >= 0; |
| } |
| return false; |
| } |
| |
| int32_t UdpTransportImpl::SetSendIP(const char* ipaddr) |
| { |
| if(!IsIpAddressValid(ipaddr,IpV6Enabled())) |
| { |
| return kIpAddressInvalid; |
| } |
| CriticalSectionScoped cs(_crit); |
| strncpy(_destIP, ipaddr,kIpAddressVersion6Length); |
| BuildRemoteRTPAddr(); |
| BuildRemoteRTCPAddr(); |
| return 0; |
| } |
| |
| int32_t UdpTransportImpl::SetSendPorts(uint16_t rtpPort, uint16_t rtcpPort) |
| { |
| CriticalSectionScoped cs(_crit); |
| _destPort = rtpPort; |
| if(rtcpPort == 0) |
| { |
| _destPortRTCP = _destPort+1; |
| } else |
| { |
| _destPortRTCP = rtcpPort; |
| } |
| BuildRemoteRTPAddr(); |
| BuildRemoteRTCPAddr(); |
| return 0; |
| } |
| |
| void UdpTransportImpl::IncomingRTPCallback(CallbackObj obj, |
| const int8_t* rtpPacket, |
| size_t rtpPacketLength, |
| const SocketAddress* from) |
| { |
| if (rtpPacket && rtpPacketLength > 0) |
| { |
| UdpTransportImpl* socketTransport = (UdpTransportImpl*) obj; |
| socketTransport->IncomingRTPFunction(rtpPacket, rtpPacketLength, from); |
| } |
| } |
| |
| void UdpTransportImpl::IncomingRTCPCallback(CallbackObj obj, |
| const int8_t* rtcpPacket, |
| size_t rtcpPacketLength, |
| const SocketAddress* from) |
| { |
| if (rtcpPacket && rtcpPacketLength > 0) |
| { |
| UdpTransportImpl* socketTransport = (UdpTransportImpl*) obj; |
| socketTransport->IncomingRTCPFunction(rtcpPacket, rtcpPacketLength, |
| from); |
| } |
| } |
| |
| void UdpTransportImpl::IncomingRTPFunction(const int8_t* rtpPacket, |
| size_t rtpPacketLength, |
| const SocketAddress* fromSocket) |
| { |
| char ipAddress[kIpAddressVersion6Length]; |
| uint32_t ipAddressLength = kIpAddressVersion6Length; |
| uint16_t portNr = 0; |
| |
| { |
| CriticalSectionScoped cs(_critFilter); |
| if (FilterIPAddress(fromSocket) == false) |
| { |
| // Packet should be filtered out. Drop it. |
| WEBRTC_TRACE(kTraceStream, kTraceTransport, _id, |
| "Incoming RTP packet blocked by IP filter"); |
| return; |
| } |
| |
| if (IPAddressCached(*fromSocket, ipAddress, ipAddressLength, portNr) < |
| 0) |
| { |
| WEBRTC_TRACE( |
| kTraceError, |
| kTraceTransport, |
| _id, |
| "UdpTransportImpl::IncomingRTPFunction - Cannot get sender\ |
| information"); |
| }else |
| { |
| // Make sure ipAddress is null terminated. |
| ipAddress[kIpAddressVersion6Length - 1] = 0; |
| strncpy(_fromIP, ipAddress, kIpAddressVersion6Length - 1); |
| } |
| |
| // Filter based on port. |
| if (_rtpFilterPort != 0 && |
| _rtpFilterPort != portNr) |
| { |
| // Drop packet. |
| memset(_fromIP, 0, sizeof(_fromIP)); |
| WEBRTC_TRACE( |
| kTraceStream, |
| kTraceTransport, |
| _id, |
| "Incoming RTP packet blocked by filter incoming from port:%d\ |
| allowed port:%d", |
| portNr, |
| _rtpFilterPort); |
| return; |
| } |
| _fromPort = portNr; |
| } |
| |
| CriticalSectionScoped cs(_critPacketCallback); |
| if (_packetCallback) |
| { |
| WEBRTC_TRACE(kTraceStream, kTraceTransport, _id, |
| "Incoming RTP packet from ip:%s port:%d", ipAddress, portNr); |
| _packetCallback->IncomingRTPPacket(rtpPacket, rtpPacketLength, |
| ipAddress, portNr); |
| } |
| } |
| |
| void UdpTransportImpl::IncomingRTCPFunction(const int8_t* rtcpPacket, |
| size_t rtcpPacketLength, |
| const SocketAddress* fromSocket) |
| { |
| char ipAddress[kIpAddressVersion6Length]; |
| uint32_t ipAddressLength = kIpAddressVersion6Length; |
| uint16_t portNr = 0; |
| |
| { |
| CriticalSectionScoped cs(_critFilter); |
| if (FilterIPAddress(fromSocket) == false) |
| { |
| // Packet should be filtered out. Drop it. |
| WEBRTC_TRACE(kTraceStream, kTraceTransport, _id, |
| "Incoming RTCP packet blocked by IP filter"); |
| return; |
| } |
| if (IPAddress(*fromSocket, ipAddress, ipAddressLength, portNr) < 0) |
| { |
| WEBRTC_TRACE( |
| kTraceError, |
| kTraceTransport, |
| _id, |
| "UdpTransportImpl::IncomingRTCPFunction - Cannot get sender\ |
| information"); |
| }else { |
| // Make sure ipAddress is null terminated. |
| ipAddress[kIpAddressVersion6Length - 1] = 0; |
| strncpy(_fromIP, ipAddress, kIpAddressVersion6Length - 1); |
| } |
| |
| // Filter based on port. |
| if (_rtcpFilterPort != 0 && |
| _rtcpFilterPort != portNr) |
| { |
| // Drop packet. |
| WEBRTC_TRACE( |
| kTraceStream, |
| kTraceTransport, |
| _id, |
| "Incoming RTCP packet blocked by filter incoming from port:%d\ |
| allowed port:%d", |
| portNr, |
| _rtpFilterPort); |
| return; |
| } |
| _fromPortRTCP = portNr; |
| } |
| |
| CriticalSectionScoped cs(_critPacketCallback); |
| if (_packetCallback) |
| { |
| WEBRTC_TRACE(kTraceStream, kTraceTransport, _id, |
| "Incoming RTCP packet from ip:%s port:%d", ipAddress, |
| portNr); |
| _packetCallback->IncomingRTCPPacket(rtcpPacket, rtcpPacketLength, |
| ipAddress, portNr); |
| } |
| } |
| |
| bool UdpTransportImpl::FilterIPAddress(const SocketAddress* fromAddress) |
| { |
| if(fromAddress->_sockaddr_storage.sin_family == AF_INET) |
| { |
| if (_filterIPAddress._sockaddr_storage.sin_family == AF_INET) |
| { |
| // IP is stored in sin_addr. |
| if (_filterIPAddress._sockaddr_in.sin_addr != 0 && |
| (_filterIPAddress._sockaddr_in.sin_addr != |
| fromAddress->_sockaddr_in.sin_addr)) |
| { |
| return false; |
| } |
| } |
| } |
| else if(fromAddress->_sockaddr_storage.sin_family == AF_INET6) |
| { |
| if (_filterIPAddress._sockaddr_storage.sin_family == AF_INET6) |
| { |
| // IP is stored in sin_6addr. |
| for (int32_t 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; |
| } |
| } |
| |
| uint16_t UdpTransport::Htons(const uint16_t port) |
| { |
| return htons(port); |
| } |
| |
| uint32_t UdpTransport::Htonl(const uint32_t a) |
| { |
| return htonl(a); |
| } |
| |
| uint32_t UdpTransport::InetAddrIPV4(const char* ip) |
| { |
| return ::inet_addr(ip); |
| } |
| |
| int32_t UdpTransport::InetPresentationToNumeric(int32_t af, |
| const char* src, |
| void* dst) |
| { |
| #if defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) |
| const int32_t result = inet_pton(af, src, dst); |
| return result > 0 ? 0 : -1; |
| |
| #elif defined(_WIN32) |
| SocketAddress temp; |
| int length=sizeof(SocketAddress); |
| |
| if(af == AF_INET) |
| { |
| int32_t 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) |
| { |
| int32_t 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 |
| } |
| |
| int32_t UdpTransport::LocalHostAddressIPV6(char n_localIP[16]) |
| { |
| |
| #if defined(_WIN32) |
| struct addrinfo *result = NULL; |
| struct addrinfo *ptr = NULL; |
| struct addrinfo hints; |
| |
| ZeroMemory(&hints, sizeof(hints)); |
| hints.ai_family = AF_INET6; |
| |
| char szHostName[256] = ""; |
| if(::gethostname(szHostName, sizeof(szHostName) - 1)) |
| { |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1, "gethostname failed"); |
| return -1; |
| } |
| |
| DWORD dwRetval = getaddrinfo(szHostName, NULL, &hints, &result); |
| if ( dwRetval != 0 ) |
| { |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1, |
| "getaddrinfo failed, error:%d", dwRetval); |
| return -1; |
| } |
| for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) |
| { |
| switch (ptr->ai_family) |
| { |
| case AF_INET6: |
| { |
| for(int i = 0; i< 16; i++) |
| { |
| n_localIP[i] = (*(SocketAddress*)ptr->ai_addr). |
| _sockaddr_in6.sin6_addr.Version6AddressUnion._s6_u8[i]; |
| } |
| bool islocalIP = true; |
| |
| for(int n = 0; n< 15; n++) |
| { |
| if(n_localIP[n] != 0) |
| { |
| islocalIP = false; |
| break; |
| } |
| } |
| |
| if(islocalIP && n_localIP[15] != 1) |
| { |
| islocalIP = false; |
| } |
| |
| if(islocalIP && ptr->ai_next) |
| { |
| continue; |
| } |
| if(n_localIP[0] == 0xfe && |
| n_localIP[1] == 0x80 && ptr->ai_next) |
| { |
| continue; |
| } |
| freeaddrinfo(result); |
| } |
| return 0; |
| default: |
| break; |
| }; |
| } |
| freeaddrinfo(result); |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1, |
| "getaddrinfo failed to find address"); |
| return -1; |
| |
| #elif defined(WEBRTC_MAC) |
| struct ifaddrs* ptrIfAddrs = NULL; |
| struct ifaddrs* ptrIfAddrsStart = NULL; |
| |
| getifaddrs(&ptrIfAddrsStart); |
| ptrIfAddrs = ptrIfAddrsStart; |
| while(ptrIfAddrs) |
| { |
| if(ptrIfAddrs->ifa_addr->sa_family == AF_INET6) |
| { |
| const struct sockaddr_in6* sock_in6 = |
| reinterpret_cast<struct sockaddr_in6*>(ptrIfAddrs->ifa_addr); |
| const struct in6_addr* sin6_addr = &sock_in6->sin6_addr; |
| |
| if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || |
| IN6_IS_ADDR_LINKLOCAL(sin6_addr)) { |
| ptrIfAddrs = ptrIfAddrs->ifa_next; |
| continue; |
| } |
| memcpy(n_localIP, sin6_addr->s6_addr, sizeof(sin6_addr->s6_addr)); |
| freeifaddrs(ptrIfAddrsStart); |
| return 0; |
| } |
| ptrIfAddrs = ptrIfAddrs->ifa_next; |
| } |
| freeifaddrs(ptrIfAddrsStart); |
| return -1; |
| #elif defined(WEBRTC_ANDROID) |
| return -1; |
| #else // WEBRTC_LINUX |
| struct |
| { |
| struct nlmsghdr n; |
| struct ifaddrmsg r; |
| } req; |
| |
| struct rtattr* rta = NULL; |
| int status; |
| char buf[16384]; // = 16 * 1024 (16 kB) |
| struct nlmsghdr* nlmp; |
| struct ifaddrmsg* rtmp; |
| struct rtattr* rtatp; |
| int rtattrlen; |
| struct in6_addr* in6p; |
| |
| int fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); |
| if (fd == -1) |
| { |
| return -1; |
| } |
| |
| // RTM_GETADDR is used to fetch the ip address from the kernel interface |
| // table. Populate the msg structure (req) the size of the message buffer |
| // is specified to netlinkmessage header, and flags values are set as |
| // NLM_F_ROOT | NLM_F_REQUEST. |
| // The request flag must be set for all messages requesting the data from |
| // kernel. The root flag is used to notify the kernel to return the full |
| // tabel. Another flag (not used) is NLM_F_MATCH. This is used to get only |
| // specified entries in the table. At the time of writing this program this |
| // flag is not implemented in kernel |
| |
| memset(&req, 0, sizeof(req)); |
| req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); |
| req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; |
| req.n.nlmsg_type = RTM_GETADDR; |
| req.r.ifa_family = AF_INET6; |
| |
| // Fill up all the attributes for the rtnetlink header. |
| // The lenght is very important. 16 signifies the ipv6 address. |
| rta = (struct rtattr*)(((char*)&req) + NLMSG_ALIGN(req.n.nlmsg_len)); |
| rta->rta_len = RTA_LENGTH(16); |
| |
| status = send(fd, &req, req.n.nlmsg_len, 0); |
| if (status < 0) |
| { |
| close(fd); |
| return -1; |
| } |
| status = recv(fd, buf, sizeof(buf), 0); |
| if (status < 0) |
| { |
| close(fd); |
| return -1; |
| } |
| if(status == 0) |
| { |
| close(fd); |
| return -1; |
| } |
| close(fd); |
| |
| // The message is stored in buff. Parse the message to get the requested |
| // data. |
| { |
| nlmp = (struct nlmsghdr*)buf; |
| int len = nlmp->nlmsg_len; |
| int req_len = len - sizeof(*nlmp); |
| |
| if (req_len < 0 || len > status) |
| { |
| return -1; |
| } |
| if (!NLMSG_OK_NO_WARNING(nlmp, status)) |
| { |
| return -1; |
| } |
| rtmp = (struct ifaddrmsg*)NLMSG_DATA(nlmp); |
| rtatp = (struct rtattr*)IFA_RTA(rtmp); |
| |
| rtattrlen = IFA_PAYLOAD(nlmp); |
| |
| for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) |
| { |
| |
| // Here we hit the fist chunk of the message. Time to validate the |
| // type. For more info on the different types see |
| // "man(7) rtnetlink" The table below is taken from man pages. |
| // Attributes |
| // rta_type value type description |
| // ------------------------------------------------------------- |
| // IFA_UNSPEC - unspecified. |
| // IFA_ADDRESS raw protocol address interface address |
| // IFA_LOCAL raw protocol address local address |
| // IFA_LABEL asciiz string name of the interface |
| // IFA_BROADCAST raw protocol address broadcast address. |
| // IFA_ANYCAST raw protocol address anycast address |
| // IFA_CACHEINFO struct ifa_cacheinfo Address information. |
| |
| if(rtatp->rta_type == IFA_ADDRESS) |
| { |
| bool islocalIP = true; |
| in6p = (struct in6_addr*)RTA_DATA(rtatp); |
| for(int n = 0; n< 15; n++) |
| { |
| if(in6p->s6_addr[n] != 0) |
| { |
| islocalIP = false; |
| break; |
| } |
| } |
| if(islocalIP && in6p->s6_addr[15] != 1) |
| { |
| islocalIP = false; |
| } |
| if(!islocalIP) |
| { |
| for(int i = 0; i< 16; i++) |
| { |
| n_localIP[i] = in6p->s6_addr[i]; |
| } |
| if(n_localIP[0] == static_cast<char> (0xfe) |
| && n_localIP[1] == static_cast<char>(0x80) ) |
| { |
| // Auto configured IP. |
| continue; |
| } |
| break; |
| } |
| } |
| } |
| } |
| return 0; |
| #endif |
| } |
| |
| int32_t UdpTransport::LocalHostAddress(uint32_t& localIP) |
| { |
| #if defined(_WIN32) |
| hostent* localHost; |
| localHost = gethostbyname( "" ); |
| if(localHost) |
| { |
| if(localHost->h_addrtype != AF_INET) |
| { |
| WEBRTC_TRACE( |
| kTraceError, |
| kTraceTransport, |
| -1, |
| "LocalHostAddress can only get local IP for IP Version 4"); |
| return -1; |
| } |
| localIP= Htonl( |
| (*(struct in_addr *)localHost->h_addr_list[0]).S_un.S_addr); |
| return 0; |
| } |
| else |
| { |
| int32_t error = WSAGetLastError(); |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1, |
| "gethostbyname failed, error:%d", error); |
| return -1; |
| } |
| #elif (defined(WEBRTC_MAC)) |
| char localname[255]; |
| if (gethostname(localname, 255) != -1) |
| { |
| hostent* localHost; |
| localHost = gethostbyname(localname); |
| if(localHost) |
| { |
| if(localHost->h_addrtype != AF_INET) |
| { |
| WEBRTC_TRACE( |
| kTraceError, |
| kTraceTransport, |
| -1, |
| "LocalHostAddress can only get local IP for IP Version 4"); |
| return -1; |
| } |
| localIP = Htonl((*(struct in_addr*)*localHost->h_addr_list).s_addr); |
| return 0; |
| } |
| } |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, -1, "gethostname failed"); |
| return -1; |
| #else // WEBRTC_LINUX |
| int sockfd, size = 1; |
| struct ifreq* ifr; |
| struct ifconf ifc; |
| |
| if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) |
| { |
| return -1; |
| } |
| ifc.ifc_len = IFRSIZE; |
| ifc.ifc_req = NULL; |
| do |
| { |
| ++size; |
| // Buffer size needed is unknown. Try increasing it until no overflow |
| // occurs. |
| if (NULL == (ifc.ifc_req = (ifreq*)realloc(ifc.ifc_req, IFRSIZE))) { |
| fprintf(stderr, "Out of memory.\n"); |
| exit(EXIT_FAILURE); |
| } |
| ifc.ifc_len = IFRSIZE; |
| if (ioctl(sockfd, SIOCGIFCONF, &ifc)) |
| { |
| free(ifc.ifc_req); |
| close(sockfd); |
| return -1; |
| } |
| } while (IFRSIZE <= ifc.ifc_len); |
| |
| ifr = ifc.ifc_req; |
| for (;(char *) ifr < (char *) ifc.ifc_req + ifc.ifc_len; ++ifr) |
| { |
| if (ifr->ifr_addr.sa_data == (ifr+1)->ifr_addr.sa_data) |
| { |
| continue; // duplicate, skip it |
| } |
| if (ioctl(sockfd, SIOCGIFFLAGS, ifr)) |
| { |
| continue; // failed to get flags, skip it |
| } |
| if(strncmp(ifr->ifr_name, "lo",3) == 0) |
| { |
| continue; |
| }else |
| { |
| struct sockaddr* saddr = &(ifr->ifr_addr); |
| SocketAddress* socket_addess = reinterpret_cast<SocketAddress*>( |
| saddr); |
| localIP = Htonl(socket_addess->_sockaddr_in.sin_addr); |
| close(sockfd); |
| free(ifc.ifc_req); |
| return 0; |
| } |
| } |
| free(ifc.ifc_req); |
| close(sockfd); |
| return -1; |
| #endif |
| } |
| |
| int32_t UdpTransport::IPAddress(const SocketAddress& address, |
| char* ip, |
| uint32_t& ipSize, |
| uint16_t& sourcePort) |
| { |
| #if defined(_WIN32) |
| DWORD dwIPSize = ipSize; |
| int32_t returnvalue = WSAAddressToStringA((LPSOCKADDR)(&address), |
| sizeof(SocketAddress), |
| NULL, |
| ip, |
| &dwIPSize); |
| if(returnvalue == -1) |
| { |
| return -1; |
| } |
| |
| uint16_t source_port = 0; |
| if(address._sockaddr_storage.sin_family == AF_INET) |
| { |
| // Parse IP assuming format "a.b.c.d:port". |
| char* ipEnd = strchr(ip,':'); |
| if(ipEnd != NULL) |
| { |
| *ipEnd = '\0'; |
| } |
| ipSize = (int32_t)strlen(ip); |
| if(ipSize == 0) |
| { |
| return -1; |
| } |
| source_port = address._sockaddr_in.sin_port; |
| } |
| else |
| { |
| // Parse IP assuming format "[address]:port". |
| char* ipEnd = strchr(ip,']'); |
| if(ipEnd != NULL) |
| { |
| // Calculate length |
| int32_t adrSize = int32_t(ipEnd - ip) - 1; |
| memmove(ip, &ip[1], adrSize); // Remove '[' |
| *(ipEnd - 1) = '\0'; |
| } |
| ipSize = (int32_t)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) |
| int32_t 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; |
| } |
| uint16_t source_port; |
| if(ipFamily == AF_INET) |
| { |
| source_port = address._sockaddr_in.sin_port; |
| } else |
| { |
| source_port = address._sockaddr_in6.sin6_port; |
| } |
| // Convert port number to network byte order. |
| sourcePort = htons(source_port); |
| return 0; |
| #else |
| return -1; |
| #endif |
| } |
| |
| bool UdpTransport::IsIpAddressValid(const char* ipadr, const bool ipV6) |
| { |
| if(ipV6) |
| { |
| int32_t len = (int32_t)strlen(ipadr); |
| if( len>39 || len == 0) |
| { |
| return false; |
| } |
| |
| int32_t i; |
| int32_t colonPos[7] = {0,0,0,0,0,0,0}; |
| int32_t lastColonPos = -2; |
| int32_t nColons = 0; |
| int32_t nDubbleColons = 0; |
| int32_t nDots = 0; |
| int32_t error = 0; |
| char c; |
| for(i = 0; i < len ; i++) |
| { |
| c=ipadr[i]; |
| if(isxdigit(c)) |
| ; |
| else if(c == ':') |
| { |
| if(nColons < 7) |
| colonPos[nColons] = i; |
| if((i-lastColonPos)==1) |
| nDubbleColons++; |
| lastColonPos=i; |
| if(nDots != 0) |
| { |
| error = 1; |
| } |
| nColons++; |
| } |
| else if(c == '.') |
| { |
| nDots++; |
| } |
| else |
| { |
| error = 1; |
| } |
| |
| } |
| if(error) |
| { |
| return false; |
| } |
| if(nDubbleColons > 1) |
| { |
| return false; |
| } |
| if(nColons > 7 || nColons < 2) |
| { |
| return false; |
| } |
| if(!(nDots == 3 || nDots == 0)) |
| { |
| return false; |
| } |
| lastColonPos = -1; |
| int32_t charsBeforeColon = 0; |
| for(i = 0; i < nColons; i++) |
| { |
| charsBeforeColon=colonPos[i]-lastColonPos-1; |
| if(charsBeforeColon > 4) |
| { |
| return false; |
| } |
| lastColonPos=colonPos[i]; |
| } |
| int32_t lengthAfterLastColon = len - lastColonPos - 1; |
| if(nDots == 0) |
| { |
| if(lengthAfterLastColon > 4) |
| return false; |
| } |
| if(nDots == 3 && lengthAfterLastColon > 0) |
| { |
| return IsIpAddressValid((ipadr+lastColonPos+1),false); |
| } |
| |
| } |
| else |
| { |
| int32_t len = (int32_t)strlen(ipadr); |
| if((len>15)||(len==0)) |
| { |
| return false; |
| } |
| |
| // IPv4 should be [0-255].[0-255].[0-255].[0-255] |
| int32_t i; |
| int32_t nDots = 0; |
| int32_t iDotPos[4] = {0,0,0,0}; |
| |
| for (i = 0; (i < len) && (nDots < 4); i++) |
| { |
| if (ipadr[i] == (char)'.') |
| { |
| // Store index of dots and count number of dots. |
| iDotPos[nDots++] = i; |
| } |
| else if (isdigit(ipadr[i]) == 0) |
| { |
| return false; |
| } |
| } |
| |
| bool allUnder256 = false; |
| // TODO (hellner): while loop seems to be abused here to get |
| // label like functionality. Fix later to avoid introducing bugs now. |
| |
| // Check that all numbers are smaller than 256. |
| do |
| { |
| if (nDots != 3 ) |
| { |
| break; |
| } |
| |
| if (iDotPos[0] <= 3) |
| { |
| char nr[4]; |
| memset(nr,0,4); |
| strncpy(nr,&ipadr[0],iDotPos[0]); |
| int32_t num = atoi(nr); |
| if (num > 255 || num < 0) |
| { |
| break; |
| } |
| } else { |
| break; |
| } |
| |
| if (iDotPos[1] - iDotPos[0] <= 4) |
| { |
| char nr[4]; |
| memset(nr,0,4); |
| strncpy(nr,&ipadr[iDotPos[0]+1], iDotPos[1] - iDotPos[0] - 1); |
| int32_t num = atoi(nr); |
| if (num > 255 || num < 0) |
| break; |
| } else { |
| break; |
| } |
| |
| if (iDotPos[2] - iDotPos[1] <= 4) |
| { |
| char nr[4]; |
| memset(nr,0,4); |
| strncpy(nr,&ipadr[iDotPos[1]+1], iDotPos[2] - iDotPos[1] - 1); |
| int32_t num = atoi(nr); |
| if (num > 255 || num < 0) |
| break; |
| } else { |
| break; |
| } |
| |
| if (len - iDotPos[2] <= 4) |
| { |
| char nr[4]; |
| memset(nr,0,4); |
| strncpy(nr,&ipadr[iDotPos[2]+1], len - iDotPos[2] -1); |
| int32_t num = atoi(nr); |
| if (num > 255 || num < 0) |
| break; |
| else |
| allUnder256 = true; |
| } else { |
| break; |
| } |
| } while(false); |
| |
| if (nDots != 3 || !allUnder256) |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| } // namespace test |
| } // namespace webrtc |