Implement independent CSeq generators for INVITE dialogs and REGISTER sessions.

Always parse CSeq in base 10, some implementations left pad with zeros.


git-svn-id: http://yate.null.ro/svn/yate/trunk@5855 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2014-06-25 12:27:56 +00:00
parent 7a41ecce69
commit 11fcab1ab1
4 changed files with 167 additions and 38 deletions

View File

@ -171,13 +171,15 @@ SIPEngine::SIPEngine(const char* userAgent)
: Mutex(true,"SIPEngine"),
m_t1(500000), m_t4(5000000), m_reqTransCount(5), m_rspTransCount(6),
m_maxForwards(70),
m_cseq(0), m_flags(0), m_lazyTrying(false),
m_flags(0), m_lazyTrying(false),
m_userAgent(userAgent), m_nc(0), m_nonce_time(0),
m_nonce_mutex(false,"SIPEngine::nonce"),
m_autoChangeParty(false)
{
debugName("sipengine");
DDebug(this,DebugInfo,"SIPEngine::SIPEngine() [%p]",this);
m_seq = new SIPSequence;
m_seq->deref();
if (m_userAgent.null())
m_userAgent << "YATE/" << YATE_VERSION;
m_allowed = "ACK";

View File

@ -43,6 +43,7 @@ SIPMessage::SIPMessage(const SIPMessage& original)
if (original.body)
setBody(original.body->clone());
setParty(original.getParty());
setSequence(original.getSequence());
bool via1 = true;
const ObjList* l = &original.header;
for (; l; l = l->next()) {
@ -75,7 +76,7 @@ SIPMessage::SIPMessage(SIPParty* ep, const char* buf, int len, unsigned int* bod
: 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)
{
DDebug(DebugInfo,"SIPMessage::SIPMessage(%p,%d) [%p]\n------\n%s------",
DDebug(DebugInfo,"SIPMessage::SIPMessage(%p,%d) [%p]\r\n------\r\n%s------",
buf,len,this,buf);
if (m_ep)
m_ep->ref();
@ -107,6 +108,7 @@ SIPMessage::SIPMessage(const SIPMessage* message, int _code, const char* _reason
version = message->version;
uri = message->uri;
method = message->method;
m_cseq = message->getCSeq();
copyAllHeaders(message,"Via");
copyAllHeaders(message,"Record-Route");
copyHeader(message,"From");
@ -296,14 +298,24 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai
hl = const_cast<MimeHeaderLine*>(getHeader("CSeq"));
if (hl) {
if (m_cseq <= 0) {
String tmp(*hl);
tmp >> m_cseq;
int sep = hl->find(' ');
if (sep > 0)
m_cseq = hl->substr(sep).toInteger(-1,10);
}
}
else {
String tmp;
if (m_cseq <= 0)
m_cseq = engine->getNextCSeq();
if (m_cseq <= 0) {
SIPSequence* seq = getSequence();
if (!seq)
seq = engine->getSequence();
#ifdef DEBUG
else
Debug(engine,DebugAll,"Using local sequence %p last=%d [%p]",
seq,seq->getLastCSeq(),this);
#endif
m_cseq = seq->getNextCSeq();
}
tmp << m_cseq << " " << method;
addHeader("CSeq",tmp);
}
@ -457,11 +469,13 @@ bool SIPMessage::parse(const char* buf, int len, unsigned int* bodyLen)
if ((clen < 0) && (name &= "Content-Length"))
clen = line->toInteger(-1,10);
else if ((m_cseq < 0) && (name &= "CSeq")) {
String seq = *line;
seq >> m_cseq;
if (m_answer) {
seq.trimBlanks().toUpper();
method = seq;
int sep = line->find(' ');
if (sep > 0) {
m_cseq = line->substr(0,sep).toInteger(-1,10);
if (m_answer) {
method = line->substr(sep + 1);
method.trimBlanks().toUpper();
}
}
}
line->destruct();
@ -633,7 +647,7 @@ const DataBlock& SIPMessage::getBuffer() const
#ifdef DEBUG
if (debugAt(DebugInfo)) {
String buf((char*)m_data.data(),m_data.length());
Debug(DebugInfo,"SIPMessage::getBuffer() [%p]\n------\n%s------",
Debug(DebugInfo,"SIPMessage::getBuffer() [%p]\r\n------\r\n%s------",
this,buf.c_str());
}
#endif
@ -810,7 +824,7 @@ SIPDialog::SIPDialog(const SIPDialog& original)
: String(original),
localURI(original.localURI), localTag(original.localTag),
remoteURI(original.remoteURI), remoteTag(original.remoteTag),
localCSeq(original.localCSeq), remoteCSeq(original.remoteCSeq)
remoteCSeq(original.remoteCSeq), m_seq(original.getSequence())
{
DDebug("SIPDialog",DebugAll,"callid '%s' local '%s;tag=%s' remote '%s;tag=%s' [%p]",
c_str(),localURI.c_str(),localTag.c_str(),remoteURI.c_str(),remoteTag.c_str(),this);
@ -823,8 +837,8 @@ SIPDialog& SIPDialog::operator=(const SIPDialog& original)
localTag = original.localTag;
remoteURI = original.remoteURI;
remoteTag = original.remoteTag;
localCSeq = original.localCSeq;
remoteCSeq = original.remoteCSeq;
setSequence(original.getSequence());
DDebug("SIPDialog",DebugAll,"callid '%s' local '%s;tag=%s' remote '%s;tag=%s' [%p]",
c_str(),localURI.c_str(),localTag.c_str(),remoteURI.c_str(),remoteTag.c_str(),this);
return *this;
@ -844,7 +858,7 @@ SIPDialog& SIPDialog::operator=(const String& callid)
SIPDialog::SIPDialog(const SIPMessage& message)
: String(message.getHeaderValue("Call-ID")),
localCSeq(-1), remoteCSeq(-1)
remoteCSeq(-1)
{
bool local = message.isOutgoing() ^ message.isAnswer();
const MimeHeaderLine* hl = message.getHeader(local ? "From" : "To");
@ -859,6 +873,7 @@ SIPDialog::SIPDialog(const SIPMessage& message)
remoteURI = remoteURI.matchString(1);
if (hl)
remoteTag = hl->getParam("tag");
setSequence(message.getSequence());
if (!(message.isOutgoing() || message.isAnswer() || message.isACK() || remoteCSeq >= message.getCSeq()))
remoteCSeq = message.getCSeq();
DDebug("SIPDialog",DebugAll,"callid '%s' local '%s;tag=%s' remote '%s;tag=%s' [%p]",
@ -883,6 +898,9 @@ SIPDialog& SIPDialog::operator=(const SIPMessage& message)
remoteURI = remoteURI.matchString(1);
if (hl)
remoteTag = hl->getParam("tag");
SIPSequence* seq = message.getSequence();
if (seq)
setSequence(seq);
if (!(message.isOutgoing() || message.isAnswer() || message.isACK() || remoteCSeq >= message.getCSeq()))
remoteCSeq = message.getCSeq();
DDebug("SIPDialog",DebugAll,"callid '%s' local '%s;tag=%s' remote '%s;tag=%s' [%p]",
@ -901,4 +919,11 @@ bool SIPDialog::matches(const SIPDialog& other, bool ignoreURIs) const
remoteURI == other.remoteURI));
}
void SIPDialog::setCSeq(int32_t cseq)
{
SIPSequence* seq = new SIPSequence(cseq);
setSequence(seq);
TelEngine::destruct(seq);
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -98,6 +98,46 @@ protected:
int m_partyPort;
};
/**
* Command Sequence Number generator
* @short SIP CSeq generator
*/
class YSIP_API SIPSequence : public RefObject, public Mutex
{
public:
/**
* Constructor
* @param cseq Sequence number to start
*/
inline SIPSequence(int32_t cseq = -1)
: Mutex(false,"CSeq"), m_cseq(cseq)
{ }
/**
* Get the last number generated by this sequence
* @return Last generated CSeq value between 0 and 2^31-1, negative if not initialized
*/
inline int32_t getLastCSeq() const
{ return m_cseq; }
/**
* Create a CSeq value suitable for use in a new request
* @return New CSeq value between 1 and 2^31-1
*/
inline int32_t getNextCSeq()
{ Lock mylock(this); return (++m_cseq > 0) ? m_cseq : (m_cseq = 1); }
/**
* Set the Command Sequence number
* @param cseq New sequence number to start from
*/
inline void setCSeq(int32_t cseq)
{ m_cseq = cseq; }
private:
int32_t m_cseq;
};
/**
* An object that holds the sip message parsed into this library model.
* This class can be used to parse a sip message from a text buffer, or it
@ -256,14 +296,14 @@ public:
* Get the Command Sequence number from this message
* @return Number part of CSEQ in this message
*/
inline int getCSeq() const
inline int32_t getCSeq() const
{ return m_cseq; }
/**
* Set the Command Sequence number for this message
* @param cseq Sequence number for this message
*/
inline void setCSeq(int cseq)
inline void setCSeq(int32_t cseq)
{ m_cseq = cseq; }
/**
@ -402,6 +442,20 @@ public:
*/
void addRoutes(const ObjList* routes);
/**
* Get the Command Sequence Number generator
* @return Pointer to the CSeq generator of this message
*/
inline SIPSequence* getSequence() const
{ return m_seq; }
/**
* Set the Command Sequence Number generator
* @param seq Pointer to the new CSeq generator of this message
*/
inline void setSequence(SIPSequence* seq)
{ m_seq = seq; }
/**
* Creates a binary buffer from a SIPMessage.
*/
@ -457,11 +511,12 @@ protected:
bool parse(const char* buf, int len, unsigned int* bodyLen);
bool parseFirst(String& line);
SIPParty* m_ep;
RefPointer<SIPSequence> m_seq;
bool m_valid;
bool m_answer;
bool m_outgoing;
bool m_ack;
int m_cseq;
int32_t m_cseq;
int m_flags;
mutable String m_string;
mutable DataBlock m_data;
@ -482,7 +537,7 @@ public:
* Default constructor, build an empty SIP dialog
*/
inline SIPDialog()
: localCSeq(-1), remoteCSeq(-1)
: remoteCSeq(-1)
{ }
/**
@ -502,7 +557,7 @@ public:
* @param callid Call ID to insert in the dialog
*/
inline explicit SIPDialog(const String& callid)
: String(callid), localCSeq(-1), remoteCSeq(-1)
: String(callid), remoteCSeq(-1)
{ }
/**
@ -598,6 +653,40 @@ public:
inline const String& toTag(bool outgoing) const
{ return outgoing ? remoteTag : localTag; }
/**
* Get the Command Sequence Number generator
* @return Pointer to the CSeq generator of this dialog
*/
inline SIPSequence* getSequence() const
{ return m_seq; }
/**
* Set the Command Sequence Number generator
* @param seq Pointer to the new CSeq generator of this dialog
*/
inline void setSequence(SIPSequence* seq)
{ m_seq = seq; }
/**
* Set a new Command Sequence generator
* @param cseq New sequence number to start from
*/
void setCSeq(int32_t cseq);
/**
* Get the last number generated by this dialog
* @return Last generated CSeq value between 0 and 2^31-1, negative if no generator
*/
inline int32_t getLastCSeq() const
{ return m_seq ? m_seq->getLastCSeq() : -1; }
/**
* Create a CSeq value suitable for use in a new request
* @return New CSeq value between 1 and 2^31-1, negative if no generator
*/
inline int32_t getNextCSeq()
{ return m_seq ? m_seq->getNextCSeq() : -1; }
/**
* Adjust the last seen remote CSeq
* @param cseq Remote sequence number
@ -634,15 +723,13 @@ public:
*/
String remoteTag;
/**
* Last generated Command Sequence Number
*/
int localCSeq;
/**
* Last seen Command Sequence Number
*/
int remoteCSeq;
protected:
RefPointer<SIPSequence> m_seq;
};
/**
@ -1291,10 +1378,18 @@ public:
{ return m_userAgent; }
/**
* Get a CSeq value suitable for use in a new request
* Get the Command Sequence Number generator
* @return Pointer to the CSeq generator of this engine
*/
inline int getNextCSeq()
{ return ++m_cseq; }
inline SIPSequence* getSequence() const
{ return m_seq; }
/**
* Get a CSeq value suitable for use in a new request
* @return New CSeq value
*/
inline int32_t getNextCSeq()
{ return m_seq->getNextCSeq(); }
/**
* Check if the engine is set up for lazy "100 Trying" messages
@ -1427,11 +1522,11 @@ protected:
int m_reqTransCount;
int m_rspTransCount;
unsigned int m_maxForwards;
int m_cseq;
int m_flags;
bool m_lazyTrying;
String m_userAgent;
String m_allowed;
RefPointer<SIPSequence> m_seq;
u_int32_t m_nc;
String m_nonce;
String m_nonce_secret;

View File

@ -671,7 +671,7 @@ public:
virtual ~YateSIPLine();
bool matchInbound(const String& addr, int port, const String& user) const;
void setupAuth(SIPMessage* msg) const;
SIPMessage* buildRegister(int expires) const;
SIPMessage* buildRegister(int expires);
void login();
void logout(bool sendLogout = true, const char* reason = 0);
bool process(SIPEvent* ev);
@ -728,6 +728,7 @@ private:
int m_flags;
int m_trans;
SIPTransaction* m_tr;
RefPointer<SIPSequence> m_seq;
bool m_marked;
bool m_valid;
String m_callid;
@ -6013,7 +6014,7 @@ YateSIPConnection::YateSIPConnection(Message& msg, const String& uri, const char
SocketAddr::appendTo(m_address,m_host,m_port);
filterDebug(m_address);
m_dialog = *m;
m_dialog.localCSeq = m->getCSeq();
m_dialog.setCSeq(m->getCSeq());
m_dialog.remoteCSeq = msg.getIntValue("remote_cseq",-1);
if (s_privacy)
copyPrivacy(*m,msg);
@ -6262,10 +6263,9 @@ SIPMessage* YateSIPConnection::createDlgMsg(const char* method, const char* uri)
m->destruct();
return 0;
}
if (m_dialog.localCSeq > 0)
m->setCSeq(++m_dialog.localCSeq);
else
m->setCSeq(m_dialog.localCSeq = plugin.ep()->engine()->getNextCSeq());
if (m_dialog.getLastCSeq() < 0)
m_dialog.setCSeq(plugin.ep()->engine()->getNextCSeq() - 1);
m->setSequence(m_dialog.getSequence());
m->addHeader("Call-ID",callid());
String tmp;
tmp << "<" << m_dialog.localURI << ">";
@ -7547,8 +7547,9 @@ bool YateSIPConnection::msgControl(Message& msg)
if (m_dialog.remoteTag)
tmp << ";tag=" << m_dialog.remoteTag;
msg.setParam("sip_to",tmp);
if (m_dialog.localCSeq >= 0)
msg.setParam("local_cseq",String(m_dialog.localCSeq));
int32_t cseq = m_dialog.getLastCSeq();
if (cseq >= 0)
msg.setParam("local_cseq",String(cseq));
if (m_dialog.remoteCSeq >= 0)
msg.setParam("remote_cseq",String(m_dialog.remoteCSeq));
ok = true;
@ -8064,7 +8065,7 @@ void YateSIPLine::changing()
logout();
}
SIPMessage* YateSIPLine::buildRegister(int expires) const
SIPMessage* YateSIPLine::buildRegister(int expires)
{
String exp(expires);
String tmp;
@ -8093,6 +8094,11 @@ SIPMessage* YateSIPLine::buildRegister(int expires) const
m->addHeader("To",tmp);
if (m_callid)
m->addHeader("Call-ID",m_callid);
if (!m_seq) {
m_seq = new SIPSequence(plugin.ep()->engine()->getNextCSeq() - 1);
m_seq->deref();
}
m->setSequence(m_seq);
m->complete(plugin.ep()->engine(),m_username,domain(),0,m_flags);
return m;
}
@ -8191,6 +8197,7 @@ void YateSIPLine::logout(bool sendLogout, const char* reason)
m->deref();
}
m_callid.clear();
m_seq = 0;
}
bool YateSIPLine::process(SIPEvent* ev)