sipvoiplink.cpp 58.9 KB
Newer Older
jpbl's avatar
jpbl committed
1
/*
2
 *  Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010 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
20
 *  (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.
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
39
#include "sip_utils.h"

jpbl's avatar
jpbl committed
40
#include "sipvoiplink.h"
41
#include "manager.h"
42
#include "logger.h"
43

44
#include "sip/sdp.h"
yanmorin's avatar
   
yanmorin committed
45
#include "sipcall.h"
Emmanuel Milou's avatar
nothing    
Emmanuel Milou committed
46
#include "sipaccount.h"
47
#include "eventthread.h"
48
#include "sdes_negotiator.h"
49
50
51

#include "dbus/dbusmanager.h"
#include "dbus/callmanager.h"
52
#include "dbus/configurationmanager.h"
53

54
#include "im/instant_messaging.h"
55

56
57
#include "audio/audiolayer.h"

58
#include "pjsip/sip_endpoint.h"
59
#include "pjsip/sip_transport_tls.h"
60
#include "pjsip/sip_uri.h"
61
#include "pjnath.h"
62

Emmanuel Milou's avatar
Emmanuel Milou committed
63
64
65
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
66
#include <istream>
67
#include <utility> // for std::pair
Emmanuel Milou's avatar
Emmanuel Milou committed
68

69
70
#include <map>

71
72
using namespace sfl;

73
74
75
SIPVoIPLink *SIPVoIPLink::instance_ = 0;
bool SIPVoIPLink::destroyed_ = false;

76
namespace {
Rafaël Carré's avatar
Rafaël Carré committed
77

78
79
/** A map to retreive SFLphone internal call id
 *  Given a SIP call ID (usefull for transaction sucha as transfer)*/
80
static std::map<std::string, std::string> transferCallID;
81

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

84
/**
85
86
87
88
 * Set audio (SDP) configuration for a call
 * localport, localip, localexternalport
 * @param call a SIPCall valid pointer
 */
89
void setCallMediaLocal(SIPCall* call, const std::string &localIP);
90

91
92
93
94
static pj_caching_pool pool_cache, *cp_ = &pool_cache;
static pj_pool_t *pool_;
static pjsip_endpoint *endpt_;
static pjsip_module mod_ua_;
95
static pj_thread_t *thread_;
Emmanuel Milou's avatar
Emmanuel Milou committed
96

97
void sdp_media_update_cb(pjsip_inv_session *inv, pj_status_t status);
98
99
100
101
102
103
104
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);
105
pj_bool_t transaction_response_cb(pjsip_rx_data *rdata) ;
Emmanuel Milou's avatar
Emmanuel Milou committed
106

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

109
110
111
112
113
114
115
/**
 * 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 *);

116
117
118
/**
 * Helper function to process refer function on call transfer
 */
119
void onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata);
120

121
122
123
124
125
126
127
128
129
130
131
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
132
} while (0)
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#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);
}

pj_bool_t transaction_response_cb(pjsip_rx_data *rdata)
{
    pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);

    if (!dlg)
        return PJ_SUCCESS;

    pjsip_transaction *tsx = pjsip_rdata_get_tsx(rdata);

    if (!tsx or tsx->method.id != PJSIP_INVITE_METHOD)
        return PJ_SUCCESS;

    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;
        pjsip_dlg_create_request(dlg, &pjsip_ack_method, rdata->msg_info.cseq->cseq, &tdata);
        pjsip_dlg_send_request(dlg, tdata, -1, NULL);
    }

    return PJ_SUCCESS;
}

pj_bool_t transaction_request_cb(pjsip_rx_data *rdata)
{
    pjsip_method *method = &rdata->msg_info.msg->line.req.method;

    if (method->id == PJSIP_ACK_METHOD && pjsip_rdata_get_dlg(rdata))
        return true;

    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);
    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);
    std::string account_id(Manager::instance().getAccountIdFromNameAndServer(userName, server));

