siptransport.cpp 19.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
/*
 *  Copyright (C) [2004, 2012] Savoir-Faire Linux Inc.
 *
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
 */

#include <map>

#include <pjsip.h>
#include <pjlib.h>
#include <pjsip_ua.h>
#include <pjlib-util.h>
#include <pjnath.h>
#include <pjnath/stun_config.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
46
#include <arpa/inet.h>
47
#include <net/if.h>
48
#include <stdexcept>
49
#include <sstream>
50

51
#include "logger.h"
52 53 54 55 56
#include "siptransport.h"
#include "manager.h"

#include "sipaccount.h"

57
#include "pjsip/sip_types.h"
58
#if HAVE_TLS
59
#include "pjsip/sip_transport_tls.h"
60
#endif
61

62 63 64
#include "dbus/dbusmanager.h"
#include "dbus/configurationmanager.h"

65
static const char * const DEFAULT_INTERFACE = "default";
66
static const char * const ANY_HOSTS = "0.0.0.0";
67

68 69
#define RETURN_IF_FAIL(A, VAL, M, ...) if (!(A)) { ERROR(M, ##__VA_ARGS__); return (VAL); }

70 71 72 73
std::string SipTransport::getSIPLocalIP()
{
    pj_sockaddr ip_addr;

74 75 76
    const pj_status_t status = pj_gethostip(pj_AF_INET(), &ip_addr);
    RETURN_IF_FAIL(status == PJ_SUCCESS, "", "Could not get local IP");
    return pj_inet_ntoa(ip_addr.ipv4.sin_addr);
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
}

std::vector<std::string> SipTransport::getAllIpInterfaceByName()
{
    static ifreq ifreqs[20];
    ifconf ifconf;

    std::vector<std::string> ifaceList;
    ifaceList.push_back("default");

    ifconf.ifc_buf = (char*) (ifreqs);
    ifconf.ifc_len = sizeof(ifreqs);

    int sock = socket(AF_INET,SOCK_STREAM,0);

    if (sock >= 0) {
        if (ioctl(sock, SIOCGIFCONF, &ifconf) >= 0)
            for (unsigned i = 0; i < ifconf.ifc_len / sizeof(ifreq); ++i)
                ifaceList.push_back(std::string(ifreqs[i].ifr_name));

        close(sock);
    }

    return ifaceList;
}

std::string SipTransport::getInterfaceAddrFromName(const std::string &ifaceName)
{
105 106 107
    if (ifaceName == DEFAULT_INTERFACE)
        return getSIPLocalIP();

108
    int fd = socket(AF_INET, SOCK_DGRAM,0);
109
    RETURN_IF_FAIL(fd >= 0, "", "Could not open socket: %m");
110 111 112 113 114 115 116 117 118 119

    ifreq ifr;
    strcpy(ifr.ifr_name, ifaceName.c_str());
    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
    ifr.ifr_addr.sa_family = AF_INET;

    ioctl(fd, SIOCGIFADDR, &ifr);
    close(fd);

    sockaddr_in *saddr_in = (sockaddr_in *) &ifr.ifr_addr;
120 121 122 123
    std::string result(inet_ntoa(saddr_in->sin_addr));
    if (result == ANY_HOSTS)
        result = getSIPLocalIP();
    return result;
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
}

std::vector<std::string> SipTransport::getAllIpInterface()
{
    pj_sockaddr addrList[16];
    unsigned addrCnt = PJ_ARRAY_SIZE(addrList);

    std::vector<std::string> ifaceList;

    if (pj_enum_ip_interface(pj_AF_INET(), &addrCnt, addrList) == PJ_SUCCESS) {
        for (unsigned i = 0; i < addrCnt; i++) {
            char addr[PJ_INET_ADDRSTRLEN];
            pj_sockaddr_print(&addrList[i], addr, sizeof(addr), 0);
            ifaceList.push_back(std::string(addr));
        }
    }

    return ifaceList;
}

