Added support for tcp/tls sip transport. The sip module can now use (bind on) more then one address for udp.

git-svn-id: http://voip.null.ro/svn/yate@4493 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2011-07-12 14:55:02 +00:00
parent 0bc6a8eb4f
commit f9f3241df5
6 changed files with 3640 additions and 403 deletions

View File

@ -1,18 +1,37 @@
; This file configures the SIP channel
;
; NOTES on UDP listeners
; - Address/port can be changed and reloaded
; - If address/port is changed for an enabled listener this will be destroyed and recreated
; - When an UDP listener is destroyed all channels using it will be dropped and
; all lines using it will be unregistered
; - If the only configured listener is 'general' this one will be the default one
; - After initializing the module will find for a default transport:
; 1: First search for a default listener whose name is not 'general'
; 2: Use 'general' if no other listener is set to be the default
[general]
; This section sets global variables of the implementation
; port: int: SIP UDP port
;port=5060
; addr: ipaddress: IP address to bind to
;addr=0.0.0.0
; maxpkt: int: Maximum received packet size, 524 to 65528, default 1500
; maxpkt: int: Maximum received UDP packet size, 524 to 65528, default 1500
; This parameter is applied on reload and can be overridden in UDP listener sections
;maxpkt=1500
; buffer: int: Requested size of socket's receive buffer, 0 to use default
; buffer: int: Requested size of UDP socket's receive buffer, 0 to use default
; This can be overridden in UDP listener sections
;buffer=0
; tcp_maxpkt: int: Maximum received TCP packet size, 524 to 65528, default 4096
; This parameter is applied on reload and can be overridden in TCP/TLS listener sections
; The parameter is not applied on reload for already created listeners or connections
;tcp_maxpkt=4096
; tcp_out_rtp_localip: ipaddress: IP address to bind local RTP to for outgoing
; TCP connections, empty to guess best
; This parameter is applied on reload for new connections only
;tcp_out_rtp_localip=
; thread: keyword: Default priority of the SIP handling threads
; Can be one of: lowest, low, normal, high, highest
; High priorities need superuser privileges on POSIX operating systems
@ -85,9 +104,6 @@
; forward_sdp: bool: Include the raw SDP body to be used as-is for forwarding RTP
;forward_sdp=disable
; rtp_localip: ipaddress: IP address to bind local RTP to, empty to guess best
;rtp_localip=
; rtp_start: bool: Start RTP when sending 200 on incoming instead of receiving ACK
;rtp_start=disable
@ -101,6 +117,11 @@
; See SIPMessage::Flags and SIPMessage::complete() in the source for gory details
;flags=0
; printmsg: boolean: Print SIP messages to output
; This parameter is applied on reload
; Defaults to yes
;printmsg=yes
[registrar]
; Controls the behaviour when acting as registrar
@ -215,3 +236,100 @@
; ignore_sdp_port: bool: Ignore SDP changes if only the port is different
; This allows preserving the local RTP session and port
;ignore_sdp_port=no
[listener general]
; This section has the following purposes:
; - Maintain compatibility with old configuration
; - Setup an UDP listener named 'general'
; This section will be processed before any other listener sections
; The following parameters can be overridden from 'general' section: maxpkt, buffer
; enable: boolean: Enable or disable the UDP listener
; This parameter is applied on reload and defaults to yes
;enable=yes
; default: boolean: Specifiy if this is the default transport to use when none specified
; Defaults to yes (unlike the other listeners)
;default=yes
; udp_force_bind: boolean: Try to use a random port if failed to bind on configured one
; Defaults to yes
;udp_force_bind=yes
; addr: ipaddress: IP address to bind to
; Leave it empty to listen on all available interfaces
;addr=
; port: integer: Port to bind to
; Defaults to 5060
;port=5060
; rtp_localip: ipaddress: IP address to bind local RTP to, empty to guess best
; This parameter is applied on reload
; RTP local IP address will default to bound IP address if not binding on all interfaces
; Explicitly set it to empty string to avoid using bound IP address
;rtp_localip=
; thread: keyword: Listener thread priority
; Can be one of: lowest, low, normal, high, highest
; High priorities need superuser privileges on POSIX operating systems
; Low priorities are not recommended except for debugging
;thread=normal
;[listener name]
; This section configures a listener named 'name' ('general' is reserved and will be ignored)
; The following parameters can be overridden from 'general' section:
; UDP: maxpkt, buffer
; TCP/TLS: tcp_maxpkt
; type: keyword: Listener type
; Allowed values:
; udp: Build an UDP listener. Ignored if multihomed is disabled
; tcp: Build a TCP listener
; tls: Build a TLS listener (encrypted TCP)
;type=
; enable: boolean: Enable or disable this listener
; This parameter is applied on reload and defaults to yes
;enable=yes
; default: boolean: UDP only: specifiy if this is the default transport to use when none specified
; Defaults to no
;default=no
; udp_force_bind: boolean: UDP only: try to use a random port if failed to bind on configured one
; Defaults to yes
;udp_force_bind=yes
; addr: ipaddress: IP address to bind to
; Leave it empty to listen on all available interfaces
;addr=
; port: integer: Port to bind to
; Defaults to 5060 for UDP and TCP, 5061 for TLS listeners
;port=
; rtp_localip: ipaddress: IP address to bind local RTP to
; This parameter is applied on reload
; TCP/TLS: this parameter is applied on reload for new connections only
; RTP local IP address will default to bound IP address if not binding on all interfaces
; Explicitly set it to empty string to avoid using bound IP address
;rtp_localip=
; backlog: integer: Maximum length of the queue of pending connections
; This parameter is ignored for UDP listeners
; Set it to 0 for system maximum
; Defaults to 5 if missing or invalid
;backlog=5
; context: string: SSL context if this is an encrypted connection
; Ignored for non TLS listeners, required for TLS listeners
;context=
; thread: keyword: Listener thread priority
; Can be one of: lowest, low, normal, high, highest
; High priorities need superuser privileges on POSIX operating systems
; Low priorities are not recommended except for debugging
;thread=normal

