summaryrefslogtreecommitdiff
path: root/orkaudio/audiocaptureplugins/voip/VoIp.cpp
diff options
context:
space:
mode:
authorGerald Begumisa <ben_g@users.sourceforge.net>2008-10-09 21:55:51 +0000
committerGerald Begumisa <ben_g@users.sourceforge.net>2008-10-09 21:55:51 +0000
commitc09609077b6f5eb70db855eed4e909d9d563ffcc (patch)
tree2031d9259e4d2ec2c4d8830c0d92a5d09e416d43 /orkaudio/audiocaptureplugins/voip/VoIp.cpp
parent5bb054adba4ee2e174886852ddde6a70a4ecb9a9 (diff)
Added RTCP support. Key functionality is the ability to set the local party basing on the RTCP SDES information. A new configuration parameter, RtcpDetect, has been added. To enable RTCP, set RtcpDetect to true. This configuration should be done under the VoIpPlugin section of config.xml.
git-svn-id: https://oreka.svn.sourceforge.net/svnroot/oreka/trunk@562 09dcff7a-b715-0410-9601-b79a96267cd0
Diffstat (limited to 'orkaudio/audiocaptureplugins/voip/VoIp.cpp')
-rw-r--r--orkaudio/audiocaptureplugins/voip/VoIp.cpp209
1 files changed, 209 insertions, 0 deletions
diff --git a/orkaudio/audiocaptureplugins/voip/VoIp.cpp b/orkaudio/audiocaptureplugins/voip/VoIp.cpp
index f2d06d0..409e923 100644
--- a/orkaudio/audiocaptureplugins/voip/VoIp.cpp
+++ b/orkaudio/audiocaptureplugins/voip/VoIp.cpp
@@ -54,6 +54,7 @@ static LoggerPtr s_sipTcpPacketLog;
static LoggerPtr s_skinnyPacketLog;
static LoggerPtr s_sipExtractionLog;
static LoggerPtr s_voipPluginLog;
+static LoggerPtr s_rtcpPacketLog;
static time_t s_lastHooveringTime;
static time_t s_lastPause;
static time_t s_lastPacketTimestamp;
@@ -1081,6 +1082,206 @@ bool TryIax2MiniVoiceFrame(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct*
return Iax2SessionsSingleton::instance()->ReportIax2Packet(info);
}
+bool TryRtcp(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, UdpHeaderStruct* udpHeader, u_char* udpPayload)
+{
+ RtcpCommonHeaderStruct* rtcpHeader = (RtcpCommonHeaderStruct*)udpPayload;
+ RtcpCommonHeaderStruct* r = NULL;
+ RtcpCommonHeaderStruct* rtcpEnd = NULL;
+ RtcpCommonHeaderStruct* rtcpThisPktEnd = NULL;
+ CStdString logMsg;
+
+ if(!DLLCONFIG.m_rtcpDetect)
+ {
+ return false;
+ }
+
+ if((ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)) < sizeof(RtcpCommonHeaderStruct))
+ {
+ // Packet too small
+ return false;
+ }
+
+ unsigned short version = (rtcpHeader->vpc & 0x00c0) >> 6;
+ unsigned short p = (rtcpHeader->vpc & 0x0020) >> 5;
+ unsigned short count = (rtcpHeader->vpc & 0x001f);
+
+ if(version != 2)
+ {
+ // Failed first header validity check in RFC1889 A.2
+ return false;
+ }
+
+ if(rtcpHeader->pt != 200 && rtcpHeader->pt != 201)
+ {
+ // Failed second header validity check in RFC1889 A.2
+ return false;
+ }
+
+ if(p != 0)
+ {
+ // Failed third header validity check in RFC1889 A.2
+ return false;
+ }
+
+ rtcpEnd = (RtcpCommonHeaderStruct*)((char*)udpPayload + (ntohs(udpHeader->len)-sizeof(UdpHeaderStruct)));
+ r = rtcpHeader;
+ unsigned short mv = 0;
+
+ r = (RtcpCommonHeaderStruct*)((unsigned int *)r + ntohs(r->length) + 1);
+ while(r < rtcpEnd && ((rtcpEnd - r) >= sizeof(RtcpCommonHeaderStruct)))
+ {
+ mv = (r->vpc & 0x00c0) >> 6;
+ if(mv != 2)
+ {
+ break;
+ }
+ r = (RtcpCommonHeaderStruct*)((unsigned int *)r + ntohs(r->length) + 1);
+ }
+
+ if(r != rtcpEnd)
+ {
+ // Failed final header validity check in RFC1889 A.2
+ return false;
+ }
+
+ char sourceIp[16], destIp[16];
+ ACE_OS::inet_ntop(AF_INET, (void*)&ipHeader->ip_src, sourceIp, sizeof(sourceIp));
+ ACE_OS::inet_ntop(AF_INET, (void*)&ipHeader->ip_dest, destIp, sizeof(destIp));
+
+ // As per RFC we should be fairly sure we have an RTCP packet and
+ // henceforth our return value will be true
+
+ // Now let's see whether we can obtain an SDES packet
+ char cname[256];
+ RtcpSdesCsrcItem *csrcItem = NULL;
+ r = rtcpHeader;
+
+ memset(cname, 0, sizeof(cname));
+
+ r = (RtcpCommonHeaderStruct*)((unsigned int *)r + ntohs(r->length) + 1);
+ while(r < rtcpEnd && ((rtcpEnd - r) >= sizeof(RtcpCommonHeaderStruct)))
+ {
+ version = (r->vpc & 0x00c0) >> 6;
+ p = (r->vpc & 0x0020) >> 5;
+ count = (r->vpc & 0x001f);
+
+ rtcpThisPktEnd = (RtcpCommonHeaderStruct*)((unsigned int *)r + ntohs(r->length) + 1);
+
+ if(r->pt == 202 && count)
+ {
+ // Check if we have CNAME in the first CSRC
+ csrcItem = (RtcpSdesCsrcItem *)((unsigned int *)r + 2);
+
+ while((csrcItem < (RtcpSdesCsrcItem *)rtcpThisPktEnd) && (csrcItem->type != 1) && (csrcItem->type != 0))
+ {
+ csrcItem = (RtcpSdesCsrcItem *)((char*)csrcItem + (int)csrcItem->length);
+ }
+
+ if(csrcItem < (RtcpSdesCsrcItem *)rtcpThisPktEnd && csrcItem->type == 1)
+ {
+ break;
+ }
+
+ csrcItem = NULL;
+ }
+
+ r = (RtcpCommonHeaderStruct*)((unsigned int *)r + ntohs(r->length) + 1);
+ }
+
+ if(csrcItem == NULL)
+ {
+ // No CNAME
+ return true;
+ }
+
+ RtcpSrcDescriptionPacketInfoRef info(new RtcpSrcDescriptionPacketInfo());
+
+ info->m_sourceIp = ipHeader->ip_src;
+ info->m_destIp = ipHeader->ip_dest;
+ info->m_sourcePort = ntohs(udpHeader->source);
+ info->m_destPort = ntohs(udpHeader->dest);
+
+ memcpy(cname, csrcItem->data, ((csrcItem->length > 254) ? 254 : csrcItem->length));
+
+ if(csrcItem->length == 0 || strncasecmp(cname, "ext", ((3 > csrcItem->length) ? csrcItem->length : 3)))
+ {
+ if(DLLCONFIG.m_inInMode == false)
+ {
+ // Not an extension
+ return true;
+ }
+ else
+ {
+ if(csrcItem->length == 0)
+ {
+ return true;
+ }
+ }
+ }
+
+ info->m_fullCname = cname;
+
+ /*
+ * Now parse the CNAME. As per RFC1889, 6.4.1, the CNAME is either
+ * in the format "user@host" or "host". However we will also support
+ * "user@host:port" or "host:port"
+ */
+ char *x = NULL, *y = NULL, *z = NULL;
+
+ x = cname;
+ y = ACE_OS::strchr(cname, '@');
+ if(!y)
+ {
+ // CNAME is in the "host" or "host:port" format only, no user
+ y = ACE_OS::strchr(cname, ':');
+ if(!y)
+ {
+ // We have no port
+ GrabToken(cname, cname+strlen(cname), info->m_cnameDomain);
+ }
+ else
+ {
+ *y++ = '\0';
+ GrabToken(x, x+strlen(x), info->m_cnameDomain);
+ if(*y)
+ {
+ GrabToken(y, y+strlen(y), info->m_cnamePort);
+ }
+ }
+ }
+ else
+ {
+ *y++ = '\0';
+ GrabToken(x, x+strlen(x), info->m_cnameUsername);
+ if(*y)
+ {
+ z = ACE_OS::strchr(y, ':');
+ if(!z)
+ {
+ // We have no port
+ GrabToken(y, y+strlen(y), info->m_cnameDomain);
+ }
+ else
+ {
+ *z++ = '\0';
+ GrabToken(y, y+strlen(y), info->m_cnameDomain);
+ if(*z)
+ {
+ GrabToken(z, z+strlen(z), info->m_cnamePort);
+ }
+ }
+ }
+ }
+
+ info->ToString(logMsg);
+ LOG4CXX_DEBUG(s_rtcpPacketLog, logMsg);
+
+ RtpSessionsSingleton::instance()->ReportRtcpSrcDescription(info);
+
+ return true;
+}
+
+
bool TryRtp(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, UdpHeaderStruct* udpHeader, u_char* udpPayload)
{
bool result = false;
@@ -2370,6 +2571,13 @@ void HandlePacket(u_char *param, const struct pcap_pkthdr *header, const u_char
detectedUsefulPacket = TryLogFailedSip(ethernetHeader, ipHeader, udpHeader, udpPayload, ipPacketEnd);
}
+ if(!detectedUsefulPacket) {
+ if(DLLCONFIG.m_rtcpDetect == true)
+ {
+ detectedUsefulPacket = TryRtcp(ethernetHeader, ipHeader, udpHeader, udpPayload);
+ }
+ }
+
if(DLLCONFIG.m_iax2Support == false)
{
detectedUsefulPacket = true; // Stop trying to detect if this UDP packet could be of interest
@@ -2763,6 +2971,7 @@ void VoIp::Initialize()
s_packetLog = Logger::getLogger("packet");
s_packetStatsLog = Logger::getLogger("packet.pcapstats");
s_rtpPacketLog = Logger::getLogger("packet.rtp");
+ s_rtcpPacketLog = Logger::getLogger("packet.rtcp");
s_sipPacketLog = Logger::getLogger("packet.sip");
s_sipTcpPacketLog = Logger::getLogger("packet.tcpsip");
s_skinnyPacketLog = Logger::getLogger("packet.skinny");