sipvoiplink.cpp 75.7 KB
Newer Older
jpbl's avatar
jpbl committed
1
/*
2
 *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
3
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
4
 *  Author: Yun Liu <yun.liu@savoirfairelinux.com>
5
 *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
6
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
7
 *
jpbl's avatar
jpbl committed
8 9
 *  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
10
 *  the Free Software Foundation; either version 3 of the License, or
jpbl's avatar
jpbl committed
11 12 13 14 15 16 17 18 19
 *  (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
20
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
21 22 23 24 25 26 27 28 29 30 31
 *
 *  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.
jpbl's avatar
jpbl committed
32
 */
Emmanuel Milou's avatar
Emmanuel Milou committed
33

34 35 36 37
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

38
#include "sip_utils.h"
39

jpbl's avatar
jpbl committed
40
#include "sipvoiplink.h"
Tristan Matthews's avatar
Tristan Matthews committed
41
#include "array_size.h"
42
#include "manager.h"
43
#include "map_utils.h"
44
#include "logger.h"
45
#include "scoped_lock.h"
46

47
#include "sip/sdp.h"
yanmorin's avatar
 
yanmorin committed
48
#include "sipcall.h"
49
#include "eventthread.h"
50
#if HAVE_SDES
51
#include "sdes_negotiator.h"
52
#endif
53
#include "array_size.h"
54

55

56
#if HAVE_INSTANT_MESSAGING
57
#include "im/instant_messaging.h"
58
#endif
59

60 61
#include "audio/audiolayer.h"

62
#ifdef SFL_VIDEO
63
#include "video/video_rtp_session.h"
64
#include "client/video_controls.h"
65
#endif
66

67
#include "client/client.h"
68
#include "client/callmanager.h"
69
#include "client/configurationmanager.h"
70

71
#include "pjsip/sip_endpoint.h"
72
#include "pjsip/sip_uri.h"
73
#include "pjnath.h"
74

Emmanuel Milou's avatar
Emmanuel Milou committed
75 76
#include <netinet/in.h>
#include <arpa/nameser.h>
77
#include <arpa/inet.h>
Emmanuel Milou's avatar
Emmanuel Milou committed
78
#include <resolv.h>
79
#include <istream>
80
#include <utility> // for std::pair
81
#include <algorithm>
Emmanuel Milou's avatar
Emmanuel Milou committed
82

83 84 85
#include "pjsip-simple/presence.h"
#include "pjsip-simple/publish.h"
#include "pres_sub_server.h"
Emmanuel Milou's avatar
Emmanuel Milou committed
86

87 88
using namespace sfl;

89 90 91
SIPVoIPLink *SIPVoIPLink::instance_ = 0;
bool SIPVoIPLink::destroyed_ = false;

92
namespace {
Rafaël Carré's avatar
Rafaël Carré committed
93

94 95 96
/** Environment variable used to set pjsip's logging level */
#define SIPLOGLEVEL "SIPLOGLEVEL"

97 98
/** A map to retreive SFLphone internal call id
 *  Given a SIP call ID (usefull for transaction sucha as transfer)*/
99
static std::map<std::string, std::string> transferCallID;
100

Emmanuel Milou's avatar
Emmanuel Milou committed
101
/**************** EXTERN VARIABLES AND FUNCTIONS (callbacks) **************************/
jpbl's avatar
jpbl committed
102

103
/**
104
 * Set audio and video (SDP) configuration for a call
105 106
 * localport, localip, localexternalport
 * @param call a SIPCall valid pointer
107
 */
108
void setCallMediaLocal(SIPCall* call, const std::string &localIP);
109

110

111 112 113 114
static pj_caching_pool pool_cache, *cp_ = &pool_cache;
static pj_pool_t *pool_;
static pjsip_endpoint *endpt_;
static pjsip_module mod_ua_;
115
static pj_thread_t *thread_;
116

117
void sdp_media_update_cb(pjsip_inv_session *inv, pj_status_t status);
118 119 120 121 122 123 124
void sdp_request_offer_cb(pjsip_inv_session *inv, const pjmedia_sdp_session *offer);
void sdp_create_offer_cb(pjsip_inv_session *inv, pjmedia_sdp_session **p_offer);
void invite_session_state_changed_cb(pjsip_inv_session *inv, pjsip_event *e);
void outgoing_request_forked_cb(pjsip_inv_session *inv, pjsip_event *e);
void transaction_state_changed_cb(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e);
void registration_cb(pjsip_regc_cbparam *param);
pj_bool_t transaction_request_cb(pjsip_rx_data *rdata);
125
pj_bool_t transaction_response_cb(pjsip_rx_data *rdata) ;
126

127
void transfer_client_cb(pjsip_evsub *sub, pjsip_event *event);
Emmanuel Milou's avatar
Emmanuel Milou committed
128

129 130 131 132 133 134 135
/**
 * Send a reINVITE inside an active dialog to modify its state
 * Local SDP session should be modified before calling this method
 * @param sip call
 */
int SIPSessionReinvite(SIPCall *);

136 137 138
/**
 * Helper function to process refer function on call transfer
 */
139
void onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata);
Emmanuel Milou's avatar
Emmanuel Milou committed
140

