Add option to stop execution of an outgoing call.

Propagate that parameter in dumb channel, tone generator and wave file.
In SIP, simulate going through the whole SIP stack before stopping execution of the call.



git-svn-id: http://voip.null.ro/svn/yate@6401 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
oana 2020-04-22 10:59:48 +00:00
parent 1db8917b18
commit 47908cf938
9 changed files with 98 additions and 19 deletions

View File

@ -1499,8 +1499,13 @@ bool Driver::received(Message &msg, int id)
if (!canAccept(false)) if (!canAccept(false))
return false; return false;
if (dest.startSkip(m_prefix,false) || if (dest.startSkip(m_prefix,false) ||
(dest.startSkip("line/",false) && hasLine(msg.getValue(YSTRING("line"))))) (dest.startSkip("line/",false) && hasLine(msg.getValue(YSTRING("line"))))) {
if (msg.getBoolValue(YSTRING("stop_call"),false) && !canStopCall()) {
msg.setParam(YSTRING("error"),"stopped_call");
return false;
}
return msgExecute(msg,dest); return msgExecute(msg,dest);
}
return false; return false;
} }

View File

@ -36,7 +36,7 @@ SIPMessage::SIPMessage(const SIPMessage& original)
body(0), m_ep(0), body(0), m_ep(0),
m_valid(original.isValid()), m_answer(original.isAnswer()), m_valid(original.isValid()), m_answer(original.isAnswer()),
m_outgoing(original.isOutgoing()), m_ack(original.isACK()), m_outgoing(original.isOutgoing()), m_ack(original.isACK()),
m_cseq(-1), m_flags(original.getFlags()) m_cseq(-1), m_flags(original.getFlags()), m_dontSend(original.m_dontSend)
{ {
DDebug(DebugAll,"SIPMessage::SIPMessage(&%p) [%p]", DDebug(DebugAll,"SIPMessage::SIPMessage(&%p) [%p]",
&original,this); &original,this);
@ -66,7 +66,8 @@ SIPMessage::SIPMessage(const SIPMessage& original)
SIPMessage::SIPMessage(const char* _method, const char* _uri, const char* _version) SIPMessage::SIPMessage(const char* _method, const char* _uri, const char* _version)
: version(_version), method(_method), uri(_uri), code(0), : version(_version), method(_method), uri(_uri), code(0),
body(0), m_ep(0), m_valid(true), body(0), m_ep(0), m_valid(true),
m_answer(false), m_outgoing(true), m_ack(false), m_cseq(-1), m_flags(-1) m_answer(false), m_outgoing(true), m_ack(false), m_cseq(-1), m_flags(-1),
m_dontSend(false)
{ {
DDebug(DebugAll,"SIPMessage::SIPMessage('%s','%s','%s') [%p]", DDebug(DebugAll,"SIPMessage::SIPMessage('%s','%s','%s') [%p]",
_method,_uri,_version,this); _method,_uri,_version,this);
@ -74,7 +75,8 @@ SIPMessage::SIPMessage(const char* _method, const char* _uri, const char* _versi
SIPMessage::SIPMessage(SIPParty* ep, const char* buf, int len, unsigned int* bodyLen) SIPMessage::SIPMessage(SIPParty* ep, const char* buf, int len, unsigned int* bodyLen)
: code(0), body(0), m_ep(ep), m_valid(false), : code(0), body(0), m_ep(ep), m_valid(false),
m_answer(false), m_outgoing(false), m_ack(false), m_cseq(-1), m_flags(-1) m_answer(false), m_outgoing(false), m_ack(false), m_cseq(-1), m_flags(-1),
m_dontSend(false)
{ {
DDebug(DebugInfo,"SIPMessage::SIPMessage(%p,%d) [%p]\r\n------\r\n%s------", DDebug(DebugInfo,"SIPMessage::SIPMessage(%p,%d) [%p]\r\n------\r\n%s------",
buf,len,this,buf); buf,len,this,buf);
@ -92,7 +94,8 @@ SIPMessage::SIPMessage(SIPParty* ep, const char* buf, int len, unsigned int* bod
SIPMessage::SIPMessage(const SIPMessage* message, int _code, const char* _reason) SIPMessage::SIPMessage(const SIPMessage* message, int _code, const char* _reason)
: code(_code), body(0), : code(_code), body(0),
m_ep(0), m_valid(false), m_ep(0), m_valid(false),
m_answer(true), m_outgoing(true), m_ack(false), m_cseq(-1), m_flags(-1) m_answer(true), m_outgoing(true), m_ack(false), m_cseq(-1), m_flags(-1),
m_dontSend(false)
{ {
DDebug(DebugAll,"SIPMessage::SIPMessage(%p,%d,'%s') [%p]", DDebug(DebugAll,"SIPMessage::SIPMessage(%p,%d,'%s') [%p]",
message,_code,_reason,this); message,_code,_reason,this);
@ -121,7 +124,8 @@ SIPMessage::SIPMessage(const SIPMessage* message, int _code, const char* _reason
SIPMessage::SIPMessage(const SIPMessage* original, const SIPMessage* answer) SIPMessage::SIPMessage(const SIPMessage* original, const SIPMessage* answer)
: method("ACK"), code(0), : method("ACK"), code(0),
body(0), m_ep(0), m_valid(false), body(0), m_ep(0), m_valid(false),
m_answer(false), m_outgoing(true), m_ack(true), m_cseq(-1), m_flags(-1) m_answer(false), m_outgoing(true), m_ack(true), m_cseq(-1), m_flags(-1),
m_dontSend(false)
{ {
DDebug(DebugAll,"SIPMessage::SIPMessage(%p,%p) [%p]",original,answer,this); DDebug(DebugAll,"SIPMessage::SIPMessage(%p,%p) [%p]",original,answer,this);
if (!(original && original->isValid())) if (!(original && original->isValid()))

View File

@ -314,6 +314,19 @@ public:
inline int getFlags() const inline int getFlags() const
{ return m_flags; } { return m_flags; }
/**
* Get value of flag that specifies the message is not to be sent on wire
* @return The value of the flag
*/
inline bool dontSend() const
{ return m_dontSend; }
/**
* Set flag that specifies the message is not to be sent on wire
* @param val Value of the flag to send
*/
inline void dontSend(bool val)
{ m_dontSend = val; }
/** /**
* Find a header line by name * Find a header line by name
* @param name Name of the header to locate * @param name Name of the header to locate
@ -523,6 +536,7 @@ protected:
mutable DataBlock m_data; mutable DataBlock m_data;
String m_authUser; String m_authUser;
String m_authPass; String m_authPass;
bool m_dontSend;
private: private:
SIPMessage(); // no, thanks SIPMessage(); // no, thanks
}; };

View File

@ -31,6 +31,9 @@ public:
~DumbDriver(); ~DumbDriver();
virtual void initialize(); virtual void initialize();
virtual bool msgExecute(Message& msg, String& dest); virtual bool msgExecute(Message& msg, String& dest);
protected:
bool canStopCall() const
{ return true; }
}; };
INIT_PLUGIN(DumbDriver); INIT_PLUGIN(DumbDriver);
@ -71,6 +74,10 @@ bool DumbDriver::msgExecute(Message& msg, String& dest)
{ {
CallEndpoint *dd = YOBJECT(CallEndpoint,msg.userData()); CallEndpoint *dd = YOBJECT(CallEndpoint,msg.userData());
if (dd) { if (dd) {
if (msg.getBoolValue(YSTRING("stop_call"),false)) {
msg.setParam(YSTRING("error"),"stopped_call");
return false;
}
DumbChannel *c = new DumbChannel(dest,msg,true); DumbChannel *c = new DumbChannel(dest,msg,true);
c->initChan(); c->initChan();
if (dd->connect(c)) { if (dd->connect(c)) {
@ -111,6 +118,7 @@ bool DumbDriver::msgExecute(Message& msg, String& dest)
m.copyParam(msg,"callername"); m.copyParam(msg,"callername");
m.copyParam(msg,"maxcall"); m.copyParam(msg,"maxcall");
m.copyParam(msg,"timeout"); m.copyParam(msg,"timeout");
m.copyParam(msg,YSTRING("stop_call"));
m.copyParams(msg,msg.getValue("copyparams")); m.copyParams(msg,msg.getValue("copyparams"));
const String& callto = msg["direct"]; const String& callto = msg["direct"];

View File

@ -182,6 +182,8 @@ public:
protected: protected:
void statusModule(String& str); void statusModule(String& str);
void statusParams(String& str); void statusParams(String& str);
bool canStopCall() const
{ return true; }
private: private:
AttachHandler* m_handler; AttachHandler* m_handler;
}; };
@ -1109,6 +1111,10 @@ bool ToneGenDriver::msgExecute(Message& msg, String& dest)
{ {
CallEndpoint* ch = YOBJECT(CallEndpoint,msg.userData()); CallEndpoint* ch = YOBJECT(CallEndpoint,msg.userData());
if (ch) { if (ch) {
if (msg.getBoolValue(YSTRING("stop_call"),false)) {
msg.setParam(YSTRING("error"),"stopped_call");
return false;
}
ToneChan *tc = new ToneChan(dest,msg["lang"]); ToneChan *tc = new ToneChan(dest,msg["lang"]);
tc->initChan(); tc->initChan();
tc->setChanParams(msg); tc->setChanParams(msg);
@ -1130,6 +1136,7 @@ bool ToneGenDriver::msgExecute(Message& msg, String& dest)
m.clearParam(YSTRING("id")); m.clearParam(YSTRING("id"));
m.setParam("module",name()); m.setParam("module",name());
m.setParam("cdrtrack",String::boolText(false)); m.setParam("cdrtrack",String::boolText(false));
m.copyParam(msg,YSTRING("stop_call"));
m.copyParam(msg,YSTRING("called")); m.copyParam(msg,YSTRING("called"));
m.copyParam(msg,YSTRING("caller")); m.copyParam(msg,YSTRING("caller"));
m.copyParam(msg,YSTRING("callername")); m.copyParam(msg,YSTRING("callername"));

View File

@ -123,6 +123,8 @@ public:
virtual bool msgExecute(Message& msg, String& dest); virtual bool msgExecute(Message& msg, String& dest);
protected: protected:
void statusParams(String& str); void statusParams(String& str);
bool canStopCall() const
{ return true; }
private: private:
AttachHandler* m_handler; AttachHandler* m_handler;
}; };
@ -1130,6 +1132,10 @@ bool WaveFileDriver::msgExecute(Message& msg, String& dest)
unsigned int maxlen = msg.getIntValue("maxlen"); unsigned int maxlen = msg.getIntValue("maxlen");
CallEndpoint* ch = YOBJECT(CallEndpoint,msg.userData()); CallEndpoint* ch = YOBJECT(CallEndpoint,msg.userData());
if (ch) { if (ch) {
if (msg.getBoolValue(YSTRING("stop_call"),false)) {
msg.setParam(YSTRING("error"),"stopped_call");
return false;
}
Debug(this,DebugInfo,"%s wave file '%s'", (meth ? "Record to" : "Play from"), Debug(this,DebugInfo,"%s wave file '%s'", (meth ? "Record to" : "Play from"),
dest.matchString(2).c_str()); dest.matchString(2).c_str());
WaveChan *c = new WaveChan(dest.matchString(2),meth,maxlen,msg,msg.getParam("callto")); WaveChan *c = new WaveChan(dest.matchString(2),meth,maxlen,msg,msg.getParam("callto"));
@ -1159,6 +1165,7 @@ bool WaveFileDriver::msgExecute(Message& msg, String& dest)
m.copyParam(msg,YSTRING("called")); m.copyParam(msg,YSTRING("called"));
m.copyParam(msg,YSTRING("caller")); m.copyParam(msg,YSTRING("caller"));
m.copyParam(msg,YSTRING("callername")); m.copyParam(msg,YSTRING("callername"));
m.copyParam(msg,YSTRING("stop_call"));
String callto(msg.getValue(YSTRING("direct"))); String callto(msg.getValue(YSTRING("direct")));
if (callto.null()) { if (callto.null()) {
const char *targ = msg.getValue(YSTRING("target")); const char *targ = msg.getValue(YSTRING("target"));

View File

@ -4288,6 +4288,10 @@ bool YJGDriver::received(Message& msg, int id)
String callto(msg.getValue("callto")); String callto(msg.getValue("callto"));
if (!callto.startSkip("jabber/",false)) if (!callto.startSkip("jabber/",false))
return Driver::received(msg,id); return Driver::received(msg,id);
if (msg.getBoolValue(YSTRING("stop_call"),false) && !canStopCall()) {
msg.setParam(YSTRING("error"),"stopped_call");
return true;
}
return msgExecute(msg,callto); return msgExecute(msg,callto);
} }
if (id == Halt) { if (id == Halt) {

View File

@ -1009,6 +1009,8 @@ public:
{ return callid == m_dialog && { return callid == m_dialog &&
m_dialog.fromTag(isOutgoing()) == fromTag && m_dialog.fromTag(isOutgoing()) == fromTag &&
m_dialog.toTag(isOutgoing()) == toTag; } m_dialog.toTag(isOutgoing()) == toTag; }
inline bool stopOCall() const
{ return m_stopOCall; }
// Build and add a callid parameter to a list // Build and add a callid parameter to a list
static inline void addCallId(NamedList& nl, const String& dialog, static inline void addCallId(NamedList& nl, const String& dialog,
const String& fromTag, const String& toTag) { const String& fromTag, const String& toTag) {
@ -1099,6 +1101,7 @@ private:
// media parameters before we sent a reINVITE // media parameters before we sent a reINVITE
NamedList m_revert; NamedList m_revert;
bool m_silent; // Silently discard SIP dialog bool m_silent; // Silently discard SIP dialog
bool m_stopOCall;
}; };
class YateSIPGenerate : public GenObject class YateSIPGenerate : public GenObject
@ -1164,6 +1167,8 @@ protected:
// Setup a listener from config // Setup a listener from config
void setupListener(const String& name, const NamedList& params, bool isGeneral, void setupListener(const String& name, const NamedList& params, bool isGeneral,
const NamedList& defs = NamedList::empty()); const NamedList& defs = NamedList::empty());
bool canStopCall() const
{ return true; }
private: private:
bool onHelp(Message& msg); bool onHelp(Message& msg);
// Add status methods // Add status methods
@ -3523,12 +3528,14 @@ int YateSIPTCPTransport::process()
SIPMessage* msg = static_cast<SIPMessage*>(o->get()); SIPMessage* msg = static_cast<SIPMessage*>(o->get());
if (s_printMsg && (o != first || m_sent < 0)) if (s_printMsg && (o != first || m_sent < 0))
printSendMsg(msg); printSendMsg(msg);
if (o != first || m_sent <= 0) if (!msg->dontSend()) {
buf += msg->getBuffer(); if (o != first || m_sent <= 0)
else { buf += msg->getBuffer();
int remaining = msg->getBuffer().length() - m_sent; else {
if (remaining > 0) int remaining = msg->getBuffer().length() - m_sent;
buf.assign(((char*)msg->getBuffer().data()) + m_sent,remaining); if (remaining > 0)
buf.assign(((char*)msg->getBuffer().data()) + m_sent,remaining);
}
} }
} }
if (buf.length()) { if (buf.length()) {
@ -3812,10 +3819,12 @@ bool YateSIPTCPTransport::sendPending(const Time& time, bool& sent)
return false; return false;
break; break;
} }
if (msg->dontSend())
break;
const DataBlock& buf = msg->getBuffer(); const DataBlock& buf = msg->getBuffer();
sent = true; sent = !msg->dontSend();
int len = buf.length(); int len = buf.length();
if (len > m_sent) { if (sent && len > m_sent) {
char* b = (char*)(buf.data()); char* b = (char*)(buf.data());
len -= m_sent; len -= m_sent;
int wr = m_sock->writeData(b + m_sent,len); int wr = m_sock->writeData(b + m_sent,len);
@ -4398,6 +4407,11 @@ bool YateUDPParty::transmit(SIPEvent* event)
Lock lck(m_transport); Lock lck(m_transport);
if (s_printMsg) if (s_printMsg)
m_transport->printSendMsg(msg,&m_addr); m_transport->printSendMsg(msg,&m_addr);
if (msg->dontSend()) {
if (event->getTransaction())
event->getTransaction()->setSilent();
return true;
}
return m_transport->send(msg->getBuffer().data(),msg->getBuffer().length(),m_addr); return m_transport->send(msg->getBuffer().data(),msg->getBuffer().length(),m_addr);
} }
String tmp; String tmp;
@ -4485,8 +4499,12 @@ bool YateTCPParty::transmit(SIPEvent* event)
const SIPMessage* msg = event->getMessage(); const SIPMessage* msg = event->getMessage();
if (!msg) if (!msg)
return false; return false;
if (m_transport) if (m_transport) {
return m_transport->send(event); bool ok = m_transport->send(event);
if (msg->dontSend() && event->getTransaction())
event->getTransaction()->setSilent();
return ok;
}
String tmp; String tmp;
getMsgLine(tmp,msg); getMsgLine(tmp,msg);
Debug(&plugin,DebugWarn,"YateTCPParty no transport to send %s [%p]", Debug(&plugin,DebugWarn,"YateTCPParty no transport to send %s [%p]",
@ -6049,7 +6067,7 @@ YateSIPConnection::YateSIPConnection(SIPEvent* ev, SIPTransaction* tr)
m_checkAllowInfo(s_checkAllowInfo), m_missingAllowInfoDefVal(s_missingAllowInfoDefVal), m_checkAllowInfo(s_checkAllowInfo), m_missingAllowInfoDefVal(s_missingAllowInfoDefVal),
m_honorDtmfDetect(s_honorDtmfDetect), m_honorDtmfDetect(s_honorDtmfDetect),
m_referring(false), m_reInviting(ReinviteNone), m_lastRseq(0), m_referring(false), m_reInviting(ReinviteNone), m_lastRseq(0),
m_revert(""), m_silent(false) m_revert(""), m_silent(false), m_stopOCall(false)
{ {
m_ipv6 = s_ipv6; m_ipv6 = s_ipv6;
setSdpDebug(this,this); setSdpDebug(this,this);
@ -6247,7 +6265,7 @@ YateSIPConnection::YateSIPConnection(Message& msg, const String& uri, const char
m_checkAllowInfo(s_checkAllowInfo), m_missingAllowInfoDefVal(s_missingAllowInfoDefVal), m_checkAllowInfo(s_checkAllowInfo), m_missingAllowInfoDefVal(s_missingAllowInfoDefVal),
m_honorDtmfDetect(s_honorDtmfDetect), m_honorDtmfDetect(s_honorDtmfDetect),
m_referring(false), m_reInviting(ReinviteNone), m_lastRseq(0), m_referring(false), m_reInviting(ReinviteNone), m_lastRseq(0),
m_revert(""), m_silent(false) m_revert(""), m_silent(false), m_stopOCall(msg.getBoolValue(YSTRING("stop_call")))
{ {
Debug(this,DebugAll,"YateSIPConnection::YateSIPConnection(%p,'%s') [%p]", Debug(this,DebugAll,"YateSIPConnection::YateSIPConnection(%p,'%s') [%p]",
&msg,uri.c_str(),this); &msg,uri.c_str(),this);
@ -6316,6 +6334,7 @@ YateSIPConnection::YateSIPConnection(Message& msg, const String& uri, const char
if (!m_party && sips() && !haveTransParams(msg,"o")) if (!m_party && sips() && !haveTransParams(msg,"o"))
setParty(msg,true,"o",m_uri.getHost(),m_uri.getPort(),this); setParty(msg,true,"o",m_uri.getHost(),m_uri.getPort(),this);
SIPMessage* m = new SIPMessage("INVITE",m_uri); SIPMessage* m = new SIPMessage("INVITE",m_uri);
m->dontSend(m_stopOCall);
setSipParty(m,line,true,msg.getValue("host"),msg.getIntValue("port")); setSipParty(m,line,true,msg.getValue("host"),msg.getIntValue("port"));
if (!m->getParty()) { if (!m->getParty()) {
String tmp; String tmp;
@ -6579,7 +6598,7 @@ void YateSIPConnection::hangup()
break; break;
case Outgoing: case Outgoing:
case Ringing: case Ringing:
if (!m_silent && m_cancel && m_tr) { if (!m_silent && !m_stopOCall && m_cancel && m_tr) {
SIPMessage* m = new SIPMessage("CANCEL",m_uri); SIPMessage* m = new SIPMessage("CANCEL",m_uri);
setSipParty(m,plugin.findLine(m_line),true,m_host,m_port); setSipParty(m,plugin.findLine(m_line),true,m_host,m_port);
if (!m->getParty()) if (!m->getParty())
@ -9289,6 +9308,10 @@ bool SIPDriver::msgExecute(Message& msg, String& dest)
return false; return false;
} }
YateSIPConnection* conn = new YateSIPConnection(msg,dest,msg.getValue(YSTRING("id"))); YateSIPConnection* conn = new YateSIPConnection(msg,dest,msg.getValue(YSTRING("id")));
if (msg.getBoolValue(YSTRING("stop_call"),false)) {
conn->destruct();
return true;
}
conn->initChan(); conn->initChan();
if (conn->getTransaction()) { if (conn->getTransaction()) {
CallEndpoint* ch = YOBJECT(CallEndpoint,msg.userData()); CallEndpoint* ch = YOBJECT(CallEndpoint,msg.userData());

View File

@ -2429,6 +2429,13 @@ protected:
*/ */
virtual void loadLimits(); virtual void loadLimits();
/**
* Module is able to simulate a call without generating anything at protocol layer
* @return True if module is able
*/
virtual bool canStopCall() const
{ return false; }
/** /**
* Set if this driver is for dynamic (variable number) channels * Set if this driver is for dynamic (variable number) channels
* @param variable True if the channels are dynamic, false for fixed * @param variable True if the channels are dynamic, false for fixed