Added optional message to verify reINVITE in media proxying mode.

git-svn-id: http://voip.null.ro/svn/yate@5915 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2014-09-19 11:36:28 +00:00
parent 61b39a94e6
commit e13b4b1a7b
2 changed files with 181 additions and 140 deletions

View File

@ -247,6 +247,9 @@
; update_target: bool: Update dialog target from Contact in reINVITE
;update_target=disable
; update_verify: bool: Use a message to verify if we should accept a reINVITE when proxying media
;update_verify=disable
; preventive_bye: bool: If possible send a BYE besides CANCEL for unanswered calls
;preventive_bye=enable

View File

@ -1000,6 +1000,8 @@ private:
void emitUpdate();
bool emitPRACK(const SIPMessage* msg);
bool startClientReInvite(NamedList& msg, bool rtpForward);
bool reInviteForward(SIPTransaction* t, MimeSdpBody* sdp, int invite);
bool reInviteProxy(SIPTransaction* t, MimeSdpBody* sdp, int invite);
// Build the 'call.route' and NOTIFY messages needed by the transfer thread
bool initTransfer(Message*& msg, SIPMessage*& sipNotify, const SIPMessage* sipRefer,
const MimeHeaderLine* refHdr, const URI& uri, const MimeHeaderLine* replaces);
@ -1212,6 +1214,7 @@ static bool s_gen_async = true;
static bool s_multi_ringing = false;
static bool s_refresh_nosdp = true;
static bool s_update_target = false;
static bool s_update_verify = false;
static bool s_preventive_bye = true;
static bool s_ignoreVia = true; // Ignore Via headers and send answer back to the source
static bool s_sipt_isup = false; // Control the application/isup body processing
@ -6822,10 +6825,6 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
if (!checkUser(t))
return;
DDebug(this,DebugAll,"YateSIPConnection::reInvite(%p) [%p]",t,this);
m_dialog.adjustCSeq(t->initialMessage());
// Change party
if (t->getEngine()->autoChangeParty() && t->initialMessage() && !t->initialMessage()->isOutgoing())
setPartyChanged(t->initialMessage()->getParty(),this);
Lock mylock(driver());
int invite = m_reInviting;
if (m_tr || m_tr2 || (invite == ReinviteRequest) || (invite == ReinviteReceived)) {
@ -6839,17 +6838,38 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
}
m_reInviting = ReinviteReceived;
mylock.drop();
m_dialog.adjustCSeq(t->initialMessage());
// Change party
if (t->getEngine()->autoChangeParty() && t->initialMessage() && !t->initialMessage()->isOutgoing())
setPartyChanged(t->initialMessage()->getParty(),this);
// hack: use a while instead of if so we can return or break out of it
MimeSdpBody* sdp = getSdpBody(t->initialMessage()->body);
while (sdp) {
// for pass-trough RTP we need support from our peer
if (m_rtpForward) {
if (sdp) {
if (m_rtpForward ? reInviteForward(t,sdp,invite) : reInviteProxy(t,sdp,invite))
return;
}
m_reInviting = invite;
if (s_refresh_nosdp && !sdp) {
// be permissive, accept session refresh with no SDP
updateTarget(t->initialMessage());
SIPMessage* m = new SIPMessage(t->initialMessage(),200);
// if required provide our own media offer
if (!m_rtpForward)
m->setBody(createSDP());
t->setResponse(m);
m->deref();
return;
}
t->setResponse(488);
}
bool YateSIPConnection::reInviteForward(SIPTransaction* t, MimeSdpBody* sdp, int invite)
{
String addr;
String natAddr;
ObjList* lst = plugin.parser().parse(sdp,addr,0,String::empty(),true);
if (!lst)
break;
return false;
// guess if the call comes from behind a NAT
if (s_auto_nat && isNatBetween(addr,m_host)) {
Debug(this,DebugInfo,"RTP NAT detected: private '%s' public '%s'",
@ -6859,6 +6879,7 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
}
Debug(this,DebugAll,"reINVITE RTP addr '%s'",addr.c_str());
// for pass-trough RTP we need support from our peer
Message msg("call.update");
complete(msg);
if (s_update_target) {
@ -6897,7 +6918,7 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
TelEngine::destruct(lst);
addSdpParams(msg,sdp);
bool ok = Engine::dispatch(msg);
Lock mylock2(driver());
Lock mylock(driver());
// if peer doesn't support updates fail the reINVITE
if (!ok) {
t->setResponse(msg.getIntValue(YSTRING("error"),dict_errors,488),msg.getValue(YSTRING("reason")));
@ -6908,7 +6929,7 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
t->setResponse(491);
// media is uncertain now so drop the call
setReason("Internal Server Error",500);
mylock2.drop();
mylock.drop();
hangup();
}
else {
@ -6917,26 +6938,54 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
t->setUserData(this);
m_tr2 = t;
}
return;
}
return true;
}
bool YateSIPConnection::reInviteProxy(SIPTransaction* t, MimeSdpBody* sdp, int invite)
{
// refuse request if we had no media at all before
if (m_mediaStatus == MediaMissing)
break;
return false;
String addr;
String natAddr;
ObjList* lst = plugin.parser().parse(sdp,addr);
if (!lst)
break;
return false;
// guess if the call comes from behind a NAT
if (s_auto_nat && isNatBetween(addr,m_host)) {
Debug(this,DebugInfo,"RTP NAT detected: private '%s' public '%s'",
addr.c_str(),m_host.c_str());
natAddr = addr;
addr = m_host;
}
// TODO: check if we should accept the new media
// many implementation don't handle well failure so we should drop
bool audioChg = (getMedia(YSTRING("audio")) != 0);
audioChg ^= ((*lst)[YSTRING("audio")] != 0);
Message ver("call.update");
if (s_update_verify) {
complete(ver);
ver.addParam("operation","verify");
ver.addParam("method",t->initialMessage()->method);
copySipHeaders(ver,*t->initialMessage());
ver.addParam("rtp_addr",addr);
if (natAddr)
ver.addParam("rtp_nat_addr",natAddr);
ver.addParam("audio_changed",String::boolText(audioChg));
putMedia(ver,lst);
addSdpParams(ver,sdp);
if (!Engine::dispatch(ver) || (ver.retValue() == YSTRING("error")) || (ver.retValue() == "-")) {
TelEngine::destruct(lst);
SIPMessage* m = new SIPMessage(t->initialMessage(),
ver.getIntValue(YSTRING("error"),dict_errors,488),ver.getValue(YSTRING("reason")));
copySipHeaders(*m,ver);
t->setResponse(m);
m->deref();
m_reInviting = invite;
return true;
}
}
if (m_rtpAddr != addr) {
m_rtpAddr = addr;
Debug(this,DebugAll,"New RTP addr '%s'",m_rtpAddr.c_str());
@ -6945,7 +6994,6 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
setMedia(0);
}
setMedia(lst);
audioChg ^= (getMedia(YSTRING("audio")) != 0);
m_mediaStatus = MediaMissing;
// let RTP guess again the local interface or use the enforced address
@ -6957,10 +7005,13 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
bool contactChg = (uri != m_uri);
SIPMessage* m = new SIPMessage(t->initialMessage(), 200);
copySipHeaders(*m,ver);
MimeSdpBody* sdpNew = createRtpSDP(true);
m->setBody(sdpNew);
t->setResponse(m);
m->deref();
// notify peer about the changes
Message* msg = message("call.update");
msg->addParam("operation","notify");
msg->addParam("mandatory","false");
@ -6977,21 +7028,7 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
putMedia(*msg);
Engine::enqueue(msg);
m_reInviting = invite;
return;
}
m_reInviting = invite;
if (s_refresh_nosdp && !sdp) {
// be permissive, accept session refresh with no SDP
updateTarget(t->initialMessage());
SIPMessage* m = new SIPMessage(t->initialMessage(),200);
// if required provide our own media offer
if (!m_rtpForward)
m->setBody(createSDP());
t->setResponse(m);
m->deref();
return;
}
t->setResponse(488);
return true;
}
bool YateSIPConnection::checkUser(SIPTransaction* t, bool refuse)
@ -8799,6 +8836,7 @@ void SIPDriver::initialize()
s_multi_ringing = s_cfg.getBoolValue("general","multi_ringing",false);
s_refresh_nosdp = s_cfg.getBoolValue("general","refresh_nosdp",true);
s_update_target = s_cfg.getBoolValue("general","update_target",false);
s_update_verify = s_cfg.getBoolValue("general","update_verify",false);
s_preventive_bye = s_cfg.getBoolValue("general","preventive_bye",true);
s_ignoreVia = s_cfg.getBoolValue("general","ignorevia",true);
s_ipv6 = s_cfg.getBoolValue("general","ipv6_support",false);