SipTransport::SipTransport(pjsip_endpoint *endpt, pj_caching_pool *cp, pj_pool_t *pool) : transportMap_(), stunSocketMap_(), cp_(cp), pool_(pool), endpt_(endpt)
145
{}
146 147 148 149 150 151 152

pj_bool_t
stun_sock_on_status_cb(pj_stun_sock * /*stun_sock*/, pj_stun_sock_op op,
                       pj_status_t status)
{
    switch (op) {
        case PJ_STUN_SOCK_DNS_OP:
Tristan Matthews's avatar
Tristan Matthews committed
153
            DEBUG("STUN operation dns resolution");
154 155
            break;
        case PJ_STUN_SOCK_BINDING_OP:
Tristan Matthews's avatar
Tristan Matthews committed
156
            DEBUG("STUN operation binding");
157 158
            break;
        case PJ_STUN_SOCK_KEEP_ALIVE_OP:
Tristan Matthews's avatar
Tristan Matthews committed
159
            DEBUG("STUN operation keep alive");
160 161
            break;
        case PJ_STUN_SOCK_MAPPED_ADDR_CHANGE:
Tristan Matthews's avatar
Tristan Matthews committed
162
            DEBUG("STUN operation address mapping change");
163 164
            break;
        default:
Tristan Matthews's avatar
Tristan Matthews committed
165
            DEBUG("STUN unknown operation");
166 167 168
            break;
    }

169
    if (status == PJ_SUCCESS)
Tristan Matthews's avatar
Tristan Matthews committed
170
        DEBUG("STUN operation success");
171
    else
Tristan Matthews's avatar
Tristan Matthews committed
172
        ERROR("STUN operation failure");
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

    // Always return true so the stun transport registration retry even on failure
    return true;
}

static pj_bool_t
stun_sock_on_rx_data_cb(pj_stun_sock * /*stun_sock*/, void * /*pkt*/,
                        unsigned /*pkt_len*/,
                        const pj_sockaddr_t * /*src_addr*/,
                        unsigned /*addr_len*/)
{
    return PJ_TRUE;
}


pj_status_t SipTransport::createStunResolver(pj_str_t serverName, pj_uint16_t port)
{
190 191
    std::string stunResolverName(serverName.ptr, serverName.slen);
    if (stunSocketMap_.find(stunResolverName) != stunSocketMap_.end()) {
Tristan Matthews's avatar
Tristan Matthews committed
192
        DEBUG("%s already added", stunResolverName.c_str());
193 194
        return PJ_SUCCESS;
    }
195

196 197 198
    pj_stun_config stunCfg;
    pj_stun_config_init(&stunCfg, &cp_->factory, 0,
            pjsip_endpt_get_ioqueue(endpt_), pjsip_endpt_get_timer_heap(endpt_));
199 200 201 202 203 204 205

    static const pj_stun_sock_cb stun_sock_cb = {
        stun_sock_on_rx_data_cb,
        NULL,
        stun_sock_on_status_cb
    };

206 207 208 209
    pj_stun_sock *stun_sock = NULL;
    pj_status_t status = pj_stun_sock_create(&stunCfg,
            stunResolverName.c_str(), pj_AF_INET(), &stun_sock_cb, NULL, NULL,
            &stun_sock);
210 211 212 213

    if (status != PJ_SUCCESS) {
        char errmsg[PJ_ERR_MSG_SIZE];
        pj_strerror(status, errmsg, sizeof(errmsg));
Tristan Matthews's avatar
Tristan Matthews committed
214 215
        ERROR("Failed to create STUN socket for %.*s: %s",
              (int) serverName.slen, serverName.ptr, errmsg);
216 217 218 219 220
        return status;
    }

    status = pj_stun_sock_start(stun_sock, &serverName, port, NULL);

221 222
    // store socket inside list
    if (status == PJ_SUCCESS) {
Tristan Matthews's avatar
Tristan Matthews committed
223
        DEBUG("Adding %s resolver", stunResolverName.c_str());
224 225
        stunSocketMap_[stunResolverName] = stun_sock;
    } else {
226 227
        char errmsg[PJ_ERR_MSG_SIZE];
        pj_strerror(status, errmsg, sizeof(errmsg));
Tristan Matthews's avatar
Tristan Matthews committed
228
        DEBUG("Error starting STUN socket for %.*s: %s",
229
              (int) serverName.slen, serverName.ptr, errmsg);
230 231 232 233 234 235
        pj_stun_sock_destroy(stun_sock);
    }

    return status;
}

