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:
parent
7a41ecce69
commit
11fcab1ab1
|
@ -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";
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue