*** empty log message ***

git-svn-id: http://voip.null.ro/svn/yate@152 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2005-01-01 22:21:32 +00:00
parent ba3a7efaca
commit 5b586386d2
8 changed files with 324 additions and 87 deletions

View File

@ -69,25 +69,27 @@ void URI::parse() const
{ {
if (m_parsed) if (m_parsed)
return; return;
DDebug("URI",DebugAll,"parsing '%s' [%p]",c_str(),this);
m_port = 0; m_port = 0;
Regexp r("<\\([^>]\\+\\)>"); Regexp r("<\\([^>]\\+\\)>");
if (const_cast<URI*>(this)->matches(r)) { if (const_cast<URI*>(this)->matches(r)) {
*const_cast<URI*>(this) = matchString(1); *const_cast<URI*>(this) = matchString(1);
DDebug("URI",DebugAll,"new value='%s'",c_str()); DDebug("URI",DebugAll,"new value='%s' [%p]",c_str(),this);
} }
// proto:[user[:passwd]@]hostname[:port][/path][?param=value[&param=value...]] // proto:[user[:passwd]@]hostname[:port][/path][?param=value[&param=value...]]
// proto:user@hostname[:port][/path][?params][&params] // proto:[user@]hostname[:port][/path][;params][?params][&params]
r = "^\\([[:alpha:]]\\+\\):\\([[:alnum:]._-]\\+\\)@\\([[:alnum:]._-]\\+\\)\\(:[0-9]\\+\\)\\?"; r = "^\\([[:alpha:]]\\+\\):\\([[:alnum:]._-]\\+@\\)\\?\\([[:alnum:]._-]\\+\\)\\(:[0-9]\\+\\)\\?";
if (const_cast<URI*>(this)->matches(r)) { if (const_cast<URI*>(this)->matches(r)) {
m_proto = matchString(1).toLower(); m_proto = matchString(1).toLower();
m_user = matchString(2); m_user = matchString(2);
m_host = matchString(3); m_user = m_user.substr(0,m_user.length()-1);
m_host = matchString(3).toLower();
String tmp = matchString(4); String tmp = matchString(4);
tmp >> ":" >> m_port; tmp >> ":" >> m_port;
DDebug("URI",DebugAll,"proto='%s' user='%s' host='%s' port=%d", DDebug("URI",DebugAll,"proto='%s' user='%s' host='%s' port=%d [%p]",
m_proto.c_str(), m_user.c_str(), m_host.c_str(), m_port); m_proto.c_str(), m_user.c_str(), m_host.c_str(), m_port, this);
} }
else { else {
m_proto.clear(); m_proto.clear();
@ -143,7 +145,7 @@ SIPEngine::SIPEngine(const char* userAgent)
Debug(DebugInfo,"SIPEngine::SIPEngine() [%p]",this); Debug(DebugInfo,"SIPEngine::SIPEngine() [%p]",this);
if (m_userAgent.null()) if (m_userAgent.null())
m_userAgent << "YATE/" << YATE_VERSION; m_userAgent << "YATE/" << YATE_VERSION;
m_allowed = "INVITE, ACK, CANCEL, BYE"; m_allowed = "ACK";
} }
SIPEngine::~SIPEngine() SIPEngine::~SIPEngine()
@ -190,6 +192,10 @@ SIPTransaction* SIPEngine::addMessage(SIPMessage* message)
Debug("SIPEngine",DebugInfo,"Message %p was an unhandled answer [%p]",message,this); Debug("SIPEngine",DebugInfo,"Message %p was an unhandled answer [%p]",message,this);
return 0; return 0;
} }
if (message->isACK()) {
Debug("SIPEngine",DebugAll,"Message %p was an unhandled ACK [%p]",message,this);
return 0;
}
message->complete(this); message->complete(this);
return new SIPTransaction(message,this,false); return new SIPTransaction(message,this,false);
} }
@ -228,6 +234,12 @@ void SIPEngine::processEvent(SIPEvent *event)
if (event) { if (event) {
if (event->isOutgoing() && event->getParty()) if (event->isOutgoing() && event->getParty())
event->getParty()->transmit(event); event->getParty()->transmit(event);
if (event->isIncoming() && (event->getState() == SIPTransaction::Trying) &&
event->getMessage() && !event->getMessage()->isAnswer()) {
Debug("SIPEngine",DebugInfo,"Rejecting unhandled request '%s' in event %p [%p]",
event->getMessage()->method.c_str(),event,this);
event->getTransaction()->setResponse(501,"Not Implemented");
}
delete event; delete event;
} }
} }

View File