185
    std::string displayName(sip_utils::parseDisplayName(rdata->msg_info.msg_buf));
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231

    if (method->id == PJSIP_OTHER_METHOD) {
        pj_str_t *str = &method->name;
        std::string request(str->ptr, str->slen);

        if (request.find("NOTIFY") != (size_t)-1) {
            int voicemail;

            if (sscanf((const char*)rdata->msg_info.msg->body->data, "Voice-Message: %d/", &voicemail) == 1 && voicemail != 0)
                Manager::instance().startVoiceMessageNotification(account_id, voicemail);
        }

        pjsip_endpt_respond_stateless(endpt_, rdata, PJSIP_SC_OK, NULL, NULL, NULL);

        return true;
    } else if (method->id == PJSIP_OPTIONS_METHOD) {
        handleIncomingOptions(rdata);
        return true;
    } 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);
        return true;
    }

    SIPAccount *account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(account_id));

    pjmedia_sdp_session *r_sdp;
    pjsip_msg_body *body = rdata->msg_info.msg->body;

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

    if (account->getActiveCodecs().empty()) {
        pjsip_endpt_respond_stateless(endpt_, rdata,
                                      PJSIP_SC_NOT_ACCEPTABLE_HERE, NULL, NULL,
                                      NULL);
        return false;
    }

    // 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);
        return true;
    }

Tristan Matthews's avatar
Tristan Matthews committed
232
    Manager::instance().hookPreference.runHook(rdata->msg_info.msg);
233
234
235
236
237

    SIPCall* call = new SIPCall(Manager::instance().getNewCallID(), Call::INCOMING, cp_);
    Manager::instance().associateCallToAccount(call->getCallId(), account_id);

    // May use the published address as well
238
    std::string addrToUse = SipTransport::getInterfaceAddrFromName(account->getLocalInterface());
239
240
241
242
    std::string addrSdp = account->isStunEnabled()
                          ? account->getPublishedAddress()
                          : addrToUse;

243
    pjsip_tpselector *tp = SIPVoIPLink::instance()->sipTransport.initTransportSelector(account->transport_, call->getMemoryPool());
244
245

    if (addrToUse == "0.0.0.0")
246
        addrToUse = SipTransport::getSIPLocalIP();
247
248
249
250
251
252
253

    if (addrSdp == "0.0.0.0")
        addrSdp = addrToUse;

    char tmp[PJSIP_MAX_URL_SIZE];
    int length = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, sip_from_uri, tmp, PJSIP_MAX_URL_SIZE);
    std::string peerNumber(tmp, length);
254
    sip_utils::stripSipUriPrefix(peerNumber);
255
256
257
258
259
260
261
262
263
264

    call->setConnectionState(Call::PROGRESSING);
    call->setPeerNumber(peerNumber);
    call->setDisplayName(displayName);
    call->initRecFilename(peerNumber);

    setCallMediaLocal(call, addrToUse);

    call->getLocalSDP()->setLocalIP(addrSdp);

265
266
    call->getAudioRtp().initConfig();
    call->getAudioRtp().initSession();
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282

    if (rdata->msg_info.msg->body) {
        char sdpbuffer[1000];
        int len = rdata->msg_info.msg->body->print_body(rdata->msg_info.msg->body, sdpbuffer, sizeof sdpbuffer);

        if (len == -1) // error
            len = 0;

        std::string sdpoffer(sdpbuffer, len);
        size_t start = sdpoffer.find("a=crypto:");

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

283
            std::vector<sfl::CryptoSuiteDefinition> localCapabilities;
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313

            for (int i = 0; i < 3; i++)
                localCapabilities.push_back(sfl::CryptoSuites[i]);

            sfl::SdesNegotiator sdesnego(localCapabilities, crypto_offer);

            if (sdesnego.negotiate()) {
                call->getAudioRtp().setRemoteCryptoInfo(sdesnego);
                call->getAudioRtp().initLocalCryptoInfo();
            }
        }
    }

    call->getLocalSDP()->receiveOffer(r_sdp, account->getActiveCodecs());

    sfl::Codec* audiocodec = Manager::instance().audioCodecFactory.instantiateCodec(PAYLOAD_CODEC_ULAW);
    call->getAudioRtp().start(static_cast<sfl::AudioCodec *>(audiocodec));

    pjsip_dialog* dialog;

    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);
        return false;
    }

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

    PJ_ASSERT_RETURN(pjsip_dlg_set_transport(dialog, tp) == PJ_SUCCESS, 1);