View File

@ -70,10 +70,12 @@ static TokenDict sip_responses[] = {
{ "Interval Too Brief", 423 },
{ "Use Identity Header", 428 },
{ "Provide Referrer Identity", 429 },
{ "Flow Failed", 430 }, // RFC5626
{ "Anonymity Disallowed", 433 },
{ "Bad Identity-Info", 436 },
{ "Unsupported Certificate", 437 },
{ "Invalid Identity Header", 438 },
{ "First Hop Lacks Outbound Support", 439 }, // RFC5626
{ "Consent Needed", 470 },
{ "Temporarily Unavailable", 480 },
{ "Call/Transaction Does Not Exist", 481 },
@ -108,14 +110,14 @@ static TokenDict sip_responses[] = {
TokenDict* TelEngine::SIPResponses = sip_responses;
SIPParty::SIPParty()
: m_reliable(false)
SIPParty::SIPParty(Mutex* mutex)
: m_mutex(mutex), m_reliable(false), m_localPort(0), m_partyPort(0)
{
DDebug(DebugAll,"SIPParty::SIPParty() [%p]",this);
}
SIPParty::SIPParty(bool reliable)
: m_reliable(reliable)
SIPParty::SIPParty(bool reliable, Mutex* mutex)
: m_mutex(mutex), m_reliable(reliable), m_localPort(0), m_partyPort(0)
{
DDebug(DebugAll,"SIPParty::SIPParty(%d) [%p]",reliable,this);
}
@ -125,6 +127,24 @@ SIPParty::~SIPParty()
DDebug(DebugAll,"SIPParty::~SIPParty() [%p]",this);
}
void SIPParty::setAddr(const String& addr, int port, bool local)
{
Lock lock(m_mutex);
String& a = local ? m_local : m_party;
int& p = local ? m_localPort : m_partyPort;
a = addr;
p = port;
DDebug(DebugAll,"SIPParty updated %s address '%s:%d' [%p]",
local ? "local" : "remote",a.c_str(),p,this);
}
void SIPParty::getAddr(String& addr, int& port, bool local)
{
Lock lock(m_mutex);
addr = local ? m_local : m_party;
port = local ? m_localPort : m_partyPort;
}
SIPEvent::SIPEvent(SIPMessage* message, SIPTransaction* transaction)
: m_message(message), m_transaction(transaction),
@ -290,7 +310,6 @@ void SIPEngine::processEvent(SIPEvent *event)
{
if (!event)
return;
Lock lock(this);
const char* type = "unknown";
if (event->isOutgoing())
type = "outgoing";

View File

@ -74,7 +74,7 @@ SIPMessage::SIPMessage(const char* _method, const char* _uri, const char* _versi
_method,_uri,_version,this);
}
SIPMessage::SIPMessage(SIPParty* ep, const char* buf, int len)
SIPMessage::SIPMessage(SIPParty* ep, const char* buf, int len, unsigned int* bodyLen)
: code(0), body(0), m_ep(ep), m_valid(false),
m_answer(false), m_outgoing(false), m_ack(false), m_cseq(-1), m_flags(-1)
{
@ -88,7 +88,7 @@ SIPMessage::SIPMessage(SIPParty* ep, const char* buf, int len)
}
if (len < 0)
len = ::strlen(buf);
m_valid = parse(buf,len);
m_valid = parse(buf,len,bodyLen);
}
SIPMessage::SIPMessage(const SIPMessage* message, int _code, const char* _reason)
@ -138,7 +138,10 @@ SIPMessage::SIPMessage(const SIPMessage* original, const SIPMessage* answer)
if (!hl) {
String tmp;
tmp << version << "/" << getParty()->getProtoName();
tmp << " " << getParty()->getLocalAddr() << ":" << getParty()->getLocalPort();
if (getParty()) {
Lock lock(getParty()->mutex());
tmp << " " << getParty()->getLocalAddr() << ":" << getParty()->getLocalPort();
}
hl = new MimeHeaderLine("Via",tmp);
header.append(hl);
}
@ -210,6 +213,9 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai
return;
}
}
String partyLAddr;
int partyLPort = 0;
getParty()->getAddr(partyLAddr,partyLPort,true);
// only set the dialog tag on ACK
if (isACK()) {
@ -220,14 +226,16 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai
}
if (!domain)
domain = getParty()->getLocalAddr();
domain = partyLAddr;
MimeHeaderLine* hl = const_cast<MimeHeaderLine*>(getHeader("Via"));
if (!hl) {
String tmp;
tmp << version << "/" << getParty()->getProtoName();
tmp << " " << getParty()->getLocalAddr() << ":" << getParty()->getLocalPort();
tmp << " " << partyLAddr << ":" << partyLPort;
hl = new MimeHeaderLine("Via",tmp);
if (isReliable() && 0 == (flags & NoConnReuse))
hl->setParam("alias");
if (!((flags & (NotReqRport|RportAfterBranch)) || isAnswer() || isACK()))
hl->setParam("rport");
header.append(hl);
@ -238,8 +246,10 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai
hl->setParam("branch",tmp);
}
if (isAnswer()) {
if (!(flags & NotSetReceived))
if (!(flags & NotSetReceived)) {
Lock lock(getParty()->mutex());
hl->setParam("received",getParty()->getPartyAddr());
}
const String* rport = hl->getParam("rport");
if (rport && rport->null() && !(flags & NotSetRport))
const_cast<String&>(*rport) = getParty()->getPartyPort();
@ -308,9 +318,9 @@ void SIPMessage::complete(SIPEngine* engine, const char* user, const char* domai
}
if (tmp)
tmp = tmp.uriEscape('@',"+?&") + "@";
tmp = "<sip:" + tmp;
tmp << getParty()->getLocalAddr() << ":";
tmp << getParty()->getLocalPort() << ">";
tmp = "<sip:" + tmp;
tmp << partyLAddr << ":";
tmp << partyLPort << ">";
addHeader("Contact",tmp);
}
@ -380,7 +390,7 @@ bool SIPMessage::parseFirst(String& line)
return true;
}
bool SIPMessage::parse(const char* buf, int len)
bool SIPMessage::parse(const char* buf, int len, unsigned int* bodyLen)
{
DDebug(DebugAll,"SIPMessage::parse(%p,%d) [%p]",buf,len,this);
String* line = 0;
@ -442,14 +452,42 @@ bool SIPMessage::parse(const char* buf, int len)
}
line->destruct();
}
if (clen >= 0) {
if (clen > len)
Debug("SIPMessage",DebugMild,"Content length is %d but only %d in buffer",clen,len);
else if (clen < len) {
DDebug("SIPMessage",DebugInfo,"Got %d garbage bytes after content",len - clen);
len = clen;
if (!bodyLen) {
if (clen >= 0) {
if (clen > len)
Debug("SIPMessage",DebugMild,"Content length is %d but only %d in buffer",clen,len);
else if (clen < len) {
DDebug("SIPMessage",DebugInfo,"Got %d garbage bytes after content",len - clen);
len = clen;
}
}
buildBody(buf,len);
}
else
*bodyLen = (clen >= 0) ? clen : 0;
DDebug(DebugAll,"SIPMessage::parse %d header lines, body %p",
header.count(),body);
return true;
}
SIPMessage* SIPMessage::fromParsing(SIPParty* ep, const char* buf, int len, unsigned int* bodyLen)
{
SIPMessage* msg = new SIPMessage(ep,buf,len,bodyLen);
if (msg->isValid())
return msg;
DDebug("SIPMessage",DebugInfo,"Invalid message");
msg->destruct();
return 0;
}
// Build message's body. Reset it before
void SIPMessage::buildBody(const char* buf, int len)
{
TelEngine::destruct(body);
if (!buf)
return;
if (len < 0)
len = ::strlen(buf);
const MimeHeaderLine* cType = getHeader("Content-Type");
if (cType)
body = MimeBody::build(buf,len,*cType);
@ -467,19 +505,8 @@ bool SIPMessage::parse(const char* buf, int len)
body->appendHdr(line);
}
}
DDebug(DebugAll,"SIPMessage::parse %d header lines, body %p",
DDebug(DebugAll,"SIPMessage::buildBody %d header lines, body %p",
header.count(),body);
return true;
}
SIPMessage* SIPMessage::fromParsing(SIPParty* ep, const char* buf, int len)
{
SIPMessage* msg = new SIPMessage(ep,buf,len);
if (msg->isValid())
return msg;
DDebug("SIPMessage",DebugInfo,"Invalid message");
msg->destruct();
return 0;
}
const MimeHeaderLine* SIPMessage::getHeader(const char* name) const
@ -612,11 +639,12 @@ void SIPMessage::setParty(SIPParty* ep)
{
if (ep == m_ep)
return;
if (m_ep)
m_ep->deref();
if (ep && !ep->ref())
ep = 0;
XDebug(DebugAll,"SIPMessage::setParty(%p) current=%p [%p]",ep,m_ep,this);
SIPParty* tmp = m_ep;
m_ep = ep;
if (m_ep)
m_ep->ref();
TelEngine::destruct(tmp);
}
MimeAuthLine* SIPMessage::buildAuth(const String& username, const String& password,

View File

@ -577,8 +577,13 @@ SIPEvent* SIPTransaction::getClientEvent(int state, int timeout)
switch (state) {
case Initial:
e = new SIPEvent(m_firstMessage,this);
if (changeState(Trying))
setTimeout(m_engine->getTimer(isInvite() ? 'A' : 'E'),5);
if (changeState(Trying)) {
bool reliable = e->getParty() && e->getParty()->isReliable();
if (!reliable)
setTimeout(m_engine->getTimer(isInvite() ? 'A' : 'E'),5);
else
setTimeout(m_engine->getTimer(isInvite() ? 'B' : 'F',true),1);
}
break;
case Trying:
if (timeout < 0)

View File

@ -59,12 +59,17 @@ class SIPEvent;
class YSIP_API SIPParty : public RefObject
{
public:
SIPParty();
SIPParty(bool reliable);
SIPParty(Mutex* mutex = 0);
SIPParty(bool reliable, Mutex* mutex = 0);
virtual ~SIPParty();
virtual void transmit(SIPEvent* event) = 0;
virtual const char* getProtoName() const = 0;
virtual bool setParty(const URI& uri) = 0;
virtual void* getTransport() = 0;
void setAddr(const String& addr, int port, bool local);
void getAddr(String& addr, int& port, bool local);
inline Mutex* mutex()
{ return m_mutex; }
inline const String& getLocalAddr() const
{ return m_local; }
inline const String& getPartyAddr() const
@ -76,8 +81,8 @@ public:
inline bool isReliable() const
{ return m_reliable; }
protected:
Mutex* m_mutex;
bool m_reliable;
bool m_init;
String m_local;
String m_party;
int m_localPort;
@ -104,6 +109,7 @@ public:
RportAfterBranch = 0x0008,
NotSetRport = 0x0010,
NotSetReceived = 0x0020,
NoConnReuse = 0x0040, // Don't add 'alias' parameter to Via header (reliable only)
};
/**
@ -118,8 +124,14 @@ public:
/**
* Creates a new SIPMessage from parsing a text buffer.
* @param ep Party to set in message
* @param buf Buffer to parse
* @param len Optional buffer length
* @param bodyLen Pointer to body length to be set if the message was received
* on a stream transport. If not 0 the buffer must contain the message
* without its body
*/
SIPMessage(SIPParty* ep, const char* buf, int len = -1);
SIPMessage(SIPParty* ep, const char* buf, int len = -1, unsigned int* bodyLen = 0);
/**
* Creates a new SIPMessage as answer to another message.
@ -138,9 +150,24 @@ public:
/**
* Construct a new SIP message by parsing a text buffer
* @param ep Party to set in message
* @param buf Buffer to parse
* @param len Optional buffer length
* @param bodyLen Pointer to body length to be set if the message was received
* on a stream transport. If not 0 the buffer must contain the message
* without its body
* @return A pointer to a valid new message or NULL
*/
static SIPMessage* fromParsing(SIPParty* ep, const char* buf, int len = -1);
static SIPMessage* fromParsing(SIPParty* ep, const char* buf, int len = -1,
unsigned int* bodyLen = 0);
/**
* Build message's body. Reset it before.
* This method should be called after parsing a partial message (headers only)
* @param buf Buffer to parse
* @param len Optional buffer length
*/
void buildBody(const char* buf, int len = -1);
/**
* Complete missing fields with defaults taken from a SIP engine
@ -411,7 +438,7 @@ public:
MimeBody* body;
protected:
bool parse(const char* buf, int len);
bool parse(const char* buf, int len, unsigned int* bodyLen);
bool parseFirst(String& line);
SIPParty* m_ep;
bool m_valid;
@ -759,6 +786,12 @@ public:
inline void setTransmit()
{ m_transmit = true; }
/**
* Change transaction status to Cleared
* This method is not thread safe
*/
inline void setCleared()
{ changeState(Cleared); }
/**
* Send back an authentication required response

File diff suppressed because it is too large Load Diff