diff options
author | Benny Prijono <bennylp@teluu.com> | 2009-10-26 11:21:37 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2009-10-26 11:21:37 +0000 |
commit | 058d9c4c6d15338e1d3b2e05ffea340eec565d9a (patch) | |
tree | f2e22ada6b8929a60cf842f83a870c1a3d2bd921 /pjsip/src/pjsua-lib | |
parent | 295cdeb355d07347f2ba1f4a66ae144fee5efbf7 (diff) |
Implement ticket #982: Support for SIP Message Summary/Message Waiting Indication (MWI, RFC 3842)
- PJSIP-SIMPLE:
- implement MWI
- PJSUA-LIB:
- added "mwi_enabled" flag in account config
- added "on_mwi_info" callback
- pjsua app:
- added "--mwi" option to enable MWI on account
- added simple callback to log the NOTIFY message
- other:
- added SIPp scenario files to simulate UAS side
- build:
- added MWI support on VS6, VS2005, MMP, and Makefile
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2968 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip/src/pjsua-lib')
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_acc.c | 10 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_core.c | 3 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_pres.c | 236 |
3 files changed, 245 insertions, 4 deletions
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c index 4bfe98c1..26ff39a7 100644 --- a/pjsip/src/pjsua-lib/pjsua_acc.c +++ b/pjsip/src/pjsua-lib/pjsua_acc.c @@ -328,7 +328,11 @@ PJ_DEF(pj_status_t) pjsua_acc_add( const pjsua_acc_config *cfg, /* If accounts has registration enabled, start registration */ if (pjsua_var.acc[id].cfg.reg_uri.slen) pjsua_acc_set_registration(id, PJ_TRUE); - + else { + /* Otherwise subscribe to MWI, if it's enabled */ + if (pjsua_var.acc[id].cfg.mwi_enabled) + pjsua_start_mwi(&pjsua_var.acc[id]); + } return PJ_SUCCESS; } @@ -1056,6 +1060,10 @@ static void regc_cb(struct pjsip_regc_cbparam *param) /* Send initial PUBLISH if it is enabled */ if (acc->cfg.publish_enabled && acc->publish_sess==NULL) pjsua_pres_init_publish_acc(acc->index); + + /* Subscribe to MWI, if it's enabled */ + if (acc->cfg.mwi_enabled) + pjsua_start_mwi(acc); } } else { diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index 0e390763..6e41cbe0 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -820,6 +820,9 @@ PJ_DEF(pj_status_t) pjsua_init( const pjsua_config *ua_cfg, status = pjsip_pres_init_module( pjsua_var.endpt, pjsip_evsub_instance()); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + /* Initialize MWI support */ + status = pjsip_mwi_init_module(pjsua_var.endpt, pjsip_evsub_instance()); + /* Init PUBLISH module */ pjsip_publishc_init_module(pjsua_var.endpt); diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c index e7866377..80337299 100644 --- a/pjsip/src/pjsua-lib/pjsua_pres.c +++ b/pjsip/src/pjsua-lib/pjsua_pres.c @@ -1853,6 +1853,230 @@ static pj_status_t refresh_client_subscriptions(void) return PJ_SUCCESS; } +/*************************************************************************** + * MWI + */ +/* Callback called when *client* subscription state has changed. */ +static void mwi_evsub_on_state( pjsip_evsub *sub, pjsip_event *event) +{ + pjsua_acc *acc; + + PJ_UNUSED_ARG(event); + + /* Note: #937: no need to acuire PJSUA_LOCK here. Since the buddy has + * a dialog attached to it, lock_buddy() will use the dialog + * lock, which we are currently holding! + */ + acc = (pjsua_acc*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); + if (!acc) + return; + + PJ_LOG(4,(THIS_FILE, + "MWI subscription for %.*s is %s", + (int)acc->cfg.id.slen, acc->cfg.id.ptr, + pjsip_evsub_get_state_name(sub))); + + if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { + /* Clear subscription */ + acc->mwi_dlg = NULL; + acc->mwi_sub = NULL; + pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL); + + } +} + +/* Callback called when we receive NOTIFY */ +static void mwi_evsub_on_rx_notify(pjsip_evsub *sub, + pjsip_rx_data *rdata, + int *p_st_code, + pj_str_t **p_st_text, + pjsip_hdr *res_hdr, + pjsip_msg_body **p_body) +{ + pjsua_mwi_info mwi_info; + pjsua_acc *acc; + + PJ_UNUSED_ARG(p_st_code); + PJ_UNUSED_ARG(p_st_text); + PJ_UNUSED_ARG(res_hdr); + PJ_UNUSED_ARG(p_body); + + acc = (pjsua_acc*) pjsip_evsub_get_mod_data(sub, pjsua_var.mod.id); + if (!acc) + return; + + /* Construct mwi_info */ + pj_bzero(&mwi_info, sizeof(mwi_info)); + mwi_info.evsub = sub; + mwi_info.rdata = rdata; + + /* Call callback */ + if (pjsua_var.ua_cfg.cb.on_mwi_info) { + (*pjsua_var.ua_cfg.cb.on_mwi_info)(acc->index, &mwi_info); + } +} + + +/* Event subscription callback. */ +static pjsip_evsub_user mwi_cb = +{ + &mwi_evsub_on_state, + NULL, /* on_tsx_state: not interested */ + NULL, /* on_rx_refresh: don't care about SUBSCRIBE refresh, unless + * we want to authenticate + */ + + &mwi_evsub_on_rx_notify, + + NULL, /* on_client_refresh: Use default behaviour, which is to + * refresh client subscription. */ + + NULL, /* on_server_timeout: Use default behaviour, which is to send + * NOTIFY to terminate. + */ +}; + +void pjsua_start_mwi(pjsua_acc *acc) +{ + pj_pool_t *tmp_pool = NULL; + pj_str_t contact; + pjsip_tx_data *tdata; + pj_status_t status; + + if (!acc->cfg.mwi_enabled) { + if (acc->mwi_sub) { + /* Terminate MWI subscription */ + pjsip_tx_data *tdata; + pjsip_evsub *sub = acc->mwi_sub; + + /* Detach sub from this account */ + acc->mwi_sub = NULL; + acc->mwi_dlg = NULL; + pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, NULL); + + /* Unsubscribe */ + status = pjsip_mwi_initiate(acc->mwi_sub, 0, &tdata); + if (status == PJ_SUCCESS) { + status = pjsip_mwi_send_request(acc->mwi_sub, tdata); + } + } + return; + } + + if (acc->mwi_sub) { + /* Subscription is already active */ + return; + + } + + /* Generate suitable Contact header unless one is already set in + * the account + */ + if (acc->contact.slen) { + contact = acc->contact; + } else { + tmp_pool = pjsua_pool_create("tmpmwi", 512, 256); + status = pjsua_acc_create_uac_contact(tmp_pool, &contact, + acc->index, &acc->cfg.id); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Unable to generate Contact header", + status); + pj_pool_release(tmp_pool); + return; + } + } + + /* Create UAC dialog */ + status = pjsip_dlg_create_uac( pjsip_ua_instance(), + &acc->cfg.id, + &contact, + &acc->cfg.id, + NULL, &acc->mwi_dlg); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Unable to create dialog", status); + if (tmp_pool) pj_pool_release(tmp_pool); + return; + } + + /* Increment the dialog's lock otherwise when presence session creation + * fails the dialog will be destroyed prematurely. + */ + pjsip_dlg_inc_lock(acc->mwi_dlg); + + /* Create UAC subscription */ + status = pjsip_mwi_create_uac(acc->mwi_dlg, &mwi_cb, + PJSIP_EVSUB_NO_EVENT_ID, &acc->mwi_sub); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Error creating MWI subscription", status); + if (tmp_pool) pj_pool_release(tmp_pool); + pjsip_dlg_dec_lock(acc->mwi_dlg); + return; + } + + /* If account is locked to specific transport, then lock dialog + * to this transport too. + */ + if (acc->cfg.transport_id != PJSUA_INVALID_ID) { + pjsip_tpselector tp_sel; + + pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); + pjsip_dlg_set_transport(acc->mwi_dlg, &tp_sel); + } + + /* Set route-set */ + if (!pj_list_empty(&acc->route_set)) { + pjsip_dlg_set_route_set(acc->mwi_dlg, &acc->route_set); + } + + /* Set credentials */ + if (acc->cred_cnt) { + pjsip_auth_clt_set_credentials( &acc->mwi_dlg->auth_sess, + acc->cred_cnt, acc->cred); + } + + /* Set authentication preference */ + pjsip_auth_clt_set_prefs(&acc->mwi_dlg->auth_sess, &acc->cfg.auth_pref); + + pjsip_evsub_set_mod_data(acc->mwi_sub, pjsua_var.mod.id, acc); + + status = pjsip_mwi_initiate(acc->mwi_sub, -1, &tdata); + if (status != PJ_SUCCESS) { + pjsip_dlg_dec_lock(acc->mwi_dlg); + if (acc->mwi_sub) { + pjsip_pres_terminate(acc->mwi_sub, PJ_FALSE); + } + acc->mwi_sub = NULL; + acc->mwi_dlg = NULL; + pjsua_perror(THIS_FILE, "Unable to create initial MWI SUBSCRIBE", + status); + if (tmp_pool) pj_pool_release(tmp_pool); + return; + } + + pjsua_process_msg_data(tdata, NULL); + + status = pjsip_pres_send_request(acc->mwi_sub, tdata); + if (status != PJ_SUCCESS) { + pjsip_dlg_dec_lock(acc->mwi_dlg); + if (acc->mwi_sub) { + pjsip_pres_terminate(acc->mwi_sub, PJ_FALSE); + } + acc->mwi_sub = NULL; + acc->mwi_dlg = NULL; + pjsua_perror(THIS_FILE, "Unable to send initial MWI SUBSCRIBE", + status); + if (tmp_pool) pj_pool_release(tmp_pool); + return; + } + + pjsip_dlg_dec_lock(acc->mwi_dlg); + if (tmp_pool) pj_pool_release(tmp_pool); + +} + + +/***************************************************************************/ + /* Timer callback to re-create client subscription */ static void pres_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry) @@ -1860,14 +2084,20 @@ static void pres_timer_cb(pj_timer_heap_t *th, unsigned i; pj_time_val delay = { PJSUA_PRES_TIMER, 0 }; - /* Retry failed PUBLISH requests */ + entry->id = PJ_FALSE; + + /* Retry failed PUBLISH and MWI SUBSCRIBE requests */ for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) { pjsua_acc *acc = &pjsua_var.acc[i]; + + /* Retry PUBLISH */ if (acc->cfg.publish_enabled && acc->publish_sess==NULL) pjsua_pres_init_publish_acc(acc->index); - } - entry->id = PJ_FALSE; + /* Re-subscribe MWI subscription if it's terminated prematurely */ + if (acc->cfg.mwi_enabled && !acc->mwi_sub) + pjsua_start_mwi(acc); + } /* #937: No need to do bulk client refresh, as buddies have their * own individual timer now. |