314
315
316
317
318
319
    if (!call->inv) {
        ERROR("SIPVoIPLink: Call invite is not initialized");
        delete call;
        return false;
    }

320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
    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.");
        pjsip_endpt_respond_stateless(endpt_, rdata, 500 /* internal server error */, NULL, NULL, NULL);
    }

    // Check if call has been transfered
    pjsip_tx_data *tdata;

    if (replaced_dlg) { // If Replace header present
        // Always answer the new INVITE with 200, regardless whether
        // the replaced call is in early or confirmed state.
        if (pjsip_inv_answer(call->inv, 200, NULL, NULL, &response) == PJ_SUCCESS)
            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);
    } else { // Prooceed with normal call flow
        PJ_ASSERT_RETURN(pjsip_inv_initial_answer(call->inv, rdata, PJSIP_SC_RINGING, NULL, NULL, &tdata) == PJ_SUCCESS, 1);
        PJ_ASSERT_RETURN(pjsip_inv_send_msg(call->inv, tdata) == PJ_SUCCESS, 1);

        call->setConnectionState(Call::RINGING);

352
        Manager::instance().incomingCall(*call, account_id);
353
354
355
356
357
        Manager::instance().getAccountLink(account_id)->addCall(call);
    }

    return true;
}
358
359
} // end anonymous namespace

Emmanuel Milou's avatar
Emmanuel Milou committed
360
361
/*************************************************************************************************/

362
SIPVoIPLink::SIPVoIPLink() : sipTransport(endpt_, cp_, pool_), evThread_(this)
363
364
{
#define TRY(ret) do { \
365
366
    if (ret != PJ_SUCCESS) \
    throw VoipLinkException(#ret " failed"); \
Tristan Matthews's avatar
Tristan Matthews committed
367
} while (0)
368
369

    srand(time(NULL)); // to get random number for RANDOM_PORT
Emmanuel Milou's avatar
Emmanuel Milou committed
370

371
372
    TRY(pj_init());
    TRY(pjlib_util_init());
373
374
    // From 0 (min) to 6 (max)
    pj_log_set_level(Logger::getDebugMode() ? 6 : 0);
375
    TRY(pjnath_init());
376

377
378
    pj_caching_pool_init(cp_, &pj_pool_factory_default_policy, 0);
    pool_ = pj_pool_create(&cp_->factory, "sflphone", 4000, 4000, NULL);
379

380
    if (!pool_)
381
        throw VoipLinkException("UserAgent: Could not initialize memory pool");
Alexandre Savard's avatar
Alexandre Savard committed
382

383
    TRY(pjsip_endpt_create(&cp_->factory, pj_gethostname()->ptr, &endpt_));
384

385
386
387
388
389
    sipTransport.setEndpoint(endpt_);
    sipTransport.setCachingPool(cp_);
    sipTransport.setPool(pool_);

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

392
393
394
395
    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_));
396
397

    // Initialize and register sflphone module
398
399
400
401
402
403
    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_));
404

405
406
    TRY(pjsip_evsub_init_module(endpt_));
    TRY(pjsip_xfer_init_module(endpt_));
407
408

    static const pjsip_inv_callback inv_cb = {
409
410
411
412
413
414
415
416
        invite_session_state_changed_cb,
        outgoing_request_forked_cb,
        transaction_state_changed_cb,
        sdp_request_offer_cb,
        sdp_create_offer_cb,
        sdp_media_update_cb,
        NULL,
        NULL,
417
    };
