From 00ed64489de3c39a6a452e11bb43b2c1090c9307 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Tue, 28 Apr 2009 22:19:49 +0000 Subject: Ticket #760: Enhancements to PUBLISH management (thanks Johan Lantz for the suggestion) - Changes in PJSUA-LIB - retry with fresh request on 412/Conditional Request Failed response - changed default Expires in PUBLISH request to none (we will not put Expires), to avoid getting 423/Interval Too Brief response - if the PUBLISH fails for any reason, it will be retried on every PJSUA_PRES_TIMER (default 300 seconds), similar to how failed SUBSCRIBE will be retried - Changes to publish.h: - added API to add headers in every PUBLISH request - Added test scenario in Python unit tests git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2661 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip/include/pjsip-simple/publish.h | 23 +++++++++++++++++++++- pjsip/include/pjsua-lib/pjsua.h | 5 +++-- pjsip/src/pjsip-simple/publishc.c | 38 ++++++++++++++++++++++++++++++++++-- pjsip/src/pjsua-lib/pjsua_pres.c | 30 +++++++++++++++++++++++++--- 4 files changed, 88 insertions(+), 8 deletions(-) (limited to 'pjsip') diff --git a/pjsip/include/pjsip-simple/publish.h b/pjsip/include/pjsip-simple/publish.h index ebbd1cf1..3c7c7d55 100644 --- a/pjsip/include/pjsip-simple/publish.h +++ b/pjsip/include/pjsip-simple/publish.h @@ -78,7 +78,9 @@ struct pjsip_publishc_cbparam int code; /**< SIP status code received. */ pj_str_t reason; /**< SIP reason phrase received. */ pjsip_rx_data *rdata; /**< The complete received response. */ - int expiration;/**< Next expiration interval. */ + int expiration;/**< Next expiration interval. If the + value is -1, it means the session + will not renew itself. */ }; @@ -189,6 +191,25 @@ PJ_DECL(pj_status_t) pjsip_publishc_set_route_set(pjsip_publishc *pubc, const pjsip_route_hdr *rs); +/** + * Set list of headers to be added to each PUBLISH request generated by + * the client publication session. Note that application can also add + * the headers to the request after calling #pjsip_publishc_publish() + * or #pjsip_publishc_unpublish(), but the benefit of this function is + * the headers will also be added to requests generated internally by + * the session, such as during session renewal/refresh. + * + * Note that calling this function will clear the previously added list + * of headers. + * + * @param pubc The client publication structure. + * @param hdr_list The list of headers. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) pjsip_publishc_set_headers(pjsip_publishc *pubc, + const pjsip_hdr *hdr_list); + /** * Create PUBLISH request for the specified client publication structure. * Application can use this function to both create initial publication diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index 99869344..e17a7f64 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -2037,7 +2037,7 @@ PJ_DECL(pj_status_t) pjsua_transport_close( pjsua_transport_id id, * Default PUBLISH expiration */ #ifndef PJSUA_PUBLISH_EXPIRATION -# define PJSUA_PUBLISH_EXPIRATION 600 +# define PJSUA_PUBLISH_EXPIRATION PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED #endif @@ -3493,7 +3493,8 @@ PJ_DECL(pj_status_t) pjsua_call_dump(pjsua_call_id call_id, /** * This specifies how long the library should retry resending SUBSCRIBE - * if the previous SUBSCRIBE failed. + * if the previous SUBSCRIBE failed. This also controls the duration + * before failed PUBLISH request will be retried. * * Default: 300 seconds */ diff --git a/pjsip/src/pjsip-simple/publishc.c b/pjsip/src/pjsip-simple/publishc.c index 6840d028..2f5b415e 100644 --- a/pjsip/src/pjsip-simple/publishc.c +++ b/pjsip/src/pjsip-simple/publishc.c @@ -81,6 +81,7 @@ struct pjsip_publishc pjsip_expires_hdr *expires_hdr; pj_uint32_t expires; pjsip_route_hdr route_set; + pjsip_hdr usr_hdr; /* Authorization sessions. */ pjsip_auth_clt_sess auth_sess; @@ -157,6 +158,7 @@ PJ_DEF(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt, return status; pj_list_init(&pubc->route_set); + pj_list_init(&pubc->usr_hdr); /* Done */ *p_pubc = pubc; @@ -186,7 +188,9 @@ PJ_DEF(pj_pool_t*) pjsip_publishc_get_pool(pjsip_publishc *pubc) static void set_expires( pjsip_publishc *pubc, pj_uint32_t expires) { - if (expires != pubc->expires) { + if (expires != pubc->expires && + expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED) + { pubc->expires_hdr = pjsip_expires_hdr_create(pubc->pool, expires); } else { pubc->expires_hdr = NULL; @@ -281,6 +285,23 @@ PJ_DEF(pj_status_t) pjsip_publishc_set_route_set( pjsip_publishc *pubc, return PJ_SUCCESS; } +PJ_DEF(pj_status_t) pjsip_publishc_set_headers( pjsip_publishc *pubc, + const pjsip_hdr *hdr_list) +{ + const pjsip_hdr *h; + + PJ_ASSERT_RETURN(pubc && hdr_list, PJ_EINVAL); + + pj_list_init(&pubc->usr_hdr); + h = hdr_list->next; + while (h != hdr_list) { + pj_list_push_back(&pubc->usr_hdr, pjsip_hdr_clone(pubc->pool, h)); + h = h->next; + } + + return PJ_SUCCESS; +} + static pj_status_t create_request(pjsip_publishc *pubc, pjsip_tx_data **p_tdata) { @@ -345,6 +366,19 @@ static pj_status_t create_request(pjsip_publishc *pubc, pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr); } + /* Add user headers */ + if (!pj_list_empty(&pubc->usr_hdr)) { + const pjsip_hdr *hdr; + + hdr = pubc->usr_hdr.next; + while (hdr != &pubc->usr_hdr) { + pjsip_hdr *new_hdr = (pjsip_hdr*) + pjsip_hdr_shallow_clone(tdata->pool, hdr); + pjsip_msg_add_hdr(tdata->msg, new_hdr); + hdr = hdr->next; + } + } + /* Done. */ *p_tdata = tdata; @@ -530,7 +564,7 @@ static void tsx_callback(void *token, pjsip_event *event) expires = (pjsip_expires_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL); - if (expires) + if (pubc->auto_refresh && expires) expiration = expires->ivalue; if (pubc->auto_refresh && expiration!=0 && expiration!=0xFFFF) { diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c index d619dd47..d980e617 100644 --- a/pjsip/src/pjsua-lib/pjsua_pres.c +++ b/pjsip/src/pjsua-lib/pjsua_pres.c @@ -961,6 +961,10 @@ static void publish_cb(struct pjsip_publishc_cbparam *param) pjsua_acc *acc = (pjsua_acc*) param->token; if (param->code/100 != 2 || param->status != PJ_SUCCESS) { + + pjsip_publishc_destroy(param->pubc); + acc->publish_sess = NULL; + if (param->status != PJ_SUCCESS) { char errmsg[PJ_ERR_MSG_SIZE]; @@ -968,6 +972,12 @@ static void publish_cb(struct pjsip_publishc_cbparam *param) PJ_LOG(1,(THIS_FILE, "Client publication (PUBLISH) failed, status=%d, msg=%s", param->status, errmsg)); + } else if (param->code == 412) { + /* 412 (Conditional Request Failed) + * The PUBLISH refresh has failed, retry with new one. + */ + pjsua_pres_init_publish_acc(acc->index); + } else { PJ_LOG(1,(THIS_FILE, "Client publication (PUBLISH) failed (%d/%.*s)", @@ -975,8 +985,14 @@ static void publish_cb(struct pjsip_publishc_cbparam *param) param->reason.ptr)); } - pjsip_publishc_destroy(param->pubc); - acc->publish_sess = NULL; + } else { + if (param->expiration == -1) { + /* Could happen if server "forgot" to include Expires header + * in the response. We will not renew, so destroy the pubc. + */ + pjsip_publishc_destroy(param->pubc); + acc->publish_sess = NULL; + } } } @@ -1091,7 +1107,7 @@ pj_status_t pjsua_pres_init_publish_acc(int acc_id) status = pjsip_publishc_init(acc->publish_sess, &STR_PRESENCE, &acc_cfg->id, &acc_cfg->id, &acc_cfg->id, - PJSUA_PRES_TIMER); + PJSUA_PUBLISH_EXPIRATION); if (status != PJ_SUCCESS) { acc->publish_sess = NULL; return status; @@ -1606,8 +1622,16 @@ static void refresh_client_subscriptions(void) static void pres_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry) { + unsigned i; pj_time_val delay = { PJSUA_PRES_TIMER, 0 }; + /* Retry failed PUBLISH requests */ + for (i=0; icfg.publish_enabled && acc->publish_sess==NULL) + pjsua_pres_init_publish_acc(acc->index); + } + entry->id = PJ_FALSE; refresh_client_subscriptions(); -- cgit v1.2.3