Added auto authorization of transactions and some client NAT support.
git-svn-id: http://voip.null.ro/svn/yate@551 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
c95258c1f9
commit
56d47dfffc
|
@ -269,7 +269,7 @@ SIPTransaction* SIPEngine::addMessage(SIPMessage* message)
|
|||
return 0;
|
||||
}
|
||||
if (message->isACK()) {
|
||||
Debug("SIPEngine",DebugAll,"Message %p was an unhandled ACK [%p]",message,this);
|
||||
DDebug("SIPEngine",DebugAll,"Message %p was an unhandled ACK [%p]",message,this);
|
||||
return 0;
|
||||
}
|
||||
message->complete(this);
|
||||
|
@ -499,7 +499,7 @@ int SIPEngine::authUser(const SIPMessage* message, String& user, bool proxy)
|
|||
long age = nonceAge(nonce);
|
||||
if (age < 0)
|
||||
continue;
|
||||
XDebug("SIPEngine",DebugAll,"authUser nonce age is %d",age);
|
||||
XDebug("SIPEngine",DebugAll,"authUser nonce age is %ld",age);
|
||||
String res(t->getParam("response"));
|
||||
delQuotes(res);
|
||||
if (res.null())
|
||||
|
|
|
@ -253,9 +253,7 @@ SIPMessage::SIPMessage(const SIPMessage& original)
|
|||
if (hl->name() &= "CSeq")
|
||||
continue;
|
||||
SIPHeaderLine* nl = hl->clone();
|
||||
// this is a new transaction/dialog so let complete() add randomness
|
||||
if ((nl->name() &= "From") || (nl->name() &= "To"))
|
||||
nl->delParam("tag");
|
||||
// this is a new transaction so let complete() add randomness
|
||||
if (via1 && (nl->name() &= "Via")) {
|
||||
via1 = false;
|
||||
nl->delParam("branch");
|
||||
|
@ -802,6 +800,14 @@ SIPAuthLine* SIPMessage::buildAuth(const String& username, const String& passwor
|
|||
return 0;
|
||||
}
|
||||
|
||||
SIPAuthLine* SIPMessage::buildAuth(const SIPMessage& original) const
|
||||
{
|
||||
if (original.getAuthUsername().null())
|
||||
return 0;
|
||||
return buildAuth(original.getAuthUsername(),original.getAuthPassword(),
|
||||
original.method,original.uri,(code == 407));
|
||||
}
|
||||
|
||||
ObjList* SIPMessage::getRoutes() const
|
||||
{
|
||||
ObjList* list = 0;
|
||||
|
|
|
@ -65,8 +65,40 @@ SIPTransaction::SIPTransaction(SIPMessage* message, SIPEngine* engine, bool outg
|
|||
}
|
||||
}
|
||||
m_invite = (getMethod() == "INVITE");
|
||||
m_engine->TransList.append(this);
|
||||
m_state = Initial;
|
||||
m_engine->TransList.append(this);
|
||||
}
|
||||
|
||||
SIPTransaction::SIPTransaction(SIPTransaction& original, SIPMessage* answer)
|
||||
: m_outgoing(true), m_invite(original.m_invite), m_transmit(false),
|
||||
m_state(Process), m_response(original.m_response), m_timeout(0),
|
||||
m_firstMessage(original.m_firstMessage), m_lastMessage(original.m_lastMessage),
|
||||
m_pending(0), m_engine(original.m_engine),
|
||||
m_branch(original.m_branch), m_callid(original.m_callid), m_tag(original.m_tag),
|
||||
m_private(0)
|
||||
{
|
||||
DDebug(DebugAll,"SIPTransaction::SIPTransaction(&%p,%p) [%p]",
|
||||
&original,answer,this);
|
||||
|
||||
SIPMessage* msg = new SIPMessage(*original.m_firstMessage);
|
||||
SIPAuthLine* auth = answer->buildAuth(*original.m_firstMessage);
|
||||
m_firstMessage->setAutoAuth();
|
||||
msg->complete(m_engine);
|
||||
msg->addHeader(auth);
|
||||
const NamedString* ns = msg->getParam("Via","branch");
|
||||
if (ns)
|
||||
original.m_branch = *ns;
|
||||
else
|
||||
original.m_branch.clear();
|
||||
ns = msg->getParam("To","tag");
|
||||
if (ns)
|
||||
original.m_tag = *ns;
|
||||
else
|
||||
original.m_tag.clear();
|
||||
original.m_firstMessage = msg;
|
||||
original.m_lastMessage = 0;
|
||||
|
||||
m_engine->TransList.append(this);
|
||||
}
|
||||
|
||||
SIPTransaction::~SIPTransaction()
|
||||
|
@ -150,7 +182,7 @@ void SIPTransaction::setLatestMessage(SIPMessage* message)
|
|||
m_lastMessage->ref();
|
||||
if (message->isAnswer()) {
|
||||
m_response = message->code;
|
||||
if (m_response > 100)
|
||||
if ((m_response > 100) && (m_response < 300))
|
||||
setDialogTag();
|
||||
}
|
||||
message->complete(m_engine,0,0,m_tag);
|
||||
|
@ -415,6 +447,8 @@ void SIPTransaction::processClientMessage(SIPMessage* message, int state)
|
|||
case Process:
|
||||
if (message->code <= 100)
|
||||
break;
|
||||
if (tryAutoAuth(message))
|
||||
break;
|
||||
if (m_invite && (m_response <= 100))
|
||||
// use the human interaction timeout in INVITEs
|
||||
setTimeout(m_engine->getUserTimeout());
|
||||
|
@ -536,4 +570,17 @@ SIPEvent* SIPTransaction::getServerEvent(int state, int timeout)
|
|||
return e;
|
||||
}
|
||||
|
||||
bool SIPTransaction::tryAutoAuth(SIPMessage* answer)
|
||||
{
|
||||
if ((answer->code != 401) && (answer->code != 407))
|
||||
return false;
|
||||
if (m_firstMessage->getAuthUsername().null())
|
||||
return false;
|
||||
setTimeout();
|
||||
SIPTransaction* tr = new SIPTransaction(*this,answer);
|
||||
changeState(Initial);
|
||||
tr->processClientMessage(answer,Process);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
||||
|
|
|
@ -409,6 +409,35 @@ public:
|
|||
SIPAuthLine* buildAuth(const String& username, const String& password,
|
||||
const String& meth, const String& uri, bool proxy = false) const;
|
||||
|
||||
/**
|
||||
* Construct a new authorization line based on this answer and original message
|
||||
* @param original Origianl outgoing message
|
||||
* @return A new authorization line to be used in a new transaction
|
||||
*/
|
||||
SIPAuthLine* buildAuth(const SIPMessage& original) const;
|
||||
|
||||
/**
|
||||
* Prepare the message for automatic client transaction authentication.
|
||||
* @param username Username for auto authentication
|
||||
* @param password Password for auto authentication
|
||||
*/
|
||||
inline void setAutoAuth(const char* username = 0, const char* password = 0)
|
||||
{ m_authUser = username; m_authPass = password; }
|
||||
|
||||
/**
|
||||
* Retrive the username to be used for auto authentication
|
||||
* @return Username for auto authentication
|
||||
*/
|
||||
inline const String& getAuthUsername() const
|
||||
{ return m_authUser; }
|
||||
|
||||
/**
|
||||
* Retrive the password to be used for auto authentication
|
||||
* @return Password for auto authentication
|
||||
*/
|
||||
inline const String& getAuthPassword() const
|
||||
{ return m_authPass; }
|
||||
|
||||
/**
|
||||
* Extract routes from Record-Route: headers
|
||||
* @return A list of SIPHeaderLine representing SIP routes
|
||||
|
@ -483,6 +512,8 @@ protected:
|
|||
int m_cseq;
|
||||
mutable String m_string;
|
||||
mutable DataBlock m_data;
|
||||
String m_authUser;
|
||||
String m_authPass;
|
||||
private:
|
||||
SIPMessage(); // no, thanks
|
||||
};
|
||||
|
@ -549,6 +580,7 @@ public:
|
|||
*/
|
||||
Cleared,
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor from first message
|
||||
* @param message A pointer to the initial message, should not be used
|
||||
|
@ -749,6 +781,19 @@ public:
|
|||
{ return m_private; }
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Constructor from previous auto authenticated transaction. This is used only internally
|
||||
* @param original Original transaction that failed authentication
|
||||
*/
|
||||
SIPTransaction(SIPTransaction& original, SIPMessage* answer);
|
||||
|
||||
/**
|
||||
* Attempt to perform automatic client transaction authentication
|
||||
* @param answer SIP answer that creates the new transaction
|
||||
* @return True if current client processing must be abandoned
|
||||
*/
|
||||
bool tryAutoAuth(SIPMessage* answer);
|
||||
|
||||
/**
|
||||
* Get an event only for client transactions
|
||||
* @param state The current state of the transaction
|
||||
|
|
|
@ -128,7 +128,7 @@ private:
|
|||
class YateUDPParty : public SIPParty
|
||||
{
|
||||
public:
|
||||
YateUDPParty(Socket* sock, const SocketAddr& addr, int local);
|
||||
YateUDPParty(Socket* sock, const SocketAddr& addr, int localPort, const char* localAddr = 0);
|
||||
~YateUDPParty();
|
||||
virtual void transmit(SIPEvent* event);
|
||||
virtual const char* getProtoName() const;
|
||||
|
@ -154,46 +154,31 @@ private:
|
|||
bool m_prack;
|
||||
};
|
||||
|
||||
class YateSIPEndPoint : public Thread
|
||||
{
|
||||
public:
|
||||
YateSIPEndPoint();
|
||||
~YateSIPEndPoint();
|
||||
bool Init(void);
|
||||
void run(void);
|
||||
bool incoming(SIPEvent* e, SIPTransaction* t);
|
||||
void invite(SIPEvent* e, SIPTransaction* t);
|
||||
void regreq(SIPEvent* e, SIPTransaction* t);
|
||||
bool generic(SIPEvent* e, SIPTransaction* t);
|
||||
bool buildParty(SIPMessage* message, const char* host = 0, int port = 0);
|
||||
inline YateSIPEngine* engine() const
|
||||
{ return m_engine; }
|
||||
inline int port() const
|
||||
{ return m_port; }
|
||||
inline Socket* socket() const
|
||||
{ return m_sock; }
|
||||
private:
|
||||
int m_port;
|
||||
Socket* m_sock;
|
||||
SocketAddr m_addr;
|
||||
YateSIPEngine *m_engine;
|
||||
|
||||
};
|
||||
|
||||
class YateSIPLine : public String
|
||||
{
|
||||
YCLASS(YateSIPLine,String)
|
||||
public:
|
||||
YateSIPLine(const String& name);
|
||||
virtual ~YateSIPLine();
|
||||
SIPAuthLine* buildAuth(const SIPMessage* answer, const String& method,
|
||||
const String& uri, bool proxy = false) const;
|
||||
SIPMessage* buildRegister(int expires, const SIPMessage* msg) const;
|
||||
void login(const SIPMessage* msg = 0);
|
||||
void setupAuth(SIPMessage* msg) const;
|
||||
SIPMessage* buildRegister(int expires) const;
|
||||
void login();
|
||||
void logout();
|
||||
bool process(SIPEvent* ev);
|
||||
void timer(const Time& when);
|
||||
bool update(const Message& msg);
|
||||
inline const String& getLocalAddr() const
|
||||
{ return m_localAddr; }
|
||||
inline const String& getPartyAddr() const
|
||||
{ return m_partyAddr; }
|
||||
inline int getLocalPort() const
|
||||
{ return m_localPort; }
|
||||
inline int getPartyPort() const
|
||||
{ return m_partyPort; }
|
||||
inline const String& getUserName() const
|
||||
{ return m_username; }
|
||||
inline const String& getAuthName() const
|
||||
{ return m_authname ? m_authname : m_username; }
|
||||
inline const String& domain() const
|
||||
{ return m_domain ? m_domain : m_registrar; }
|
||||
inline bool valid() const
|
||||
|
@ -205,18 +190,50 @@ public:
|
|||
private:
|
||||
void clearTransaction();
|
||||
bool change(String& dest, const String& src);
|
||||
bool change(int& dest, int src);
|
||||
String m_registrar;
|
||||
String m_username;
|
||||
String m_authname;
|
||||
String m_password;
|
||||
String m_outbound;
|
||||
String m_domain;
|
||||
String m_display;
|
||||
Time m_resend;
|
||||
int m_interval;
|
||||
bool m_retry;
|
||||
SIPTransaction* m_tr;
|
||||
bool m_marked;
|
||||
bool m_valid;
|
||||
String m_localAddr;
|
||||
String m_partyAddr;
|
||||
int m_localPort;
|
||||
int m_partyPort;
|
||||
bool m_localDetect;
|
||||
};
|
||||
|
||||
class YateSIPEndPoint : public Thread
|
||||
{
|
||||
public:
|
||||
YateSIPEndPoint();
|
||||
~YateSIPEndPoint();
|
||||
bool Init(void);
|
||||
void run(void);
|
||||
bool incoming(SIPEvent* e, SIPTransaction* t);
|
||||
void invite(SIPEvent* e, SIPTransaction* t);
|
||||
void regreq(SIPEvent* e, SIPTransaction* t);
|
||||
bool generic(SIPEvent* e, SIPTransaction* t);
|
||||
bool buildParty(SIPMessage* message, const char* host = 0, int port = 0, const YateSIPLine* line = 0);
|
||||
inline YateSIPEngine* engine() const
|
||||
{ return m_engine; }
|
||||
inline int port() const
|
||||
{ return m_port; }
|
||||
inline Socket* socket() const
|
||||
{ return m_sock; }
|
||||
private:
|
||||
void addMessage(const char* buf, int len, const SocketAddr& addr, int port);
|
||||
int m_port;
|
||||
Socket* m_sock;
|
||||
SocketAddr m_addr;
|
||||
YateSIPEngine *m_engine;
|
||||
};
|
||||
|
||||
class YateSIPConnection : public Channel
|
||||
|
@ -270,6 +287,8 @@ public:
|
|||
{ return m_host; }
|
||||
inline int getPort() const
|
||||
{ return m_port; }
|
||||
inline const String& getRtpAddr() const
|
||||
{ return m_externalAddr ? m_externalAddr : m_rtpLocalAddr; }
|
||||
private:
|
||||
void setMedia(ObjList* media);
|
||||
void clearTransaction();
|
||||
|
@ -287,7 +306,6 @@ private:
|
|||
SIPTransaction* m_tr;
|
||||
bool m_hungup;
|
||||
bool m_byebye;
|
||||
bool m_retry;
|
||||
int m_state;
|
||||
String m_reason;
|
||||
int m_reasonCode;
|
||||
|
@ -295,6 +313,8 @@ private:
|
|||
// SIP dialog of this call, used for re-INVITE or BYE
|
||||
SIPDialog m_dialog;
|
||||
URI m_uri;
|
||||
// our external IP address, possibly outside of a NAT
|
||||
String m_externalAddr;
|
||||
// if we do RTP forwarding or not
|
||||
bool m_rtpForward;
|
||||
// remote RTP address
|
||||
|
@ -365,6 +385,7 @@ public:
|
|||
YateSIPConnection* findCall(const String& callid);
|
||||
YateSIPConnection* findDialog(const SIPDialog& dialog);
|
||||
YateSIPLine* findLine(const String& line);
|
||||
YateSIPLine* findLine(const String& addr, int port, const String& user = String::empty());
|
||||
bool validLine(const String& line);
|
||||
private:
|
||||
YateSIPEndPoint *m_endpoint;
|
||||
|
@ -375,6 +396,7 @@ static ObjList s_lines;
|
|||
static Configuration s_cfg;
|
||||
static int s_maxForwards = 20;
|
||||
static bool s_privacy = false;
|
||||
static bool s_auto_nat = true;
|
||||
|
||||
// Parse a SDP and return a possibly filtered list of SDP media
|
||||
static ObjList* parseSDP(const SDPBody* sdp, String& addr, ObjList* oldMedia = 0, const char* media = 0)
|
||||
|
@ -453,7 +475,7 @@ static ObjList* parseSDP(const SDPBody* sdp, String& addr, ObjList* oldMedia = 0
|
|||
payload = "ilbc30";
|
||||
}
|
||||
|
||||
XDebug(&plugin,DebugAll,"Payload %d format '%s'",var,payload);
|
||||
XDebug(&plugin,DebugAll,"Payload %d format '%s'",var,payload.c_str());
|
||||
if (payload && s_cfg.getBoolValue("codecs",payload,defcodecs && DataTranslator::canConvert(payload))) {
|
||||
if (fmt)
|
||||
fmt << ",";
|
||||
|
@ -682,16 +704,19 @@ void RtpMedia::update(const Message& msg, bool pickFormat)
|
|||
m_format = msg.getValue("format");
|
||||
}
|
||||
|
||||
YateUDPParty::YateUDPParty(Socket* sock, const SocketAddr& addr, int local)
|
||||
YateUDPParty::YateUDPParty(Socket* sock, const SocketAddr& addr, int localPort, const char* localAddr)
|
||||
: m_sock(sock), m_addr(addr)
|
||||
{
|
||||
m_local = "localhost";
|
||||
m_localPort = local;
|
||||
DDebug(&plugin,DebugAll,"YateUDPParty::YateUDPParty() %s:%d [%p]",localAddr,localPort,this);
|
||||
m_localPort = localPort;
|
||||
m_party = m_addr.host();
|
||||
m_partyPort = m_addr.port();
|
||||
Socket s(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
|
||||
if (s.valid()) {
|
||||
if (s.connect(m_addr)) {
|
||||
if (localAddr)
|
||||
m_local = localAddr;
|
||||
else {
|
||||
m_local = "localhost";
|
||||
Socket s(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
|
||||
if (s.valid() && s.connect(m_addr)) {
|
||||
SocketAddr laddr;
|
||||
if (s.getSockName(laddr))
|
||||
m_local = laddr.host();
|
||||
|
@ -704,6 +729,7 @@ YateUDPParty::YateUDPParty(Socket* sock, const SocketAddr& addr, int local)
|
|||
|
||||
YateUDPParty::~YateUDPParty()
|
||||
{
|
||||
DDebug(&plugin,DebugAll,"YateUDPParty::~YateUDPParty() [%p]",this);
|
||||
m_sock = 0;
|
||||
}
|
||||
|
||||
|
@ -736,7 +762,7 @@ const char* YateUDPParty::getProtoName() const
|
|||
|
||||
bool YateUDPParty::setParty(const URI& uri)
|
||||
{
|
||||
if (m_partyPort && m_party && s_cfg.getBoolValue("general","ignorevia"))
|
||||
if (m_partyPort && m_party && s_cfg.getBoolValue("general","ignorevia",true))
|
||||
return true;
|
||||
if (uri.getHost().null())
|
||||
return false;
|
||||
|
@ -845,11 +871,20 @@ YateSIPEndPoint::~YateSIPEndPoint()
|
|||
}
|
||||
}
|
||||
|
||||
bool YateSIPEndPoint::buildParty(SIPMessage* message, const char* host, int port)
|
||||
bool YateSIPEndPoint::buildParty(SIPMessage* message, const char* host, int port, const YateSIPLine* line)
|
||||
{
|
||||
if (message->isAnswer())
|
||||
return false;
|
||||
DDebug(&plugin,DebugAll,"YateSIPEndPoint::buildParty(%p,'%s',%d,%p)",
|
||||
message,host,port,line);
|
||||
URI uri(message->uri);
|
||||
if (line) {
|
||||
if (!host)
|
||||
host = line->getPartyAddr();
|
||||
if (port <= 0)
|
||||
port = line->getPartyPort();
|
||||
line->setupAuth(message);
|
||||
}
|
||||
if (!host) {
|
||||
host = uri.getHost().safe();
|
||||
if (port <= 0)
|
||||
|
@ -865,7 +900,12 @@ bool YateSIPEndPoint::buildParty(SIPMessage* message, const char* host, int port
|
|||
addr.port(port);
|
||||
DDebug(&plugin,DebugAll,"built addr: %s:%d",
|
||||
addr.host().c_str(),addr.port());
|
||||
YateUDPParty* party = new YateUDPParty(m_sock,addr,m_port);
|
||||
// reuse the variables now we finished with them
|
||||
host = line ? line->getLocalAddr().c_str() : 0;
|
||||
port = line ? line->getLocalPort() : 0;
|
||||
if (port <= 0)
|
||||
port = m_port;
|
||||
YateUDPParty* party = new YateUDPParty(m_sock,addr,port,host);
|
||||
message->setParty(party);
|
||||
party->deref();
|
||||
return true;
|
||||
|
@ -911,6 +951,28 @@ bool YateSIPEndPoint::Init()
|
|||
return true;
|
||||
}
|
||||
|
||||
void YateSIPEndPoint::addMessage(const char* buf, int len, const SocketAddr& addr, int port)
|
||||
{
|
||||
SIPMessage* msg = SIPMessage::fromParsing(0,buf,len);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
if (!msg->isAnswer()) {
|
||||
URI uri(msg->uri);
|
||||
YateSIPLine* line = plugin.findLine(addr.host(),addr.port(),uri.getUser());
|
||||
const char* host = 0;
|
||||
if (line && line->getLocalPort()) {
|
||||
host = line->getLocalAddr();
|
||||
port = line->getLocalPort();
|
||||
}
|
||||
YateUDPParty* party = new YateUDPParty(m_sock,addr,port,host);
|
||||
msg->setParty(party);
|
||||
party->deref();
|
||||
}
|
||||
m_engine->addMessage(msg);
|
||||
msg->deref();
|
||||
}
|
||||
|
||||
void YateSIPEndPoint::run()
|
||||
{
|
||||
struct timeval tv;
|
||||
|
@ -936,7 +998,8 @@ void YateSIPEndPoint::run()
|
|||
Debug(&plugin,DebugInfo,"Received %d bytes SIP message from %s:%d\n------\n%s------",
|
||||
res,m_addr.host().c_str(),m_addr.port(),buf);
|
||||
// we got already the buffer and here we start to do "good" stuff
|
||||
m_engine->addMessage(new YateUDPParty(m_sock,m_addr,m_port),buf,res);
|
||||
addMessage(buf,res,m_addr,m_port);
|
||||
//m_engine->addMessage(new YateUDPParty(m_sock,m_addr,m_port),buf,res);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else
|
||||
|
@ -1063,7 +1126,7 @@ void YateSIPEndPoint::regreq(SIPEvent* e, SIPTransaction* t)
|
|||
int age = t->authUser(user);
|
||||
DDebug(&plugin,DebugAll,"User '%s' age %d",user.c_str(),age);
|
||||
if ((age < 0) || (age > 10)) {
|
||||
t->requestAuth("realm","",age > 0);
|
||||
t->requestAuth(s_cfg.getValue("general","realm","Yate"),"",age >= 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1101,7 +1164,7 @@ bool YateSIPEndPoint::generic(SIPEvent* e, SIPTransaction* t)
|
|||
int age = t->authUser(user);
|
||||
DDebug(&plugin,DebugAll,"User '%s' age %d",user.c_str(),age);
|
||||
if ((age < 0) || (age > 10)) {
|
||||
t->requestAuth("realm","",age > 0);
|
||||
t->requestAuth("realm","",age >= 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1136,7 +1199,7 @@ bool YateSIPEndPoint::generic(SIPEvent* e, SIPTransaction* t)
|
|||
// Incoming call constructor - just before starting the routing thread
|
||||
YateSIPConnection::YateSIPConnection(SIPEvent* ev, SIPTransaction* tr)
|
||||
: Channel(plugin,0,false),
|
||||
m_tr(tr), m_hungup(false), m_byebye(true), m_retry(false),
|
||||
m_tr(tr), m_hungup(false), m_byebye(true),
|
||||
m_state(Incoming), m_rtpForward(false), m_rtpMedia(0),
|
||||
m_sdpSession(0), m_sdpVersion(0), m_port(0), m_route(0), m_routes(0),
|
||||
m_authBye(true), m_mediaStatus(MediaMissing)
|
||||
|
@ -1155,19 +1218,30 @@ YateSIPConnection::YateSIPConnection(SIPEvent* ev, SIPTransaction* tr)
|
|||
m_tr->setUserData(this);
|
||||
|
||||
URI uri(m_tr->getURI());
|
||||
YateSIPLine* line = plugin.findLine(m_host,m_port,m_uri.getUser());
|
||||
Message *m = message("call.route");
|
||||
|
||||
String user;
|
||||
int age = tr->authUser(user);
|
||||
DDebug(this,DebugAll,"User '%s' age %d",user.c_str(),age);
|
||||
if (age >= 0) {
|
||||
if (age < 10) {
|
||||
m_user = user;
|
||||
m->addParam("username",m_user);
|
||||
if (line) {
|
||||
// call comes from line we have registered to - trust it...
|
||||
m_user = line->getUserName();
|
||||
m_externalAddr = line->getLocalAddr();
|
||||
m_line = *line;
|
||||
m->addParam("username",m_user);
|
||||
m->addParam("in_line",m_line);
|
||||
}
|
||||
else {
|
||||
String user;
|
||||
int age = tr->authUser(user);
|
||||
DDebug(this,DebugAll,"User '%s' age %d",user.c_str(),age);
|
||||
if (age >= 0) {
|
||||
if (age < 10) {
|
||||
m_user = user;
|
||||
m->addParam("username",m_user);
|
||||
}
|
||||
else
|
||||
m->addParam("expired_user",user);
|
||||
m->addParam("xsip_nonce_age",String(age));
|
||||
}
|
||||
else
|
||||
m->addParam("expired_user",user);
|
||||
m->addParam("xsip_nonce_age",String(age));
|
||||
}
|
||||
if (s_privacy)
|
||||
copyPrivacy(*m,*ev->getMessage());
|
||||
|
@ -1192,7 +1266,7 @@ YateSIPConnection::YateSIPConnection(SIPEvent* ev, SIPTransaction* tr)
|
|||
if (m_rtpMedia) {
|
||||
m_rtpForward = true;
|
||||
// guess if the call comes from behind a NAT
|
||||
if (s_cfg.getBoolValue("general","nat",true) && isPrivateAddr(m_rtpAddr) && !isPrivateAddr(m_host)) {
|
||||
if (s_auto_nat && isPrivateAddr(m_rtpAddr) && !isPrivateAddr(m_host)) {
|
||||
Debug(this,DebugInfo,"NAT detected: private '%s' public '%s'",
|
||||
m_rtpAddr.c_str(),m_host.c_str());
|
||||
m->addParam("rtp_nat_addr",m_rtpAddr);
|
||||
|
@ -1217,7 +1291,7 @@ YateSIPConnection::YateSIPConnection(SIPEvent* ev, SIPTransaction* tr)
|
|||
// Outgoing call constructor - in call.execute handler
|
||||
YateSIPConnection::YateSIPConnection(Message& msg, const String& uri, const char* target)
|
||||
: Channel(plugin,0,true),
|
||||
m_tr(0), m_hungup(false), m_byebye(true), m_retry(true),
|
||||
m_tr(0), m_hungup(false), m_byebye(true),
|
||||
m_state(Outgoing), m_rtpForward(false), m_rtpMedia(0),
|
||||
m_sdpSession(0), m_sdpVersion(0), m_port(0), m_route(0), m_routes(0),
|
||||
m_authBye(false), m_mediaStatus(MediaMissing)
|
||||
|
@ -1229,20 +1303,23 @@ YateSIPConnection::YateSIPConnection(Message& msg, const String& uri, const char
|
|||
m_rtpForward = msg.getBoolValue("rtp_forward");
|
||||
m_line = msg.getValue("line");
|
||||
String tmp;
|
||||
if (m_line && (uri.find('@') < 0)) {
|
||||
YateSIPLine* line = plugin.findLine(m_line);
|
||||
if (line) {
|
||||
YateSIPLine* line = 0;
|
||||
if (m_line) {
|
||||
line = plugin.findLine(m_line);
|
||||
if (line && (uri.find('@') < 0)) {
|
||||
if (!uri.startsWith("sip:"))
|
||||
tmp = "sip:";
|
||||
tmp << uri << "@" << line->domain();
|
||||
}
|
||||
if (line)
|
||||
m_externalAddr = line->getLocalAddr();
|
||||
}
|
||||
if (tmp.null())
|
||||
tmp = uri;
|
||||
m_uri = tmp;
|
||||
m_uri.parse();
|
||||
SIPMessage* m = new SIPMessage("INVITE",m_uri);
|
||||
plugin.ep()->buildParty(m,msg.getValue("host"),msg.getIntValue("port"));
|
||||
plugin.ep()->buildParty(m,msg.getValue("host"),msg.getIntValue("port"),line);
|
||||
if (!m->getParty()) {
|
||||
Debug(this,DebugWarn,"Could not create party for '%s' [%p]",m_uri.c_str(),this);
|
||||
m->destruct();
|
||||
|
@ -1254,7 +1331,9 @@ YateSIPConnection::YateSIPConnection(Message& msg, const String& uri, const char
|
|||
}
|
||||
int maxf = msg.getIntValue("antiloop",s_maxForwards);
|
||||
m->addHeader("Max-Forwards",String(maxf));
|
||||
m->complete(plugin.ep()->engine(),msg.getValue("caller"),msg.getValue("domain"));
|
||||
m->complete(plugin.ep()->engine(),
|
||||
msg.getValue("caller"),
|
||||
msg.getValue("domain",(line ? line->domain().c_str() : 0)));
|
||||
if (plugin.ep()->engine()->prack())
|
||||
m->addHeader("Supported","100rel");
|
||||
m_host = m->getParty()->getPartyAddr();
|
||||
|
@ -1363,7 +1442,7 @@ void YateSIPConnection::hangup()
|
|||
case Ringing:
|
||||
if (m_tr) {
|
||||
SIPMessage* m = new SIPMessage("CANCEL",m_uri);
|
||||
plugin.ep()->buildParty(m,m_host,m_port);
|
||||
plugin.ep()->buildParty(m,m_host,m_port,plugin.findLine(m_line));
|
||||
if (!m->getParty())
|
||||
Debug(this,DebugWarn,"Could not create party for '%s:%d' [%p]",
|
||||
m_host.c_str(),m_port,this);
|
||||
|
@ -1411,7 +1490,7 @@ SIPMessage* YateSIPConnection::createDlgMsg(const char* method, const char* uri)
|
|||
uri = m_uri;
|
||||
SIPMessage* m = new SIPMessage(method,uri);
|
||||
m->addRoutes(m_routes);
|
||||
plugin.ep()->buildParty(m,m_host,m_port);
|
||||
plugin.ep()->buildParty(m,m_host,m_port,plugin.findLine(m_line));
|
||||
if (!m->getParty()) {
|
||||
Debug(this,DebugWarn,"Could not create party for '%s:%d' [%p]",
|
||||
m_host.c_str(),m_port,this);
|
||||
|
@ -1639,7 +1718,7 @@ SDPBody* YateSIPConnection::createRtpSDP(const char* addr, const Message& msg)
|
|||
if (!dispatchRtp(m,addr,false,true))
|
||||
return 0;
|
||||
}
|
||||
return createSDP(m_rtpLocalAddr);
|
||||
return createSDP(getRtpAddr());
|
||||
}
|
||||
|
||||
// Creates a set of started external RTP channels from remote addr and builds SDP from them
|
||||
|
@ -1656,7 +1735,7 @@ SDPBody* YateSIPConnection::createRtpSDP(bool start)
|
|||
if (!dispatchRtp(m,m_rtpAddr,start,true))
|
||||
return 0;
|
||||
}
|
||||
return createSDP(m_rtpLocalAddr);
|
||||
return createSDP(getRtpAddr());
|
||||
}
|
||||
|
||||
// Starts an already created set of external RTP channels
|
||||
|
@ -1799,33 +1878,6 @@ bool YateSIPConnection::process(SIPEvent* ev)
|
|||
const SIPMessage* msg = ev->getMessage();
|
||||
int code = ev->getTransaction()->getResponseCode();
|
||||
if (msg && !msg->isOutgoing() && msg->isAnswer() && (code >= 300)) {
|
||||
if (m_retry && m_line
|
||||
&& ((code == 401) || (code == 407))
|
||||
&& plugin.validLine(m_line)) {
|
||||
// try only once to add credentials
|
||||
m_retry = false;
|
||||
YateSIPLine* line = plugin.findLine(m_line);
|
||||
if (line) {
|
||||
SIPMessage* m = new SIPMessage(*m_tr->initialMessage());
|
||||
SIPAuthLine* auth = line->buildAuth(msg,m->method,m->uri,(code == 407));
|
||||
m->addHeader(auth);
|
||||
|
||||
m_tr->setUserData(0);
|
||||
m_tr->deref();
|
||||
m_tr = 0;
|
||||
|
||||
m_tr = plugin.ep()->engine()->addMessage(m);
|
||||
m->deref();
|
||||
if (m_tr) {
|
||||
m_tr->ref();
|
||||
m_callid = m_tr->getCallID();
|
||||
m_tr->setUserData(this);
|
||||
}
|
||||
else
|
||||
setReason("Internal server failure",500);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
setReason(msg->reason,code);
|
||||
hangup();
|
||||
}
|
||||
|
@ -1848,7 +1900,7 @@ bool YateSIPConnection::process(SIPEvent* ev)
|
|||
DDebug(this,DebugInfo,"YateSIPConnection got SDP [%p]",this);
|
||||
setMedia(parseSDP(static_cast<SDPBody*>(msg->body),m_rtpAddr,m_rtpMedia));
|
||||
// guess if the call comes from behind a NAT
|
||||
if (s_cfg.getBoolValue("general","nat",true) && isPrivateAddr(m_rtpAddr) && !isPrivateAddr(m_host)) {
|
||||
if (s_auto_nat && isPrivateAddr(m_rtpAddr) && !isPrivateAddr(m_host)) {
|
||||
Debug(this,DebugInfo,"NAT detected: private '%s' public '%s'",
|
||||
m_rtpAddr.c_str(),m_host.c_str());
|
||||
natAddr = m_rtpAddr;
|
||||
|
@ -1908,7 +1960,7 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
|
|||
if (!lst)
|
||||
break;
|
||||
// guess if the call comes from behind a NAT
|
||||
if (s_cfg.getBoolValue("general","nat",true) && isPrivateAddr(addr) && !isPrivateAddr(m_host)) {
|
||||
if (s_auto_nat && isPrivateAddr(addr) && !isPrivateAddr(m_host)) {
|
||||
Debug(this,DebugInfo,"NAT detected: private '%s' public '%s'",
|
||||
addr.c_str(),m_host.c_str());
|
||||
addr = m_host;
|
||||
|
@ -1938,7 +1990,7 @@ bool YateSIPConnection::checkUser(SIPTransaction* t, bool refuse)
|
|||
if (m_user.null())
|
||||
return true;
|
||||
int age = t->authUser(m_user);
|
||||
if ((age > 0) && (age <= 10))
|
||||
if ((age >= 0) && (age <= 10))
|
||||
return true;
|
||||
DDebug(this,DebugAll,"YateSIPConnection::checkUser(%p) failed, age %d [%p]",t,age,this);
|
||||
if (refuse)
|
||||
|
@ -2116,7 +2168,8 @@ void YateSIPConnection::callRejected(const char* error, const char* reason, cons
|
|||
|
||||
YateSIPLine::YateSIPLine(const String& name)
|
||||
: String(name), m_resend((u_int64_t)0), m_interval(0),
|
||||
m_retry(false), m_tr(0), m_marked(false), m_valid(false)
|
||||
m_tr(0), m_marked(false), m_valid(false),
|
||||
m_localPort(0), m_partyPort(0), m_localDetect(false)
|
||||
{
|
||||
DDebug(&plugin,DebugInfo,"YateSIPLine::YateSIPLine('%s') [%p]",c_str(),this);
|
||||
s_lines.append(this);
|
||||
|
@ -2129,22 +2182,19 @@ YateSIPLine::~YateSIPLine()
|
|||
logout();
|
||||
}
|
||||
|
||||
SIPAuthLine* YateSIPLine::buildAuth(const SIPMessage* answer, const String& method,
|
||||
const String& uri, bool proxy) const
|
||||
void YateSIPLine::setupAuth(SIPMessage* msg) const
|
||||
{
|
||||
return answer ? answer->buildAuth(m_username,m_password,method,uri,proxy) : 0;
|
||||
if (msg)
|
||||
msg->setAutoAuth(getAuthName(),m_password);
|
||||
}
|
||||
|
||||
SIPMessage* YateSIPLine::buildRegister(int expires, const SIPMessage* msg) const
|
||||
SIPMessage* YateSIPLine::buildRegister(int expires) const
|
||||
{
|
||||
String exp(expires);
|
||||
String tmp;
|
||||
tmp << "sip:" << m_registrar;
|
||||
SIPMessage* m = new SIPMessage("REGISTER",tmp);
|
||||
if (msg)
|
||||
m->setParty(msg->getParty());
|
||||
else
|
||||
plugin.ep()->buildParty(m);
|
||||
plugin.ep()->buildParty(m,0,0,this);
|
||||
if (!m->getParty()) {
|
||||
Debug(&plugin,DebugWarn,"Could not create party for '%s' [%p]",
|
||||
m_registrar.c_str(),this);
|
||||
|
@ -2166,30 +2216,23 @@ SIPMessage* YateSIPLine::buildRegister(int expires, const SIPMessage* msg) const
|
|||
return m;
|
||||
}
|
||||
|
||||
void YateSIPLine::login(const SIPMessage* msg)
|
||||
void YateSIPLine::login()
|
||||
{
|
||||
if (m_registrar.null() || m_username.null()) {
|
||||
logout();
|
||||
m_retry = false;
|
||||
m_valid = true;
|
||||
return;
|
||||
}
|
||||
DDebug(&plugin,DebugInfo,"YateSIPLine '%s' logging in [%p]",c_str(),this);
|
||||
clearTransaction();
|
||||
m_retry = true;
|
||||
|
||||
SIPMessage* m = buildRegister(m_interval,msg);
|
||||
SIPMessage* m = buildRegister(m_interval);
|
||||
if (!m) {
|
||||
m_retry = false;
|
||||
m_valid = false;
|
||||
return;
|
||||
}
|
||||
if (msg) {
|
||||
SIPAuthLine* auth = buildAuth(msg,m->method,m->uri,(msg->code == 407));
|
||||
m->addHeader(auth);
|
||||
m_retry = false;
|
||||
}
|
||||
DDebug(&plugin,DebugInfo,"YateSIPLine '%s' emiting %p for answer %p [%p]",
|
||||
c_str(),m,msg,this);
|
||||
DDebug(&plugin,DebugInfo,"YateSIPLine '%s' emiting %p [%p]",
|
||||
c_str(),m,this);
|
||||
m_tr = plugin.ep()->engine()->addMessage(m);
|
||||
if (m_tr) {
|
||||
m_tr->ref();
|
||||
|
@ -2203,10 +2246,12 @@ void YateSIPLine::logout()
|
|||
m_resend = 0;
|
||||
bool sendLogout = m_valid && m_registrar && m_username;
|
||||
clearTransaction();
|
||||
m_retry = false;
|
||||
m_valid = false;
|
||||
if (sendLogout) {
|
||||
SIPMessage* m = buildRegister(0,0);
|
||||
DDebug(&plugin,DebugInfo,"YateSIPLine '%s' logging out [%p]",c_str(),this);
|
||||
SIPMessage* m = buildRegister(0);
|
||||
m_partyAddr.clear();
|
||||
m_partyPort = 0;
|
||||
if (!m)
|
||||
return;
|
||||
plugin.ep()->engine()->addMessage(m);
|
||||
|
@ -2222,9 +2267,8 @@ bool YateSIPLine::process(SIPEvent* ev)
|
|||
return false;
|
||||
if (ev->getState() == SIPTransaction::Cleared) {
|
||||
clearTransaction();
|
||||
m_retry = false;
|
||||
m_valid = false;
|
||||
m_resend = m_interval*1000000 + Time::now();
|
||||
m_resend = m_interval*(int64_t)1000000 + Time::now();
|
||||
return false;
|
||||
}
|
||||
const SIPMessage* msg = ev->getMessage();
|
||||
|
@ -2233,26 +2277,29 @@ bool YateSIPLine::process(SIPEvent* ev)
|
|||
if (ev->getState() != SIPTransaction::Process)
|
||||
return false;
|
||||
clearTransaction();
|
||||
DDebug(&plugin,DebugAll,"YateSIPLine '%s' got answer %d%s [%p]",
|
||||
c_str(),msg->code,m_retry ? " (may retry)" : "",this);
|
||||
DDebug(&plugin,DebugAll,"YateSIPLine '%s' got answer %d [%p]",
|
||||
c_str(),msg->code,this);
|
||||
switch (msg->code) {
|
||||
case 200:
|
||||
m_retry = false;
|
||||
m_valid = true;
|
||||
m_resend = m_interval*1000000 + Time::now();
|
||||
Debug(&plugin,DebugInfo,"SIP line '%s' logon success",c_str());
|
||||
break;
|
||||
case 401:
|
||||
case 407:
|
||||
if (m_retry) {
|
||||
m_retry = false;
|
||||
login(msg);
|
||||
break;
|
||||
if (msg->getParty()) {
|
||||
if (m_localDetect) {
|
||||
m_localAddr = msg->getParty()->getLocalAddr();
|
||||
m_localPort = msg->getParty()->getLocalPort();
|
||||
DDebug(&plugin,DebugInfo,"SIP line '%s' on local address %s:%d",
|
||||
c_str(),m_localAddr.c_str(),m_localPort);
|
||||
}
|
||||
m_partyAddr = msg->getParty()->getPartyAddr();
|
||||
m_partyPort = msg->getParty()->getPartyPort();
|
||||
}
|
||||
m_valid = true;
|
||||
// re-register at 3/4 of the expire interval
|
||||
m_resend = m_interval*(int64_t)750000 + Time::now();
|
||||
Debug(&plugin,DebugInfo,"SIP line '%s' logon success to %s:%d",
|
||||
c_str(),m_partyAddr.c_str(),m_partyPort);
|
||||
break;
|
||||
default:
|
||||
m_retry = false;
|
||||
m_valid = false;
|
||||
Debug(&plugin,DebugInfo,"SIP line '%s' logon failure %d",c_str(),msg->code);
|
||||
Debug(&plugin,DebugWarn,"SIP line '%s' logon failure %d",c_str(),msg->code);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -2261,7 +2308,7 @@ void YateSIPLine::timer(const Time& when)
|
|||
{
|
||||
if (!m_resend || (m_resend > when))
|
||||
return;
|
||||
m_resend = m_interval*1000000 + when;
|
||||
m_resend = m_interval*(int64_t)1000000 + when;
|
||||
login();
|
||||
}
|
||||
|
||||
|
@ -2286,17 +2333,50 @@ bool YateSIPLine::change(String& dest, const String& src)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool YateSIPLine::change(int& dest, int src)
|
||||
{
|
||||
if (dest == src)
|
||||
return false;
|
||||
// we need to log out before any parameter changes
|
||||
logout();
|
||||
dest = src;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YateSIPLine::update(const Message& msg)
|
||||
{
|
||||
DDebug(&plugin,DebugInfo,"YateSIPLine::update() '%s' [%p]",c_str(),this);
|
||||
String oper(msg.getValue("operation"));
|
||||
if (oper == "logout") {
|
||||
logout();
|
||||
return true;
|
||||
}
|
||||
bool chg = false;
|
||||
chg = change(m_registrar,msg.getValue("registrar")) || chg;
|
||||
chg = change(m_outbound,msg.getValue("outbound")) || chg;
|
||||
chg = change(m_username,msg.getValue("username")) || chg;
|
||||
chg = change(m_authname,msg.getValue("authname")) || chg;
|
||||
chg = change(m_password,msg.getValue("password")) || chg;
|
||||
chg = change(m_domain,msg.getValue("domain")) || chg;
|
||||
m_display = msg.getValue("description");
|
||||
m_interval = msg.getIntValue("interval",600);
|
||||
String tmp(msg.getValue("localaddress"));
|
||||
m_localDetect = (tmp == "auto");
|
||||
if (!m_localDetect) {
|
||||
int port = 0;
|
||||
if (tmp) {
|
||||
int sep = tmp.find(':');
|
||||
if (sep > 0) {
|
||||
port = tmp.substr(sep+1).toInteger(5060);
|
||||
tmp = tmp.substr(0,sep);
|
||||
}
|
||||
else if (sep < 0)
|
||||
port = 5060;
|
||||
}
|
||||
chg = change(m_localAddr,tmp) || chg;
|
||||
chg = change(m_localPort,port) || chg;
|
||||
}
|
||||
tmp = msg.getValue("operation");
|
||||
// if something changed we logged out so try to climb back
|
||||
if (chg)
|
||||
login();
|
||||
|
@ -2377,8 +2457,13 @@ bool SipHandler::received(Message &msg)
|
|||
uri = uri.matchString(1);
|
||||
if (!(method && uri))
|
||||
return false;
|
||||
YateSIPLine* line = plugin.findLine(msg.getValue("line"));
|
||||
if (line && !line->valid()) {
|
||||
msg.setParam("error","offline");
|
||||
return false;
|
||||
}
|
||||
SIPMessage* sip = new SIPMessage(method,uri);
|
||||
plugin.ep()->buildParty(sip,msg.getValue("host"),msg.getIntValue("port"));
|
||||
plugin.ep()->buildParty(sip,msg.getValue("host"),msg.getIntValue("port"),line);
|
||||
copySipHeaders(*sip,msg);
|
||||
const char* type = msg.getValue("xsip_type");
|
||||
const char* body = msg.getValue("xsip_body");
|
||||
|
@ -2426,6 +2511,7 @@ YateSIPConnection* SIPDriver::findDialog(const SIPDialog& dialog)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// find line by name
|
||||
YateSIPLine* SIPDriver::findLine(const String& line)
|
||||
{
|
||||
if (line.null())
|
||||
|
@ -2434,6 +2520,25 @@ YateSIPLine* SIPDriver::findLine(const String& line)
|
|||
return l ? static_cast<YateSIPLine*>(l->get()) : 0;
|
||||
}
|
||||
|
||||
// find line by party address and port
|
||||
YateSIPLine* SIPDriver::findLine(const String& addr, int port, const String& user)
|
||||
{
|
||||
if (!(port && addr))
|
||||
return 0;
|
||||
Lock mylock(this);
|
||||
ObjList* l = s_lines.skipNull();
|
||||
for (; l; l = l->skipNext()) {
|
||||
YateSIPLine* sl = static_cast<YateSIPLine*>(l->get());
|
||||
if (sl->getPartyPort() && (sl->getPartyPort() == port) && (sl->getPartyAddr() == addr)) {
|
||||
if (user && (sl->getUserName() != user))
|
||||
continue;
|
||||
return sl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check if a line is either empty or valid (logged in or no registrar)
|
||||
bool SIPDriver::validLine(const String& line)
|
||||
{
|
||||
if (line.null())
|
||||
|
@ -2460,8 +2565,11 @@ bool SIPDriver::msgExecute(Message& msg, String& dest)
|
|||
Debug(this,DebugWarn,"SIP call found but no data channel!");
|
||||
return false;
|
||||
}
|
||||
if (!validLine(msg.getValue("line")))
|
||||
if (!validLine(msg.getValue("line"))) {
|
||||
// asked to use a line but it's not registered
|
||||
msg.setParam("error","offline");
|
||||
return false;
|
||||
}
|
||||
YateSIPConnection* conn = new YateSIPConnection(msg,dest,msg.getValue("id"));
|
||||
if (conn->getTransaction()) {
|
||||
CallEndpoint* ch = static_cast<CallEndpoint*>(msg.userData());
|
||||
|
@ -2494,6 +2602,7 @@ void SIPDriver::initialize()
|
|||
s_cfg.load();
|
||||
s_maxForwards = s_cfg.getIntValue("general","maxforwards",20);
|
||||
s_privacy = s_cfg.getBoolValue("general","privacy");
|
||||
s_auto_nat = s_cfg.getBoolValue("general","nat",true);
|
||||
if (!m_endpoint) {
|
||||
m_endpoint = new YateSIPEndPoint();
|
||||
if (!(m_endpoint->Init())) {
|
||||
|
|
Loading…
Reference in New Issue