418
    TRY(pjsip_inv_usage_init(endpt_, &inv_cb));
419
420

    static const pj_str_t allowed[] = { { (char*) "INFO", 4}, { (char*) "REGISTER", 8}, { (char*) "OPTIONS", 7}, { (char*) "MESSAGE", 7 } };       //  //{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6}
421
    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ALLOW, NULL, PJ_ARRAY_SIZE(allowed), allowed);
422
423

    static const pj_str_t text_plain = { (char*) "text/plain", 10 };
424
    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ACCEPT, NULL, 1, &text_plain);
425
426

    static const pj_str_t accepted = { (char*) "application/sdp", 15 };
427
    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ACCEPT, NULL, 1, &accepted);
428

429
    DEBUG("UserAgent: pjsip version %s for %s initialized", pj_get_version(), PJ_OS_NAME);
430

431
    TRY(pjsip_replaces_init_module(endpt_));
Tristan Matthews's avatar
Tristan Matthews committed
432
#undef TRY
433

434
435
    handlingEvents_ = true;
    evThread_.start();
yanmorin's avatar
   
yanmorin committed
436
}
jpbl's avatar
jpbl committed
437

Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
438
439
SIPVoIPLink::~SIPVoIPLink()
{
440
441
442
443
444
445
446
    handlingEvents_ = false;
    if (thread_) {
        pj_thread_join(thread_);
        pj_thread_destroy(thread_);
        DEBUG("PJ thread destroy finished");
        thread_ = 0;
    }
447
448

    const pj_time_val tv = {0, 10};
449
450
    pjsip_endpt_handle_events(endpt_, &tv);
    pjsip_endpt_destroy(endpt_);
451

452
453
    pj_pool_release(pool_);
    pj_caching_pool_destroy(cp_);
454
455

    pj_shutdown();
456
457
}

458
SIPVoIPLink* SIPVoIPLink::instance()
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
459
{
460
461
462
463
464
465
466
467
468
469
470
    assert(!destroyed_);
    if (!instance_)
        instance_ = new SIPVoIPLink;
    return instance_;
}

void SIPVoIPLink::destroy()
{
    delete instance_;
    destroyed_ = true;
    instance_ = 0;
yanmorin's avatar
   
yanmorin committed
471
472
}

473
474
// Called from EventThread::run (not main thread)
bool SIPVoIPLink::getEvent()
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
475
{
476
    static pj_thread_desc desc;
477

478
    // We have to register the external thread so it could access the pjsip frameworks
479
480
    if (!pj_thread_is_registered()) {
        DEBUG("%s: Registering thread", __PRETTY_FUNCTION__);
481
        pj_thread_register(NULL, desc, &thread_);
482
    }
yanmorin's avatar
   
yanmorin committed
483

Rafaël Carré's avatar
Rafaël Carré committed
484
    static const pj_time_val timeout = {0, 10};
485
    pjsip_endpt_handle_events(endpt_, &timeout);
486
    return handlingEvents_;
487
}
488

489
void SIPVoIPLink::sendRegister(Account *a)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
490
{
491
    SIPAccount *account = dynamic_cast<SIPAccount*>(a);
492

493
494
495
    if (!account)
        throw VoipLinkException("SipVoipLink: Account is not SIPAccount");
    sipTransport.createSipTransport(*account);
496

497
498
    account->setRegister(true);
    account->setRegistrationState(Trying);
499

500
    pjsip_regc *regc = account->getRegistrationInfo();
501

502
    if (pjsip_regc_create(endpt_, (void *) account, &registration_cb, &regc) != PJ_SUCCESS)
503
504
505
        throw VoipLinkException("UserAgent: Unable to create regc structure.");

    std::string srvUri(account->getServerUri());
506

507
508
509
    // std::string address, port;
    // findLocalAddressFromUri(srvUri, account->transport_, address, port);
    pj_str_t pjSrv = pj_str((char*) srvUri.c_str());
510

511
    // Generate the FROM header
512
    std::string from(account->getFromUri());
513
    pj_str_t pjFrom = pj_str((char*) from.c_str());
514

515
516
517
518
519
    // Get the received header
    std::string received(account->getReceivedParameter());

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

522
523
524
525
526
    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());
