From 904f78828de920dbf1540b45a105bcd23480233a Mon Sep 17 00:00:00 2001 From: Alexandre Savard <alexandre.savard@savoirfairelinux.com> Date: Tue, 24 Apr 2012 10:23:50 -0400 Subject: [PATCH] #9910: create new udp transport to fix registration failure with 606 error & received parameter --- daemon/src/sip/sipaccount.h | 4 +++ daemon/src/sip/siptransport.cpp | 51 +++++++++++++++++++++++++++++++++ daemon/src/sip/siptransport.h | 16 +++++++++++ daemon/src/sip/sipvoiplink.cpp | 23 +++++++++++---- 4 files changed, 89 insertions(+), 5 deletions(-) diff --git a/daemon/src/sip/sipaccount.h b/daemon/src/sip/sipaccount.h index 82ac7d9e87..007c4cab15 100644 --- a/daemon/src/sip/sipaccount.h +++ b/daemon/src/sip/sipaccount.h @@ -511,7 +511,11 @@ class SIPAccount : public Account { */ static void keepAliveRegistrationCb(pj_timer_heap_t *th, pj_timer_entry *te); + /** + * Pointer to the transport used by this acccount + */ pjsip_transport* transport_; + private: NON_COPYABLE(SIPAccount); diff --git a/daemon/src/sip/siptransport.cpp b/daemon/src/sip/siptransport.cpp index 74385255c2..e1f10dadcd 100644 --- a/daemon/src/sip/siptransport.cpp +++ b/daemon/src/sip/siptransport.cpp @@ -54,6 +54,7 @@ #include "sipaccount.h" +#include "pjsip/sip_types.h" #include "dbus/dbusmanager.h" #include "dbus/configurationmanager.h" @@ -428,6 +429,9 @@ SipTransport::createUdpTransport(const std::string &interface, unsigned int port pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &udpString, &boundAddr); pj_status_t status; pjsip_transport *transport = NULL; + + + if (boundAddr.addr.sa_family == pj_AF_INET()) { status = pjsip_udp_transport_start(endpt_, &boundAddr.ipv4, NULL, 1, &transport); if (status != PJ_SUCCESS) { @@ -448,6 +452,53 @@ SipTransport::createUdpTransport(const std::string &interface, unsigned int port return transport; } +pjsip_transport * +SipTransport::createUdpTransport(const std::string &interface, unsigned int port, std::string& publicAddr, unsigned int publicPort) +{ + // init socket to bind this transport to + pj_uint16_t listeningPort = (pj_uint16_t) port; + pjsip_transport *transport; + + DEBUG("SipTransport: Update UDP transport on %s:%d with public addr %s:%d", interface.c_str(), port, publicAddr.c_str(), publicPort); + + // determine the ip address for this transport + std::string listeningAddress; + if (interface == DEFAULT_INTERFACE) + listeningAddress = getSIPLocalIP(); + else + listeningAddress = getInterfaceAddrFromName(interface); + + if (listeningAddress.empty()) { + ERROR("SipTransport: Could not determine ip address for this transport"); + return NULL; + } + + std::ostringstream fullAddress; + fullAddress << listeningAddress << ":" << listeningPort; + pj_str_t udpString; + std::string fullAddressStr(fullAddress.str()); + pj_cstr(&udpString, fullAddressStr.c_str()); + pj_sockaddr boundAddr; + pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &udpString, &boundAddr); + + pj_str_t public_addr = pj_str((char *) publicAddr.c_str()); + pjsip_host_port hostPort; + hostPort.host = public_addr; + hostPort.port = publicPort; + + pj_status_t status; + // status = pjsip_udp_transport_restart(transport, PJSIP_UDP_TRANSPORT_DESTROY_SOCKET, PJ_INVALID_SOCKET, &boundAddr.ipv4, &hostPort); + status = pjsip_udp_transport_start(endpt_, &boundAddr.ipv4, &hostPort, 1, &transport); + if (status != PJ_SUCCESS) { + ERROR("SipTransport: Could not start new transport with address %s:%d, error code %d", publicAddr.c_str(), publicPort, status); + } + + // dump debug information to stdout + pjsip_tpmgr_dump_transports(pjsip_endpt_get_tpmgr(endpt_)); + + return transport; +} + pjsip_tpselector *SipTransport::initTransportSelector(pjsip_transport *transport, pj_pool_t *tp_pool) const { if (!transport) { diff --git a/daemon/src/sip/siptransport.h b/daemon/src/sip/siptransport.h index cbbad8c7ec..3d5537e7df 100644 --- a/daemon/src/sip/siptransport.h +++ b/daemon/src/sip/siptransport.h @@ -101,6 +101,10 @@ class SipTransport { */ void createSipTransport(SIPAccount &account); + /** + * Create the default sip transport on 5060. In case this port is already used + * increme + */ void createDefaultSipUdpTransport(); /** @@ -126,6 +130,18 @@ class SipTransport { */ void findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, std::string &address, std::string &port) const; + /** + * Create a new udp transport specifying the bound address AND the published address. + * The published address is the address to appears in the sip VIA header. This is used + * essentially when the client is behind a trafic routing device. + * + * @param The interface to bind this transport with + * @param The requested udp port number + * @param The public address for this transport + * @param The public port for this transport + */ + pjsip_transport *createUdpTransport(const std::string &interface, unsigned int port, std::string& publicAddr, unsigned int publicPort); + private: NON_COPYABLE(SipTransport); diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp index 306c23f6e1..9dce39431a 100644 --- a/daemon/src/sip/sipvoiplink.cpp +++ b/daemon/src/sip/sipvoiplink.cpp @@ -489,6 +489,7 @@ bool SIPVoIPLink::getEvent() void SIPVoIPLink::sendRegister(Account *a) { SIPAccount *account = dynamic_cast<SIPAccount*>(a); + if (!account) throw VoipLinkException("SipVoipLink: Account is not SIPAccount"); sipTransport.createSipTransport(*account); @@ -511,12 +512,19 @@ void SIPVoIPLink::sendRegister(Account *a) std::string from(account->getFromUri()); pj_str_t pjFrom = pj_str((char*) from.c_str()); - // Get the contact header for this account - std::string contact(account->getContactHeader()); + // Get the received header + std::string received(account->getReceivedParameter()); + + // Get the contact header + std::string contact = account->getContactHeader(); pj_str_t pjContact = pj_str((char*) contact.c_str()); - std::string received(account->getReceivedParameter()); - pj_str_t pjReceived = pj_str((char *) received.c_str()); + if(!received.empty()) { + // Set received parameter string to empty in order to avoid creating new transport for each register + account->setReceivedParameter(""); + // Explicitely set the bound address port to 0 so that pjsip determine a random port by itself + account->transport_= sipTransport.createUdpTransport(account->getLocalInterface(), 0, received, account->getLocalPort()); + } if (pjsip_regc_init(regc, &pjSrv, &pjFrom, &pjFrom, 1, &pjContact, account->getRegistrationExpire()) != PJ_SUCCESS) throw VoipLinkException("Unable to initialize account registration structure"); @@ -536,7 +544,6 @@ void SIPVoIPLink::sendRegister(Account *a) pj_list_push_back(&hdr_list, (pjsip_hdr*) h); pjsip_regc_add_headers(regc, &hdr_list); - pjsip_tx_data *tdata; if (pjsip_regc_register(regc, PJ_TRUE, &tdata) != PJ_SUCCESS) @@ -1588,6 +1595,11 @@ void registration_cb(pjsip_regc_cbparam *param) return; } + if(param->code == 200) { + account->setRegister(true); + account->setRegistrationState(Registered); + } + if (account->isContactUpdateEnabled()) update_contact_header(param, account); @@ -1615,6 +1627,7 @@ void registration_cb(pjsip_regc_cbparam *param) case PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE: lookForReceivedParameter(param, account); account->setRegistrationState(ErrorNotAcceptable); + SIPVoIPLink::instance()->sendRegister(account); break; case PJSIP_SC_SERVICE_UNAVAILABLE: -- GitLab