141 142 143 144 145 146 147 148 149 150 151
void handleIncomingOptions(pjsip_rx_data *rdata)
{
    pjsip_tx_data *tdata;

    if (pjsip_endpt_create_response(endpt_, rdata, PJSIP_SC_OK, NULL, &tdata) != PJ_SUCCESS)
        return;

#define ADD_HDR(hdr) do { \
    const pjsip_hdr *cap_hdr = hdr; \
    if (cap_hdr) \
    pjsip_msg_add_hdr (tdata->msg, (pjsip_hdr*) pjsip_hdr_clone (tdata->pool, cap_hdr)); \
Tristan Matthews's avatar
Tristan Matthews committed
152
} while (0)
153 154 155 156 157 158 159 160 161 162 163 164 165 166
#define ADD_CAP(cap) ADD_HDR(pjsip_endpt_get_capability(endpt_, cap, NULL));

    ADD_CAP(PJSIP_H_ALLOW);
    ADD_CAP(PJSIP_H_ACCEPT);
    ADD_CAP(PJSIP_H_SUPPORTED);
    ADD_HDR(pjsip_evsub_get_allow_events_hdr(NULL));

    pjsip_response_addr res_addr;
    pjsip_get_response_addr(tdata->pool, rdata, &res_addr);

    if (pjsip_endpt_send_response(endpt_, &res_addr, tdata, NULL, NULL) != PJ_SUCCESS)
        pjsip_tx_data_dec_ref(tdata);
}

167 168
// return PJ_FALSE so that eventuall other modules will handle these requests
// TODO: move Voicemail to separate module
169 170 171 172 173
pj_bool_t transaction_response_cb(pjsip_rx_data *rdata)
{
    pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);

    if (!dlg)
174
        return PJ_FALSE;
175 176 177 178

    pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);

    if (!tsx or tsx->method.id != PJSIP_INVITE_METHOD)
179
        return PJ_FALSE;
180 181 182 183 184 185 186

    if (tsx->status_code / 100 == 2) {
        /**
         * Send an ACK message inside a transaction. PJSIP send automatically, non-2xx ACK response.
         * ACK for a 2xx response must be send using this method.
         */
        pjsip_tx_data *tdata;
187 188 189 190
        if (rdata->msg_info.cseq) {
            pjsip_dlg_create_request(dlg, &pjsip_ack_method, rdata->msg_info.cseq->cseq, &tdata);
            pjsip_dlg_send_request(dlg, tdata, -1, NULL);
        }
191 192
    }

193
    return PJ_FALSE;
194 195
}

196
void updateSDPFromSTUN(SIPCall &call, SIPAccount &account, const SipTransport &transport)
197 198 199 200 201 202 203 204 205
{
    std::vector<long> socketDescriptors(call.getAudioRtp().getSocketDescriptors());

    try {
        std::vector<pj_sockaddr_in> stunPorts(transport.getSTUNAddresses(account, socketDescriptors));

        // FIXME: get video sockets
        stunPorts.resize(4);

206
        account.setPublishedAddress(pj_inet_ntoa(stunPorts[0].sin_addr));
207
        // published IP MUST be updated first, since RTCP depends on it
208
        call.getLocalSDP()->setPublishedIP(account.getPublishedAddress());
209 210 211 212 213 214
        call.getLocalSDP()->updatePorts(stunPorts);
    } catch (const std::runtime_error &e) {
        ERROR("%s", e.what());
    }
}