236
pj_status_t SipTransport::destroyStunResolver(const std::string &serverName)
237 238 239 240 241 242 243
{
    std::map<std::string, pj_stun_sock *>::iterator it;
    it = stunSocketMap_.find(serverName);

    DEBUG("***************** Destroy Stun Resolver *********************");

    if (it != stunSocketMap_.end()) {
Tristan Matthews's avatar
Tristan Matthews committed
244
        DEBUG("Deleting STUN resolver %s", it->first.c_str());
245 246
        if (it->second)
            pj_stun_sock_destroy(it->second);
247 248 249 250 251 252
        stunSocketMap_.erase(it);
    }

    return PJ_SUCCESS;
}

253
#if HAVE_TLS
254
pjsip_tpfactory* SipTransport::createTlsListener(SIPAccount &account)
255 256 257
{
    pj_sockaddr_in local_addr;
    pj_sockaddr_in_init(&local_addr, 0, 0);
258
    local_addr.sin_port = pj_htons(account.getTlsListenerPort());
259

260
    RETURN_IF_FAIL(account.getTlsSetting() != NULL, NULL, "TLS settings not specified");
261

262
    std::string interface(account.getLocalInterface());
263 264 265 266 267 268
    std::string listeningAddress;
    if (interface == DEFAULT_INTERFACE)
        listeningAddress = getSIPLocalIP();
    else
        listeningAddress = getInterfaceAddrFromName(interface);

269
    if (listeningAddress.empty())
Tristan Matthews's avatar
Tristan Matthews committed
270
        ERROR("Could not determine IP address for this transport");
271

272
    pj_str_t pjAddress;
273
    pj_cstr(&pjAddress, listeningAddress.c_str());
274
    pj_sockaddr_in_set_str_addr(&local_addr, &pjAddress);
275
    pj_sockaddr_in_set_port(&local_addr, account.getTlsListenerPort());
276

277
    pjsip_tpfactory *listener = NULL;
278 279
    const pj_status_t status = pjsip_tls_transport_start(endpt_, account.getTlsSetting(), &local_addr, NULL, 1, &listener);
    RETURN_IF_FAIL(status == PJ_SUCCESS, NULL, "Failed to start TLS listener");
280
    return listener;
281 282 283
}

pjsip_transport *
284
SipTransport::createTlsTransport(SIPAccount &account)
285
{
286 287 288 289 290
    std::string remoteSipUri(account.getServerUri());
    static const char SIPS_PREFIX[] = "<sips:";
    size_t sips = remoteSipUri.find(SIPS_PREFIX) + (sizeof SIPS_PREFIX) - 1;
    size_t trns = remoteSipUri.find(";transport");
    std::string remoteAddr(remoteSipUri.substr(sips, trns-sips));
291 292 293 294 295
    std::string ipAddr = "";
    int port = DEFAULT_SIP_TLS_PORT;

    // parse c string
    size_t pos = remoteAddr.find(":");
296
    if (pos != std::string::npos) {
297
        ipAddr = remoteAddr.substr(0, pos);
298
        port = atoi(remoteAddr.substr(pos + 1, remoteAddr.length() - pos).c_str());
299
    } else
300
        ipAddr = remoteAddr;
301 302

    pj_str_t remote;
303
    pj_cstr(&remote, ipAddr.c_str());
304 305

    pj_sockaddr_in rem_addr;
306
    pj_sockaddr_in_init(&rem_addr, &remote, (pj_uint16_t) port);
307

308 309 310 311
    // The local tls listener
    static pjsip_tpfactory *localTlsListener = NULL;

    if (localTlsListener == NULL)
312
        localTlsListener = createTlsListener(account);
313

Tristan Matthews's avatar
Tristan Matthews committed
314
    DEBUG("Get new tls transport from transport manager");
315
    pjsip_transport *transport = NULL;
316 317
    pjsip_endpt_acquire_transport(endpt_, PJSIP_TRANSPORT_TLS, &rem_addr,
                                  sizeof rem_addr, NULL, &transport);
318
    RETURN_IF_FAIL(transport != NULL, NULL, "Could not create new TLS transport");
319 320
    return transport;
}
321
#endif
322