@ -38,6 +38,12 @@ HeaderLine::HeaderLine(const char *name, const String& value)
if (value.null()) if (value.null())
return; return;
int sp = value.find(';'); int sp = value.find(';');
// skip past URIs with parameters
int lim = value.find('<');
if ((sp >= 0) && (lim >= 0) && (lim < sp)) {
lim = value.find('>');
sp = value.find(';',lim);
}
if (sp < 0) { if (sp < 0) {
assign(value); assign(value);
return; return;
@ -67,7 +73,7 @@ HeaderLine::HeaderLine(const char *name, const String& value)
m_params.append(new NamedString(pname)); m_params.append(new NamedString(pname));
} }
} }
sp = ep+1; sp = ep;
} }
} }
@ -101,6 +107,22 @@ const NamedString* HeaderLine::getParam(const char *name) const
return 0; return 0;
} }
void HeaderLine::setParam(const char *name, const char *value)
{
ObjList* p = m_params.find(name);
if (p)
*static_cast<NamedString*>(p->get()) = value;
else
m_params.append(new NamedString(name,value));
}
void HeaderLine::delParam(const char *name)
{
ObjList* p = m_params.find(name);
if (p)
p->remove();
}
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), : version(_version), method(_method), uri(_uri),
body(0), m_ep(0), m_valid(true), body(0), m_ep(0), m_valid(true),
@ -145,9 +167,6 @@ SIPMessage::SIPMessage(const SIPMessage* message, int _code, const char* _reason
copyHeader(message,"To"); copyHeader(message,"To");
copyHeader(message,"Call-ID"); copyHeader(message,"Call-ID");
copyHeader(message,"CSeq"); copyHeader(message,"CSeq");
#if 0
body = message->body ? message->body->clone() : 0;
#endif
m_valid = true; m_valid = true;
} }
@ -216,14 +235,11 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai
if (!hl->getParam("branch")) { if (!hl->getParam("branch")) {
String tmp("z9hG4bK"); String tmp("z9hG4bK");
tmp << (int)::random(); tmp << (int)::random();
hl->addParam("branch",tmp); hl->setParam("branch",tmp);
} }
if (isAnswer()) { if (isAnswer()) {
if (!hl->getParam("received")) hl->setParam("received",getParty()->getPartyAddr());
hl->addParam("received",getParty()->getPartyAddr()); hl->setParam("rport",String(getParty()->getPartyPort()));
if (!hl->getParam("rport"))
hl->addParam("rport",String(getParty()->getPartyPort()));
} }
hl = const_cast<HeaderLine*>(getHeader("From")); hl = const_cast<HeaderLine*>(getHeader("From"));
@ -234,7 +250,7 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai
header.append(hl); header.append(hl);
} }
if (!hl->getParam("tag")) if (!hl->getParam("tag"))
hl->addParam("tag",String((int)::random())); hl->setParam("tag",String((int)::random()));
hl = const_cast<HeaderLine*>(getHeader("To")); hl = const_cast<HeaderLine*>(getHeader("To"));
if (!hl) { if (!hl) {
@ -244,7 +260,7 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai
header.append(hl); header.append(hl);
} }
if (dlgTag && !hl->getParam("tag")) if (dlgTag && !hl->getParam("tag"))
hl->addParam("tag",dlgTag); hl->setParam("tag",dlgTag);
if (!getHeader("Call-ID")) { if (!getHeader("Call-ID")) {
String tmp; String tmp;
@ -266,10 +282,14 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai
if (!getHeader("Contact")) { if (!getHeader("Contact")) {
String tmp; String tmp;
if (isAnswer())
tmp = *getHeader("To");
if (tmp.null()) {
tmp << "<sip:" << user << "@" << getParty()->getLocalAddr(); tmp << "<sip:" << user << "@" << getParty()->getLocalAddr();
if (getParty()->getLocalPort() != 5060) if (getParty()->getLocalPort() != 5060)
tmp << ":" << getParty()->getLocalPort(); tmp << ":" << getParty()->getLocalPort();
tmp << ">"; tmp << ">";
}
addHeader("Contact",tmp); addHeader("Contact",tmp);
} }
@ -461,6 +481,18 @@ const NamedString* SIPMessage::getParam(const char* name, const char* param) con
return hl ? hl->getParam(param) : 0; return hl ? hl->getParam(param) : 0;
} }
const String& SIPMessage::getHeaderValue(const char* name) const
{
const HeaderLine* hl = getHeader(name);
return hl ? *hl : String::empty();
}
const String& SIPMessage::getParamValue(const char* name, const char* param) const
{
const NamedString* ns = getParam(name,param);
return ns ? *ns : String::empty();
}
const String& SIPMessage::getHeaders() const const String& SIPMessage::getHeaders() const
{ {
if (isValid() && m_string.null()) { if (isValid() && m_string.null()) {
@ -477,8 +509,11 @@ const String& SIPMessage::getHeaders() const
const ObjList* p = &(t->params()); const ObjList* p = &(t->params());
for (; p; p = p->next()) { for (; p; p = p->next()) {
NamedString* s = static_cast<NamedString*>(p->get()); NamedString* s = static_cast<NamedString*>(p->get());
if (s) if (s) {
m_string << ";" << s->name() << "=" << *s; m_string << ";" << s->name();
if (!s->null())
m_string << "=" << *s;
}
} }
m_string << "\r\n"; m_string << "\r\n";
} }

View File

@ -165,6 +165,7 @@ SIPEvent* SIPTransaction::getEvent()
if (m_timeout && (Time::now() >= m_timeout)) { if (m_timeout && (Time::now() >= m_timeout)) {
timeout = --m_timeouts; timeout = --m_timeouts;
m_timeout = (m_timeouts) ? Time::now() + m_delay : 0; m_timeout = (m_timeouts) ? Time::now() + m_delay : 0;
m_delay *= 2; // exponential back-off
Debug("SIPTransaction",DebugAll,"Fired timer #%d [%p]",timeout,this); Debug("SIPTransaction",DebugAll,"Fired timer #%d [%p]",timeout,this);
} }
@ -243,10 +244,22 @@ bool SIPTransaction::processMessage(SIPMessage* message, const String& branch)
DDebug("SIPTransaction",DebugAll,"processMessage(%p,'%s') [%p]", DDebug("SIPTransaction",DebugAll,"processMessage(%p,'%s') [%p]",
message,branch.c_str(),this); message,branch.c_str(),this);
if (branch) { if (branch) {
if (branch != m_branch) if (branch != m_branch) {
// different branch is allowed only for ACK in incoming INVITE...
if (!(isInvite() && isIncoming() && message->isACK()))
return false; return false;
if (getMethod() != message->method) { // ...and only if we sent a 200 response...
if (isOutgoing() || !isInvite() || !message->isACK()) if (!m_lastMessage || ((m_lastMessage->code / 100) != 2))
return false;
// ...and if also matches the CSeq, Call-ID and To: tag
if ((m_firstMessage->getCSeq() != message->getCSeq()) ||
(getCallID() != message->getHeaderValue("Call-ID")) ||
(getLocalTag() != message->getParamValue("To","tag")))
return false;
Debug("SIPTransaction",DebugWarn,"Found non-branch ACK response to our 2xx");
}
else if (getMethod() != message->method) {
if (!(isIncoming() && isInvite() && message->isACK()))
return false; return false;
} }
} }
@ -310,7 +323,7 @@ SIPEvent* SIPTransaction::getClientEvent(int state, int timeout)
case Initial: case Initial:
e = new SIPEvent(m_firstMessage,this); e = new SIPEvent(m_firstMessage,this);
if (changeState(Trying)) if (changeState(Trying))
setTimeout(m_engine->getTimer(isInvite() ? 'A' : 'E'),8); setTimeout(m_engine->getTimer(isInvite() ? 'A' : 'E'),5);
break; break;
case Trying: case Trying:
if (timeout < 0) if (timeout < 0)
@ -348,6 +361,7 @@ void SIPTransaction::processServerMessage(SIPMessage* message, int state)
case Retrans: case Retrans:
if (message->isACK()) { if (message->isACK()) {
setTimeout(); setTimeout();
setPendingEvent(new SIPEvent(message,this));
changeState(Cleared); changeState(Cleared);
} }
else else
@ -384,7 +398,7 @@ SIPEvent* SIPTransaction::getServerEvent(int state, int timeout)
break; break;
case Finish: case Finish:
e = new SIPEvent(m_lastMessage,this); e = new SIPEvent(m_lastMessage,this);
setTimeout(m_engine->getTimer('G'),8); setTimeout(m_engine->getTimer('G'),5);
changeState(Retrans); changeState(Retrans);
break; break;
} }