215 216
pj_bool_t transaction_request_cb(pjsip_rx_data *rdata)
{
217

218
    if (!rdata or !rdata->msg_info.msg) {
Tristan Matthews's avatar
Tristan Matthews committed
219
        ERROR("rx_data is NULL");
220
        return PJ_FALSE;
221
    }
222
    pjsip_method *method = &rdata->msg_info.msg->line.req.method;
223
    if (!method) {
Tristan Matthews's avatar
Tristan Matthews committed
224
        ERROR("method is NULL");
225
        return PJ_FALSE;
226
    }
227 228

    if (method->id == PJSIP_ACK_METHOD && pjsip_rdata_get_dlg(rdata))
229
        return PJ_FALSE;
230

231 232
    if (!rdata->msg_info.to or !rdata->msg_info.from) {
        ERROR("NULL from/to fields");
233
        return PJ_FALSE;
234
    }
235 236
    pjsip_sip_uri *sip_to_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(rdata->msg_info.to->uri);
    pjsip_sip_uri *sip_from_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(rdata->msg_info.from->uri);
237 238
    if (!sip_to_uri or !sip_from_uri) {
        ERROR("NULL uri");
239
        return PJ_FALSE;
240
    }
241 242
    std::string userName(sip_to_uri->user.ptr, sip_to_uri->user.slen);
    std::string server(sip_from_uri->host.ptr, sip_from_uri->host.slen);
243
    std::string account_id(SIPVoIPLink::instance()->getAccountIdFromNameAndServer(userName, server));
244

245
    std::string displayName(sip_utils::parseDisplayName(rdata->msg_info.msg_buf));
246

247
    pjsip_msg_body *body = rdata->msg_info.msg->body;
248 249 250 251
    if (method->id == PJSIP_OTHER_METHOD) {
        pj_str_t *str = &method->name;
        std::string request(str->ptr, str->slen);

252
        if (request.find("NOTIFY") != std::string::npos) {
253 254 255 256 257
            if (body and body->data) {
                int voicemail = 0;
                int ret = sscanf((const char*) body->data, "Voice-Message: %d/", &voicemail);
                if (ret == 1 and voicemail != 0)
                    Manager::instance().startVoiceMessageNotification(account_id, voicemail);
258
            }
259 260 261
        }

        pjsip_endpt_respond_stateless(endpt_, rdata, PJSIP_SC_OK, NULL, NULL, NULL);
262
        return PJ_FALSE;
263 264
    } else if (method->id == PJSIP_OPTIONS_METHOD) {
        handleIncomingOptions(rdata);
265
        return PJ_FALSE;
266 267
    } else if (method->id != PJSIP_INVITE_METHOD && method->id != PJSIP_ACK_METHOD) {
        pjsip_endpt_respond_stateless(endpt_, rdata, PJSIP_SC_METHOD_NOT_ALLOWED, NULL, NULL, NULL);
268
        return PJ_FALSE;
269 270
    }

271
    SIPAccount *account = Manager::instance().getSipAccount(account_id);
272 273
    if (!account) {
        ERROR("Could not find account %s", account_id.c_str());
274
        return PJ_FALSE;
275
    }
276 277 278 279 280 281

    pjmedia_sdp_session *r_sdp;

    if (!body || pjmedia_sdp_parse(rdata->tp_info.pool, (char*) body->data, body->len, &r_sdp) != PJ_SUCCESS)
        r_sdp = NULL;

282
    if (account->getActiveAudioCodecs().empty()) {
283 284 285
        pjsip_endpt_respond_stateless(endpt_, rdata,
                                      PJSIP_SC_NOT_ACCEPTABLE_HERE, NULL, NULL,
                                      NULL);
286
        return PJ_FALSE;
287 288 289 290 291 292 293
    }

    // Verify that we can handle the request
    unsigned options = 0;

    if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, endpt_, NULL) != PJ_SUCCESS) {
        pjsip_endpt_respond_stateless(endpt_, rdata, PJSIP_SC_METHOD_NOT_ALLOWED, NULL, NULL, NULL);
294
        return PJ_FALSE;
295 296
    }