323 324 325 326 327 328 329 330 331
namespace {
std::string transportMapKey(const std::string &interface, int port)
{
    std::ostringstream os;
    os << interface << ":" << port;
    return os.str();
}
}

332
void SipTransport::createSipTransport(SIPAccount &account)
333 334 335
{
    shutdownSipTransport(account);

336
#if HAVE_TLS
337 338 339
    if (account.isTlsEnabled()) {
        account.transport_ = createTlsTransport(account);
    } else if (account.isStunEnabled()) {
340 341 342
#else
    if (account.isStunEnabled()) {
#endif
343 344
        account.transport_ = createStunTransport(account);
        if (account.transport_ == NULL) {
Tristan Matthews's avatar
Tristan Matthews committed
345
            WARN("falling back to UDP transport");
346 347 348
            account.transport_ = createUdpTransport(account.getLocalInterface(), account.getLocalPort());
        }
    } else {
349
        // if this transport already exists, reuse it
350 351
        std::string key(transportMapKey(account.getLocalInterface(), account.getLocalPort()));
        std::map<std::string, pjsip_transport *>::iterator iter = transportMap_.find(key);
352

353 354
        if (iter != transportMap_.end()) {
            account.transport_ = iter->second;
355
            pjsip_transport_add_ref(account.transport_);
356 357 358 359 360
        } else
            account.transport_ = createUdpTransport(account.getLocalInterface(), account.getLocalPort());
    }

    if (!account.transport_) {
361
#if HAVE_TLS
362
        if (account.isTlsEnabled())
363
            throw std::runtime_error("Could not create TLS connection");
364
        else
365
#endif
366
            throw std::runtime_error("Could not create new UDP transport");
367 368 369
    }
}

370 371
pjsip_transport *
SipTransport::createUdpTransport(const std::string &interface, unsigned int port)
372 373 374 375
{
    // init socket to bind this transport to
    pj_uint16_t listeningPort = (pj_uint16_t) port;

376
    // determine the IP address for this transport
377
    std::string listeningAddress;
378
    if (interface == DEFAULT_INTERFACE)
379
        listeningAddress = getSIPLocalIP();
380
    else
381 382
        listeningAddress = getInterfaceAddrFromName(interface);

383 384
    RETURN_IF_FAIL(not listeningAddress.empty(), NULL, "Could not determine ip address for this transport");
    RETURN_IF_FAIL(listeningPort != 0, NULL, "Could not determine port for this transport");
385

386 387
    std::ostringstream fullAddress;
    fullAddress << listeningAddress << ":" << listeningPort;
388
    pj_str_t udpString;
389 390
    std::string fullAddressStr(fullAddress.str());
    pj_cstr(&udpString, fullAddressStr.c_str());
391
    pj_sockaddr boundAddr;
392 393
    pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &udpString, &boundAddr);
    pj_status_t status;
394
    pjsip_transport *transport = NULL;
395

396 397
    if (boundAddr.addr.sa_family == pj_AF_INET()) {
        status = pjsip_udp_transport_start(endpt_, &boundAddr.ipv4, NULL, 1, &transport);
398
        RETURN_IF_FAIL(status == PJ_SUCCESS, NULL, "UDP IPV4 Transport did not start");
399 400
    } else if (boundAddr.addr.sa_family == pj_AF_INET6()) {
        status = pjsip_udp_transport_start6(endpt_, &boundAddr.ipv6, NULL, 1, &transport);
401
        RETURN_IF_FAIL(status == PJ_SUCCESS, NULL, "UDP IPV6 Transport did not start");
402 403
    }

404
    DEBUG("Created UDP transport on %s:%d", interface.c_str(), port);
Tristan Matthews's avatar
Tristan Matthews committed
405
    DEBUG("Listening address %s", fullAddressStr.c_str());
406 407
    // dump debug information to stdout
    pjsip_tpmgr_dump_transports(pjsip_endpt_get_tpmgr(endpt_));
408
    transportMap_[transportMapKey(interface, port)] = transport;
409 410 411 412

    return transport;
}