527
528
529
        if(account->transport_ == NULL) {
            ERROR("UserAgent: Could not create new udp transport with public address: %s:%d", received.c_str(), account->getLocalPort());
        }
530
    }
531

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

535
    if (!account->getServiceRoute().empty())
536
        pjsip_regc_set_route_set(regc, sip_utils::createRouteSet(account->getServiceRoute(), pool_));
537

538
    pjsip_regc_set_credentials(regc, account->getCredentialCount(), account->getCredInfo());
539

540
    pjsip_hdr hdr_list;
541
542
    pj_list_init(&hdr_list);
    std::string useragent(account->getUserAgentName());
543
    pj_str_t pJuseragent = pj_str((char*) useragent.c_str());
544
    const pj_str_t STR_USER_AGENT = { (char*) "User-Agent", 10 };
545

546
    pjsip_generic_string_hdr *h = pjsip_generic_string_hdr_create(pool_, &STR_USER_AGENT, &pJuseragent);
547
548
    pj_list_push_back(&hdr_list, (pjsip_hdr*) h);
    pjsip_regc_add_headers(regc, &hdr_list);
jpbl's avatar
jpbl committed
549

550
    pjsip_tx_data *tdata;
Emmanuel Milou's avatar
Emmanuel Milou committed
551

552
553
    if (pjsip_regc_register(regc, PJ_TRUE, &tdata) != PJ_SUCCESS)
        throw VoipLinkException("Unable to initialize transaction data for account registration");
Emmanuel Milou's avatar
Emmanuel Milou committed
554

555
    if (pjsip_regc_set_transport(regc, sipTransport.initTransportSelector(account->transport_, pool_)) != PJ_SUCCESS)
556
        throw VoipLinkException("Unable to set transport");
557

558
559
    // decrease transport's ref count, counter incrementation is managed when acquiring transport
    pjsip_transport_dec_ref(account->transport_);
560

561
562
563
    // pjsip_regc_send increment the transport ref count by one,
    if (pjsip_regc_send(regc, tdata) != PJ_SUCCESS)
        throw VoipLinkException("Unable to send account registration request");
564

565
566
567
568
569
570
    // Decrease transport's ref count, since coresponding reference counter decrementation
    // is performed in pjsip_regc_destroy. This function is never called in SFLphone as the
    // regc data structure is permanently associated to the account at first registration.
    pjsip_transport_dec_ref(account->transport_);

    account->setRegistrationInfo(regc);
571
572
573
574

    // start the periodic registration request based on Expire header
    // account determines itself if a keep alive is required
    account->startKeepAliveTimer();
575
576
}

577
void SIPVoIPLink::sendUnregister(Account *a)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
578
{
579
    SIPAccount *account = dynamic_cast<SIPAccount *>(a);
580

581
    // This may occurs if account failed to register and is in state INVALID
582
    if (!account->isRegistered()) {
583
        account->setRegistrationState(Unregistered);
584
        return;
585
586
    }

587
588
589
    // Make sure to cancel any ongoing timers before unregister
    account->stopKeepAliveTimer();

590
    pjsip_regc *regc = account->getRegistrationInfo();
591

592
    if (!regc)
593
        throw VoipLinkException("Registration structure is NULL");
594

595
    pjsip_tx_data *tdata = NULL;
596
597

    if (pjsip_regc_unregister(regc, &tdata) != PJ_SUCCESS)
598
        throw VoipLinkException("Unable to unregister sip account");
599

600
    if (pjsip_regc_send(regc, tdata) != PJ_SUCCESS)
601
        throw VoipLinkException("Unable to send request to unregister sip account");
602

603
    account->setRegister(false);
jpbl's avatar
jpbl committed
604
605
}

