#3674: refactor contact header generation, add update contact header in registration_cb

This commit is contained in:
Alexandre Savard
2012-01-24 18:28:26 -05:00
parent 82a7100b5b
commit 203abebdaa
4 changed files with 256 additions and 75 deletions

View File

@ -56,6 +56,7 @@ SIPAccount::SIPAccount(const std::string& accountID)
, transportType_(PJSIP_TRANSPORT_UNSPECIFIED)
, cred_(NULL)
, tlsSetting_()
, contactHeader_()
, stunServerName_()
, stunPort_(0)
, dtmfType_(OVERRTP)
@ -755,11 +756,20 @@ std::string SIPAccount::getServerUri() const
return "<" + scheme + hostname_ + transport + ">";
}
std::string SIPAccount::getContactHeader(const std::string& address, const std::string& port) const
std::string SIPAccount::getContactHeader() const
{
std::string scheme;
std::string transport;
// Use the CONTACT header provided by the registrar if any
if(!contactHeader_.empty())
return contactHeader_;
// Else we determine this infor based on transport information
std::string address, port;
SIPVoIPLink *siplink = dynamic_cast<SIPVoIPLink *>(link_);
siplink->findLocalAddressFromTransport(transport_, transportType_, address, port);
// UDP does not require the transport specification
if (transportType_ == PJSIP_TRANSPORT_TLS) {
scheme = "sips:";

View File

@ -117,15 +117,45 @@ class SIPAccount : public Account {
registrationStateDetailed_ = details;
}
/**
* Serialize internal state of this account for configuration
* @param YamlEmitter the configuration engine which generate the configuration file
*/
virtual void serialize(Conf::YamlEmitter *emitter);
/**
* Populate the internal state for this account based on info stored in the configuration file
* @param The configuration node for this account
*/
virtual void unserialize(Conf::MappingNode *map);
/**
* Set the internal state for this account, mainly used to manage account details from the client application.
* @param The map containing the account information.
*/
virtual void setAccountDetails(std::map<std::string, std::string> details);
/**
* Return an map containing the internal state of this account. Client application can use this method to manage
* account info.
* @return A map containing the account information.
*/
virtual std::map<std::string, std::string> getAccountDetails() const;
/**
* Return the information for the default IP to IP account
*/
std::map<std::string, std::string> getIp2IpDetails() const;
/**
* Return the TLS settings, mainly used to return security information to
* a client application
*/
std::map<std::string, std::string> getTlsSettings() const;
/**
* Manage the TLS settings from a client application
*/
void setTlsSettings(const std::map<std::string, std::string>& details);
/**
@ -189,7 +219,7 @@ class SIPAccount : public Account {
/**
* Set the expiration for this account as found in
* the "Expire" sip header or the Contact "expire" param.
* the "Expire" sip header or the CONTACT's "expire" param.
*/
void setRegistrationExpire(int expire) {
if(expire > 0)
@ -197,7 +227,7 @@ class SIPAccount : public Account {
}
/**
* Doubles the Expiration Interval of Contact Addresses.
* Doubles the Expiration Interval sepecified for registration.
*/
void doubleRegistrationExpire() {
registrationExpire_ *= 2;
@ -228,7 +258,6 @@ class SIPAccount : public Account {
* Get the registration stucture that is used
* for PJSIP in the registration process.
* Settings are loaded from configuration file.
* @param void
* @return pjsip_regc* A pointer to the registration structure
*/
pjsip_regc* getRegistrationInfo() {
@ -330,11 +359,20 @@ class SIPAccount : public Account {
std::string getServerUri() const;
/**
* Set the contact header
* @param port Optional port. Otherwise set to the port defined for that account.
* @param hostname Optional local address. Otherwise set to the hostname defined for that account.
*/
void setContactHeader(std::string& contact)
{
contactHeader_ = contact;
}
/**
* Get the contact header for
* @return pj_str_t The contact header based on account information
*/
std::string getContactHeader(const std::string& address, const std::string& port) const;
std::string getContactHeader(void) const;
/**
* Get the local interface name on which this account is bound.
@ -508,25 +546,60 @@ class SIPAccount : public Account {
*/
pj_uint16_t tlsListenerPort_;
/**
* Transport type used for this sip account. Currently supported types:
* PJSIP_TRANSPORT_UNSPECIFIED
* PJSIP_TRANSPORT_UDP
* PJSIP_TRANSPORT_TLS
*/
pjsip_transport_type_e transportType_;
//Credential information
/**
* Credential information stored for further registration.
*/
pjsip_cred_info *cred_;
// The TLS settings, if tls is chosen as
// a sip transport.
/**
* The TLS settings, used only if tls is chosen as a sip transport.
*/
pjsip_tls_setting tlsSetting_;
// The STUN server name, if applicable for internal use only
/**
* The CONTACT header used for registration as provided by the registrar, this value could differ
* from the host name in case the registrar is inside a subnetwork (such as a VPN).
* The header will be stored
*/
std::string contactHeader_;
/**
* The STUN server name (hostname)
*/
pj_str_t stunServerName_;
// The STUN server port, if applicable
/**
* The STUN server port
*/
pj_uint16_t stunPort_;
/**
* DTMF type used for this account SIPINFO or RTP
*/
DtmfType dtmfType_;
/**
* Determine if TLS is enabled for this account. TLS provides a secured channel for
* SIP signalization. It is independant than the media encription provided by SRTP or ZRTP.
*/
std::string tlsEnable_;
/**
* Specify the TLS port
*/
int tlsPort_;
/**
* Certificate autority file
*/
std::string tlsCaListFile_;
std::string tlsCertificateFile_;
std::string tlsPrivateKeyFile_;
@ -540,21 +613,56 @@ class SIPAccount : public Account {
std::string tlsNegotiationTimeoutSec_;
std::string tlsNegotiationTimeoutMsec_;
/**
* The stun server hostname (optional), used to provide the public IP address in case the softphone
* stay behind a NAT.
*/
std::string stunServer_;
/**
* Determine if STUN public address resolution is required to register this account. In this case a
* STUN server hostname must be specified.
*/
bool stunEnabled_;
/**
* Determine if SRTP is enabled for this account, SRTP and ZRTP are mutually exclusive
* This only determine if the media channel is secured. One could only enable TLS
* with no secured media channel.
*/
bool srtpEnabled_;
/**
* Specifies the type of key exchange usd for SRTP (sdes/zrtp)
*/
std::string srtpKeyExchange_;
/**
* Determine if the softphone should fallback on non secured media channel if SRTP negotiation fails.
* Make sure other SIP endpoints share the same behavior since it could result in encrypted data to be
* played through the audio device.
*/
bool srtpFallback_;
/**
* Determine if the SAS sould be displayed on client side. SAS is a 4-charcter string
* that end users should verbaly validate to ensure the channel is secured. Used especially
* to prevent man-in-the-middle attack.
*/
bool zrtpDisplaySas_;
/**
* Only display SAS 4-character string once at the begining of the call.
*/
bool zrtpDisplaySasOnce_;
bool zrtpHelloHash_;
bool zrtpNotSuppWarning_;
/*
* Details about the registration state.
* This is a protocol Code:Description pair.
*/
/**
* Details about the registration state.
* This is a protocol Code:Description pair.
*/
std::pair<int, std::string> registrationStateDetailed_;
/**
@ -563,10 +671,6 @@ class SIPAccount : public Account {
*/
pj_timer_entry keepAliveTimer_;
/**
* Delay coresponding to a registration interval
*/
// pj_time_val keepAliveDelay_;
};
#endif

View File

@ -296,14 +296,18 @@ void SIPVoIPLink::sendRegister(Account *a)
std::string srvUri(account->getServerUri());
std::string address, port;
findLocalAddressFromUri(srvUri, account->transport_, address, port);
// std::string address, port;
// findLocalAddressFromUri(srvUri, account->transport_, address, port);
pj_str_t pjSrv = pj_str((char*) srvUri.c_str());
// Generate the FROM header
std::string from(account->getFromUri());
pj_str_t pjFrom = pj_str((char*) from.c_str());
std::string contact(account->getContactHeader(address, port));
// Store the CONTACT header for future usage
// account->setContactHeader(address, port);
std::string contact(account->getContactHeader());
pj_str_t pjContact = pj_str((char*) contact.c_str());
pj_str_t pjSrv = pj_str((char*) srvUri.c_str());
if (pjsip_regc_init(regc, &pjSrv, &pjFrom, &pjFrom, 1, &pjContact, account->getRegistrationExpire()) != PJ_SUCCESS)
throw VoipLinkException("Unable to initialize account registration structure");
@ -803,16 +807,20 @@ SIPVoIPLink::SIPStartCall(SIPCall *call)
std::string toUri(call->getPeerNumber()); // expecting a fully well formed sip uri
std::string address, port;
findLocalAddressFromUri(toUri, account->transport_, address, port);
// std::string address, port;
// findLocalAddressFromUri(toUri, account->transport_, address, port);
std::string from(account->getFromUri());
pj_str_t pjFrom = pj_str((char*) from.c_str());
std::string contact(account->getContactHeader(address, port));
pj_str_t pjContact = pj_str((char*) contact.c_str());
pj_str_t pjTo = pj_str((char*) toUri.c_str());
pjsip_dialog *dialog;
// Create the from header
std::string from(account->getFromUri());
pj_str_t pjFrom = pj_str((char*) from.c_str());
// Get the contact header
std::string contact(account->getContactHeader());
pj_str_t pjContact = pj_str((char*) contact.c_str());
pjsip_dialog *dialog = NULL;
if (pjsip_dlg_create_uac(pjsip_ua_instance(), &pjFrom, &pjContact, &pjTo, NULL, &dialog) != PJ_SUCCESS)
return false;
@ -1130,7 +1138,7 @@ void SIPVoIPLink::createUdpTransport(SIPAccount *account)
transportMap_[account->getLocalPort()] = account->transport_;
}
pjsip_tpselector *SIPVoIPLink::initTransportSelector(pjsip_transport *transport, pj_pool_t *tp_pool)
pjsip_tpselector *SIPVoIPLink::initTransportSelector(pjsip_transport *transport, pj_pool_t *tp_pool) const
{
assert(transport);
pjsip_tpselector *tp = (pjsip_tpselector *) pj_pool_zalloc(tp_pool, sizeof(pjsip_tpselector));
@ -1199,67 +1207,62 @@ void SIPVoIPLink::shutdownSipTransport(SIPAccount *account)
}
}
void SIPVoIPLink::findLocalAddressFromUri(const std::string& uri, pjsip_transport *transport, std::string& addr, std::string &port)
void SIPVoIPLink::findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, std::string &addr, std::string &port) const
{
// Initialize the sip port with the default SIP port
std::stringstream ss;
ss << DEFAULT_SIP_PORT;
port = ss.str();
pjsip_uri *genericUri = pjsip_parse_uri(pool_, (char*)uri.data(), uri.size(), 0);
// Initialize the sip address with the hostname
const pj_str_t *pjMachineName = pj_gethostname();
addr = std::string(pjMachineName->ptr, pjMachineName->slen);
if (genericUri == NULL)
// Update address and port with active transport
if(!transport) {
ERROR("SIPVoIPLink: Transport is NULL in findLocalAddress, using local address %s:%s", addr.c_str(), port.c_str());
return;
pjsip_sip_uri *sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(genericUri);
if (sip_uri == NULL)
return;
pjsip_transport_type_e transportType;
if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
transportType = PJSIP_TRANSPORT_TLS;
ss.str("");
ss << DEFAULT_SIP_TLS_PORT;
port = ss.str();
} else {
if (transport == NULL)
transport = localUDPTransport_;
transportType = PJSIP_TRANSPORT_UDP;
}
// get the transport manager associated with the SIP enpoint
pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt_);
if (!tpmgr)
if (!tpmgr) {
ERROR("SIPVoIPLink: Transport manager is NULL in findLocalAddress, using local address %s:%s", addr.c_str(), port.c_str());
return;
}
pjsip_tpselector *tp_sel = NULL;
if (transportType == PJSIP_TRANSPORT_UDP and transport)
tp_sel = initTransportSelector(transport, pool_);
// initialize a transport selector
// TODO Need to determine why we exclude TLS here...
// if (transportType == PJSIP_TRANSPORT_UDP and transport_)
pjsip_tpselector *tp_sel = initTransportSelector(transport, pool_);
if(!tp_sel) {
ERROR("SIPVoIPLink: Could not initialize transport selector, using local address %s:%s", addr.c_str(), port.c_str());
return;
}
pj_str_t localAddress = {0,0};
int i_port = 0;
if (pjsip_tpmgr_find_local_addr(tpmgr, pool_, transportType, tp_sel, &localAddress, &i_port) != PJ_SUCCESS)
// Find the local address and port for this transport
if (pjsip_tpmgr_find_local_addr(tpmgr, pool_, transportType, tp_sel, &localAddress, &i_port) != PJ_SUCCESS) {
WARN("SIPVoIPLink: Could not retreive local address and port from transport, using %s:%s", addr.c_str(), port.c_str());
return;
}
// Update local address based on the transport type
addr = std::string(localAddress.ptr, localAddress.slen);
// Fallback on local ip provided by pj_gethostip()
if (addr == "0.0.0.0")
addr = getSIPLocalIP();
// Determine the local port based on transport information
ss.str("");
ss << i_port;
port = ss.str();
}
namespace {
std::string parseDisplayName(const char * buffer)
{
@ -1605,13 +1608,77 @@ void transaction_state_changed_cb(pjsip_inv_session *inv UNUSED, pjsip_transacti
}
}
static void update_contact_header(struct pjsip_regc_cbparam *param, SIPAccount *account)
{
pj_pool_t *pool = NULL;
pjsip_contact_hdr *contact_hdr = NULL;
pjsip_sip_uri *uri = NULL;
std::string currentContactHeader = "";
// if(!account->updateContactAllowed())
// return;
pool = pj_pool_create(&cp_->factory, "tmp", 512, 512, NULL);
if(pool == NULL) {
ERROR("SIPVoIPLink: Could not create temporary memory pool in transport header");
return;
}
if(param->contact_cnt == 0) {
WARN("SIPVoIPLink: No contact header in registration callback");
pj_pool_release(pool);
return;
}
contact_hdr = param->contact[0];
uri = (pjsip_sip_uri*) contact_hdr->uri;
if(uri == NULL) {
ERROR("SIPVoIPLink: Could not find uri in contact header");
pj_pool_release(pool);
return;
}
uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri);
if (uri->port == 0) {
// TODO: make this base on transport type
uri->port = 5060; //pjsip_transport_get_default_port_for_type(tp_type);
}
std::string recvContactHost(uri->host.ptr, uri->host.slen);
std::stringstream ss;
ss << uri->port;
std::string recvContactPort = ss.str();
DEBUG("SIPVoIPLink: Current contact header %s:%s", recvContactHost.c_str(), recvContactPort.c_str());
currentContactHeader = account->getContactHeader();
DEBUG("SIPVoIPLink: Current contact header %s", currentContactHeader.c_str());
// DEBUG("Received contact header %s",
pj_pool_release(pool);
}
void registration_cb(struct pjsip_regc_cbparam *param)
{
SIPAccount *account = static_cast<SIPAccount *>(param->token);
if (account == NULL)
return;
ERROR("SipVoipLink: REGISTRATION CALLBACK");
if (account == NULL) {
ERROR("SipVoipLink: account does'nt exist in registration callback");
return;
}
if (param == NULL) {
ERROR("SipVoipLink: regsitration callback param is NULL");
return;
}
DEBUG("SipVoipLink: Contact header from UAS, %d contact(s)", param->contact_cnt);
update_contact_header(param, account);
const pj_str_t *description = pjsip_get_status_text(param->code);
if (param->code && description) {

View File

@ -260,7 +260,7 @@ class SIPVoIPLink : public VoIPLink {
*
* @return A pointer to the transport selector structure
*/
pjsip_tpselector *initTransportSelector(pjsip_transport *, pj_pool_t *);
pjsip_tpselector *initTransportSelector(pjsip_transport *, pj_pool_t *) const;
/**
* This function unset the transport for a given account.
@ -282,6 +282,16 @@ class SIPVoIPLink : public VoIPLink {
*/
void createDefaultSipUdpTransport();
/**
* Get the correct address to use (ie advertised) from
* a uri. The corresponding transport that should be used
* with that uri will be discovered.
*
* @param uri The uri from which we want to discover the address to use
* @param transport The transport to use to discover the address
*/
void findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, std::string &address, std::string &port) const;
private:
/**
* Start a SIP Call
@ -331,16 +341,6 @@ class SIPVoIPLink : public VoIPLink {
*/
void createStunTransport(SIPAccount *account);
/**
* Get the correct address to use (ie advertised) from
* a uri. The corresponding transport that should be used
* with that uri will be discovered.
*
* @param uri The uri from which we want to discover the address to use
* @param transport The transport to use to discover the address
*/
void findLocalAddressFromUri(const std::string& uri, pjsip_transport *transport, std::string &address, std::string &port);
/**
* UDP Transports are stored in this map in order to retreive them in case
* several accounts would share the same port number.