From 576816f821b60bc8580b310248bac409ed30915e Mon Sep 17 00:00:00 2001 From: Gerald Begumisa Date: Fri, 24 Aug 2007 21:37:49 +0000 Subject: Added support for SIP 200 OK message with ability to adjust the session RTP IP address and port if NAT is detected git-svn-id: https://oreka.svn.sourceforge.net/svnroot/oreka/trunk@474 09dcff7a-b715-0410-9601-b79a96267cd0 --- .../audiocaptureplugins/voip/PacketHeaderDefs.h | 2 + orkaudio/audiocaptureplugins/voip/RtpSession.cpp | 42 +++++++++++++++ orkaudio/audiocaptureplugins/voip/RtpSession.h | 16 ++++++ orkaudio/audiocaptureplugins/voip/VoIp.cpp | 60 ++++++++++++++++++++-- 4 files changed, 116 insertions(+), 4 deletions(-) (limited to 'orkaudio') diff --git a/orkaudio/audiocaptureplugins/voip/PacketHeaderDefs.h b/orkaudio/audiocaptureplugins/voip/PacketHeaderDefs.h index f054c43..ad6906d 100644 --- a/orkaudio/audiocaptureplugins/voip/PacketHeaderDefs.h +++ b/orkaudio/audiocaptureplugins/voip/PacketHeaderDefs.h @@ -337,8 +337,10 @@ struct Iax2MetaTrunkEntryTs { #define SIP_METHOD_INVITE_SIZE 6 #define SIP_METHOD_BYE_SIZE 3 +#define SIP_RESPONSE_200_OK_SIZE 11 #define SIP_METHOD_INVITE "INVITE" #define SIP_METHOD_BYE "BYE" +#define SIP_RESPONSE_200_OK "SIP/2.0 200" #endif diff --git a/orkaudio/audiocaptureplugins/voip/RtpSession.cpp b/orkaudio/audiocaptureplugins/voip/RtpSession.cpp index 91a483e..e29ad76 100644 --- a/orkaudio/audiocaptureplugins/voip/RtpSession.cpp +++ b/orkaudio/audiocaptureplugins/voip/RtpSession.cpp @@ -697,6 +697,7 @@ void RtpSession::ReportSipInvite(SipInviteInfoRef& invite) invite->ToString(inviteString); CStdString logMsg; logMsg.Format("[%s] associating INVITE:%s", m_trackingId, inviteString); + m_fromRtpIp = invite->m_fromRtpIp; LOG4CXX_INFO(m_log, logMsg); } m_invites.push_front(invite); @@ -916,6 +917,41 @@ void RtpSessions::ReportSipErrorPacket(SipFailureMessageInfoRef& info) return; } +void RtpSessions::ReportSip200Ok(Sip200OkInfoRef info) +{ + std::map::iterator pair; + + pair = m_byCallId.find(info->m_callId); + if (pair != m_byCallId.end()) + { + RtpSessionRef session = pair->second; + + if(info->m_hasSdp && DLLCONFIG.IsPartOfLan(session->m_fromRtpIp) && !DLLCONFIG.IsPartOfLan(info->m_fromRtpIp) && !session->m_numRtpPackets) + { + char szFromRtpIp[16]; + + ACE_OS::inet_ntop(AF_INET, (void*)&info->m_fromRtpIp, szFromRtpIp, sizeof(szFromRtpIp)); + m_byIpAndPort.erase(session->m_ipAndPort); + session->m_ipAndPort = CStdString(szFromRtpIp) + "," + info->m_fromRtpPort; + + pair = m_byIpAndPort.find(session->m_ipAndPort); + if (pair != m_byIpAndPort.end()) + { + RtpSessionRef session2 = pair->second; + + if(session2->m_protocol == RtpSession::ProtRawRtp) + { + Stop(session2); + } + } + + m_byIpAndPort.insert(std::make_pair(session->m_ipAndPort, session)); + + LOG4CXX_INFO(m_log, "[" + session->m_trackingId + "] updated RTP address: " + session->m_ipAndPort); + } + } +} + void RtpSessions::ReportSipBye(SipByeInfo bye) { std::map::iterator pair; @@ -1751,3 +1787,9 @@ void SipFailureMessageInfo::ToString(CStdString& string) string.Format("sender:%s rcvr:%s smac:%s rmac:%s callid:%s errorcode:%s errorstr:\"%s\"", senderIp, receiverIp, senderMac, receiverMac, m_callId, m_errorCode, m_errorString); } +Sip200OkInfo::Sip200OkInfo() +{ + m_fromRtpIp.s_addr = 0; + m_hasSdp = false; +} + diff --git a/orkaudio/audiocaptureplugins/voip/RtpSession.h b/orkaudio/audiocaptureplugins/voip/RtpSession.h index 5475cb9..ec9d262 100644 --- a/orkaudio/audiocaptureplugins/voip/RtpSession.h +++ b/orkaudio/audiocaptureplugins/voip/RtpSession.h @@ -70,6 +70,20 @@ public: CStdString m_callId; }; + +class Sip200OkInfo +{ +public: + Sip200OkInfo(); + CStdString m_callId; + bool m_hasSdp; + struct in_addr m_fromRtpIp; + CStdString m_fromRtpPort; +}; + +typedef boost::shared_ptr Sip200OkInfoRef; + + //============================================================= class EndpointInfo @@ -104,6 +118,7 @@ public: CStdString m_trackingId; CStdString m_ipAndPort; // IP address and TCP port of one side of the session, serves as a key for session storage and retrieval. Not necessarily the same as the capturePort (capturePort is usually the client (phone) IP+port) + struct in_addr m_fromRtpIp; CStdString m_callId; SipInviteInfoRef m_invite; ACE_Time_Value m_creationDate; // When the session is first created @@ -180,6 +195,7 @@ public: void ReportSkinnySoftKeyResume(SkSoftKeyEventMessageStruct* skEvent, IpHeaderStruct* ipHeader); void ReportRtpPacket(RtpPacketInfoRef& rtpPacket); void ReportSipErrorPacket(SipFailureMessageInfoRef& sipError); + void ReportSip200Ok(Sip200OkInfoRef info); void Hoover(time_t now); EndpointInfoRef GetEndpointInfo(struct in_addr endpointIp); void StartCapture(CStdString& party); diff --git a/orkaudio/audiocaptureplugins/voip/VoIp.cpp b/orkaudio/audiocaptureplugins/voip/VoIp.cpp index 2db26d7..60bcf0d 100644 --- a/orkaudio/audiocaptureplugins/voip/VoIp.cpp +++ b/orkaudio/audiocaptureplugins/voip/VoIp.cpp @@ -1360,6 +1360,55 @@ bool TrySipTcp(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, T return result; } +bool TrySip200Ok(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, UdpHeaderStruct* udpHeader, u_char* udpPayload, u_char* packetEnd) +{ + bool result = false; + + int sipLength = ntohs(udpHeader->len) - sizeof(UdpHeaderStruct); + char* sipEnd = (char*)udpPayload + sipLength; + if(sipLength < SIP_RESPONSE_200_OK_SIZE || sipEnd > (char*)packetEnd) + { + ; // packet too short + } + else if (memcmp(SIP_RESPONSE_200_OK, (void*)udpPayload, SIP_RESPONSE_200_OK_SIZE) == 0) + { + result = true; + + Sip200OkInfoRef info(new Sip200OkInfo()); + + char* callIdField = memFindAfter("\r\ni:", (char*)udpPayload, sipEnd); + char* audioField = NULL; + char* connectionAddressField = NULL; + + if(callIdField) + { + GrabTokenSkipLeadingWhitespaces(callIdField, sipEnd, info->m_callId); + audioField = memFindAfter("m=audio ", callIdField, sipEnd); + connectionAddressField = memFindAfter("c=IN IP4 ", callIdField, sipEnd); + } + if(audioField && connectionAddressField) + { + info->m_hasSdp = true; + + GrabToken(audioField, sipEnd, info->m_fromRtpPort); + + CStdString connectionAddress; + GrabToken(connectionAddressField, sipEnd, connectionAddress); + struct in_addr fromIp; + if(connectionAddress.size()) + { + if(ACE_OS::inet_aton((PCSTR)connectionAddress, &fromIp)) + { + info->m_fromRtpIp = fromIp; + } + } + } + + RtpSessionsSingleton::instance()->ReportSip200Ok(info); + } + return result; +} + bool TrySipInvite(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader, UdpHeaderStruct* udpHeader, u_char* udpPayload, u_char* packetEnd) { bool result = false; @@ -1367,12 +1416,11 @@ bool TrySipInvite(EthernetHeaderStruct* ethernetHeader, IpHeaderStruct* ipHeader int sipLength = ntohs(udpHeader->len) - sizeof(UdpHeaderStruct); char* sipEnd = (char*)udpPayload + sipLength; - if(sipLength < sizeof(SIP_METHOD_INVITE) || sipEnd > (char*)packetEnd) + if(sipLength < SIP_METHOD_INVITE_SIZE || sipEnd > (char*)packetEnd) { - return false; + ; // packet too short } - - if (memcmp(SIP_METHOD_INVITE, (void*)udpPayload, SIP_METHOD_INVITE_SIZE) == 0) + else if (memcmp(SIP_METHOD_INVITE, (void*)udpPayload, SIP_METHOD_INVITE_SIZE) == 0) { result = true; @@ -1827,6 +1875,10 @@ void HandlePacket(u_char *param, const struct pcap_pkthdr *header, const u_char detectedUsefulPacket= TrySipInvite(ethernetHeader, ipHeader, udpHeader, udpPayload, ipPacketEnd); } + if(!detectedUsefulPacket) { + detectedUsefulPacket= TrySip200Ok(ethernetHeader, ipHeader, udpHeader, udpPayload, ipPacketEnd); + } + if(!detectedUsefulPacket) { detectedUsefulPacket = TrySipBye(ethernetHeader, ipHeader, udpHeader, udpPayload, ipPacketEnd); } -- cgit v1.2.3