606
void SIPVoIPLink::registerKeepAliveTimer(pj_timer_entry &timer, pj_time_val &delay)
607
{
608
    if (timer.id == -1)
609
610
        WARN("UserAgent: Timer already scheduled");

611
612
613
614
615
616
617
618
619
620
621
622
    switch (pjsip_endpt_schedule_timer(endpt_, &timer, &delay)) {
        case PJ_SUCCESS:
            break;
        default:
            ERROR("UserAgent: Could not schedule new timer in pjsip endpoint");
            /* fallthrough */
        case PJ_EINVAL:
            ERROR("UserAgent: Invalid timer or delay entry");
            break;
        case PJ_EINVALIDOP:
            ERROR("Invalid timer entry, maybe already scheduled");
            break;
623
    }
624
625
626
627
}

void SIPVoIPLink::cancelKeepAliveTimer(pj_timer_entry& timer)
{
628
    pjsip_endpt_cancel_timer(endpt_, &timer);
629
630
}

631
Call *SIPVoIPLink::newOutgoingCall(const std::string& id, const std::string& toUrl)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
632
{
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
    static const char * const SIP_SCHEME = "sip:";
    static const char * const SIPS_SCHEME = "sips:";

    DEBUG("UserAgent: New outgoing call");

    bool IPToIP = toUrl.find(SIP_SCHEME) == 0 or
                  toUrl.find(SIPS_SCHEME) == 0;

    Manager::instance().setIPToIPForCall(id, IPToIP);

    try {
        if (IPToIP) {
            return SIPNewIpToIpCall(id, toUrl);
        }
        else {
            return newRegisteredAccountCall(id, toUrl);
        }
    }
    catch(...) {
        throw;
    }
}

Call *SIPVoIPLink::SIPNewIpToIpCall(const std::string& id, const std::string& to)
{
    DEBUG("UserAgent: New IP to IP call to %s", to.c_str());

    SIPAccount *account = Manager::instance().getIP2IPAccount();

    if (!account)
        throw VoipLinkException("Could not retrieve default account for IP2IP call");

    SIPCall *call = new SIPCall(id, Call::OUTGOING, cp_);

    call->setIPToIP(true);
    call->initRecFilename(to);

    std::string localAddress(SipTransport::getInterfaceAddrFromName(account->getLocalInterface()));

    if (localAddress == "0.0.0.0")
        localAddress = SipTransport::getSIPLocalIP();

    setCallMediaLocal(call, localAddress);

    std::string toUri = account->getToUri(to);
    call->setPeerNumber(toUri);

    sfl::Codec* audiocodec = Manager::instance().audioCodecFactory.instantiateCodec(PAYLOAD_CODEC_ULAW);

    // Audio Rtp Session must be initialized before creating initial offer in SDP session
    // since SDES require crypto attribute.
    call->getAudioRtp().initConfig();
    call->getAudioRtp().initSession();
    call->getAudioRtp().initLocalCryptoInfo();
    call->getAudioRtp().start(static_cast<sfl::AudioCodec *>(audiocodec));

    // Building the local SDP offer
    call->getLocalSDP()->setLocalIP(localAddress);
    call->getLocalSDP()->createOffer(account->getActiveCodecs());

    if (!SIPStartCall(call)) {
        delete call;
        throw VoipLinkException("Could not create new call");
    }

    return call;
}

Call *SIPVoIPLink::newRegisteredAccountCall(const std::string& id, const std::string& toUrl)
{
    DEBUG("UserAgent: New registered account call to %s", toUrl.c_str());

705
706
    SIPAccount *account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(Manager::instance().getAccountFromCall(id)));

707
    if (account == NULL) // TODO: We should investigate how we could get rid of this error and create a IP2IP call instead
708
        throw VoipLinkException("Could not get account for this call");
709

710
    SIPCall* call = new SIPCall(id, Call::OUTGOING, cp_);
Emmanuel Milou's avatar
Emmanuel Milou committed
711

