summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenri Herscher <henri@oreka.org>2007-08-07 20:05:53 +0000
committerHenri Herscher <henri@oreka.org>2007-08-07 20:05:53 +0000
commitf514b2da9713da1dc3fd5fca983bdcfaeeefed3d (patch)
treecee40c49401c468f80a6047700d0b858d742e02c
parentad3a60beee501f9e89a539035fb3ff07d6a2e5cd (diff)
Added possibility to log failed SIP calls (SIP CANCEL or SIP INVITE with 4xx, 5xx or 6xx error code) using SipLogFailedCalls config parameter.
git-svn-id: https://oreka.svn.sourceforge.net/svnroot/oreka/trunk@462 09dcff7a-b715-0410-9601-b79a96267cd0
-rw-r--r--orkaudio/audiocaptureplugins/voip/RtpSession.h2
-rw-r--r--orkaudio/audiocaptureplugins/voip/SipTcp.cpp71
-rw-r--r--orkaudio/audiocaptureplugins/voip/VoIp.cpp192
-rw-r--r--orkaudio/audiocaptureplugins/voip/VoIpConfig.cpp2
-rw-r--r--orkaudio/audiocaptureplugins/voip/VoIpConfig.h1
5 files changed, 218 insertions, 50 deletions
diff --git a/orkaudio/audiocaptureplugins/voip/RtpSession.h b/orkaudio/audiocaptureplugins/voip/RtpSession.h
index 2919926..98464f1 100644
--- a/orkaudio/audiocaptureplugins/voip/RtpSession.h
+++ b/orkaudio/audiocaptureplugins/voip/RtpSession.h
@@ -41,6 +41,8 @@ public:
CStdString m_callId;
bool m_validated; // true when an RTP stream has been seen for the INVITE
std::map<CStdString, CStdString> m_extractedFields;
+
+ time_t m_recvTime;
};
typedef boost::shared_ptr<SipInviteInfo> SipInviteInfoRef;
diff --git a/orkaudio/audiocaptureplugins/voip/SipTcp.cpp b/orkaudio/audiocaptureplugins/voip/SipTcp.cpp
index eaa86e3..8b02838 100644
--- a/orkaudio/audiocaptureplugins/voip/SipTcp.cpp
+++ b/orkaudio/audiocaptureplugins/voip/SipTcp.cpp
@@ -111,6 +111,20 @@ static char* memFindAfter(char* toFind, char* start, char* stop)
return NULL;
}
+// Implementation of strcasestr() - works like strstr() but
+// is case insensitive
+char* memFindStr(char* toFind, char* start, char* stop)
+{
+ for(char * ptr = start; (ptr<stop) && (ptr != NULL); ptr = (char *)memchr(ptr+1, toFind[0],(stop - start)))
+ {
+ if(ACE_OS::strncasecmp(toFind, ptr, strlen(toFind)) == 0)
+ {
+ return (ptr);
+ }
+ }
+ return NULL;
+}
+
static char* memFindEOL(char* start, char* limit)
{
char* c = start;
@@ -200,7 +214,7 @@ bool SipTcpStream::SipRequestIsComplete()
char *pBufStart = (char*)m_sipRequest->GetBuffer();
char *pBufEnd = pBufStart+m_sipRequest->Size();
- char *contentLengthHeader = ACE_OS::strstr(pBufStart, "Content-Length: ");
+ char *contentLengthHeader = memFindStr("Content-Length: ", pBufStart, pBufEnd);
char *contentLength = memFindAfter("Content-Length: ", pBufStart, pBufEnd);
int cLength = 0;
@@ -208,23 +222,62 @@ bool SipTcpStream::SipRequestIsComplete()
return false;
char *eol = memFindEOL(contentLengthHeader, pBufEnd);
+
if(eol == contentLengthHeader)
return false;
cLength = ACE_OS::atoi(contentLength);
- if(!cLength)
- return true;
- /* Step over newlines */
- while(*eol && (*eol == '\r' || *eol == '\n'))
- eol++;
+ /* Step over headers */
+ bool lnl = false, headerEndLocated = false;
+ while(eol < pBufEnd) {
+ if(*eol == '\r' && ((eol+1) < pBufEnd) && (*(eol+1) == '\n')) {
+ if(lnl == true) {
+ eol += 2;
+ headerEndLocated = true;
+ break;
+ }
+
+ eol += 2;
+ lnl = true;
+ continue;
+ }
+
+ if(*eol == '\n') {
+ if(lnl == true) {
+ eol += 1;
+ headerEndLocated = true;
+ break;
+ }
+
+ eol += 1;
+ lnl = true;
+ continue;
+ }
+
+ eol += 1;
+ lnl = false;
+ continue;
+ }
- if(!*eol)
+ if(!headerEndLocated)
return false;
+ if(eol >= pBufEnd)
+ {
+ if(cLength == 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
if(strlen(eol) == cLength)
- return true;
-
+ return true;
+
return false;
}
diff --git a/orkaudio/audiocaptureplugins/voip/VoIp.cpp b/orkaudio/audiocaptureplugins/voip/VoIp.cpp
index e0cfbac..9b357b1 100644
--- a/orkaudio/audiocaptureplugins/voip/VoIp.cpp
+++ b/orkaudio/audiocaptureplugins/voip/VoIp.cpp
@@ -68,6 +68,7 @@ static unsigned int s_numPacketsPerSecond;
static unsigned int s_minPacketsPerSecond;
static unsigned int s_maxPacketsPerSecond;
static std::list<SipTcpStreamRef> s_SipTcpStreams;
+static std::list<SipInviteInfoRef> s_SipInvites;
VoIpConfigTopObjectRef g_VoIpConfigTopObjectRef;
#define DLLCONFIG g_VoIpConfigTopObjectRef.get()->m_config
@@ -1082,6 +1083,82 @@ bool TrySipBye(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, U
bool TrySipInvite(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, UdpHeaderStruct* udpHeader, u_char* udpPayload, u_char* packetEnd);
bool TrySipBye(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, UdpHeaderStruct* udpHeader, u_char* udpPayload, u_char* packetEnd);
+bool TryLogFailedSip(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, UdpHeaderStruct* udpHeader, u_char* udpPayload, u_char* packetEnd)
+{
+ if(DLLCONFIG.m_sipLogFailedCalls == false)
+ {
+ return false;
+ }
+
+ int sipLength = ntohs(udpHeader->len) - sizeof(UdpHeaderStruct);
+ char* sipEnd = (char*)udpPayload + sipLength;
+ CStdString callId, errorCode, logMsg;
+ std::list<SipInviteInfoRef> toErase;
+ bool result = false;
+
+ if(sipLength < 9 || sipEnd > (char*)packetEnd)
+ {
+ return false;
+ }
+
+ if((memcmp("SIP/2.0 4", (void*)udpPayload, 9) == 0) ||
+ (memcmp("SIP/2.0 5", (void*)udpPayload, 9) == 0) ||
+ (memcmp("SIP/2.0 6", (void*)udpPayload, 9) == 0) ||
+ (memcmp("CANCEL ", (void*)udpPayload, 7) == 0))
+ {
+ char* callIdField = memFindAfter("Call-ID:", (char*)udpPayload, sipEnd);
+ char* eCode = memFindAfter("SIP/2.0 ", (char*)udpPayload, sipEnd);
+
+ if(callIdField)
+ {
+ GrabTokenSkipLeadingWhitespaces(callIdField, sipEnd, callId);
+ }
+
+ if((memcmp("CANCEL ", (void*)udpPayload, 7) == 0))
+ {
+ errorCode.Format("CANCEL");
+ }
+ else
+ {
+ if(eCode)
+ {
+ GrabLine(eCode, sipEnd, errorCode);
+ }
+ }
+ }
+
+ if(callId.size() && errorCode.size())
+ {
+ result = true;
+ }
+
+ int found = 0;
+
+ for(std::list<SipInviteInfoRef>::iterator it = s_SipInvites.begin(); it != s_SipInvites.end(); it++)
+ {
+ SipInviteInfoRef inviteInfo = *it;
+
+ if(callId.size() && (inviteInfo->m_callId.CompareNoCase(callId) == 0) && !found) {
+ found = 1;
+ logMsg.Format("SIP INVITE (call-id:%s) failed (\"%s\")",
+ inviteInfo->m_callId, errorCode);
+ LOG4CXX_INFO(s_sipPacketLog, logMsg);
+ toErase.push_back(inviteInfo);
+ } else {
+ if((time(NULL) - inviteInfo->m_recvTime) >= 60)
+ toErase.push_back(inviteInfo);
+ }
+ }
+
+ for(std::list<SipInviteInfoRef>::iterator it2 = toErase.begin(); it2 != toErase.end(); it2++)
+ {
+ SipInviteInfoRef inviteInfo = *it2;
+ s_SipInvites.remove(inviteInfo);
+ }
+
+ return result;
+}
+
static bool SipByeTcpToUdp(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader,TcpHeaderStruct* tcpHeader, u_char *pBuffer, int bLength)
{
UdpHeaderStruct udpHeader;
@@ -1104,25 +1181,42 @@ static bool SipInviteTcpToUdp(EthernetHeaderStruct* ethernetHeader, IpHeaderStru
return TrySipInvite(ethernetHeader, ipHeader, &udpHeader, pBuffer, pBuffer+bLength);
}
+static bool SipFailedTcpToUdp(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, TcpHeaderStruct* tcpHeader, u_char *pBuffer, int bLength)
+{
+ UdpHeaderStruct udpHeader;
+
+ udpHeader.source = tcpHeader->source;
+ udpHeader.dest = tcpHeader->dest;
+ udpHeader.len = htons(bLength+sizeof(UdpHeaderStruct));
+
+ return TryLogFailedSip(ethernetHeader, ipHeader, &udpHeader, pBuffer, pBuffer+bLength);
+}
+
bool TrySipTcp(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, TcpHeaderStruct* tcpHeader)
{
int tcpLengthPayloadLength = 0;
bool result = false;
std::list<SipTcpStreamRef> toErase;
+ u_char* startTcpPayload;
if(ntohs(tcpHeader->source) != 5060 && ntohs(tcpHeader->dest) != 5060)
return false;
- u_char* startTcpPayload = (u_char*)tcpHeader + TCP_HEADER_LENGTH;
+ startTcpPayload = (u_char*)tcpHeader + (tcpHeader->off * 4);
tcpLengthPayloadLength = ((u_char*)ipHeader+ntohs(ipHeader->ip_len)) - startTcpPayload;
- if(tcpLengthPayloadLength < SIP_METHOD_INVITE_SIZE)
- {
- return false;
- }
+ if(tcpLengthPayloadLength < SIP_METHOD_INVITE_SIZE+3)
+ {
+ LOG4CXX_INFO(s_sipTcpPacketLog, "Payload shorter");
+ return false;
+ }
if((memcmp(SIP_METHOD_INVITE, (void*)startTcpPayload, SIP_METHOD_INVITE_SIZE) == 0) ||
- (memcmp(SIP_METHOD_BYE, (void*)startTcpPayload, SIP_METHOD_BYE_SIZE) == 0))
+ (memcmp(SIP_METHOD_BYE, (void*)startTcpPayload, SIP_METHOD_BYE_SIZE) == 0) ||
+ (memcmp("SIP/2.0 4", (void*)startTcpPayload, 9) == 0) ||
+ (memcmp("SIP/2.0 5", (void*)startTcpPayload, 9) == 0) ||
+ (memcmp("SIP/2.0 6", (void*)startTcpPayload, 9) == 0) ||
+ (memcmp("CANCEL ", (void*)startTcpPayload, 7) == 0))
{
SipTcpStreamRef tcpstream(new SipTcpStream());
int exists = 0;
@@ -1166,12 +1260,23 @@ bool TrySipTcp(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, T
CStdString tcpStream;
tcpstream->ToString(tcpStream);
- LOG4CXX_INFO(s_sipTcpPacketLog, "Obtained complete TCP Stream: " + tcpStream);
+ LOG4CXX_DEBUG(s_sipTcpPacketLog, "Obtained complete TCP Stream: " + tcpStream);
+
+ bool usefulPacket = false;
+
+ usefulPacket = SipInviteTcpToUdp(ethernetHeader, ipHeader, tcpHeader, buffer->GetBuffer(), buffer->Size());
- if(memcmp(SIP_METHOD_INVITE, (void*)buffer->GetBuffer(), SIP_METHOD_INVITE_SIZE) == 0)
- return SipInviteTcpToUdp(ethernetHeader, ipHeader, tcpHeader, buffer->GetBuffer(), buffer->Size());
+ if(!usefulPacket)
+ {
+ usefulPacket = SipByeTcpToUdp(ethernetHeader, ipHeader, tcpHeader, buffer->GetBuffer(), buffer->Size());
+ }
+
+ if(!usefulPacket)
+ {
+ usefulPacket = SipFailedTcpToUdp(ethernetHeader, ipHeader, tcpHeader, buffer->GetBuffer(), buffer->Size());
+ }
- return SipByeTcpToUdp(ethernetHeader, ipHeader, tcpHeader, buffer->GetBuffer(), buffer->Size());
+ return usefulPacket;
}
s_SipTcpStreams.push_back(tcpstream);
@@ -1207,10 +1312,18 @@ bool TrySipTcp(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, T
tcpstream->ToString(tcpStream);
LOG4CXX_INFO(s_sipTcpPacketLog, "TCP Stream updated to completion: " + tcpStream);
- if(memcmp(SIP_METHOD_INVITE, (void*)buffer->GetBuffer(), SIP_METHOD_INVITE_SIZE) == 0) {
- SipInviteTcpToUdp(ethernetHeader, ipHeader, tcpHeader, buffer->GetBuffer(), buffer->Size());
- } else {
- SipByeTcpToUdp(ethernetHeader, ipHeader, tcpHeader, buffer->GetBuffer(), buffer->Size());
+ bool usefulPacket = false;
+
+ usefulPacket = SipInviteTcpToUdp(ethernetHeader, ipHeader, tcpHeader, buffer->GetBuffer(), buffer->Size());
+
+ if(!usefulPacket)
+ {
+ usefulPacket = SipByeTcpToUdp(ethernetHeader, ipHeader, tcpHeader, buffer->GetBuffer(), buffer->Size());
+ }
+
+ if(!usefulPacket)
+ {
+ usefulPacket = SipFailedTcpToUdp(ethernetHeader, ipHeader, tcpHeader, buffer->GetBuffer(), buffer->Size());
}
toErase.push_back(tcpstream);
@@ -1354,6 +1467,7 @@ bool TrySipInvite(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader
}
info->m_senderIp = ipHeader->ip_src;
info->m_receiverIp = ipHeader->ip_dest;
+ info->m_recvTime = time(NULL);
memcpy(info->m_senderMac, ethernetHeader->sourceMac, sizeof(info->m_senderMac));
memcpy(info->m_receiverMac, ethernetHeader->destinationMac, sizeof(info->m_receiverMac));
@@ -1365,6 +1479,7 @@ bool TrySipInvite(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader
if(drop == false && info->m_fromRtpPort.size() && info->m_from.size() && info->m_to.size() && info->m_callId.size())
{
RtpSessionsSingleton::instance()->ReportSipInvite(info);
+ s_SipInvites.push_back(info);
}
}
return result;
@@ -1686,17 +1801,20 @@ void HandlePacket(u_char *param, const struct pcap_pkthdr *header, const u_char
MutexSentinel mutexSentinel(s_mutex); // serialize access for competing pcap threads
- detectedUsefulPacket = TryRtp(ethernetHeader, ipHeader, udpHeader, udpPayload);
+ detectedUsefulPacket = TryRtp(ethernetHeader, ipHeader, udpHeader, udpPayload);
- if(!detectedUsefulPacket) {
- detectedUsefulPacket= TrySipInvite(ethernetHeader, ipHeader, udpHeader,
- udpPayload, ipPacketEnd);
- }
+ if(!detectedUsefulPacket) {
+ detectedUsefulPacket= TrySipInvite(ethernetHeader, ipHeader, udpHeader, udpPayload, ipPacketEnd);
+ }
+
+ if(!detectedUsefulPacket) {
+ detectedUsefulPacket = TrySipBye(ethernetHeader, ipHeader, udpHeader, udpPayload, ipPacketEnd);
+ }
+
+ if(!detectedUsefulPacket) {
+ detectedUsefulPacket = TryLogFailedSip(ethernetHeader, ipHeader, udpHeader, udpPayload, ipPacketEnd);
+ }
- if(!detectedUsefulPacket) {
- detectedUsefulPacket = TrySipBye(ethernetHeader, ipHeader, udpHeader,
- udpPayload, ipPacketEnd);
- }
if(DLLCONFIG.m_iax2Support == false)
{
detectedUsefulPacket = true; // Stop trying to detect if this UDP packet could be of interest
@@ -1707,44 +1825,36 @@ void HandlePacket(u_char *param, const struct pcap_pkthdr *header, const u_char
}
if(!detectedUsefulPacket) {
- detectedUsefulPacket = TryIax2Accept(ethernetHeader, ipHeader, udpHeader,
- udpPayload);
+ detectedUsefulPacket = TryIax2Accept(ethernetHeader, ipHeader, udpHeader, udpPayload);
}
if(!detectedUsefulPacket) {
- detectedUsefulPacket = TryIax2Authreq(ethernetHeader, ipHeader, udpHeader,
- udpPayload);
+ detectedUsefulPacket = TryIax2Authreq(ethernetHeader, ipHeader, udpHeader, udpPayload);
}
if(!detectedUsefulPacket) {
- detectedUsefulPacket = TryIax2Hangup(ethernetHeader, ipHeader, udpHeader,
- udpPayload);
+ detectedUsefulPacket = TryIax2Hangup(ethernetHeader, ipHeader, udpHeader, udpPayload);
}
if(!detectedUsefulPacket) {
- detectedUsefulPacket = TryIax2ControlHangup(ethernetHeader, ipHeader, udpHeader,
- udpPayload);
+ detectedUsefulPacket = TryIax2ControlHangup(ethernetHeader, ipHeader, udpHeader, udpPayload);
}
if(!detectedUsefulPacket) {
- detectedUsefulPacket = TryIax2Reject(ethernetHeader, ipHeader, udpHeader,
- udpPayload);
+ detectedUsefulPacket = TryIax2Reject(ethernetHeader, ipHeader, udpHeader, udpPayload);
}
if(!detectedUsefulPacket) {
- detectedUsefulPacket = TryIax2FullVoiceFrame(ethernetHeader, ipHeader,
- udpHeader, udpPayload);
+ detectedUsefulPacket = TryIax2FullVoiceFrame(ethernetHeader, ipHeader, udpHeader, udpPayload);
}
if(!detectedUsefulPacket) {
- detectedUsefulPacket = TryIax2MetaTrunkFrame(ethernetHeader, ipHeader,
- udpHeader, udpPayload);
+ detectedUsefulPacket = TryIax2MetaTrunkFrame(ethernetHeader, ipHeader, udpHeader, udpPayload);
}
- if(!detectedUsefulPacket) {
- detectedUsefulPacket = TryIax2MiniVoiceFrame(ethernetHeader, ipHeader,
- udpHeader, udpPayload);
- }
+ if(!detectedUsefulPacket) {
+ detectedUsefulPacket = TryIax2MiniVoiceFrame(ethernetHeader, ipHeader, udpHeader, udpPayload);
+ }
}
}
else if(ipHeader->ip_p == IPPROTO_TCP)
diff --git a/orkaudio/audiocaptureplugins/voip/VoIpConfig.cpp b/orkaudio/audiocaptureplugins/voip/VoIpConfig.cpp
index c392e06..bdced26 100644
--- a/orkaudio/audiocaptureplugins/voip/VoIpConfig.cpp
+++ b/orkaudio/audiocaptureplugins/voip/VoIpConfig.cpp
@@ -39,6 +39,7 @@ VoIpConfig::VoIpConfig()
m_iax2Support = false; // Disabled by default
m_rtpDetectOnOddPorts = false;
m_sipOverTcpSupport = false; // Disabled by default
+ m_sipLogFailedCalls = false;
m_useMacIfNoLocalParty = false; // Uses IP address by default
m_skinnyIgnoreStopMediaTransmission = false;
@@ -82,6 +83,7 @@ void VoIpConfig::Define(Serializer* s)
s->BoolValue("RtpDetectOnOddPorts", m_rtpDetectOnOddPorts);
s->CsvValue("SipExtractFields", m_sipExtractFields);
s->BoolValue("SipOverTcpSupport", m_sipOverTcpSupport);
+ s->BoolValue("SipLogFailedCalls", m_sipLogFailedCalls);
s->BoolValue("UseMacIfNoLocalParty", m_useMacIfNoLocalParty);
s->BoolValue("SkinnyIgnoreStopMediaTransmission", m_skinnyIgnoreStopMediaTransmission);
diff --git a/orkaudio/audiocaptureplugins/voip/VoIpConfig.h b/orkaudio/audiocaptureplugins/voip/VoIpConfig.h
index 5448b6a..c1e8b48 100644
--- a/orkaudio/audiocaptureplugins/voip/VoIpConfig.h
+++ b/orkaudio/audiocaptureplugins/voip/VoIpConfig.h
@@ -73,6 +73,7 @@ public:
bool m_rtpDetectOnOddPorts;
bool m_iax2Support;
bool m_sipOverTcpSupport;
+ bool m_sipLogFailedCalls;
bool m_useMacIfNoLocalParty;
bool m_skinnyIgnoreStopMediaTransmission;