View File

@ -37,6 +37,12 @@ public:
URI(const String& uri); URI(const String& uri);
URI(const URI& uri); URI(const URI& uri);
URI(const char* proto, const char* user, const char* host, int port = 0); URI(const char* proto, const char* user, const char* host, int port = 0);
inline URI& operator=(const URI& value)
{ String::operator=(value); return *this; }
inline URI& operator=(const String& value)
{ String::operator=(value); return *this; }
inline URI& operator=(const char value)
{ String::operator=(value); return *this; }
inline const String& getProtocol() const inline const String& getProtocol() const
{ parse(); return m_proto; } { parse(); return m_proto; }
inline const String& getUser() const inline const String& getUser() const
@ -155,8 +161,8 @@ public:
virtual ~HeaderLine(); virtual ~HeaderLine();
inline const ObjList& params() const inline const ObjList& params() const
{ return m_params; } { return m_params; }
inline void addParam(const char *name, const char *value = 0) void setParam(const char *name, const char *value = 0);
{ m_params.append(new NamedString(name,value)); } void delParam(const char *name);
const NamedString* getParam(const char *name) const; const NamedString* getParam(const char *name) const;
protected: protected:
ObjList m_params; ObjList m_params;
@ -303,6 +309,21 @@ public:
*/ */
const NamedString* getParam(const char* name, const char* param) const; const NamedString* getParam(const char* name, const char* param) const;
/**
* Get a string value (without parameters) from a header line
* @param name Name of the header to locate
* @return The value hold in the header or an empty String
*/
const String& getHeaderValue(const char* name) const;
/**
* Get a string value from a parameter in a header line
* @param name Name of the header to locate
* @param param Name of the parameter to locate in the tag
* @return The value hold in the parameter or an empty String
*/
const String& getParamValue(const char* name, const char* param) const;
/** /**
* Append a new header line constructed from name and content * Append a new header line constructed from name and content
*/ */
@ -465,6 +486,13 @@ public:
inline bool isOutgoing() const inline bool isOutgoing() const
{ return m_outgoing; } { return m_outgoing; }
/**
* Check if this transaction was initiated locally or by the remote peer
* @return True if the transaction was created by an incoming message
*/
inline bool isIncoming() const
{ return !m_outgoing; }
/** /**
* Check if this transaction is an INVITE transaction or not * Check if this transaction is an INVITE transaction or not
* @return True if the transaction is an INVITE * @return True if the transaction is an INVITE

View File

@ -126,6 +126,8 @@ void StringMatchPrivate::fixup()
rmatch[i].rm_eo -= rmatch[i].rm_so; rmatch[i].rm_eo -= rmatch[i].rm_so;
c = i; c = i;
} }
else
rmatch[i].rm_eo = 0;
} }
// Cope with the regexp stupidity. // Cope with the regexp stupidity.
if (c > 1) { if (c > 1) {
@ -226,8 +228,9 @@ String::~String()
String& String::assign(const char *value, int len) String& String::assign(const char *value, int len)
{ {
if (len && value && *value) { if (len && value && *value) {
if (len < 0) int vlen = ::strlen(value);
len = ::strlen(value); if ((len < 0) || (len > vlen))
len = vlen;
if (value != m_string || len != (int)m_length) { if (value != m_string || len != (int)m_length) {
char *data = (char *) ::malloc(len+1); char *data = (char *) ::malloc(len+1);
::memcpy(data,value,len); ::memcpy(data,value,len);

View File

@ -699,7 +699,9 @@ void YateH323Connection::OnEstablished()
void YateH323Connection::OnCleared() void YateH323Connection::OnCleared()
{ {
Debug(DebugInfo,"YateH323Connection::OnCleared() [%p]",this); int reason = GetCallEndReason();
Debug(DebugInfo,"YateH323Connection::OnCleared() reason: %d [%p]",
reason,this);
setStatus("cleared"); setStatus("cleared");
Message *m = new Message("call.hangup"); Message *m = new Message("call.hangup");
m->addParam("driver","h323"); m->addParam("driver","h323");

View File

@ -46,8 +46,12 @@ public:
bool SniffHandler::received(Message &msg) bool SniffHandler::received(Message &msg)
{ {
Output("Sniffed '%s' time=%llu thread=%p retval='%s'", if (msg == "engine.timer")
msg.c_str(),msg.msgTime().usec(),Thread::current(),msg.retValue().c_str()); return false;
Output("Sniffed '%s' time=%llu thread=%p data=%p retval='%s'",
msg.c_str(),msg.msgTime().usec(),
Thread::current(),
msg.userData(),msg.retValue().c_str());
unsigned n = msg.length(); unsigned n = msg.length();
for (unsigned i = 0; i < n; i++) { for (unsigned i = 0; i < n; i++) {
NamedString *s = msg.getParam(i); NamedString *s = msg.getParam(i);

View File

@ -44,16 +44,32 @@
using namespace TelEngine; using namespace TelEngine;
/* Payloads for the AV profile */ /* Yate Payloads for the AV profile */
static TokenDict dict_payloads[] = { static TokenDict dict_payloads[] = {
{ "mulaw", 0 }, { "mulaw", 0 },
{ "alaw", 8 },
{ "gsm", 3 }, { "gsm", 3 },
{ "lpc10", 7 }, { "lpc10", 7 },
{ "alaw", 8 },
{ "slin", 11 }, { "slin", 11 },
{ "g726", 2 }, { "g726", 2 },
{ "g722", 9 }, { "g722", 9 },
{ "g723", 12 }, { "g723", 4 },
{ "g728", 15 },
{ "g729", 18 },
};
/* SDP Payloads for the AV profile */
static TokenDict dict_rtpmap[] = {
{ "PCMU/8000", 0 },
{ "PCMA/8000", 8 },
{ "GSM/8000", 3 },
{ "LPC/8000", 7 },
{ "L16/8000", 11 },
{ "G726-32/8000", 2 },
{ "G722/8000", 9 },
{ "G723/8000", 4 },
{ "G728/8000", 15 },
{ "G729/8000", 18 },
}; };
static Configuration s_cfg; static Configuration s_cfg;
@ -94,9 +110,7 @@ class YateSIPEndPoint;
class YateSIPEngine : public SIPEngine class YateSIPEngine : public SIPEngine
{ {
public: public:
inline YateSIPEngine(YateSIPEndPoint* ep) YateSIPEngine(YateSIPEndPoint* ep);
: m_ep(ep)
{ }
virtual bool buildParty(SIPMessage* message); virtual bool buildParty(SIPMessage* message);
private: private:
YateSIPEndPoint* m_ep; YateSIPEndPoint* m_ep;
@ -111,8 +125,8 @@ public:
// YateSIPConnection *findconn(int did); // YateSIPConnection *findconn(int did);
// void terminateall(void); // void terminateall(void);
void run(void); void run(void);
void incoming(SIPEvent* e); bool incoming(SIPEvent* e, SIPTransaction* t);
void invite(SIPEvent* e); void invite(SIPEvent* e, SIPTransaction* t);
bool buildParty(SIPMessage* message); bool buildParty(SIPMessage* message);
inline ObjList &calls() inline ObjList &calls()
{ return m_calls; } { return m_calls; }
@ -139,8 +153,11 @@ public:
bool process(SIPEvent* ev); bool process(SIPEvent* ev);
void ringing(Message* msg = 0); void ringing(Message* msg = 0);
void answered(Message* msg = 0); void answered(Message* msg = 0);
inline const String& id() const void doBye(SIPTransaction* t);
{ return m_id; } void doCancel(SIPTransaction* t);
void hangup();
inline String id() const
{ return "sip/" + m_id; }
inline const String& status() const inline const String& status() const
{ return m_status; } { return m_status; }
inline void setStatus(const char *status) inline void setStatus(const char *status)
@ -153,10 +170,11 @@ public:
{ return m_tr; } { return m_tr; }
static YateSIPConnection* find(const String& id); static YateSIPConnection* find(const String& id);
private: private:
SDPBody* createSDP(const char* addr, const char* port, const char* formats); SDPBody* createSDP(const char* addr, const char* port, const char* formats, const char* format = 0);
SDPBody* createPasstroughSDP(Message &msg); SDPBody* createPasstroughSDP(Message &msg);
SDPBody* createRtpSDP(SIPMessage* msg, const char* formats); SDPBody* createRtpSDP(SIPMessage* msg, const char* formats);
SDPBody* createRtpSDP(); SDPBody* createRtpSDP(bool start = false);
bool startRtp();
SIPTransaction* m_tr; SIPTransaction* m_tr;
String m_id; String m_id;
String m_target; String m_target;
@ -164,6 +182,7 @@ private:
String m_rtpid; String m_rtpid;
String m_rtpAddr; String m_rtpAddr;
String m_rtpPort; String m_rtpPort;
String m_rtpFormat;
String m_formats; String m_formats;
}; };
@ -256,6 +275,9 @@ YateUDPParty::YateUDPParty(int fd,struct sockaddr_in sin, int local)
} }
::close(s); ::close(s);
} }
Debug(DebugAll,"YateUDPParty local %s:%d party %s:%d",
m_local.c_str(),m_localPort,
m_party.c_str(),m_partyPort);
} }
YateUDPParty::~YateUDPParty() YateUDPParty::~YateUDPParty()
@ -305,6 +327,14 @@ bool YateUDPParty::setParty(const URI& uri)
return true; return true;
} }
YateSIPEngine::YateSIPEngine(YateSIPEndPoint* ep)
: m_ep(ep)
{
addAllowed("INVITE");
addAllowed("BYE");
addAllowed("CANCEL");
}
bool YateSIPEngine::buildParty(SIPMessage* message) bool YateSIPEngine::buildParty(SIPMessage* message)
{ {
return m_ep->buildParty(message); return m_ep->buildParty(message);
@ -434,35 +464,54 @@ void YateSIPEndPoint::run ()
} }
// m_engine->process(); // m_engine->process();
SIPEvent* e = m_engine->getEvent(); SIPEvent* e = m_engine->getEvent();
if (e) { // hack: use a loop so we can use break and continue
for (; e; m_engine->processEvent(e),e = 0) {
if (!e->getTransaction())
continue;
YateSIPConnection* conn = static_cast<YateSIPConnection*>(e->getTransaction()->getUserData()); YateSIPConnection* conn = static_cast<YateSIPConnection*>(e->getTransaction()->getUserData());
if (conn) { if (conn) {
if (conn->process(e)) if (conn->process(e)) {
delete e;
else
m_engine->processEvent(e);
}
else if ((e->getState() == SIPTransaction::Trying) && !e->isOutgoing()) {
incoming(e);
delete e; delete e;
break;
} }
else else
m_engine->processEvent(e); continue;
}
if ((e->getState() == SIPTransaction::Trying) &&
!e->isOutgoing() && incoming(e,e->getTransaction())) {
delete e;
break;
}
} }
} }
} }
void YateSIPEndPoint::incoming(SIPEvent* e) bool YateSIPEndPoint::incoming(SIPEvent* e, SIPTransaction* t)
{ {
if (e->getTransaction() && e->getTransaction()->isInvite()) { if (e->getTransaction()->isInvite())
invite(e); invite(e,t);
return; else if (t->getMethod() == "BYE") {
YateSIPConnection* conn = YateSIPConnection::find(t->getCallID());
if (conn)
conn->doBye(t);
else
t->setResponse(481,"Call/Transaction Does Not Exist");
} }
else if (t->getMethod() == "CANCEL") {
YateSIPConnection* conn = YateSIPConnection::find(t->getCallID());
if (conn)
conn->doCancel(t);
else
t->setResponse(481,"Call/Transaction Does Not Exist");
}
else
return false;
return true;
} }
static int s_maxqueue = 5; static int s_maxqueue = 5;
void YateSIPEndPoint::invite(SIPEvent* e) void YateSIPEndPoint::invite(SIPEvent* e, SIPTransaction* t)
{ {
if (Engine::exiting()) { if (Engine::exiting()) {
Debug(DebugWarn,"Dropping call, engine is exiting"); Debug(DebugWarn,"Dropping call, engine is exiting");
@ -476,8 +525,8 @@ void YateSIPEndPoint::invite(SIPEvent* e)
return; return;
} }
String callid(e->getTransaction()->getCallID()); String callid(t->getCallID());
URI uri(e->getTransaction()->getURI()); URI uri(t->getURI());
const HeaderLine* hl = e->getMessage()->getHeader("From"); const HeaderLine* hl = e->getMessage()->getHeader("From");
URI from(hl ? *hl : ""); URI from(hl ? *hl : "");
Message *m = new Message("call.preroute"); Message *m = new Message("call.preroute");
@ -493,11 +542,11 @@ void YateSIPEndPoint::invite(SIPEvent* e)
m->addParam("rtp.port",port); m->addParam("rtp.port",port);
m->addParam("formats",formats); m->addParam("formats",formats);
} }
SipMsgThread *t = new SipMsgThread(e->getTransaction(),m); SipMsgThread *thr = new SipMsgThread(t,m);
if (!t->startup()) { if (!thr->startup()) {
Debug(DebugWarn,"Error starting routing thread! [%p]",this); Debug(DebugWarn,"Error starting routing thread %p ! [%p]",thr,this);
delete t; delete thr;
e->getTransaction()->setResponse(500, "Server Internal Error"); t->setResponse(500, "Server Internal Error");
} }
} }
@ -525,6 +574,10 @@ YateSIPConnection::YateSIPConnection(Message& msg, SIPTransaction* tr)
m_rtpAddr = msg.getValue("rtp.addr"); m_rtpAddr = msg.getValue("rtp.addr");
m_rtpPort = msg.getValue("rtp.port"); m_rtpPort = msg.getValue("rtp.port");
m_formats = msg.getValue("formats"); m_formats = msg.getValue("formats");
int q = m_formats.find(',');
m_rtpFormat = m_formats.substr(0,q);
Debug(DebugAll,"addr '%s' port %s formats '%s' format '%s'",
m_rtpAddr.c_str(),m_rtpPort.c_str(),m_formats.c_str(),m_rtpFormat.c_str());
} }
// Outgoing call constructor - in call.execute handler // Outgoing call constructor - in call.execute handler
@ -556,11 +609,24 @@ YateSIPConnection::~YateSIPConnection()
Debug(DebugAll,"YateSIPConnection::~YateSIPConnection() [%p]",this); Debug(DebugAll,"YateSIPConnection::~YateSIPConnection() [%p]",this);
Lock lock(s_mutex); Lock lock(s_mutex);
s_calls.remove(this,false); s_calls.remove(this,false);
hangup();
}
void YateSIPConnection::hangup()
{
Message *m = new Message("call.hangup");
m->addParam("driver","sip");
m->addParam("id",id());
if (m_target)
m->addParam("targetid",m_target);
Engine::enqueue(m);
if (m_tr) { if (m_tr) {
m_tr->setUserData(0); m_tr->setUserData(0);
m_tr->setResponse(487,"Request Terminated"); m_tr->setResponse(487,"Request Terminated");
m_tr->deref(); m_tr->deref();
} }
else
disconnect();
} }
// Creates a SDP from RTP address data present in message // Creates a SDP from RTP address data present in message
@ -592,60 +658,98 @@ SDPBody* YateSIPConnection::createRtpSDP(SIPMessage* msg, const char* formats)
} }
// Creates a started external RTP channel from remote addr and builds SDP from it // Creates a started external RTP channel from remote addr and builds SDP from it
SDPBody* YateSIPConnection::createRtpSDP() SDPBody* YateSIPConnection::createRtpSDP(bool start)
{ {
Message m("chan.rtp"); Message m("chan.rtp");
m.addParam("direction","bidir"); m.addParam("direction","bidir");
m.addParam("remoteip",m_rtpAddr); m.addParam("remoteip",m_rtpAddr);
if (start) {
m.addParam("remoteport",m_rtpPort); m.addParam("remoteport",m_rtpPort);
m.addParam("format","alaw"); m.addParam("format",m_rtpFormat);
}
m.userData(static_cast<DataEndpoint *>(this)); m.userData(static_cast<DataEndpoint *>(this));
if (Engine::dispatch(m)) { if (Engine::dispatch(m)) {
m_rtpid = m.getValue("rtpid"); m_rtpid = m.getValue("rtpid");
return createSDP(m.getValue("localip"),m.getValue("localport"),m_formats); if (start)
m_rtpFormat = m.getValue("format");
return createSDP(m.getValue("localip"),m.getValue("localport"),m_formats,m_rtpFormat);
} }
return 0; return 0;
} }
SDPBody* YateSIPConnection::createSDP(const char* addr, const char* port, const char* formats) // Starts an already created external RTP channel
bool YateSIPConnection::startRtp()
{
if (m_rtpid.null())
return false;
Debug(DebugAll,"YateSIPConnection::startSDP() [%p]",this);
Message m("chan.rtp");
m.addParam("rtpid",m_rtpid);
m.addParam("direction","bidir");
m.addParam("remoteip",m_rtpAddr);
m.addParam("remoteport",m_rtpPort);
m.addParam("format",m_rtpFormat);
m.userData(static_cast<DataEndpoint *>(this));
return Engine::dispatch(m);
}
SDPBody* YateSIPConnection::createSDP(const char* addr, const char* port, const char* formats, const char* format)
{ {
Debug(DebugAll,"YateSIPConnection::createSDP('%s','%s','%s') [%p]", Debug(DebugAll,"YateSIPConnection::createSDP('%s','%s','%s') [%p]",
addr,port,formats,this); addr,port,formats,this);
int t = Time::now() / 1000000UL; // return 0;
int t = Time::now() / 10000000000ULL;
String tmp; String tmp;
tmp << "IN IP4 " << addr; tmp << "IN IP4 " << addr;
String owner; String owner;
owner << "1001 " << t << " " << t << " " << tmp; owner << "1001 " << t << " " << t << " " << tmp;
String frm(formats); String frm(format ? format : formats);
if (frm.null()) if (frm.null())
frm = "alaw,mulaw"; frm = "alaw,mulaw";
ObjList* l = frm.split(',',false); ObjList* l = frm.split(',',false);
frm = "audio "; frm = "audio ";
frm << port << " RTP/AVP"; frm << port << " RTP/AVP";
ObjList rtpmap;
ObjList* f = l; ObjList* f = l;
for (; f; f = f->next()) { for (; f; f = f->next()) {
String* s = static_cast<String*>(f->get()); String* s = static_cast<String*>(f->get());
if (s) { if (s) {
int payload = s->toInteger(dict_payloads,-1); int payload = s->toInteger(dict_payloads,-1);
if (payload >= 0) if (payload >= 0) {
frm << " " << payload; frm << " " << payload;
const char* map = lookup(payload,dict_rtpmap);
if (map) {
String* tmp = new String("rtpmap:");
*tmp << payload << " " << map;
rtpmap.append(tmp);
}
}
} }
} }
delete l; delete l;
// frm << " 101";
// rtpmap.append(new String("rtpmap:101 telephone-event/8000"));
SDPBody* sdp = new SDPBody; SDPBody* sdp = new SDPBody;
sdp->addLine("v","0"); sdp->addLine("v","0");
sdp->addLine("o",owner); sdp->addLine("o",owner);
sdp->addLine("s","Call"); sdp->addLine("s","Session");
sdp->addLine("t","0 0");
sdp->addLine("c",tmp); sdp->addLine("c",tmp);
sdp->addLine("t","0 0");
sdp->addLine("m",frm); sdp->addLine("m",frm);
// sdp->addLine("a","rtpmap:8 PCMA/8000/1"); for (f = &rtpmap; f; f = f->next()) {
String* s = static_cast<String*>(f->get());
if (s)
sdp->addLine("a",*s);
}
rtpmap.clear();
return sdp; return sdp;
} }
void YateSIPConnection::disconnected(bool final, const char *reason) void YateSIPConnection::disconnected(bool final, const char *reason)
{ {
Debug(DebugAll,"YateSIPConnection::disconnected() '%s'",reason); Debug(DebugAll,"YateSIPConnection::disconnected() '%s' [%p]",reason,this);
setStatus("disconnected"); setStatus("disconnected");
setTarget(); setTarget();
} }
@ -654,9 +758,42 @@ bool YateSIPConnection::process(SIPEvent* ev)
{ {
Debug(DebugInfo,"YateSIPConnection::process(%p) %s [%p]", Debug(DebugInfo,"YateSIPConnection::process(%p) %s [%p]",
ev,SIPTransaction::stateName(ev->getState()),this); ev,SIPTransaction::stateName(ev->getState()),this);
if (ev->getState() == SIPTransaction::Cleared) {
Lock lock(s_mutex);
if (m_tr) {
Debug(DebugInfo,"YateSIPConnection clearing transaction %p [%p]",
m_tr,this);
m_tr->setUserData(0);
m_tr->deref();
m_tr = 0;
}
}
else if (ev->getMessage() && ev->getMessage()->isACK()) {
Debug(DebugInfo,"YateSIPConnection got ACK [%p]",this);
startRtp();
}
return false; return false;
} }
void YateSIPConnection::doBye(SIPTransaction* t)
{
Debug(DebugAll,"YateSIPConnection::doBye(%p) [%p]",t,this);
t->setResponse(200,"OK");
hangup();
}
void YateSIPConnection::doCancel(SIPTransaction* t)
{
Debug(DebugAll,"YateSIPConnection::doCancel(%p) [%p]",t,this);
if (m_tr) {
t->setResponse(200,"OK");
m_tr->setResponse(487,"Request Terminated");
disconnect("Cancelled");
}
else
t->setResponse(481,"Call/Transaction Does Not Exist");
}
void YateSIPConnection::ringing(Message* msg) void YateSIPConnection::ringing(Message* msg)
{ {
if (m_tr && (m_tr->getState() == SIPTransaction::Process)) { if (m_tr && (m_tr->getState() == SIPTransaction::Process)) {
@ -678,8 +815,6 @@ void YateSIPConnection::answered(Message* msg)
m->setBody(sdp); m->setBody(sdp);
m_tr->setResponse(m); m_tr->setResponse(m);
m->deref(); m->deref();
m_tr->deref();
m_tr = 0;
} }
setStatus("answered"); setStatus("answered");
} }
@ -738,7 +873,9 @@ void SipMsgThread::run()
s_route.unlock(); s_route.unlock();
Debug(DebugAll,"Started routing thread for %s (%p) [%p]", Debug(DebugAll,"Started routing thread for %s (%p) [%p]",
m_id.c_str(),m_tr,this); m_id.c_str(),m_tr,this);
m_tr->ref();
bool ok = route(); bool ok = route();
m_tr->deref();
s_route.lock(); s_route.lock();
s_count--; s_count--;
if (ok) if (ok)
@ -783,15 +920,15 @@ bool SIPConnHandler::received(Message &msg, int id)
switch (id) { switch (id) {
case Answered: case Answered:
case Ringing: case Ringing:
callid = msg.getParam("targetid"); callid = msg.getValue("targetid");
break; break;
case Drop: case Drop:
callid = msg.getParam("id"); callid = msg.getValue("id");
break; break;
default: default:
return false; return false;
} }
if (callid.null()) { if (!callid.startSkip("sip/",false) || callid.null()) {
if (id == Drop) { if (id == Drop) {
Debug("SIP",DebugInfo,"Dropping all calls"); Debug("SIP",DebugInfo,"Dropping all calls");
s_calls.clear(); s_calls.clear();
@ -800,6 +937,8 @@ bool SIPConnHandler::received(Message &msg, int id)
} }
Lock lock(s_mutex); Lock lock(s_mutex);
YateSIPConnection* conn = YateSIPConnection::find(callid); YateSIPConnection* conn = YateSIPConnection::find(callid);
Debug("SIP",DebugInfo,"Connhandler lookup '%s' returned %p",
callid.c_str(),conn);
if (!conn) if (!conn)
return false; return false;
switch (id) { switch (id) {