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))
return 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 false;
}

View File

@ -36,7 +36,7 @@ SIPMessage::SIPMessage(const SIPMessage& original)
body(0), m_ep(0),
m_valid(original.isValid()), m_answer(original.isAnswer()),
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]",
&original,this);
@ -66,7 +66,8 @@ SIPMessage::SIPMessage(const SIPMessage& original)
SIPMessage::SIPMessage(const char* _method, const char* _uri, const char* _version)
: version(_version), method(_method), uri(_uri), code(0),
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]",
_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)
: 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------",
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)
: code(_code), body(0),
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]",
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)
: method("ACK"), code(0),
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);
if (!(original && original->isValid()))

View File

@ -314,6 +314,19 @@ public:
inline int getFlags() const
{ 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
* @param name Name of the header to locate
@ -523,6 +536,7 @@ protected:
mutable DataBlock m_data;
String m_authUser;
String m_authPass;
bool m_dontSend;
private:
SIPMessage(); // no, thanks
};

View File

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

View File

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

View File

@ -123,6 +123,8 @@ public:
virtual bool msgExecute(Message& msg, String& dest);
protected:
void statusParams(String& str);
bool canStopCall() const
{ return true; }
private:
AttachHandler* m_handler;
};
@ -1130,6 +1132,10 @@ bool WaveFileDriver::msgExecute(Message& msg, String& dest)
unsigned int maxlen = msg.getIntValue("maxlen");
CallEndpoint* ch = YOBJECT(CallEndpoint,msg.userData());
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"),
dest.matchString(2).c_str());
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("caller"));
m.copyParam(msg,YSTRING("callername"));
m.copyParam(msg,YSTRING("stop_call"));
String callto(msg.getValue(YSTRING("direct")));
if (callto.null()) {
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"));
if (!callto.startSkip("jabber/",false))
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);
}
if (id == Halt) {

View File

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

View File

@ -2429,6 +2429,13 @@ protected:
*/
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
* @param variable True if the channels are dynamic, false for fixed