712
    // If toUri is not a well formatted sip URI, use account information to process it
713
    std::string toUri;
714

715
716
    if (toUrl.find("sip:") != std::string::npos or
        toUrl.find("sips:") != std::string::npos)
717
        toUri = toUrl;
718
    else
719
        toUri = account->getToUri(toUrl);
720

721
    call->setPeerNumber(toUri);
722
    std::string localAddr(SipTransport::getInterfaceAddrFromName(account->getLocalInterface()));
723

724
    if (localAddr == "0.0.0.0")
725
        localAddr = SipTransport::getSIPLocalIP();
726

727
    setCallMediaLocal(call, localAddr);
Emmanuel Milou's avatar
Emmanuel Milou committed
728

729
    // May use the published address as well
730
    std::string addrSdp = account->isStunEnabled() ?
731
    account->getPublishedAddress() :
732
    SipTransport::getInterfaceAddrFromName(account->getLocalInterface());
733

734
    if (addrSdp == "0.0.0.0")
735
        addrSdp = SipTransport::getSIPLocalIP();
Emmanuel Milou's avatar
Emmanuel Milou committed
736

737
738
739
    // Initialize the session using ULAW as default codec in case of early media
    // The session should be ready to receive media once the first INVITE is sent, before
    // the session initialization is completed
740
741
    sfl::Codec* audiocodec = Manager::instance().audioCodecFactory.instantiateCodec(PAYLOAD_CODEC_ULAW);

742
    if (audiocodec == NULL) {
743
744
        delete call;
        throw VoipLinkException("Could not instantiate codec for early media");
745
    }
746

747
    try {
748
749
        call->getAudioRtp().initConfig();
        call->getAudioRtp().initSession();
750
751
        call->getAudioRtp().initLocalCryptoInfo();
        call->getAudioRtp().start(static_cast<sfl::AudioCodec *>(audiocodec));
752
    } catch (...) {
753
        delete call;
754
755
        throw VoipLinkException("Could not start rtp session for early media");
    }
756

757
    call->initRecFilename(toUrl);
758

759
760
    call->getLocalSDP()->setLocalIP(addrSdp);
    call->getLocalSDP()->createOffer(account->getActiveCodecs());
761

762
763
764
765
    if (!SIPStartCall(call)) {
        delete call;
        throw VoipLinkException("Could not send outgoing INVITE request for new call");
    }
jpbl's avatar
jpbl committed
766

767
    return call;
768
}
769

770
void
771
SIPVoIPLink::answer(Call *call)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
772
{
773
    if (!call)
774
        return;
775
    call->answer();
Yun Liu's avatar
Yun Liu committed
776
777
}

778
void
779
SIPVoIPLink::hangup(const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
780
{
781
    SIPCall* call = getSIPCall(id);
782

783
    std::string account_id(Manager::instance().getAccountFromCall(id));
784
785
    SIPAccount *account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(account_id));

786
    if (account == NULL)
787
        throw VoipLinkException("Could not find account for this call");
788

789
    pjsip_inv_session *inv = call->inv;
790

791
    if (inv == NULL)
792
        throw VoipLinkException("No invite session for this call");
793

794
    // Looks for sip routes
Tristan Matthews's avatar
Tristan Matthews committed
795
    if (not account->getServiceRoute().empty()) {
796
        pjsip_route_hdr *route_set = sip_utils::createRouteSet(account->getServiceRoute(), inv->pool);
797
        pjsip_dlg_set_route_set(inv->dlg, route_set);
798
    }
799

800
    pjsip_tx_data *tdata = NULL;
801

802
    // User hangup current call. Notify peer
803
    if (pjsip_inv_end_session(inv, 404, NULL, &tdata) != PJ_SUCCESS || !tdata)
804
        return;
805

806
    if (pjsip_inv_send_msg(inv, tdata) != PJ_SUCCESS)
807
        return;
808

809
    // Make sure user data is NULL in callbacks
810
    inv->mod_data[mod_ua_.id] = NULL;
811

812
    if (Manager::instance().isCurrentCall(id))
813
        call->getAudioRtp().stop();
814

815
    removeCall(id);
alexandresavard's avatar
alexandresavard committed
816
817
}