Tristan Matthews's avatar
Tristan Matthews committed
297
    Manager::instance().hookPreference.runHook(rdata->msg_info.msg);
298

299
    SIPCall* call = new SIPCall(Manager::instance().getNewCallID(), Call::INCOMING, cp_, account_id);
300 301

    // May use the published address as well
302
    std::string addrToUse = SipTransport::getInterfaceAddrFromName(account->getLocalInterface());
303
    std::string addrSdp = account->isStunEnabled() or (not account->getPublishedSameasLocal())
304 305 306
                          ? account->getPublishedAddress()
                          : addrToUse;

307
    pjsip_tpselector *tp_sel = SIPVoIPLink::instance()->sipTransport.createTransportSelector(account->transport_, call->getMemoryPool());
308 309

    char tmp[PJSIP_MAX_URL_SIZE];
310 311
    size_t length = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, sip_from_uri, tmp, PJSIP_MAX_URL_SIZE);
    std::string peerNumber(tmp, std::min(length, sizeof tmp));
312
    sip_utils::stripSipUriPrefix(peerNumber);
313

Tristan Matthews's avatar
Tristan Matthews committed
314 315 316 317
    const std::string remote_user(sip_from_uri->user.ptr, sip_from_uri->user.slen);
    const std::string remote_hostname(sip_from_uri->host.ptr, sip_from_uri->host.slen);
    if (not remote_user.empty() and not remote_hostname.empty())
        peerNumber = remote_user + "@" + remote_hostname;
318

319 320 321 322 323 324 325
    call->setConnectionState(Call::PROGRESSING);
    call->setPeerNumber(peerNumber);
    call->setDisplayName(displayName);
    call->initRecFilename(peerNumber);

    setCallMediaLocal(call, addrToUse);

326
    call->getLocalSDP()->setPublishedIP(addrSdp);
327

328
    call->getAudioRtp().initConfig();
329 330 331 332 333 334 335
    try {
        call->getAudioRtp().initSession();
    } catch (const ost::Socket::Error &err) {
        ERROR("AudioRtp socket error");
        delete call;
        return PJ_FALSE;
    }
336

337 338 339
    if (account->isStunEnabled())
        updateSDPFromSTUN(*call, *account, SIPVoIPLink::instance()->sipTransport);

340
    if (body and body->len > 0 and call->getAudioRtp().isSdesEnabled()) {
341 342
        std::string sdpOffer(static_cast<const char*>(body->data), body->len);
        size_t start = sdpOffer.find("a=crypto:");
343 344 345 346

        // Found crypto header in SDP
        if (start != std::string::npos) {
            CryptoOffer crypto_offer;
347
            crypto_offer.push_back(std::string(sdpOffer.substr(start, (sdpOffer.size() - start) - 1)));
348

349 350
            const size_t size = ARRAYSIZE(sfl::CryptoSuites);
            std::vector<sfl::CryptoSuiteDefinition> localCapabilities(size);
351

352 353
            std::copy(sfl::CryptoSuites, sfl::CryptoSuites + size,
                      localCapabilities.begin());
354

355
#if HAVE_SDES
356 357 358 359 360 361
            sfl::SdesNegotiator sdesnego(localCapabilities, crypto_offer);

            if (sdesnego.negotiate()) {
                call->getAudioRtp().setRemoteCryptoInfo(sdesnego);
                call->getAudioRtp().initLocalCryptoInfo();
            }
362
#endif
363 364 365
        }
    }

366
    call->getLocalSDP()->receiveOffer(r_sdp, account->getActiveAudioCodecs(), account->getActiveVideoCodecs());
367

368
    sfl::AudioCodec* ac = Manager::instance().audioCodecFactory.instantiateCodec(PAYLOAD_CODEC_ULAW);
369 370 371
    if (!ac) {
        ERROR("Could not instantiate codec");
        delete call;
372
        return PJ_FALSE;
373
    }
374 375 376
    std::vector<sfl::AudioCodec *> audioCodecs;
    audioCodecs.push_back(ac);
    call->getAudioRtp().start(audioCodecs);
377

378
    pjsip_dialog *dialog = 0;
379 380 381 382

    if (pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, NULL, &dialog) != PJ_SUCCESS) {
        delete call;
        pjsip_endpt_respond_stateless(endpt_, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL, NULL);
383
        return PJ_FALSE;
384 385 386 387
    }

    pjsip_inv_create_uas(dialog, rdata, call->getLocalSDP()->getLocalSdpSession(), 0, &call->inv);

