Index: webrtc/test/channel_transport/udp_transport_impl.cc |
diff --git a/webrtc/test/channel_transport/udp_transport_impl.cc b/webrtc/test/channel_transport/udp_transport_impl.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..897c8085226261bd0d9e61f15acc12568a8b4a1a |
--- /dev/null |
+++ b/webrtc/test/channel_transport/udp_transport_impl.cc |
@@ -0,0 +1,3005 @@ |
+/* |
+ * 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 |