413
pjsip_transport *
414
SipTransport::createUdpTransport(const std::string &interface, unsigned int port, const std::string &publicAddr, unsigned int publicPort)
415 416 417
{
    // init socket to bind this transport to
    pj_uint16_t listeningPort = (pj_uint16_t) port;
418
    pjsip_transport *transport = NULL;
419

Tristan Matthews's avatar
Tristan Matthews committed
420 421
    DEBUG("Update UDP transport on %s:%d with public addr %s:%d",
          interface.c_str(), port, publicAddr.c_str(), publicPort);
422 423

    // determine the ip address for this transport
424
    std::string listeningAddress(getInterfaceAddrFromName(interface));
425

426
    RETURN_IF_FAIL(not listeningAddress.empty(), NULL, "Could not determine ip address for this transport");
427 428 429 430 431 432 433 434 435 436 437 438 439 440

    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;

441
    pj_status_t status = pjsip_udp_transport_start(endpt_, &boundAddr.ipv4, &hostPort, 1, &transport);
442 443
    RETURN_IF_FAIL(status == PJ_SUCCESS, NULL,
            "Could not start new transport with address %s:%d, error code %d", publicAddr.c_str(), publicPort, status);
444 445 446 447 448 449 450

    // dump debug information to stdout
    pjsip_tpmgr_dump_transports(pjsip_endpt_get_tpmgr(endpt_));

    return transport;
}

451
pjsip_tpselector *SipTransport::createTransportSelector(pjsip_transport *transport, pj_pool_t *tp_pool) const
452
{
453
    RETURN_IF_FAIL(transport != NULL, NULL, "Transport is not initialized");
454 455 456 457 458 459
    pjsip_tpselector *tp = (pjsip_tpselector *) pj_pool_zalloc(tp_pool, sizeof(pjsip_tpselector));
    tp->type = PJSIP_TPSELECTOR_TRANSPORT;
    tp->u.transport = transport;
    return tp;
}