388
    if (!dialog or !tp_sel or pjsip_dlg_set_transport(dialog, tp_sel) != PJ_SUCCESS) {
389 390
        ERROR("Could not set transport for dialog");
        delete call;
391
        return PJ_FALSE;
392
    }
393

394
    if (!call->inv) {
Tristan Matthews's avatar
Tristan Matthews committed
395
        ERROR("Call invite is not initialized");
396
        delete call;
397
        return PJ_FALSE;
398 399
    }

400 401 402 403 404 405 406 407
    call->inv->mod_data[mod_ua_.id] = call;

    // Check whether Replaces header is present in the request and process accordingly.
    pjsip_dialog *replaced_dlg;
    pjsip_tx_data *response;

    if (pjsip_replaces_verify_request(rdata, &replaced_dlg, PJ_FALSE, &response) != PJ_SUCCESS) {
        ERROR("Something wrong with Replaces request.");
408
        delete call;
409
        pjsip_endpt_respond_stateless(endpt_, rdata, 500 /* internal server error */, NULL, NULL, NULL);
410
        return PJ_FALSE;
411 412 413
    }

    // Check if call has been transfered
414
    pjsip_tx_data *tdata = 0;
415

416 417
    // If Replace header present
    if (replaced_dlg) {
418 419
        // Always answer the new INVITE with 200 if the replaced call is in early or confirmed state.
        if (pjsip_inv_answer(call->inv, PJSIP_SC_OK, NULL, NULL, &response) == PJ_SUCCESS)
420 421 422 423 424 425 426 427
            pjsip_inv_send_msg(call->inv, response);

        // Get the INVITE session associated with the replaced dialog.
        pjsip_inv_session *replaced_inv = pjsip_dlg_get_inv_session(replaced_dlg);

        // Disconnect the "replaced" INVITE session.
        if (pjsip_inv_end_session(replaced_inv, PJSIP_SC_GONE, NULL, &tdata) == PJ_SUCCESS && tdata)
            pjsip_inv_send_msg(replaced_inv, tdata);
428
    } else { // Proceed with normal call flow
429
        if (pjsip_inv_initial_answer(call->inv, rdata, PJSIP_SC_TRYING, NULL, NULL, &tdata) != PJ_SUCCESS) {
430 431
            ERROR("Could not answer invite");
            delete call;
432
            return PJ_FALSE;
433
        }
434 435 436 437 438 439 440 441 442 443

        if (pjsip_inv_send_msg(call->inv, tdata) != PJ_SUCCESS) {
            ERROR("Could not send msg for invite");
            delete call;
            return PJ_FALSE;
        }

        call->setConnectionState(Call::TRYING);

        if (pjsip_inv_answer(call->inv, PJSIP_SC_RINGING, NULL, NULL, &tdata) != PJ_SUCCESS) {
444 445
            ERROR("Could not answer invite");
            delete call;
446
            return PJ_FALSE;
447
        }
448

449 450
        // contactStr must stay in scope as long as tdata
        const std::string contactStr(account->getContactHeader());
451
        sip_utils::addContactHeader(contactStr, tdata);
452

453 454 455
        if (pjsip_inv_send_msg(call->inv, tdata) != PJ_SUCCESS) {
            ERROR("Could not send msg for invite");
            delete call;
456
            return PJ_FALSE;
457
        }
458 459 460

        call->setConnectionState(Call::RINGING);

461
        Manager::instance().incomingCall(*call, account_id);
462
        SIPVoIPLink::instance()->addSipCall(call);
463
    }
464
    return PJ_FALSE;
465
}
466
} // end anonymous namespace
Emmanuel Milou's avatar
Emmanuel Milou committed
467 468

/*************************************************************************************************/
469 470 471 472 473 474 475
pjsip_endpoint * SIPVoIPLink::getEndpoint() {
    return endpt_;
}

pjsip_module * SIPVoIPLink::getMod() {
    return &mod_ua_;
}
jpbl's avatar
jpbl committed
476

477 478
SIPVoIPLink::SIPVoIPLink() : sipTransport(endpt_, cp_, pool_), sipAccountMap_(),
    sipCallMapMutex_(), sipCallMap_(), evThread_(this)
