summaryrefslogtreecommitdiffstats
path: root/src/rtpudpv6transmitter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rtpudpv6transmitter.cpp')
-rw-r--r--src/rtpudpv6transmitter.cpp1889
1 files changed, 1889 insertions, 0 deletions
diff --git a/src/rtpudpv6transmitter.cpp b/src/rtpudpv6transmitter.cpp
new file mode 100644
index 0000000..6bf04d4
--- /dev/null
+++ b/src/rtpudpv6transmitter.cpp
@@ -0,0 +1,1889 @@
+/*
+
+ This file is a part of JRTPLIB
+ Copyright (c) 1999-2007 Jori Liesenborgs
+
+ Contact: jori.liesenborgs@gmail.com
+
+ This library was developed at the "Expertisecentrum Digitale Media"
+ (http://www.edm.uhasselt.be), a research center of the Hasselt University
+ (http://www.uhasselt.be). The library is based upon work done for
+ my thesis at the School for Knowledge Technology (Belgium/The Netherlands).
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ IN THE SOFTWARE.
+
+*/
+
+#include "rtpudpv6transmitter.h"
+
+#ifdef RTP_SUPPORT_IPV6
+
+#include "rtprawpacket.h"
+#include "rtpipv6address.h"
+#include "rtptimeutilities.h"
+#include "rtpdefines.h"
+#include <stdio.h>
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ #define RTPSOCKERR INVALID_SOCKET
+ #define RTPCLOSE(x) closesocket(x)
+ #define RTPSOCKLENTYPE int
+ #define RTPIOCTL ioctlsocket
+#else // not Win32
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <sys/ioctl.h>
+ #include <net/if.h>
+ #include <string.h>
+ #include <netdb.h>
+ #include <unistd.h>
+
+ #ifdef RTP_HAVE_SYS_FILIO
+ #include <sys/filio.h>
+ #endif // RTP_HAVE_SYS_FILIO
+ #ifdef RTP_HAVE_SYS_SOCKIO
+ #include <sys/sockio.h>
+ #endif // RTP_HAVE_SYS_SOCKIO
+ #ifdef RTP_SUPPORT_IFADDRS
+ #include <ifaddrs.h>
+ #endif // RTP_SUPPORT_IFADDRS
+
+
+ #define RTPSOCKERR -1
+ #define RTPCLOSE(x) close(x)
+
+ #ifdef RTP_SOCKLENTYPE_UINT
+ #define RTPSOCKLENTYPE unsigned int
+ #else
+ #define RTPSOCKLENTYPE int
+ #endif // RTP_SOCKLENTYPE_UINT
+
+ #define RTPIOCTL ioctl
+#endif // WIN32
+
+#include "rtpdebug.h"
+
+#define RTPUDPV6TRANS_MAXPACKSIZE 65535
+#define RTPUDPV6TRANS_IFREQBUFSIZE 8192
+
+#define RTPUDPV6TRANS_IS_MCASTADDR(x) (x.s6_addr[0] == 0xFF)
+
+#define RTPUDPV6TRANS_MCASTMEMBERSHIP(socket,type,mcastip,status) {\
+ struct ipv6_mreq mreq;\
+ \
+ mreq.ipv6mr_multiaddr = mcastip;\
+ mreq.ipv6mr_interface = mcastifidx;\
+ status = setsockopt(socket,IPPROTO_IPV6,type,(const char *)&mreq,sizeof(struct ipv6_mreq));\
+ }
+#ifdef RTP_SUPPORT_THREAD
+ #define MAINMUTEX_LOCK { if (threadsafe) mainmutex.Lock(); }
+ #define MAINMUTEX_UNLOCK { if (threadsafe) mainmutex.Unlock(); }
+ #define WAITMUTEX_LOCK { if (threadsafe) waitmutex.Lock(); }
+ #define WAITMUTEX_UNLOCK { if (threadsafe) waitmutex.Unlock(); }
+#else
+ #define MAINMUTEX_LOCK
+ #define MAINMUTEX_UNLOCK
+ #define WAITMUTEX_LOCK
+ #define WAITMUTEX_UNLOCK
+#endif // RTP_SUPPORT_THREAD
+
+inline bool operator==(const in6_addr &ip1,const in6_addr &ip2)
+{
+ if (memcmp(&ip1,&ip2,sizeof(in6_addr)) == 0)
+ return true;
+ return false;
+}
+
+RTPUDPv6Transmitter::RTPUDPv6Transmitter(RTPMemoryManager *mgr) : RTPTransmitter(mgr),
+ destinations(GetMemoryManager(),RTPMEM_TYPE_CLASS_DESTINATIONLISTHASHELEMENT),
+ multicastgroups(GetMemoryManager(),RTPMEM_TYPE_CLASS_MULTICASTHASHELEMENT),
+ acceptignoreinfo(GetMemoryManager(),RTPMEM_TYPE_CLASS_ACCEPTIGNOREHASHELEMENT)
+{
+ created = false;
+ init = false;
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ timeinit.Dummy();
+#endif // WIN32 || _WIN32_WCE
+}
+
+RTPUDPv6Transmitter::~RTPUDPv6Transmitter()
+{
+ Destroy();
+}
+
+int RTPUDPv6Transmitter::Init(bool tsafe)
+{
+ if (init)
+ return ERR_RTP_UDPV6TRANS_ALREADYINIT;
+
+#ifdef RTP_SUPPORT_THREAD
+ threadsafe = tsafe;
+ if (threadsafe)
+ {
+ int status;
+
+ status = mainmutex.Init();
+ if (status < 0)
+ return ERR_RTP_UDPV6TRANS_CANTINITMUTEX;
+ status = waitmutex.Init();
+ if (status < 0)
+ return ERR_RTP_UDPV6TRANS_CANTINITMUTEX;
+ }
+#else
+ if (tsafe)
+ return ERR_RTP_NOTHREADSUPPORT;
+#endif // RTP_SUPPORT_THREAD
+
+ init = true;
+ return 0;
+}
+
+int RTPUDPv6Transmitter::Create(size_t maximumpacketsize,const RTPTransmissionParams *transparams)
+{
+ const RTPUDPv6TransmissionParams *params,defaultparams;
+ struct sockaddr_in6 addr;
+ RTPSOCKLENTYPE size;
+ int status;
+
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_ALREADYCREATED;
+ }
+
+ // Obtain transmission parameters
+
+ if (transparams == 0)
+ params = &defaultparams;
+ else
+ {
+ if (transparams->GetTransmissionProtocol() != RTPTransmitter::IPv6UDPProto)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_ILLEGALPARAMETERS;
+ }
+ params = (const RTPUDPv6TransmissionParams *)transparams;
+ }
+
+ // Check if portbase is even
+ if (params->GetPortbase()%2 != 0)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_PORTBASENOTEVEN;
+ }
+
+ // create sockets
+
+ rtpsock = socket(PF_INET6,SOCK_DGRAM,0);
+ if (rtpsock == RTPSOCKERR)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTCREATESOCKET;
+ }
+ rtcpsock = socket(PF_INET6,SOCK_DGRAM,0);
+ if (rtcpsock == RTPSOCKERR)
+ {
+ RTPCLOSE(rtpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTCREATESOCKET;
+ }
+
+ // set socket buffer sizes
+
+ size = params->GetRTPReceiveBuffer();
+ if (setsockopt(rtpsock,SOL_SOCKET,SO_RCVBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTSETRTPRECEIVEBUF;
+ }
+ size = params->GetRTPSendBuffer();
+ if (setsockopt(rtpsock,SOL_SOCKET,SO_SNDBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTSETRTPTRANSMITBUF;
+ }
+ size = params->GetRTCPReceiveBuffer();
+ if (setsockopt(rtcpsock,SOL_SOCKET,SO_RCVBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTSETRTCPRECEIVEBUF;
+ }
+ size = params->GetRTCPSendBuffer();
+ if (setsockopt(rtcpsock,SOL_SOCKET,SO_SNDBUF,(const char *)&size,sizeof(int)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTSETRTCPTRANSMITBUF;
+ }
+
+ // bind sockets
+
+ bindIP = params->GetBindIP();
+ mcastifidx = params->GetMulticastInterfaceIndex();
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons(params->GetPortbase());
+ addr.sin6_addr = bindIP;
+ if (bind(rtpsock,(struct sockaddr *)&addr,sizeof(struct sockaddr_in6)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTBINDRTPSOCKET;
+ }
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons(params->GetPortbase()+1);
+ addr.sin6_addr = bindIP;
+ if (bind(rtcpsock,(struct sockaddr *)&addr,sizeof(struct sockaddr_in6)) != 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_CANTBINDRTCPSOCKET;
+ }
+
+ // Try to obtain local IP addresses
+
+ localIPs = params->GetLocalIPList();
+ if (localIPs.empty()) // User did not provide list of local IP addresses, calculate them
+ {
+ int status;
+
+ if ((status = CreateLocalIPList()) < 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return status;
+ }
+
+#ifdef RTPDEBUG
+ std::cout << "Found these local IP addresses:" << std::endl;
+
+ std::list<in6_addr>::const_iterator it;
+
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ RTPIPv6Address a(*it);
+
+ std::cout << a.GetAddressString() << std::endl;
+ }
+#endif // RTPDEBUG
+ }
+
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+ if (SetMulticastTTL(params->GetMulticastTTL()))
+ supportsmulticasting = true;
+ else
+ supportsmulticasting = false;
+#else // no multicast support enabled
+ supportsmulticasting = false;
+#endif // RTP_SUPPORT_IPV6MULTICAST
+
+ if ((status = CreateAbortDescriptors()) < 0)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ MAINMUTEX_UNLOCK
+ return status;
+ }
+
+ if (maximumpacketsize > RTPUDPV6TRANS_MAXPACKSIZE)
+ {
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ DestroyAbortDescriptors();
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+ maxpacksize = maximumpacketsize;
+ portbase = params->GetPortbase();
+ multicastTTL = params->GetMulticastTTL();
+ receivemode = RTPTransmitter::AcceptAll;
+
+ localhostname = 0;
+ localhostnamelength = 0;
+
+ waitingfordata = false;
+ created = true;
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+void RTPUDPv6Transmitter::Destroy()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK;
+ return;
+ }
+
+ if (localhostname)
+ {
+ RTPDeleteByteArray(localhostname,GetMemoryManager());
+ localhostname = 0;
+ localhostnamelength = 0;
+ }
+
+ RTPCLOSE(rtpsock);
+ RTPCLOSE(rtcpsock);
+ destinations.Clear();
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+ multicastgroups.Clear();
+#endif // RTP_SUPPORT_IPV6MULTICAST
+ FlushPackets();
+ ClearAcceptIgnoreInfo();
+ localIPs.clear();
+ created = false;
+
+ if (waitingfordata)
+ {
+ AbortWaitInternal();
+ DestroyAbortDescriptors();
+ MAINMUTEX_UNLOCK
+ WAITMUTEX_LOCK // to make sure that the WaitForIncomingData function ended
+ WAITMUTEX_UNLOCK
+ }
+ else
+ DestroyAbortDescriptors();
+
+ MAINMUTEX_UNLOCK
+}
+
+RTPTransmissionInfo *RTPUDPv6Transmitter::GetTransmissionInfo()
+{
+ if (!init)
+ return 0;
+
+ MAINMUTEX_LOCK
+ RTPTransmissionInfo *tinf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPTRANSMISSIONINFO) RTPUDPv6TransmissionInfo(localIPs,rtpsock,rtcpsock);
+ MAINMUTEX_UNLOCK
+ return tinf;
+}
+
+int RTPUDPv6Transmitter::GetLocalHostName(uint8_t *buffer,size_t *bufferlength)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+
+ if (localhostname == 0)
+ {
+ if (localIPs.empty())
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOLOCALIPS;
+ }
+
+ std::list<in6_addr>::const_iterator it;
+ std::list<std::string> hostnames;
+
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ bool founddouble = false;
+ bool foundentry = true;
+
+ while (!founddouble && foundentry)
+ {
+ struct hostent *he;
+ in6_addr ip = (*it);
+
+ he = gethostbyaddr((char *)&ip,sizeof(in6_addr),AF_INET6);
+ if (he != 0)
+ {
+ std::string hname = std::string(he->h_name);
+ std::list<std::string>::const_iterator it;
+
+ for (it = hostnames.begin() ; !founddouble && it != hostnames.end() ; it++)
+ if ((*it) == hname)
+ founddouble = true;
+
+ if (!founddouble)
+ hostnames.push_back(hname);
+
+ int i = 0;
+ while (!founddouble && he->h_aliases[i] != 0)
+ {
+ std::string hname = std::string(he->h_aliases[i]);
+
+ for (it = hostnames.begin() ; !founddouble && it != hostnames.end() ; it++)
+ if ((*it) == hname)
+ founddouble = true;
+
+ if (!founddouble)
+ {
+ hostnames.push_back(hname);
+ i++;
+ }
+ }
+ }
+ else
+ foundentry = false;
+ }
+ }
+
+ bool found = false;
+
+ if (!hostnames.empty()) // try to select the most appropriate hostname
+ {
+ std::list<std::string>::const_iterator it;
+
+ hostnames.sort();
+ for (it = hostnames.begin() ; !found && it != hostnames.end() ; it++)
+ {
+ if ((*it).find('.') != std::string::npos)
+ {
+ found = true;
+ localhostnamelength = (*it).length();
+ localhostname = RTPNew(GetMemoryManager(),RTPMEM_TYPE_OTHER) uint8_t [localhostnamelength+1];
+ if (localhostname == 0)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(localhostname,(*it).c_str(),localhostnamelength);
+ localhostname[localhostnamelength] = 0;
+ }
+ }
+ }
+
+ if (!found) // use an IP address
+ {
+ in6_addr ip;
+ int len;
+ char str[48];
+ uint16_t ip16[8];
+ int i,j;
+
+ it = localIPs.begin();
+ ip = (*it);
+
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2)
+ {
+ ip16[j] = (((uint16_t)ip.s6_addr[i])<<8);
+ ip16[j] |= ((uint16_t)ip.s6_addr[i+1]);
+ }
+
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7]);
+ len = strlen(str);
+
+ localhostnamelength = len;
+ localhostname = RTPNew(GetMemoryManager(),RTPMEM_TYPE_OTHER) uint8_t [localhostnamelength+1];
+ if (localhostname == 0)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(localhostname,str,localhostnamelength);
+ localhostname[localhostnamelength] = 0;
+ }
+ }
+
+ if ((*bufferlength) < localhostnamelength)
+ {
+ *bufferlength = localhostnamelength; // tell the application the required size of the buffer
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_TRANS_BUFFERLENGTHTOOSMALL;
+ }
+
+ memcpy(buffer,localhostname,localhostnamelength);
+ *bufferlength = localhostnamelength;
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+bool RTPUDPv6Transmitter::ComesFromThisTransmitter(const RTPAddress *addr)
+{
+ if (!init)
+ return false;
+
+ if (addr == 0)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (created && addr->GetAddressType() == RTPAddress::IPv6Address)
+ {
+ const RTPIPv6Address *addr2 = (const RTPIPv6Address *)addr;
+ bool found = false;
+ std::list<in6_addr>::const_iterator it;
+
+ it = localIPs.begin();
+ while (!found && it != localIPs.end())
+ {
+ in6_addr itip = *it;
+ in6_addr addrip = addr2->GetIP();
+ if (memcmp(&addrip,&itip,sizeof(in6_addr)) == 0)
+ found = true;
+ else
+ ++it;
+ }
+
+ if (!found)
+ v = false;
+ else
+ {
+ if (addr2->GetPort() == portbase) // check for RTP port
+ v = true;
+ else if (addr2->GetPort() == (portbase+1)) // check for RTCP port
+ v = true;
+ else
+ v = false;
+ }
+ }
+ else
+ v = false;
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+int RTPUDPv6Transmitter::Poll()
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ int status;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ status = PollSocket(true); // poll RTP socket
+ if (status >= 0)
+ status = PollSocket(false); // poll RTCP socket
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv6Transmitter::WaitForIncomingData(const RTPTime &delay,bool *dataavailable)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ fd_set fdset;
+ struct timeval tv;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (waitingfordata)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_ALREADYWAITING;
+ }
+
+ FD_ZERO(&fdset);
+ FD_SET(rtpsock,&fdset);
+ FD_SET(rtcpsock,&fdset);
+ FD_SET(abortdesc[0],&fdset);
+ tv.tv_sec = delay.GetSeconds();
+ tv.tv_usec = delay.GetMicroSeconds();
+
+ waitingfordata = true;
+
+ WAITMUTEX_LOCK
+ MAINMUTEX_UNLOCK
+
+ if (select(FD_SETSIZE,&fdset,0,0,&tv) < 0)
+ {
+ MAINMUTEX_LOCK
+ waitingfordata = false;
+ MAINMUTEX_UNLOCK
+ WAITMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_ERRORINSELECT;
+ }
+
+ MAINMUTEX_LOCK
+ waitingfordata = false;
+ if (!created) // destroy called
+ {
+ MAINMUTEX_UNLOCK;
+ WAITMUTEX_UNLOCK
+ return 0;
+ }
+
+ // if aborted, read from abort buffer
+ if (FD_ISSET(abortdesc[0],&fdset))
+ {
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ char buf[1];
+
+ recv(abortdesc[0],buf,1,0);
+#else
+ unsigned char buf[1];
+
+ read(abortdesc[0],buf,1);
+#endif // WIN32
+ }
+
+ if (dataavailable != 0)
+ {
+ if (FD_ISSET(rtpsock,&fdset) || FD_ISSET(rtcpsock,&fdset))
+ *dataavailable = true;
+ else
+ *dataavailable = false;
+ }
+
+ MAINMUTEX_UNLOCK
+ WAITMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv6Transmitter::AbortWait()
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (!waitingfordata)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTWAITING;
+ }
+
+ AbortWaitInternal();
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv6Transmitter::SendRTPData(const void *data,size_t len)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (len > maxpacksize)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+ destinations.GotoFirstElement();
+ while (destinations.HasCurrentElement())
+ {
+ sendto(rtpsock,(const char *)data,len,0,(const struct sockaddr *)destinations.GetCurrentElement().GetRTPSockAddr(),sizeof(struct sockaddr_in6));
+ destinations.GotoNextElement();
+ }
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv6Transmitter::SendRTCPData(const void *data,size_t len)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (len > maxpacksize)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_SPECIFIEDSIZETOOBIG;
+ }
+
+ destinations.GotoFirstElement();
+ while (destinations.HasCurrentElement())
+ {
+ sendto(rtcpsock,(const char *)data,len,0,(const struct sockaddr *)destinations.GetCurrentElement().GetRTCPSockAddr(),sizeof(struct sockaddr_in6));
+ destinations.GotoNextElement();
+ }
+
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv6Transmitter::AddDestination(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+
+ RTPIPv6Address &address = (RTPIPv6Address &)addr;
+ RTPIPv6Destination dest(address.GetIP(),address.GetPort());
+ int status = destinations.AddElement(dest);
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv6Transmitter::DeleteDestination(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+
+ RTPIPv6Address &address = (RTPIPv6Address &)addr;
+ RTPIPv6Destination dest(address.GetIP(),address.GetPort());
+ int status = destinations.DeleteElement(dest);
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv6Transmitter::ClearDestinations()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created)
+ destinations.Clear();
+ MAINMUTEX_UNLOCK
+}
+
+bool RTPUDPv6Transmitter::SupportsMulticasting()
+{
+ if (!init)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (!created)
+ v = false;
+ else
+ v = supportsmulticasting;
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+
+int RTPUDPv6Transmitter::JoinMulticastGroup(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ in6_addr mcastIP = address.GetIP();
+
+ if (!RTPUDPV6TRANS_IS_MCASTADDR(mcastIP))
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTAMULTICASTADDRESS;
+ }
+
+ status = multicastgroups.AddElement(mcastIP);
+ if (status >= 0)
+ {
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtpsock,IPV6_JOIN_GROUP,mcastIP,status);
+ if (status != 0)
+ {
+ multicastgroups.DeleteElement(mcastIP);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_COULDNTJOINMULTICASTGROUP;
+ }
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtcpsock,IPV6_JOIN_GROUP,mcastIP,status);
+ if (status != 0)
+ {
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtpsock,IPV6_LEAVE_GROUP,mcastIP,status);
+ multicastgroups.DeleteElement(mcastIP);
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_COULDNTJOINMULTICASTGROUP;
+ }
+ }
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv6Transmitter::LeaveMulticastGroup(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ in6_addr mcastIP = address.GetIP();
+
+ if (!RTPUDPV6TRANS_IS_MCASTADDR(mcastIP))
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTAMULTICASTADDRESS;
+ }
+
+ status = multicastgroups.DeleteElement(mcastIP);
+ if (status >= 0)
+ {
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtpsock,IPV6_LEAVE_GROUP,mcastIP,status);
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtcpsock,IPV6_LEAVE_GROUP,mcastIP,status);
+ status = 0;
+ }
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv6Transmitter::LeaveAllMulticastGroups()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created)
+ {
+ multicastgroups.GotoFirstElement();
+ while (multicastgroups.HasCurrentElement())
+ {
+ in6_addr mcastIP;
+ int status = 0;
+
+ mcastIP = multicastgroups.GetCurrentElement();
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtpsock,IPV6_LEAVE_GROUP,mcastIP,status);
+ RTPUDPV6TRANS_MCASTMEMBERSHIP(rtcpsock,IPV6_LEAVE_GROUP,mcastIP,status);
+ multicastgroups.GotoNextElement();
+ }
+ multicastgroups.Clear();
+ }
+ MAINMUTEX_UNLOCK
+}
+
+#else // no multicast support
+
+int RTPUDPv6Transmitter::JoinMulticastGroup(const RTPAddress &addr)
+{
+ return ERR_RTP_UDPV6TRANS_NOMULTICASTSUPPORT;
+}
+
+int RTPUDPv6Transmitter::LeaveMulticastGroup(const RTPAddress &addr)
+{
+ return ERR_RTP_UDPV6TRANS_NOMULTICASTSUPPORT;
+}
+
+void RTPUDPv6Transmitter::LeaveAllMulticastGroups()
+{
+}
+
+#endif // RTP_SUPPORT_IPV6MULTICAST
+
+int RTPUDPv6Transmitter::SetReceiveMode(RTPTransmitter::ReceiveMode m)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (m != receivemode)
+ {
+ receivemode = m;
+ acceptignoreinfo.Clear();
+ }
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+int RTPUDPv6Transmitter::AddToIgnoreList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::IgnoreSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ status = ProcessAddAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv6Transmitter::DeleteFromIgnoreList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::IgnoreSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ status = ProcessDeleteAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv6Transmitter::ClearIgnoreList()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created && receivemode == RTPTransmitter::IgnoreSome)
+ ClearAcceptIgnoreInfo();
+ MAINMUTEX_UNLOCK
+}
+
+int RTPUDPv6Transmitter::AddToAcceptList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::AcceptSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ status = ProcessAddAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+int RTPUDPv6Transmitter::DeleteFromAcceptList(const RTPAddress &addr)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+
+ int status;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (addr.GetAddressType() != RTPAddress::IPv6Address)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_INVALIDADDRESSTYPE;
+ }
+ if (receivemode != RTPTransmitter::AcceptSome)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_DIFFERENTRECEIVEMODE;
+ }
+
+ const RTPIPv6Address &address = (const RTPIPv6Address &)addr;
+ status = ProcessDeleteAcceptIgnoreEntry(address.GetIP(),address.GetPort());
+
+ MAINMUTEX_UNLOCK
+ return status;
+}
+
+void RTPUDPv6Transmitter::ClearAcceptList()
+{
+ if (!init)
+ return;
+
+ MAINMUTEX_LOCK
+ if (created && receivemode == RTPTransmitter::AcceptSome)
+ ClearAcceptIgnoreInfo();
+ MAINMUTEX_UNLOCK
+}
+
+int RTPUDPv6Transmitter::SetMaximumPacketSize(size_t s)
+{
+ if (!init)
+ return ERR_RTP_UDPV6TRANS_NOTINIT;
+
+ MAINMUTEX_LOCK
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_NOTCREATED;
+ }
+ if (s > RTPUDPV6TRANS_MAXPACKSIZE)
+ {
+ MAINMUTEX_UNLOCK
+ return ERR_RTP_UDPV6TRANS_SPECIFIEDSIZETOOBIG;
+ }
+ maxpacksize = s;
+ MAINMUTEX_UNLOCK
+ return 0;
+}
+
+bool RTPUDPv6Transmitter::NewDataAvailable()
+{
+ if (!init)
+ return false;
+
+ MAINMUTEX_LOCK
+
+ bool v;
+
+ if (!created)
+ v = false;
+ else
+ {
+ if (rawpacketlist.empty())
+ v = false;
+ else
+ v = true;
+ }
+
+ MAINMUTEX_UNLOCK
+ return v;
+}
+
+RTPRawPacket *RTPUDPv6Transmitter::GetNextPacket()
+{
+ if (!init)
+ return 0;
+
+ MAINMUTEX_LOCK
+
+ RTPRawPacket *p;
+
+ if (!created)
+ {
+ MAINMUTEX_UNLOCK
+ return 0;
+ }
+ if (rawpacketlist.empty())
+ {
+ MAINMUTEX_UNLOCK
+ return 0;
+ }
+
+ p = *(rawpacketlist.begin());
+ rawpacketlist.pop_front();
+
+ MAINMUTEX_UNLOCK
+ return p;
+}
+
+// Here the private functions start...
+
+
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+bool RTPUDPv6Transmitter::SetMulticastTTL(uint8_t ttl)
+{
+ int ttl2,status;
+
+ ttl2 = (int)ttl;
+ status = setsockopt(rtpsock,IPPROTO_IPV6,IPV6_MULTICAST_HOPS,(const char *)&ttl2,sizeof(int));
+ if (status != 0)
+ return false;
+ status = setsockopt(rtcpsock,IPPROTO_IPV6,IPV6_MULTICAST_HOPS,(const char *)&ttl2,sizeof(int));
+ if (status != 0)
+ return false;
+ return true;
+}
+#endif // RTP_SUPPORT_IPV6MULTICAST
+
+
+void RTPUDPv6Transmitter::FlushPackets()
+{
+ std::list<RTPRawPacket*>::const_iterator it;
+
+ for (it = rawpacketlist.begin() ; it != rawpacketlist.end() ; ++it)
+ RTPDelete(*it,GetMemoryManager());
+ rawpacketlist.clear();
+}
+
+int RTPUDPv6Transmitter::PollSocket(bool rtp)
+{
+ RTPSOCKLENTYPE fromlen;
+ int recvlen;
+ char packetbuffer[RTPUDPV6TRANS_MAXPACKSIZE];
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ SOCKET sock;
+ unsigned long len;
+#else
+ size_t len;
+ int sock;
+#endif // WIN32
+ struct sockaddr_in6 srcaddr;
+
+ if (rtp)
+ sock = rtpsock;
+ else
+ sock = rtcpsock;
+
+ len = 0;
+ RTPIOCTL(sock,FIONREAD,&len);
+ if (len <= 0)
+ return 0;
+
+ while (len > 0)
+ {
+ RTPTime curtime = RTPTime::CurrentTime();
+ fromlen = sizeof(struct sockaddr_in6);
+ recvlen = recvfrom(sock,packetbuffer,RTPUDPV6TRANS_MAXPACKSIZE,0,(struct sockaddr *)&srcaddr,&fromlen);
+ if (recvlen > 0)
+ {
+ bool acceptdata;
+
+ // got data, process it
+ if (receivemode == RTPTransmitter::AcceptAll)
+ acceptdata = true;
+ else
+ acceptdata = ShouldAcceptData(srcaddr.sin6_addr,ntohs(srcaddr.sin6_port));
+
+ if (acceptdata)
+ {
+ RTPRawPacket *pack;
+ RTPIPv6Address *addr;
+ uint8_t *datacopy;
+
+ addr = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPADDRESS) RTPIPv6Address(srcaddr.sin6_addr,ntohs(srcaddr.sin6_port));
+ if (addr == 0)
+ return ERR_RTP_OUTOFMEM;
+ datacopy = RTPNew(GetMemoryManager(),(rtp)?RTPMEM_TYPE_BUFFER_RECEIVEDRTPPACKET:RTPMEM_TYPE_BUFFER_RECEIVEDRTCPPACKET) uint8_t[recvlen];
+ if (datacopy == 0)
+ {
+ RTPDelete(addr,GetMemoryManager());
+ return ERR_RTP_OUTOFMEM;
+ }
+ memcpy(datacopy,packetbuffer,recvlen);
+
+ pack = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_RTPRAWPACKET) RTPRawPacket(datacopy,recvlen,addr,curtime,rtp,GetMemoryManager());
+ if (pack == 0)
+ {
+ RTPDelete(addr,GetMemoryManager());
+ RTPDeleteByteArray(datacopy,GetMemoryManager());
+ return ERR_RTP_OUTOFMEM;
+ }
+ rawpacketlist.push_back(pack);
+ }
+ }
+ len = 0;
+ RTPIOCTL(sock,FIONREAD,&len);
+ }
+ return 0;
+}
+
+int RTPUDPv6Transmitter::ProcessAddAcceptIgnoreEntry(in6_addr ip,uint16_t port)
+{
+ acceptignoreinfo.GotoElement(ip);
+ if (acceptignoreinfo.HasCurrentElement()) // An entry for this IP address already exists
+ {
+ PortInfo *portinf = acceptignoreinfo.GetCurrentElement();
+
+ if (port == 0) // select all ports
+ {
+ portinf->all = true;
+ portinf->portlist.clear();
+ }
+ else if (!portinf->all)
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = portinf->portlist.begin();
+ end = portinf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == port) // already in list
+ return 0;
+ }
+ portinf->portlist.push_front(port);
+ }
+ }
+ else // got to create an entry for this IP address
+ {
+ PortInfo *portinf;
+ int status;
+
+ portinf = RTPNew(GetMemoryManager(),RTPMEM_TYPE_CLASS_ACCEPTIGNOREPORTINFO) PortInfo();
+ if (port == 0) // select all ports
+ portinf->all = true;
+ else
+ portinf->portlist.push_front(port);
+
+ status = acceptignoreinfo.AddElement(ip,portinf);
+ if (status < 0)
+ {
+ RTPDelete(portinf,GetMemoryManager());
+ return status;
+ }
+ }
+ return 0;
+}
+
+void RTPUDPv6Transmitter::ClearAcceptIgnoreInfo()
+{
+ acceptignoreinfo.GotoFirstElement();
+ while (acceptignoreinfo.HasCurrentElement())
+ {
+ PortInfo *inf;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ RTPDelete(inf,GetMemoryManager());
+ acceptignoreinfo.GotoNextElement();
+ }
+ acceptignoreinfo.Clear();
+}
+
+int RTPUDPv6Transmitter::ProcessDeleteAcceptIgnoreEntry(in6_addr ip,uint16_t port)
+{
+ acceptignoreinfo.GotoElement(ip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return ERR_RTP_UDPV6TRANS_NOSUCHENTRY;
+
+ PortInfo *inf;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (port == 0) // delete all entries
+ {
+ inf->all = false;
+ inf->portlist.clear();
+ }
+ else // a specific port was selected
+ {
+ if (inf->all) // currently, all ports are selected. Add the one to remove to the list
+ {
+ // we have to check if the list doesn't contain the port already
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == port) // already in list: this means we already deleted the entry
+ return ERR_RTP_UDPV6TRANS_NOSUCHENTRY;
+ }
+ inf->portlist.push_front(port);
+ }
+ else // check if we can find the port in the list
+ {
+ std::list<uint16_t>::iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; ++it)
+ {
+ if (*it == port) // found it!
+ {
+ inf->portlist.erase(it);
+ return 0;
+ }
+ }
+ // didn't find it
+ return ERR_RTP_UDPV6TRANS_NOSUCHENTRY;
+ }
+ }
+ return 0;
+}
+
+bool RTPUDPv6Transmitter::ShouldAcceptData(in6_addr srcip,uint16_t srcport)
+{
+ if (receivemode == RTPTransmitter::AcceptSome)
+ {
+ PortInfo *inf;
+
+ acceptignoreinfo.GotoElement(srcip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return false;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (!inf->all) // only accept the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return true;
+ }
+ return false;
+ }
+ else // accept all, except the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return false;
+ }
+ return true;
+ }
+ }
+ else // IgnoreSome
+ {
+ PortInfo *inf;
+
+ acceptignoreinfo.GotoElement(srcip);
+ if (!acceptignoreinfo.HasCurrentElement())
+ return true;
+
+ inf = acceptignoreinfo.GetCurrentElement();
+ if (!inf->all) // ignore the ports in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return false;
+ }
+ return true;
+ }
+ else // ignore all, except the ones in the list
+ {
+ std::list<uint16_t>::const_iterator it,begin,end;
+
+ begin = inf->portlist.begin();
+ end = inf->portlist.end();
+ for (it = begin ; it != end ; it++)
+ {
+ if (*it == srcport)
+ return true;
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+#if (defined(WIN32) || defined(_WIN32_WCE))
+
+int RTPUDPv6Transmitter::CreateAbortDescriptors()
+{
+ SOCKET listensock;
+ int size;
+ struct sockaddr_in6 addr;
+
+ listensock = socket(PF_INET6,SOCK_STREAM,0);
+ if (listensock == RTPSOCKERR)
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ addr.sin6_family = AF_INET6;
+ if (bind(listensock,(struct sockaddr *)&addr,sizeof(struct sockaddr_in6)) != 0)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ size = sizeof(struct sockaddr_in6);
+ if (getsockname(listensock,(struct sockaddr*)&addr,&size) != 0)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ unsigned short connectport = ntohs(addr.sin6_port);
+
+ abortdesc[0] = socket(PF_INET6,SOCK_STREAM,0);
+ if (abortdesc[0] == RTPSOCKERR)
+ {
+ RTPCLOSE(listensock);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ addr.sin6_family = AF_INET6;
+ if (bind(abortdesc[0],(struct sockaddr *)&addr,sizeof(struct sockaddr_in6)) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ if (listen(listensock,1) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_addr = in6addr_loopback;
+ addr.sin6_port = htons(connectport);
+
+ if (connect(abortdesc[0],(struct sockaddr *)&addr,sizeof(struct sockaddr_in6)) != 0)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ memset(&addr,0,sizeof(struct sockaddr_in6));
+ size = sizeof(struct sockaddr_in6);
+ abortdesc[1] = accept(listensock,(struct sockaddr *)&addr,&size);
+ if (abortdesc[1] == RTPSOCKERR)
+ {
+ RTPCLOSE(listensock);
+ RTPCLOSE(abortdesc[0]);
+ return ERR_RTP_UDPV6TRANS_CANTCREATEABORTDESCRIPTORS;
+ }
+
+ // okay, got the connection, close the listening socket
+
+ RTPCLOSE(listensock);
+ return 0;
+}
+
+void RTPUDPv6Transmitter::DestroyAbortDescriptors()
+{
+ RTPCLOSE(abortdesc[0]);
+ RTPCLOSE(abortdesc[1]);
+}
+
+#else // in a non winsock environment we can use pipes
+
+int RTPUDPv6Transmitter::CreateAbortDescriptors()
+{
+ if (pipe(abortdesc) < 0)
+ return ERR_RTP_UDPV6TRANS_CANTCREATEPIPE;
+ return 0;
+}
+
+void RTPUDPv6Transmitter::DestroyAbortDescriptors()
+{
+ close(abortdesc[0]);
+ close(abortdesc[1]);
+}
+
+#endif // WIN32
+
+int RTPUDPv6Transmitter::CreateLocalIPList()
+{
+ // first try to obtain the list from the network interface info
+
+ if (!GetLocalIPList_Interfaces())
+ {
+ // If this fails, we'll have to depend on DNS info
+ GetLocalIPList_DNS();
+ }
+ AddLoopbackAddress();
+ return 0;
+}
+
+#if (defined(WIN32) || defined(_WIN32_WCE))
+
+bool RTPUDPv6Transmitter::GetLocalIPList_Interfaces()
+{
+ unsigned char buffer[RTPUDPV6TRANS_IFREQBUFSIZE];
+ DWORD outputsize;
+ DWORD numaddresses,i;
+ SOCKET_ADDRESS_LIST *addrlist;
+
+ if (WSAIoctl(rtpsock,SIO_ADDRESS_LIST_QUERY,NULL,0,&buffer,RTPUDPV6TRANS_IFREQBUFSIZE,&outputsize,NULL,NULL))
+ return false;
+
+ addrlist = (SOCKET_ADDRESS_LIST *)buffer;
+ numaddresses = addrlist->iAddressCount;
+ for (i = 0 ; i < numaddresses ; i++)
+ {
+ SOCKET_ADDRESS *sockaddr = &(addrlist->Address[i]);
+ if (sockaddr->iSockaddrLength == sizeof(struct sockaddr_in6)) // IPv6 address
+ {
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr->lpSockaddr;
+
+ localIPs.push_back(addr->sin6_addr);
+ }
+ }
+
+ if (localIPs.empty())
+ return false;
+ return true;
+}
+
+#else
+
+#ifdef RTP_SUPPORT_IFADDRS
+
+bool RTPUDPv6Transmitter::GetLocalIPList_Interfaces()
+{
+ struct ifaddrs *addrs,*tmp;
+
+ getifaddrs(&addrs);
+ tmp = addrs;
+
+ while (tmp != 0)
+ {
+ if (tmp->ifa_addr != 0 && tmp->ifa_addr->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *)tmp->ifa_addr;
+ localIPs.push_back(inaddr->sin6_addr);
+ }
+ tmp = tmp->ifa_next;
+ }
+
+ freeifaddrs(addrs);
+
+ if (localIPs.empty())
+ return false;
+ return true;
+}
+
+#else
+
+bool RTPUDPv6Transmitter::GetLocalIPList_Interfaces()
+{
+ return false;
+}
+
+#endif // RTP_SUPPORT_IFADDRS
+
+#endif // WIN32
+
+void RTPUDPv6Transmitter::GetLocalIPList_DNS()
+{
+ int status;
+ char name[1024];
+
+ gethostname(name,1023);
+ name[1023] = 0;
+
+ struct addrinfo hints;
+ struct addrinfo *res,*tmp;
+
+ memset(&hints,0,sizeof(struct addrinfo));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = 0;
+ hints.ai_protocol = 0;
+
+ if ((status = getaddrinfo(name,0,&hints,&res)) != 0)
+ return;
+
+ tmp = res;
+ while (tmp != 0)
+ {
+ if (tmp->ai_family == AF_INET6)
+ {
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *)(tmp->ai_addr);
+ localIPs.push_back(addr->sin6_addr);
+ }
+ tmp = tmp->ai_next;
+ }
+
+ freeaddrinfo(res);
+}
+
+
+void RTPUDPv6Transmitter::AbortWaitInternal()
+{
+#if (defined(WIN32) || defined(_WIN32_WCE))
+ send(abortdesc[1],"*",1,0);
+#else
+ write(abortdesc[1],"*",1);
+#endif // WIN32
+}
+
+
+void RTPUDPv6Transmitter::AddLoopbackAddress()
+{
+ std::list<in6_addr>::const_iterator it;
+ bool found = false;
+
+ for (it = localIPs.begin() ; !found && it != localIPs.end() ; it++)
+ {
+ if ((*it) == in6addr_loopback)
+ found = true;
+ }
+
+ if (!found)
+ localIPs.push_back(in6addr_loopback);
+}
+
+#ifdef RTPDEBUG
+void RTPUDPv6Transmitter::Dump()
+{
+ if (!init)
+ std::cout << "Not initialized" << std::endl;
+ else
+ {
+ MAINMUTEX_LOCK
+
+ if (!created)
+ std::cout << "Not created" << std::endl;
+ else
+ {
+ char str[48];
+ in6_addr ip;
+ uint16_t ip16[8];
+ std::list<in6_addr>::const_iterator it;
+ int i,j;
+
+ std::cout << "Portbase: " << portbase << std::endl;
+ std::cout << "RTP socket descriptor: " << rtpsock << std::endl;
+ std::cout << "RTCP socket descriptor: " << rtcpsock << std::endl;
+ ip = bindIP;
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2) { ip16[j] = (((uint16_t)ip.s6_addr[i])<<8); ip16[j] |= ((uint16_t)ip.s6_addr[i+1]); }
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7]);
+ std::cout << "Bind IP address: " << str << std::endl;
+ std::Cout << "Multicast interface index: " << mcastifidx << std::endl;
+ std::cout << "Local IP addresses:" << std::endl;
+ for (it = localIPs.begin() ; it != localIPs.end() ; it++)
+ {
+ ip = (*it);
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2) { ip16[j] = (((uint16_t)ip.s6_addr[i])<<8); ip16[j] |= ((uint16_t)ip.s6_addr[i+1]); }
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7]);
+ std::cout << " " << str << std::endl;
+ }
+ std::cout << "Multicast TTL: " << (int)multicastTTL << std::endl;
+ std::cout << "Receive mode: ";
+ switch (receivemode)
+ {
+ case RTPTransmitter::AcceptAll:
+ std::cout << "Accept all";
+ break;
+ case RTPTransmitter::AcceptSome:
+ std::cout << "Accept some";
+ break;
+ case RTPTransmitter::IgnoreSome:
+ std::cout << "Ignore some";
+ }
+ std::cout << std::endl;
+ if (receivemode != RTPTransmitter::AcceptAll)
+ {
+ acceptignoreinfo.GotoFirstElement();
+ while(acceptignoreinfo.HasCurrentElement())
+ {
+ ip = acceptignoreinfo.GetCurrentKey();
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2) { ip16[j] = (((uint16_t)ip.s6_addr[i])<<8); ip16[j] |= ((uint16_t)ip.s6_addr[i+1]); }
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7]);
+ PortInfo *pinfo = acceptignoreinfo.GetCurrentElement();
+ std::cout << " " << str << ": ";
+ if (pinfo->all)
+ {
+ std::cout << "All ports";
+ if (!pinfo->portlist.empty())
+ std::cout << ", except ";
+ }
+
+ std::list<uint16_t>::const_iterator it;
+
+ for (it = pinfo->portlist.begin() ; it != pinfo->portlist.end() ; )
+ {
+ std::cout << (*it);
+ it++;
+ if (it != pinfo->portlist.end())
+ std::cout << ", ";
+ }
+ std::cout << std::endl;
+ }
+ }
+
+ std::cout << "Local host name: ";
+ if (localhostname == 0)
+ std::cout << "Not set";
+ else
+ std::cout << localhostname;
+ std::cout << std::endl;
+
+ std::cout << "List of destinations: ";
+ destinations.GotoFirstElement();
+ if (destinations.HasCurrentElement())
+ {
+ std::cout << std::endl;
+ do
+ {
+ std::cout << " " << destinations.GetCurrentElement().GetDestinationString() << std::endl;
+ destinations.GotoNextElement();
+ } while (destinations.HasCurrentElement());
+ }
+ else
+ std::cout << "Empty" << std::endl;
+
+ std::cout << "Supports multicasting: " << ((supportsmulticasting)?"Yes":"No") << std::endl;
+#ifdef RTP_SUPPORT_IPV6MULTICAST
+ std::cout << "List of multicast groups: ";
+ multicastgroups.GotoFirstElement();
+ if (multicastgroups.HasCurrentElement())
+ {
+ std::cout << std::endl;
+ do
+ {
+ ip = multicastgroups.GetCurrentElement();
+ for (i = 0,j = 0 ; j < 8 ; j++,i += 2) { ip16[j] = (((uint16_t)ip.s6_addr[i])<<8); ip16[j] |= ((uint16_t)ip.s6_addr[i+1]); }
+ RTP_SNPRINTF(str,48,"%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",(int)ip16[0],(int)ip16[1],(int)ip16[2],(int)ip16[3],(int)ip16[4],(int)ip16[5],(int)ip16[6],(int)ip16[7]);
+ std::cout << " " << str << std::endl;
+ multicastgroups.GotoNextElement();
+ } while (multicastgroups.HasCurrentElement());
+ }
+ else
+ std::cout << "Empty" << std::endl;
+#endif // RTP_SUPPORT_IPV6MULTICAST
+
+ std::cout << "Number of raw packets in queue: " << rawpacketlist.size() << std::endl;
+ std::cout << "Maximum allowed packet size: " << maxpacksize << std::endl;
+ }
+
+ MAINMUTEX_UNLOCK
+ }
+
+}
+#endif // RTPDEBUG
+
+#endif // RTP_SUPPORT_IPV6
+