460
pjsip_transport *SipTransport::createStunTransport(SIPAccount &account)
461
{
462 463 464 465 466 467
#define RETURN_IF_STUN_FAIL(A, M, ...) \
    if (!(A)) { \
        ERROR(M, ##__VA_ARGS__); \
        Manager::instance().getDbusManager()->getConfigurationManager()->stunStatusFailure(account.getAccountID()); \
        return NULL; }

468 469
    pj_str_t serverName = account.getStunServerName();
    pj_uint16_t port = account.getStunPort();
470

Tristan Matthews's avatar
Tristan Matthews committed
471
    DEBUG("Create STUN transport  server name: %s, port: %d", serverName, port);
472
    RETURN_IF_STUN_FAIL(createStunResolver(serverName, port) == PJ_SUCCESS, "Can't resolve STUN server");
473 474 475 476 477

    pj_sock_t sock = PJ_INVALID_SOCKET;

    pj_sockaddr_in boundAddr;

478 479
    RETURN_IF_STUN_FAIL(pj_sockaddr_in_init(&boundAddr, &serverName, 0) == PJ_SUCCESS,
                        "Can't initialize IPv4 socket on %*s:%i", serverName.slen, serverName.ptr, port);
480

481 482
    RETURN_IF_STUN_FAIL(pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock) == PJ_SUCCESS,
                        "Can't create or bind socket");
483 484 485 486 487

    // Query the mapped IP address and port on the 'outside' of the NAT
    pj_sockaddr_in pub_addr;

    if (pjstun_get_mapped_addr(&cp_->factory, 1, &sock, &serverName, port, &serverName, port, &pub_addr) != PJ_SUCCESS) {
Tristan Matthews's avatar
Tristan Matthews committed
488
        ERROR("Can't contact STUN server");
489
        pj_sock_close(sock);
490
        Manager::instance().getDbusManager()->getConfigurationManager()->stunStatusFailure(account.getAccountID());
491 492 493 494 495 496 497 498
        return NULL;
    }

    pjsip_host_port a_name = {
        pj_str(pj_inet_ntoa(pub_addr.sin_addr)),
        pj_ntohs(pub_addr.sin_port)
    };

499
    pjsip_transport *transport;
500 501 502 503 504 505
    pjsip_udp_transport_attach2(endpt_, PJSIP_TRANSPORT_UDP, sock, &a_name, 1,
                                &transport);

    pjsip_tpmgr_dump_transports(pjsip_endpt_get_tpmgr(endpt_));

    return transport;
506
#undef RETURN_IF_STUN_FAIL
507 508
}

509
void SipTransport::shutdownSipTransport(SIPAccount &account)
510
{
511 512
    if (account.isStunEnabled()) {
        pj_str_t stunServerName = account.getStunServerName();
513 514 515 516
        std::string server(stunServerName.ptr, stunServerName.slen);
        destroyStunResolver(server);
    }

517 518 519
    if (account.transport_) {
        pjsip_transport_dec_ref(account.transport_);
        account.transport_ = NULL;
520 521 522 523 524
    }
}

void SipTransport::findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, std::string &addr, std::string &port) const
{
525 526
#define RETURN_IF_NULL(A, M, ...) if ((A) == NULL) { ERROR(M, ##__VA_ARGS__); return; }

527 528 529 530 531 532 533 534 535 536
    // Initialize the sip port with the default SIP port
    std::stringstream ss;
    ss << DEFAULT_SIP_PORT;
    port = ss.str();

    // Initialize the sip address with the hostname
    const pj_str_t *pjMachineName = pj_gethostname();
    addr = std::string(pjMachineName->ptr, pjMachineName->slen);

    // Update address and port with active transport
537
    RETURN_IF_NULL(transport, "Transport is NULL in findLocalAddress, using local address %s:%s", addr.c_str(), port.c_str());
538 539 540

    // get the transport manager associated with the SIP enpoint
    pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt_);
541
    RETURN_IF_NULL(tpmgr, "Transport manager is NULL in findLocalAddress, using local address %s:%s", addr.c_str(), port.c_str());
542 543 544 545

    // initialize a transport selector
    // TODO Need to determine why we exclude TLS here...
    // if (transportType == PJSIP_TRANSPORT_UDP and transport_)
546
    pjsip_tpselector *tp_sel = createTransportSelector(transport, pool_);
547
    RETURN_IF_NULL(tp_sel, "Could not initialize transport selector, using local address %s:%s", addr.c_str(), port.c_str());
548 549 550 551 552 553 554 555 556 557 558 559 560 561

    pj_str_t localAddress = {0,0};
    int i_port = 0;

    // 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("SipTransport: Could not retrieve 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()
562
    if (addr == ANY_HOSTS)
563 564 565 566 567 568
        addr = getSIPLocalIP();

    // Determine the local port based on transport information
    ss.str("");
    ss << i_port;
    port = ss.str();
569 570

#undef RETURN_IF_FAIL
571
}