479 480 481 482
#ifdef SFL_VIDEO
    , keyframeRequestsMutex_()
    , keyframeRequests_()
#endif
Emmanuel Milou's avatar
[#2402]  
Emmanuel Milou committed
483
{
484

485
#define TRY(ret) do { \
486 487
    if (ret != PJ_SUCCESS) \
    throw VoipLinkException(#ret " failed"); \
Tristan Matthews's avatar
Tristan Matthews committed
488
} while (0)
yanmorin's avatar
 
yanmorin committed
489

490 491 492 493 494 495
    pthread_mutex_init(&sipCallMapMutex_, NULL);

#ifdef SFL_VIDEO
    pthread_mutex_init(&keyframeRequestsMutex_, NULL);
#endif

496
    srand(time(NULL)); // to get random number for RANDOM_PORT
497

498
    TRY(pj_init());
499

500
    TRY(pjlib_util_init());
501 502

    setSipLogLevel();
503
    TRY(pjnath_init());
504

505
    pj_caching_pool_init(cp_, &pj_pool_factory_default_policy, 0);
506
    pool_ = pj_pool_create(&cp_->factory, PACKAGE, 4000, 4000, NULL);
507

508
    if (!pool_)
509
        throw VoipLinkException("UserAgent: Could not initialize memory pool");
510

511
    TRY(pjsip_endpt_create(&cp_->factory, pj_gethostname()->ptr, &endpt_));
512

513 514 515 516 517
    sipTransport.setEndpoint(endpt_);
    sipTransport.setCachingPool(cp_);
    sipTransport.setPool(pool_);

    if (SipTransport::getSIPLocalIP().empty())
518
        throw VoipLinkException("UserAgent: Unable to determine network capabilities");
519

520 521 522 523
    TRY(pjsip_tsx_layer_init_module(endpt_));
    TRY(pjsip_ua_init_module(endpt_, NULL));
    TRY(pjsip_replaces_init_module(endpt_)); // See the Replaces specification in RFC 3891
    TRY(pjsip_100rel_init_module(endpt_));
Emmanuel Milou's avatar
Emmanuel Milou committed
524

525
    // Initialize and register sflphone module
526 527 528 529 530 531
    mod_ua_.name = pj_str((char*) PACKAGE);
    mod_ua_.id = -1;
    mod_ua_.priority = PJSIP_MOD_PRIORITY_APPLICATION;
    mod_ua_.on_rx_request = &transaction_request_cb;
    mod_ua_.on_rx_response = &transaction_response_cb;
    TRY(pjsip_endpt_register_module(endpt_, &mod_ua_));
532

533 534
    TRY(pjsip_evsub_init_module(endpt_));
    TRY(pjsip_xfer_init_module(endpt_));
535

536
    // presence/publish management
537
    TRY(pjsip_pres_init_module(endpt_, pjsip_evsub_instance()));
538
    TRY(pjsip_endpt_register_module(endpt_, &PresSubServer::mod_presence_server));
539

540
    static const pjsip_inv_callback inv_cb = {
541 542 543 544
        invite_session_state_changed_cb,
        outgoing_request_forked_cb,
        transaction_state_changed_cb,
        sdp_request_offer_cb,
545
#ifdef __ANDROID__ // FIXME depends on pjsip
546
        NULL,
547
#endif
548 549 550 551
        sdp_create_offer_cb,
        sdp_media_update_cb,
        NULL,
        NULL,
552
    };
553
    TRY(pjsip_inv_usage_init(endpt_, &inv_cb));
Emmanuel Milou's avatar
Emmanuel Milou committed
554

555
    static const pj_str_t allowed[] = {
556 557 558 559 560 561 562 563 564 565
        CONST_PJ_STR("INFO"),
        CONST_PJ_STR("REGISTER"),
        CONST_PJ_STR("OPTIONS"),
        CONST_PJ_STR("MESSAGE"),
        CONST_PJ_STR("INVITE"),
        CONST_PJ_STR("ACK"),
        CONST_PJ_STR("BYE"),
        CONST_PJ_STR("NOTIFY"),
        CONST_PJ_STR("PUBLISH"),
        CONST_PJ_STR("CANCEL")};
566

567
    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ALLOW, NULL, PJ_ARRAY_SIZE(allowed), allowed);
Emmanuel Milou's avatar
Emmanuel Milou committed
568

569
    static const pj_str_t text_plain = CONST_PJ_STR("text/plain");
570
    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ACCEPT, NULL, 1, &text_plain);
