Added optional message to verify reINVITE in media proxying mode.
git-svn-id: http://yate.null.ro/svn/yate/trunk@5915 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
cef24d27f8
commit
f9e6470a90
|
@ -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
|
||||
|
||||
|
|
|
@ -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,145 +6838,15 @@ 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) {
|
||||
String addr;
|
||||
String natAddr;
|
||||
ObjList* lst = plugin.parser().parse(sdp,addr,0,String::empty(),true);
|
||||
if (!lst)
|
||||
break;
|
||||
// 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;
|
||||
}
|
||||
Debug(this,DebugAll,"reINVITE RTP addr '%s'",addr.c_str());
|
||||
|
||||
Message msg("call.update");
|
||||
complete(msg);
|
||||
if (s_update_target) {
|
||||
bool addrChg = false;
|
||||
SIPParty* party = t->initialMessage()->getParty();
|
||||
if (party) {
|
||||
String addr;
|
||||
party->appendAddr(addr,false);
|
||||
if (addr != m_address) {
|
||||
msg.setParam("address",addr);
|
||||
msg.addParam("address_old",m_address);
|
||||
addrChg = true;
|
||||
}
|
||||
}
|
||||
msg.addParam("address_changed",String::boolText(addrChg));
|
||||
bool contactChg = false;
|
||||
const MimeHeaderLine* co = t->initialMessage()->getHeader("Contact");
|
||||
if (co) {
|
||||
URI uri(*co);
|
||||
uri.parse();
|
||||
if (uri != m_uri) {
|
||||
msg.addParam("contact",uri);
|
||||
msg.addParam("contact_old",m_uri);
|
||||
contactChg = true;
|
||||
}
|
||||
}
|
||||
msg.addParam("contact_changed",String::boolText(contactChg));
|
||||
}
|
||||
msg.addParam("operation","request");
|
||||
copySipHeaders(msg,*t->initialMessage());
|
||||
msg.addParam("rtp_forward","yes");
|
||||
msg.addParam("rtp_addr",addr);
|
||||
if (natAddr)
|
||||
msg.addParam("rtp_nat_addr",natAddr);
|
||||
putMedia(msg,lst);
|
||||
TelEngine::destruct(lst);
|
||||
addSdpParams(msg,sdp);
|
||||
bool ok = Engine::dispatch(msg);
|
||||
Lock mylock2(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")));
|
||||
m_reInviting = invite;
|
||||
}
|
||||
else if (m_tr2) {
|
||||
// ouch! this shouldn't have happened!
|
||||
t->setResponse(491);
|
||||
// media is uncertain now so drop the call
|
||||
setReason("Internal Server Error",500);
|
||||
mylock2.drop();
|
||||
hangup();
|
||||
}
|
||||
else {
|
||||
// we remember the request and leave it pending
|
||||
t->ref();
|
||||
t->setUserData(this);
|
||||
m_tr2 = t;
|
||||
}
|
||||
if (sdp) {
|
||||
if (m_rtpForward ? reInviteForward(t,sdp,invite) : reInviteProxy(t,sdp,invite))
|
||||
return;
|
||||
}
|
||||
// refuse request if we had no media at all before
|
||||
if (m_mediaStatus == MediaMissing)
|
||||
break;
|
||||
String addr;
|
||||
ObjList* lst = plugin.parser().parse(sdp,addr);
|
||||
if (!lst)
|
||||
break;
|
||||
// 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());
|
||||
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);
|
||||
if (m_rtpAddr != addr) {
|
||||
m_rtpAddr = addr;
|
||||
Debug(this,DebugAll,"New RTP addr '%s'",m_rtpAddr.c_str());
|
||||
// clear all data endpoints - createRtpSDP will build new ones
|
||||
if (!s_rtp_preserve)
|
||||
setMedia(0);
|
||||
}
|
||||
setMedia(lst);
|
||||
audioChg ^= (getMedia(YSTRING("audio")) != 0);
|
||||
|
||||
m_mediaStatus = MediaMissing;
|
||||
// let RTP guess again the local interface or use the enforced address
|
||||
setRtpLocalAddr(m_rtpLocalAddr);
|
||||
addr = m_address;
|
||||
String uri = m_uri;
|
||||
updateTarget(t->initialMessage());
|
||||
bool addrChg = (addr != m_address);
|
||||
bool contactChg = (uri != m_uri);
|
||||
|
||||
SIPMessage* m = new SIPMessage(t->initialMessage(), 200);
|
||||
MimeSdpBody* sdpNew = createRtpSDP(true);
|
||||
m->setBody(sdpNew);
|
||||
t->setResponse(m);
|
||||
m->deref();
|
||||
Message* msg = message("call.update");
|
||||
msg->addParam("operation","notify");
|
||||
msg->addParam("mandatory","false");
|
||||
if (addrChg)
|
||||
msg->addParam("address_old",addr);
|
||||
msg->addParam("address_changed",String::boolText(addrChg));
|
||||
if (contactChg) {
|
||||
msg->addParam("contact",m_uri);
|
||||
msg->addParam("contact_old",uri);
|
||||
}
|
||||
msg->addParam("contact_changed",String::boolText(contactChg));
|
||||
msg->addParam("audio_changed",String::boolText(audioChg));
|
||||
msg->addParam("mute",String::boolText(MediaStarted != m_mediaStatus));
|
||||
putMedia(*msg);
|
||||
Engine::enqueue(msg);
|
||||
m_reInviting = invite;
|
||||
return;
|
||||
}
|
||||
m_reInviting = invite;
|
||||
if (s_refresh_nosdp && !sdp) {
|
||||
|
@ -6994,6 +6863,174 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
|
|||
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)
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
bool addrChg = false;
|
||||
SIPParty* party = t->initialMessage()->getParty();
|
||||
if (party) {
|
||||
String addr;
|
||||
party->appendAddr(addr,false);
|
||||
if (addr != m_address) {
|
||||
msg.setParam("address",addr);
|
||||
msg.addParam("address_old",m_address);
|
||||
addrChg = true;
|
||||
}
|
||||
}
|
||||
msg.addParam("address_changed",String::boolText(addrChg));
|
||||
bool contactChg = false;
|
||||
const MimeHeaderLine* co = t->initialMessage()->getHeader("Contact");
|
||||
if (co) {
|
||||
URI uri(*co);
|
||||
uri.parse();
|
||||
if (uri != m_uri) {
|
||||
msg.addParam("contact",uri);
|
||||
msg.addParam("contact_old",m_uri);
|
||||
contactChg = true;
|
||||
}
|
||||
}
|
||||
msg.addParam("contact_changed",String::boolText(contactChg));
|
||||
}
|
||||
msg.addParam("operation","request");
|
||||
copySipHeaders(msg,*t->initialMessage());
|
||||
msg.addParam("rtp_forward","yes");
|
||||
msg.addParam("rtp_addr",addr);
|
||||
if (natAddr)
|
||||
msg.addParam("rtp_nat_addr",natAddr);
|
||||
putMedia(msg,lst);
|
||||
TelEngine::destruct(lst);
|
||||
addSdpParams(msg,sdp);
|
||||
bool ok = Engine::dispatch(msg);
|
||||
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")));
|
||||
m_reInviting = invite;
|
||||
}
|
||||
else if (m_tr2) {
|
||||
// ouch! this shouldn't have happened!
|
||||
t->setResponse(491);
|
||||
// media is uncertain now so drop the call
|
||||
setReason("Internal Server Error",500);
|
||||
mylock.drop();
|
||||
hangup();
|
||||
}
|
||||
else {
|
||||
// we remember the request and leave it pending
|
||||
t->ref();
|
||||
t->setUserData(this);
|
||||
m_tr2 = t;
|
||||
}
|
||||
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)
|
||||
return false;
|
||||
String addr;
|
||||
String natAddr;
|
||||
ObjList* lst = plugin.parser().parse(sdp,addr);
|
||||
if (!lst)
|
||||
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;
|
||||
}
|
||||
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());
|
||||
// clear all data endpoints - createRtpSDP will build new ones
|
||||
if (!s_rtp_preserve)
|
||||
setMedia(0);
|
||||
}
|
||||
setMedia(lst);
|
||||
|
||||
m_mediaStatus = MediaMissing;
|
||||
// let RTP guess again the local interface or use the enforced address
|
||||
setRtpLocalAddr(m_rtpLocalAddr);
|
||||
addr = m_address;
|
||||
String uri = m_uri;
|
||||
updateTarget(t->initialMessage());
|
||||
bool addrChg = (addr != m_address);
|
||||
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");
|
||||
if (addrChg)
|
||||
msg->addParam("address_old",addr);
|
||||
msg->addParam("address_changed",String::boolText(addrChg));
|
||||
if (contactChg) {
|
||||
msg->addParam("contact",m_uri);
|
||||
msg->addParam("contact_old",uri);
|
||||
}
|
||||
msg->addParam("contact_changed",String::boolText(contactChg));
|
||||
msg->addParam("audio_changed",String::boolText(audioChg));
|
||||
msg->addParam("mute",String::boolText(MediaStarted != m_mediaStatus));
|
||||
putMedia(*msg);
|
||||
Engine::enqueue(msg);
|
||||
m_reInviting = invite;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YateSIPConnection::checkUser(SIPTransaction* t, bool refuse)
|
||||
{
|
||||
// don't try to authenticate requests from server
|
||||
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue