123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815 |
- /*
- * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
- * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
- *
- * 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 2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include <pjsip-simple/publish.h>
- #include <pjsip/sip_auth.h>
- #include <pjsip/sip_endpoint.h>
- #include <pjsip/sip_errno.h>
- #include <pjsip/sip_event.h>
- #include <pjsip/sip_msg.h>
- #include <pjsip/sip_transaction.h>
- #include <pjsip/sip_uri.h>
- #include <pjsip/sip_util.h>
- #include <pj/assert.h>
- #include <pj/guid.h>
- #include <pj/log.h>
- #include <pj/os.h>
- #include <pj/pool.h>
- #include <pj/rand.h>
- #include <pj/string.h>
- #include <pj/timer.h>
- #define REFRESH_TIMER 1
- #define DELAY_BEFORE_REFRESH PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH
- #define THIS_FILE "publishc.c"
- /* Let's define this enum, so that it'll trigger compilation error
- * when somebody define the same enum in sip_msg.h
- */
- enum
- {
- PJSIP_PUBLISH_METHOD = PJSIP_OTHER_METHOD,
- };
- const pjsip_method pjsip_publish_method =
- {
- (pjsip_method_e)PJSIP_PUBLISH_METHOD,
- { "PUBLISH", 7 }
- };
- /**
- * Pending request list.
- */
- typedef struct pending_publish
- {
- PJ_DECL_LIST_MEMBER(struct pending_publish);
- pjsip_tx_data *tdata;
- } pending_publish;
- /**
- * SIP client publication structure.
- */
- struct pjsip_publishc
- {
- pj_pool_t *pool;
- pjsip_endpoint *endpt;
- pj_bool_t _delete_flag;
- int pending_tsx;
- pj_bool_t in_callback;
- pj_mutex_t *mutex;
- pjsip_publishc_opt opt;
- void *token;
- pjsip_publishc_cb *cb;
- pj_str_t event;
- pj_str_t str_target_uri;
- pjsip_uri *target_uri;
- pjsip_cid_hdr *cid_hdr;
- pjsip_cseq_hdr *cseq_hdr;
- pj_str_t from_uri;
- pjsip_from_hdr *from_hdr;
- pjsip_to_hdr *to_hdr;
- pj_str_t etag;
- pjsip_expires_hdr *expires_hdr;
- pj_uint32_t expires;
- pjsip_route_hdr route_set;
- pjsip_hdr usr_hdr;
- pjsip_host_port via_addr;
- const void *via_tp;
- /* Authorization sessions. */
- pjsip_auth_clt_sess auth_sess;
- /* Auto refresh publication. */
- pj_bool_t auto_refresh;
- pj_time_val last_refresh;
- pj_time_val next_refresh;
- pj_timer_entry timer;
- /* Pending PUBLISH request */
- pending_publish pending_reqs;
- pending_publish pending_reqs_empty;
- };
- PJ_DEF(void) pjsip_publishc_opt_default(pjsip_publishc_opt *opt)
- {
- pj_bzero(opt, sizeof(*opt));
- opt->queue_request = PJSIP_PUBLISHC_QUEUE_REQUEST;
- }
- /*
- * Initialize client publication module.
- */
- PJ_DEF(pj_status_t) pjsip_publishc_init_module(pjsip_endpoint *endpt)
- {
- /* Note:
- Commented out the capability registration below, since it's
- wrong to include PUBLISH in Allow header of INVITE requests/
- responses.
- 13.2.1 Creating the Initial INVITE
- An Allow header field (Section 20.5) SHOULD be present in the
- INVITE. It indicates what methods can be invoked within a dialog
- 20.5 Allow
- The Allow header field lists the set of methods supported by the
- UA generating the message.
- While the semantic of Allow header in non-dialog requests is unclear,
- it's probably best not to include PUBLISH in Allow header for now
- until we can find out how to customize the inclusion of methods in
- Allow header for in-dialog vs out-dialog requests.
- return pjsip_endpt_add_capability( endpt, NULL, PJSIP_H_ALLOW, NULL,
- 1, &pjsip_publish_method.name);
- */
- PJ_UNUSED_ARG(endpt);
- return PJ_SUCCESS;
- }
- PJ_DEF(pj_status_t) pjsip_publishc_create( pjsip_endpoint *endpt,
- const pjsip_publishc_opt *opt,
- void *token,
- pjsip_publishc_cb *cb,
- pjsip_publishc **p_pubc)
- {
- pj_pool_t *pool;
- pjsip_publishc *pubc;
- pjsip_publishc_opt default_opt;
- pj_status_t status;
- /* Verify arguments. */
- PJ_ASSERT_RETURN(endpt && cb && p_pubc, PJ_EINVAL);
- pool = pjsip_endpt_create_pool(endpt, "pubc%p", 1024, 1024);
- PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
- pubc = PJ_POOL_ZALLOC_T(pool, pjsip_publishc);
- pubc->pool = pool;
- pubc->endpt = endpt;
- pubc->token = token;
- pubc->cb = cb;
- pubc->expires = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED;
- if (!opt) {
- pjsip_publishc_opt_default(&default_opt);
- opt = &default_opt;
- }
- pj_memcpy(&pubc->opt, opt, sizeof(*opt));
- pj_list_init(&pubc->pending_reqs);
- pj_list_init(&pubc->pending_reqs_empty);
- status = pj_mutex_create_recursive(pubc->pool, "pubc%p", &pubc->mutex);
- if (status != PJ_SUCCESS) {
- pj_pool_release(pool);
- return status;
- }
- status = pjsip_auth_clt_init(&pubc->auth_sess, endpt, pubc->pool, 0);
- if (status != PJ_SUCCESS) {
- pj_mutex_destroy(pubc->mutex);
- pj_pool_release(pool);
- return status;
- }
- pj_list_init(&pubc->route_set);
- pj_list_init(&pubc->usr_hdr);
- /* Done */
- *p_pubc = pubc;
- return PJ_SUCCESS;
- }
- PJ_DEF(pj_status_t) pjsip_publishc_destroy(pjsip_publishc *pubc)
- {
- PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
- if (pubc->pending_tsx || pubc->in_callback) {
- pubc->_delete_flag = 1;
- pubc->cb = NULL;
- } else {
- /* Cancel existing timer, if any */
- if (pubc->timer.id != 0) {
- pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
- pubc->timer.id = 0;
- }
- if (pubc->mutex)
- pj_mutex_destroy(pubc->mutex);
- pjsip_auth_clt_deinit(&pubc->auth_sess);
- pjsip_endpt_release_pool(pubc->endpt, pubc->pool);
- }
- return PJ_SUCCESS;
- }
- PJ_DEF(pj_pool_t*) pjsip_publishc_get_pool(pjsip_publishc *pubc)
- {
- return pubc->pool;
- }
- static void set_expires( pjsip_publishc *pubc, pj_uint32_t 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;
- }
- }
- PJ_DEF(pj_status_t) pjsip_publishc_init(pjsip_publishc *pubc,
- const pj_str_t *event,
- const pj_str_t *target_uri,
- const pj_str_t *from_uri,
- const pj_str_t *to_uri,
- pj_uint32_t expires)
- {
- pj_str_t tmp;
- PJ_ASSERT_RETURN(pubc && event && target_uri && from_uri && to_uri &&
- expires, PJ_EINVAL);
- /* Copy event type */
- pj_strdup_with_null(pubc->pool, &pubc->event, event);
- /* Copy server URL. */
- pj_strdup_with_null(pubc->pool, &pubc->str_target_uri, target_uri);
- /* Set server URL. */
- tmp = pubc->str_target_uri;
- pubc->target_uri = pjsip_parse_uri( pubc->pool, tmp.ptr, tmp.slen, 0);
- if (pubc->target_uri == NULL) {
- return PJSIP_EINVALIDURI;
- }
- /* Set "From" header. */
- pj_strdup_with_null(pubc->pool, &pubc->from_uri, from_uri);
- tmp = pubc->from_uri;
- pubc->from_hdr = pjsip_from_hdr_create(pubc->pool);
- pubc->from_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
- PJSIP_PARSE_URI_AS_NAMEADDR);
- if (!pubc->from_hdr->uri) {
- return PJSIP_EINVALIDURI;
- }
- /* Set "To" header. */
- pj_strdup_with_null(pubc->pool, &tmp, to_uri);
- pubc->to_hdr = pjsip_to_hdr_create(pubc->pool);
- pubc->to_hdr->uri = pjsip_parse_uri(pubc->pool, tmp.ptr, tmp.slen,
- PJSIP_PARSE_URI_AS_NAMEADDR);
- if (!pubc->to_hdr->uri) {
- return PJSIP_EINVALIDURI;
- }
- /* Set "Expires" header, if required. */
- set_expires( pubc, expires);
- /* Set "Call-ID" header. */
- pubc->cid_hdr = pjsip_cid_hdr_create(pubc->pool);
- pj_create_unique_string(pubc->pool, &pubc->cid_hdr->id);
- /* Set "CSeq" header. */
- pubc->cseq_hdr = pjsip_cseq_hdr_create(pubc->pool);
- pubc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
- pjsip_method_set( &pubc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
- /* Done. */
- return PJ_SUCCESS;
- }
- PJ_DEF(pj_status_t) pjsip_publishc_set_credentials( pjsip_publishc *pubc,
- int count,
- const pjsip_cred_info cred[] )
- {
- PJ_ASSERT_RETURN(pubc && count && cred, PJ_EINVAL);
- return pjsip_auth_clt_set_credentials(&pubc->auth_sess, count, cred);
- }
- PJ_DEF(pj_status_t) pjsip_publishc_set_route_set( pjsip_publishc *pubc,
- const pjsip_route_hdr *route_set)
- {
- const pjsip_route_hdr *chdr;
- PJ_ASSERT_RETURN(pubc && route_set, PJ_EINVAL);
- pj_list_init(&pubc->route_set);
- chdr = route_set->next;
- while (chdr != route_set) {
- pj_list_push_back(&pubc->route_set, pjsip_hdr_clone(pubc->pool, chdr));
- chdr = chdr->next;
- }
- 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;
- }
- PJ_DEF(pj_status_t) pjsip_publishc_set_via_sent_by(pjsip_publishc *pubc,
- pjsip_host_port *via_addr,
- pjsip_transport *via_tp)
- {
- PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
- if (!via_addr)
- pj_bzero(&pubc->via_addr, sizeof(pubc->via_addr));
- else {
- if (pj_strcmp(&pubc->via_addr.host, &via_addr->host))
- pj_strdup(pubc->pool, &pubc->via_addr.host, &via_addr->host);
- pubc->via_addr.port = via_addr->port;
- }
- pubc->via_tp = via_tp;
- return PJ_SUCCESS;
- }
- static pj_status_t create_request(pjsip_publishc *pubc,
- pjsip_tx_data **p_tdata)
- {
- const pj_str_t STR_EVENT = { "Event", 5 };
- pj_status_t status;
- pjsip_generic_string_hdr *hdr;
- pjsip_tx_data *tdata;
- PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
- /* Create the request. */
- status = pjsip_endpt_create_request_from_hdr( pubc->endpt,
- &pjsip_publish_method,
- pubc->target_uri,
- pubc->from_hdr,
- pubc->to_hdr,
- NULL,
- pubc->cid_hdr,
- pubc->cseq_hdr->cseq,
- NULL,
- &tdata);
- if (status != PJ_SUCCESS)
- return status;
- /* Add cached authorization headers. */
- pjsip_auth_clt_init_req( &pubc->auth_sess, tdata );
- /* Add Route headers from route set, ideally after Via header */
- if (!pj_list_empty(&pubc->route_set)) {
- pjsip_hdr *route_pos;
- const pjsip_route_hdr *route;
- route_pos = (pjsip_hdr*)
- pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
- if (!route_pos)
- route_pos = &tdata->msg->hdr;
- route = pubc->route_set.next;
- while (route != &pubc->route_set) {
- pjsip_hdr *new_hdr = (pjsip_hdr*)
- pjsip_hdr_shallow_clone(tdata->pool, route);
- pj_list_insert_after(route_pos, new_hdr);
- route_pos = new_hdr;
- route = route->next;
- }
- }
- /* Add Event header */
- hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_EVENT,
- &pubc->event);
- if (hdr)
- pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
- /* Add SIP-If-Match if we have etag */
- if (pubc->etag.slen) {
- const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
- hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_HNAME,
- &pubc->etag);
- if (hdr)
- pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
- }
- /* Add user headers */
- if (!pj_list_empty(&pubc->usr_hdr)) {
- const pjsip_hdr *uhdr;
- uhdr = pubc->usr_hdr.next;
- while (uhdr != &pubc->usr_hdr) {
- pjsip_hdr *new_hdr = (pjsip_hdr*)
- pjsip_hdr_shallow_clone(tdata->pool, uhdr);
- pjsip_msg_add_hdr(tdata->msg, new_hdr);
- uhdr = uhdr->next;
- }
- }
- /* Done. */
- *p_tdata = tdata;
- return PJ_SUCCESS;
- }
- PJ_DEF(pj_status_t) pjsip_publishc_publish(pjsip_publishc *pubc,
- pj_bool_t auto_refresh,
- pjsip_tx_data **p_tdata)
- {
- pj_status_t status;
- pjsip_tx_data *tdata;
- PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
- status = create_request(pubc, &tdata);
- if (status != PJ_SUCCESS)
- return status;
- /* Add Expires header */
- if (pubc->expires_hdr) {
- pjsip_hdr *dup;
- dup = (pjsip_hdr*)
- pjsip_hdr_shallow_clone(tdata->pool, pubc->expires_hdr);
- if (dup)
- pjsip_msg_add_hdr(tdata->msg, dup);
- }
- /* Cancel existing timer */
- if (pubc->timer.id != 0) {
- pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
- pubc->timer.id = 0;
- }
- pubc->auto_refresh = auto_refresh;
- /* Done */
- *p_tdata = tdata;
- return PJ_SUCCESS;
- }
- PJ_DEF(pj_status_t) pjsip_publishc_unpublish(pjsip_publishc *pubc,
- pjsip_tx_data **p_tdata)
- {
- pjsip_tx_data *tdata;
- pjsip_msg *msg;
- pjsip_expires_hdr *expires;
- pj_status_t status;
- PJ_ASSERT_RETURN(pubc && p_tdata, PJ_EINVAL);
- if (pubc->timer.id != 0) {
- pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
- pubc->timer.id = 0;
- }
- status = create_request(pubc, &tdata);
- if (status != PJ_SUCCESS)
- return status;
- msg = tdata->msg;
- /* Add Expires:0 header */
- expires = pjsip_expires_hdr_create(tdata->pool, 0);
- pjsip_msg_add_hdr( msg, (pjsip_hdr*)expires);
- *p_tdata = tdata;
- return PJ_SUCCESS;
- }
- PJ_DEF(pj_status_t) pjsip_publishc_update_expires( pjsip_publishc *pubc,
- pj_uint32_t expires )
- {
- PJ_ASSERT_RETURN(pubc, PJ_EINVAL);
- set_expires( pubc, expires );
- return PJ_SUCCESS;
- }
- static void call_callback(pjsip_publishc *pubc, pj_status_t status,
- int st_code, const pj_str_t *reason,
- pjsip_rx_data *rdata, pj_uint32_t expiration)
- {
- struct pjsip_publishc_cbparam cbparam;
- cbparam.pubc = pubc;
- cbparam.token = pubc->token;
- cbparam.status = status;
- cbparam.code = st_code;
- cbparam.reason = *reason;
- cbparam.rdata = rdata;
- cbparam.expiration = expiration;
- (*pubc->cb)(&cbparam);
- }
- static void pubc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
- struct pj_timer_entry *entry)
- {
- pjsip_publishc *pubc = (pjsip_publishc*) entry->user_data;
- pjsip_tx_data *tdata;
- pj_status_t status;
-
- PJ_UNUSED_ARG(timer_heap);
- entry->id = 0;
- status = pjsip_publishc_publish(pubc, 1, &tdata);
- if (status != PJ_SUCCESS) {
- char errmsg[PJ_ERR_MSG_SIZE];
- pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
- call_callback(pubc, status, 400, &reason, NULL,
- PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED);
- return;
- }
- status = pjsip_publishc_send(pubc, tdata);
- /* No need to call callback as it should have been called */
- }
- static void tsx_callback(void *token, pjsip_event *event)
- {
- pj_status_t status;
- pjsip_publishc *pubc = (pjsip_publishc*) token;
- pjsip_transaction *tsx = event->body.tsx_state.tsx;
-
- /* Decrement pending transaction counter. */
- pj_assert(pubc->pending_tsx > 0);
- --pubc->pending_tsx;
- /* Mark that we're in callback to prevent deletion (#1164) */
- ++pubc->in_callback;
- /* If publication data has been deleted by user then remove publication
- * data from transaction's callback, and don't call callback.
- */
- if (pubc->_delete_flag) {
- /* Nothing to do */
- ;
- } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
- tsx->status_code == PJSIP_SC_UNAUTHORIZED)
- {
- pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
- pjsip_tx_data *tdata;
- status = pjsip_auth_clt_reinit_req( &pubc->auth_sess,
- rdata,
- tsx->last_tx,
- &tdata);
- if (status != PJ_SUCCESS) {
- call_callback(pubc, status, tsx->status_code,
- &rdata->msg_info.msg->line.status.reason,
- rdata, PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED);
- } else {
- status = pjsip_publishc_send(pubc, tdata);
- }
- } else {
- pjsip_rx_data *rdata;
- pj_uint32_t expiration = PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED;
- if (tsx->status_code/100 == 2) {
- pjsip_msg *msg;
- pjsip_expires_hdr *expires;
- pjsip_generic_string_hdr *etag_hdr;
- const pj_str_t STR_ETAG = { "SIP-ETag", 8 };
- rdata = event->body.tsx_state.src.rdata;
- msg = rdata->msg_info.msg;
- /* Save ETag value */
- etag_hdr = (pjsip_generic_string_hdr*)
- pjsip_msg_find_hdr_by_name(msg, &STR_ETAG, NULL);
- if (etag_hdr) {
- pj_strdup(pubc->pool, &pubc->etag, &etag_hdr->hvalue);
- } else {
- pubc->etag.slen = 0;
- }
- /* Update expires value */
- expires = (pjsip_expires_hdr*)
- pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
- if (pubc->auto_refresh && expires)
- expiration = expires->ivalue;
-
- if (pubc->auto_refresh && expiration!=0 &&
- expiration!=PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED)
- {
- pj_time_val delay = { 0, 0};
- /* Cancel existing timer, if any */
- if (pubc->timer.id != 0) {
- pjsip_endpt_cancel_timer(pubc->endpt, &pubc->timer);
- pubc->timer.id = 0;
- }
- delay.sec = expiration - DELAY_BEFORE_REFRESH;
- if (pubc->expires != PJSIP_PUBC_EXPIRATION_NOT_SPECIFIED &&
- delay.sec > (pj_int32_t)pubc->expires)
- {
- delay.sec = pubc->expires;
- }
- if (delay.sec < DELAY_BEFORE_REFRESH)
- delay.sec = DELAY_BEFORE_REFRESH;
- pubc->timer.cb = &pubc_refresh_timer_cb;
- pubc->timer.id = REFRESH_TIMER;
- pubc->timer.user_data = pubc;
- pjsip_endpt_schedule_timer( pubc->endpt, &pubc->timer, &delay);
- pj_gettimeofday(&pubc->last_refresh);
- pubc->next_refresh = pubc->last_refresh;
- pubc->next_refresh.sec += delay.sec;
- }
- } else {
- rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ?
- event->body.tsx_state.src.rdata : NULL;
- }
- /* Call callback. */
- // if (expiration == 0xFFFF) expiration = -1;
- /* Temporarily increment pending_tsx to prevent callback from
- * destroying pubc.
- */
- ++pubc->pending_tsx;
- call_callback(pubc, PJ_SUCCESS, tsx->status_code,
- (rdata ? &rdata->msg_info.msg->line.status.reason
- : pjsip_get_status_text(tsx->status_code)),
- rdata, expiration);
- --pubc->pending_tsx;
- /* If we have pending request(s), send them now */
- pj_mutex_lock(pubc->mutex);
- while (!pj_list_empty(&pubc->pending_reqs)) {
- pending_publish *pp = pubc->pending_reqs.next;
- pjsip_tx_data *tdata = pp->tdata;
- /* Remove the request from pending request list,
- * and keep the unused entry into pending_reqs_empty pool.
- */
- pj_list_erase(pp);
- pj_list_push_back(&pubc->pending_reqs_empty, pp);
- /* Add SIP-If-Match if we have etag and the request doesn't have
- * one (https://github.com/pjsip/pjproject/issues/996)
- */
- if (pubc->etag.slen) {
- const pj_str_t STR_HNAME = { "SIP-If-Match", 12 };
- pjsip_generic_string_hdr *sim_hdr;
- sim_hdr = (pjsip_generic_string_hdr*)
- pjsip_msg_find_hdr_by_name(tdata->msg, &STR_HNAME, NULL);
- if (!sim_hdr) {
- /* Create the header */
- sim_hdr = pjsip_generic_string_hdr_create(tdata->pool,
- &STR_HNAME,
- &pubc->etag);
- pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)sim_hdr);
- } else {
- /* Update */
- if (pj_strcmp(&pubc->etag, &sim_hdr->hvalue))
- pj_strdup(tdata->pool, &sim_hdr->hvalue, &pubc->etag);
- }
- }
- status = pjsip_publishc_send(pubc, tdata);
- if (status == PJ_EPENDING) {
- pj_assert(!"Not expected");
- pjsip_tx_data_dec_ref(tdata);
- } else if (status == PJ_SUCCESS) {
- break;
- }
- }
- pj_mutex_unlock(pubc->mutex);
- }
- /* No longer in callback. */
- --pubc->in_callback;
- /* Delete the record if user destroy pubc during the callback. */
- if (pubc->_delete_flag && pubc->pending_tsx==0) {
- pjsip_publishc_destroy(pubc);
- }
- }
- PJ_DEF(pj_status_t) pjsip_publishc_send(pjsip_publishc *pubc,
- pjsip_tx_data *tdata)
- {
- pj_status_t status;
- pjsip_cseq_hdr *cseq_hdr;
- pj_uint32_t cseq;
- PJ_ASSERT_RETURN(pubc && tdata, PJ_EINVAL);
- /* Make sure we don't have pending transaction. */
- pj_mutex_lock(pubc->mutex);
- if (pubc->pending_tsx) {
- if (pubc->opt.queue_request) {
- pending_publish *pp = NULL;
- if (pj_list_empty(&pubc->pending_reqs_empty)) {
- pp = PJ_POOL_ZALLOC_T(pubc->pool, pending_publish);
- } else {
- pp = pubc->pending_reqs_empty.next;
- pj_list_erase(pp);
- }
- pp->tdata = tdata;
- pj_list_push_back(&pubc->pending_reqs, pp);
- pj_mutex_unlock(pubc->mutex);
- PJ_LOG(4,(THIS_FILE, "Request is queued, pubc has another "
- "transaction pending"));
- return PJ_EPENDING;
- } else {
- pjsip_tx_data_dec_ref(tdata);
- pj_mutex_unlock(pubc->mutex);
- PJ_LOG(4,(THIS_FILE, "Unable to send request, pubc has another "
- "transaction pending"));
- return PJ_EBUSY;
- }
- }
- /* If via_addr is set, use this address for the Via header. */
- if (pubc->via_addr.host.slen > 0) {
- tdata->via_addr = pubc->via_addr;
- tdata->via_tp = pubc->via_tp;
- }
- /* Invalidate message buffer. */
- pjsip_tx_data_invalidate_msg(tdata);
- /* Increment CSeq */
- cseq = ++pubc->cseq_hdr->cseq;
- cseq_hdr = (pjsip_cseq_hdr*)
- pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
- cseq_hdr->cseq = cseq;
- /* Increment pending transaction first, since transaction callback
- * may be called even before send_request() returns!
- */
- ++pubc->pending_tsx;
- pj_mutex_unlock(pubc->mutex);
- status = pjsip_endpt_send_request(pubc->endpt, tdata, -1, pubc,
- &tsx_callback);
- if (status!=PJ_SUCCESS) {
- // no need to decrement, callback has been called and it should
- // already decremented pending_tsx. Decrementing this here may
- // cause accessing freed memory location.
- //--pubc->pending_tsx;
- PJ_PERROR(4,(THIS_FILE, status, "Error sending request"));
- }
- return status;
- }
|