818
void
819
SIPVoIPLink::peerHungup(const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
820
{
821
    SIPCall* call = getSIPCall(id);
Alexandre Savard's avatar
Alexandre Savard committed
822

823
    // User hangup current call. Notify peer
824
    pjsip_tx_data *tdata = NULL;
825
826

    if (pjsip_inv_end_session(call->inv, 404, NULL, &tdata) != PJ_SUCCESS || !tdata)
827
        return;
828

829
    if (pjsip_inv_send_msg(call->inv, tdata) != PJ_SUCCESS)
830
        return;
831

832
    // Make sure user data is NULL in callbacks
833
    call->inv->mod_data[mod_ua_.id ] = NULL;
834

835
    if (Manager::instance().isCurrentCall(id))
836
        call->getAudioRtp().stop();
837

838
    removeCall(id);
839
840
}

841
void
842
SIPVoIPLink::onhold(const std::string& id)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
843
{
844
    SIPCall *call = getSIPCall(id);
845
    call->setState(Call::HOLD);
846
    call->getAudioRtp().stop();
847
848

    Sdp *sdpSession = call->getLocalSDP();
849

850
    if (!sdpSession)
851
        throw VoipLinkException("Could not find sdp session");
852
853
854
855
856

    sdpSession->removeAttributeFromLocalAudioMedia("sendrecv");
    sdpSession->removeAttributeFromLocalAudioMedia("sendonly");
    sdpSession->addAttributeToLocalAudioMedia("sendonly");

857
    SIPSessionReinvite(call);
858
859
}

860
void
861
SIPVoIPLink::offhold(const std::string& id)
862
{
863
864
865
    SIPCall *call = getSIPCall(id);

    Sdp *sdpSession = call->getLocalSDP();
866

867
    if (sdpSession == NULL)
868
        throw VoipLinkException("Could not find sdp session");
869

870
    try {
871
        int pl = PAYLOAD_CODEC_ULAW;
872
        sfl::Codec *sessionMedia = sdpSession->getSessionMedia();
873

874
        if (sessionMedia)
875
            pl = sessionMedia->getPayloadType();
876

877
        // Create a new instance for this codec
878
879
        sfl::Codec* audiocodec = Manager::instance().audioCodecFactory.instantiateCodec(pl);

880
        if (audiocodec == NULL)
881
            throw VoipLinkException("Could not instantiate codec");
882

883
884
        call->getAudioRtp().initConfig();
        call->getAudioRtp().initSession();
885
        call->getAudioRtp().start(static_cast<sfl::AudioCodec *>(audiocodec));
886
    } catch (const SdpException &e) {
887
        ERROR("UserAgent: Exception: %s", e.what());
888
889
    } catch (...) {
        throw VoipLinkException("Could not create audio rtp session");
890
891
892
893
894
    }

    sdpSession->removeAttributeFromLocalAudioMedia("sendrecv");
    sdpSession->removeAttributeFromLocalAudioMedia("sendonly");
    sdpSession->addAttributeToLocalAudioMedia("sendrecv");
895

896
    if (SIPSessionReinvite(call) == PJ_SUCCESS)
897
        call->setState(Call::ACTIVE);
898
899
}

900
void SIPVoIPLink::sendTextMessage(const std::string &callID,
901
902
                                  const std::string &message,
                                  const std::string &from)
Emmanuel Milou's avatar
[#2402]    
Emmanuel Milou committed
903
{
904
    using namespace sfl::InstantMessaging;
905
    SIPCall *call;
906

907
    try {
908
909
        call = getSIPCall(callID);
    } catch (const VoipLinkException &e) {
Rafaël Carré's avatar
Rafaël Carré committed
910
        return;
Tristan Matthews's avatar