571

572
    static const pj_str_t accepted = CONST_PJ_STR("application/sdp");
573
    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ACCEPT, NULL, 1, &accepted);
574

Tristan Matthews's avatar
Tristan Matthews committed
575
    DEBUG("pjsip version %s for %s initialized", pj_get_version(), PJ_OS_NAME);
Emmanuel Milou's avatar
Emmanuel Milou committed
576

577
    TRY(pjsip_replaces_init_module(endpt_));
Tristan Matthews's avatar
Tristan Matthews committed
578
#undef TRY
579

580 581
    handlingEvents_ = true;
    evThread_.start();
yanmorin's avatar
 
yanmorin committed
582
}
jpbl's avatar
jpbl committed
583

Emmanuel Milou's avatar
[#2402]  
Emmanuel Milou committed
584 585
SIPVoIPLink::~SIPVoIPLink()
{
586 587 588 589
    const int MAX_TIMEOUT_ON_LEAVING = 5;
    for (int timeout = 0; pjsip_tsx_layer_get_tsx_count() and timeout < MAX_TIMEOUT_ON_LEAVING; timeout++)
        sleep(1);

590 591 592 593 594 595 596
    handlingEvents_ = false;
    if (thread_) {
        pj_thread_join(thread_);
        pj_thread_destroy(thread_);
        DEBUG("PJ thread destroy finished");
        thread_ = 0;
    }
Emmanuel Milou's avatar
Emmanuel Milou committed
597

598
    const pj_time_val tv = {0, 10};
599 600
    pjsip_endpt_handle_events(endpt_, &tv);
    pjsip_endpt_destroy(endpt_);
601

602 603
    pj_pool_release(pool_);
    pj_caching_pool_destroy(cp_);
604

605
    pj_shutdown();
606
    clearSipCallMap();
607 608 609

    std::for_each(sipAccountMap_.begin(), sipAccountMap_.end(), unloadAccount);
    sipAccountMap_.clear();
610 611 612 613 614

    pthread_mutex_destroy(&sipCallMapMutex_);
#ifdef SFL_VIDEO
    pthread_mutex_destroy(&keyframeRequestsMutex_);
#endif
615
}
616

617
SIPVoIPLink* SIPVoIPLink::instance()
Emmanuel Milou's avatar
[#2402]  
Emmanuel Milou committed
618
{
619
    assert(!destroyed_);
Emeric Vigier's avatar
Emeric Vigier committed
620
    if (!instance_) {
621
        DEBUG("creating SIPVoIPLink instance");
622
        instance_ = new SIPVoIPLink;
623
    }
624 625
    return instance_;
}
626

627 628 629 630 631
void SIPVoIPLink::destroy()
{
    delete instance_;
    destroyed_ = true;
    instance_ = 0;
yanmorin's avatar
 
yanmorin committed
632
}
633

634 635 636 637 638 639 640
std::string
SIPVoIPLink::getAccountIdFromNameAndServer(const std::string &userName,
                                           const std::string &server) const
{
    DEBUG("username = %s, server = %s", userName.c_str(), server.c_str());
    // Try to find the account id from username and server name by full match

641 642
    for (const auto &item : sipAccountMap_) {
        SIPAccount *account = static_cast<SIPAccount*>(item.second);
643
        if (account and account->matches(userName, server, endpt_, pool_))
644
            return item.first;
645 646 647 648 649 650
    }

    DEBUG("Username %s or server %s doesn't match any account, using IP2IP", userName.c_str(), server.c_str());
    return SIPAccount::IP2IP_PROFILE;
}

651 652
void SIPVoIPLink::setSipLogLevel()
{
653
    char *envvar = getenv(SIPLOGLEVEL);
654
    int level = 0;
655

656
    if (envvar != NULL) {
657 658
        std::string loglevel = envvar;

659 660 661 662 663 664 665
        if ( ! (std::istringstream(loglevel) >> level) ) level = 0;

        level = level > 6 ? 6 : level;
        level = level < 0 ? 0 : level;
    }
    // From 0 (min) to 6 (max)
    pj_log_set_level(level);
666 667
}

668 669
// Called from EventThread::run (not main thread)
bool SIPVoIPLink::getEvent()
Emmanuel Milou's avatar
[#2402]  
Emmanuel Milou committed
670
{
671
    static pj_thread_desc desc;
672

673
    // We have to register the external thread so it could access the pjsip frameworks
674
    if (!pj_thread_is_registered()) {
Tristan Matthews's avatar
Tristan Matthews committed
675
        DEBUG("Registering thread");
676
        pj_thread_register(NULL, desc, &thread_);
677
    }
678

Rafaël Carré's avatar
Rafaël Carré committed
679
    static const pj_time_val timeout = {0, 10};
680
    pjsip_endpt_handle_events(endpt_, &timeout);
681 682 683
#ifdef SFL_VIDEO
    dequeKeyframeRequests();
#endif
684
    return handlingEvents_;
685
}
686

687
void SIPVoIPLink::sendRegister(Account *a)
Emmanuel Milou's avatar
[#2402]  
Emmanuel Milou committed
688
{
689
    SIPAccount *account = static_cast<SIPAccount*>(a);
690

691 692
    if (!account)
        throw VoipLinkException("SipVoipLink: Account is not SIPAccount");
693 694 695 696 697
    try {
        sipTransport.createSipTransport(*account);
    } catch (const std::runtime_error &e) {
        ERROR("%s", e.what());
    }
698

699
    account->setRegister(true);
700
    account->setRegistrationState(TRYING);
701

702
    pjsip_regc *regc = account->getRegistrationInfo();
703

704
    if (pjsip_regc_create(endpt_, (void *) account, &registration_cb, &regc) != PJ_SUCCESS)
705
        throw VoipLinkException("UserAgent: Unable to create regc structure.");
706

707
    std::string srvUri(account->getServerUri());
708

709 710 711
    // std::string address, port;
    // findLocalAddressFromUri(srvUri, account->transport_, address, port);
    pj_str_t pjSrv = pj_str((char*) srvUri.c_str());
jpbl's avatar
jpbl committed
712

713
    // Generate the FROM header
714
    std::string from(account->getFromUri());
715
    pj_str_t pjFrom = pj_str((char*) from.c_str());
716

717 718 719 720 721
    // Get the received header
    std::string received(account->getReceivedParameter());

    // Get the contact header
    std::string contact = account->getContactHeader();
722
    pj_str_t pjContact = pj_str((char*) contact.c_str());
723

724

725 726 727 728 729
    if (account->transport_) {
        if (account->isStunEnabled()) {
            DEBUG("Setting VIA sent-by to %s:%u", account->transport_->local_name.host.ptr, account->transport_->local_name.port);
            if (pjsip_regc_set_via_sent_by(regc, &account->transport_->local_name, account->transport_) != PJ_SUCCESS)
                throw VoipLinkException("Unable to set the \"sent-by\" field");
730
        } else if (not account->getPublishedSameasLocal() or (not received.empty() and received != account->getPublishedAddress())) {
731 732 733 734
            DEBUG("Setting VIA sent-by to %s:%d", received.c_str(), account->getRPort());
            if (pjsip_regc_set_via_sent_by(regc, account->getViaAddr(), account->transport_) != PJ_SUCCESS)
                throw VoipLinkException("Unable to set the \"sent-by\" field");
        }
735
    }
736

737 738
    if (pjsip_regc_init(regc, &pjSrv, &pjFrom, &pjFrom, 1, &pjContact, account->getRegistrationExpire()) != PJ_SUCCESS)
        throw VoipLinkException("Unable to initialize account registration structure");
739

740
    if (account->hasServiceRoute())
741
        pjsip_regc_set_route_set(regc, sip_utils::createRouteSet(account->getServiceRoute(), pool_));
742

743
    pjsip_regc_set_credentials(regc, account->getCredentialCount(), account->getCredInfo());
jpbl's avatar
jpbl committed
744

745
    pjsip_hdr hdr_list;
746 747
    pj_list_init(&hdr_list);
    std::string useragent(account->getUserAgentName());
748
    pj_str_t pJuseragent = pj_str((char*) useragent.c_str());