diff options
Diffstat (limited to 'pjsip')
-rw-r--r-- | pjsip/include/pjsip-simple/evsub.h | 11 | ||||
-rw-r--r-- | pjsip/src/pjsip-simple/evsub.c | 66 | ||||
-rw-r--r-- | pjsip/src/pjsip-simple/evsub_msg.c | 6 | ||||
-rw-r--r-- | pjsip/src/pjsip-simple/presence.c | 38 |
4 files changed, 88 insertions, 33 deletions
diff --git a/pjsip/include/pjsip-simple/evsub.h b/pjsip/include/pjsip-simple/evsub.h index 25ad4891..25a20b12 100644 --- a/pjsip/include/pjsip-simple/evsub.h +++ b/pjsip/include/pjsip-simple/evsub.h @@ -346,6 +346,17 @@ PJ_DECL(const char*) pjsip_evsub_get_state_name(pjsip_evsub *sub); /** + * Get subscription termination reason, if any. If remote did not + * send termination reason, this function will return empty string. + * + * @param sub Event subscription instance. + * + * @return NULL terminated string. + */ +PJ_DECL(const pj_str_t*) pjsip_evsub_get_termination_reason(pjsip_evsub *sub); + + +/** * Call this function to create request to initiate subscription, to * refresh subcription, or to request subscription termination. * diff --git a/pjsip/src/pjsip-simple/evsub.c b/pjsip/src/pjsip-simple/evsub.c index 085d496e..2d629c04 100644 --- a/pjsip/src/pjsip-simple/evsub.c +++ b/pjsip/src/pjsip-simple/evsub.c @@ -221,6 +221,7 @@ struct pjsip_evsub pj_str_t state_str; /**< String describing the state. */ pjsip_evsub_state dst_state; /**< Pending state to be set. */ pj_str_t dst_state_str;/**< Pending state to be set. */ + pj_str_t term_reason; /**< Termination reason. */ pjsip_method method; /**< Method that established subscr.*/ pjsip_event_hdr *event; /**< Event description. */ pjsip_expires_hdr *expires; /**< Expires header */ @@ -550,7 +551,8 @@ static void evsub_destroy( pjsip_evsub *sub ) * Set subscription session state. */ static void set_state( pjsip_evsub *sub, pjsip_evsub_state state, - const pj_str_t *state_str, pjsip_event *event) + const pj_str_t *state_str, pjsip_event *event, + const pj_str_t *reason) { pjsip_evsub_state prev_state = sub->state; pj_str_t old_state_str = sub->state_str; @@ -562,6 +564,9 @@ static void set_state( pjsip_evsub *sub, pjsip_evsub_state state, else sub->state_str = evsub_state_names[state]; + if (reason && sub->term_reason.slen==0) + pj_strdup(sub->pool, &sub->term_reason, reason); + PJ_LOG(4,(sub->obj_name, "Subscription state changed %.*s --> %.*s", (int)old_state_str.slen, @@ -638,9 +643,12 @@ static void on_timer( pj_timer_heap_t *timer_heap, case TIMER_TYPE_UAC_TERMINATE: { + pj_str_t timeout = {"timeout", 7}; + PJ_LOG(5,(sub->obj_name, "Timeout waiting for final NOTIFY. " "Terminating..")); - set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL); + set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL, + &timeout); } break; @@ -912,7 +920,7 @@ PJ_DEF(pj_status_t) pjsip_evsub_terminate( pjsip_evsub *sub, */ sub->call_cb = notify; - set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL); + set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL, NULL); pjsip_dlg_dec_lock(sub->dlg); return PJ_SUCCESS; @@ -934,6 +942,13 @@ PJ_DEF(const char*) pjsip_evsub_get_state_name(pjsip_evsub *sub) return sub->state_str.ptr; } +/* + * Get termination reason. + */ +PJ_DEF(const pj_str_t*) pjsip_evsub_get_termination_reason(pjsip_evsub *sub) +{ + return &sub->term_reason; +} /* * Initiate client subscription @@ -1085,10 +1100,10 @@ static pjsip_sub_state_hdr* sub_state_create( pj_pool_t *pool, switch (state) { case PJSIP_EVSUB_STATE_NULL: case PJSIP_EVSUB_STATE_SENT: - case PJSIP_EVSUB_STATE_ACCEPTED: pj_assert(!"Invalid state!"); /* Treat as pending */ + case PJSIP_EVSUB_STATE_ACCEPTED: case PJSIP_EVSUB_STATE_PENDING: sub_state->sub_state = STR_PENDING; sub_state->expires_param = delay.sec; @@ -1155,7 +1170,9 @@ PJ_DEF(pj_status_t) pjsip_evsub_notify( pjsip_evsub *sub, /* Add Authentication headers. */ pjsip_auth_clt_init_req( &sub->dlg->auth_sess, tdata ); - + /* Update reason */ + if (reason) + pj_strdup(sub->dlg->pool, &sub->term_reason, reason); /* Save destination state. */ sub->dst_state = state; @@ -1218,7 +1235,7 @@ PJ_DEF(pj_status_t) pjsip_evsub_send_request( pjsip_evsub *sub, set_state(sub, sub->dst_state, (sub->dst_state_str.slen ? &sub->dst_state_str : NULL), - NULL); + NULL, NULL); sub->dst_state = PJSIP_EVSUB_STATE_NULL; sub->dst_state_str.slen = 0; @@ -1546,7 +1563,7 @@ static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx, if (sub->state == PJSIP_EVSUB_STATE_NULL && tsx->state == PJSIP_TSX_STATE_CALLING) { - set_state(sub, PJSIP_EVSUB_STATE_SENT, NULL, event); + set_state(sub, PJSIP_EVSUB_STATE_SENT, NULL, event, NULL); return; } @@ -1587,8 +1604,7 @@ static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx, if (status != PJ_SUCCESS) { /* Authentication failed! */ set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, - NULL, - event); + NULL, event, &tsx->status_text); return; } @@ -1646,7 +1662,7 @@ static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx, /* Set state, if necessary */ pj_assert(sub->state != PJSIP_EVSUB_STATE_NULL); if (sub->state == PJSIP_EVSUB_STATE_SENT) { - set_state(sub, PJSIP_EVSUB_STATE_ACCEPTED, NULL, event); + set_state(sub, PJSIP_EVSUB_STATE_ACCEPTED, NULL, event, NULL); } } else { @@ -1685,7 +1701,7 @@ static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx, /* Set state to TERMINATED */ set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, - NULL, event); + NULL, event, &tsx->status_text); } @@ -1771,7 +1787,12 @@ static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx, unsigned timeout = TIME_UAC_WAIT_NOTIFY; set_timer(sub, TIMER_TYPE_UAC_WAIT_NOTIFY, timeout); } else { - set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL); + char errmsg[PJ_ERR_MSG_SIZE]; + pj_str_t reason; + + reason = pj_strerror(status, errmsg, sizeof(errmsg)); + set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL, + &reason); } return; @@ -1815,9 +1836,15 @@ static void on_tsx_state_uac( pjsip_evsub *sub, pjsip_transaction *tsx, /* Set the state */ if (status == PJ_SUCCESS) { - set_state(sub, new_state, new_state_str, event); + set_state(sub, new_state, new_state_str, event, + &sub_state->reason_param); } else { - set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event); + char errmsg[PJ_ERR_MSG_SIZE]; + pj_str_t reason; + + reason = pj_strerror(status, errmsg, sizeof(errmsg)); + set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event, + &reason); } @@ -1858,6 +1885,7 @@ static void on_tsx_state_uas( pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_msg_body *body = NULL; pjsip_evsub_state old_state; pj_str_t old_state_str; + pj_str_t reason = { NULL, 0 }; pj_status_t status; @@ -1944,9 +1972,9 @@ static void on_tsx_state_uas( pjsip_evsub *sub, pjsip_transaction *tsx, if (st_code/100==2) { if (sub->expires->ivalue == 0) { - set_state(sub, sub->state, NULL, event); + set_state(sub, sub->state, NULL, event, &reason); } else if (sub->state == PJSIP_EVSUB_STATE_NULL) { - set_state(sub, sub->state, NULL, event); + set_state(sub, sub->state, NULL, event, &reason); } /* Set UAS timeout timer, when state is not terminated. */ @@ -1980,7 +2008,8 @@ static void on_tsx_state_uas( pjsip_evsub *sub, pjsip_transaction *tsx, if (status != PJ_SUCCESS) { /* Can't authenticate. Terminate session (?) */ - set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL); + set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, NULL, + &tsx->status_text); return; } @@ -1993,7 +2022,8 @@ static void on_tsx_state_uas( pjsip_evsub *sub, pjsip_transaction *tsx, (tsx->status_code==481 || tsx->status_code==408 || tsx->status_code/100 == 7)) { - set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event); + set_state(sub, PJSIP_EVSUB_STATE_TERMINATED, NULL, event, + &tsx->status_text); return; } diff --git a/pjsip/src/pjsip-simple/evsub_msg.c b/pjsip/src/pjsip-simple/evsub_msg.c index 3c3b520b..f2e59c9b 100644 --- a/pjsip/src/pjsip-simple/evsub_msg.c +++ b/pjsip/src/pjsip-simple/evsub_msg.c @@ -19,6 +19,7 @@ #include <pjsip-simple/evsub_msg.h> #include <pjsip/print_util.h> #include <pjsip/sip_parser.h> +#include <pjlib-util/string.h> #include <pj/pool.h> #include <pj/string.h> #include <pj/except.h> @@ -166,8 +167,9 @@ static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr, *p++ = ':'; *p++ = ' '; - copy_advance(p, hdr->sub_state); - copy_advance_pair(p, ";reason=", 8, hdr->reason_param); + copy_advance_escape(p, hdr->sub_state, pc->pjsip_TOKEN_SPEC); + copy_advance_pair_escape(p, ";reason=", 8, hdr->reason_param, + pc->pjsip_TOKEN_SPEC); if (hdr->expires_param >= 0) { pj_memcpy(p, ";expires=", 9); p += 9; diff --git a/pjsip/src/pjsip-simple/presence.c b/pjsip/src/pjsip-simple/presence.c index 842e0a6a..b3fb85d2 100644 --- a/pjsip/src/pjsip-simple/presence.c +++ b/pjsip/src/pjsip-simple/presence.c @@ -461,8 +461,13 @@ PJ_DEF(pj_status_t) pjsip_pres_notify( pjsip_evsub *sub, pres = (pjsip_pres*) pjsip_evsub_get_mod_data(sub, mod_presence.id); PJ_ASSERT_RETURN(pres != NULL, PJSIP_SIMPLE_ENOPRESENCE); - /* Must have at least one presence info. */ - PJ_ASSERT_RETURN(pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO); + /* Must have at least one presence info, unless state is + * PJSIP_EVSUB_STATE_TERMINATED. This could happen if subscription + * has not been active (e.g. we're waiting for user authorization) + * and remote cancels the subscription. + */ + PJ_ASSERT_RETURN(state==PJSIP_EVSUB_STATE_TERMINATED || + pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO); /* Lock object. */ @@ -474,11 +479,14 @@ PJ_DEF(pj_status_t) pjsip_pres_notify( pjsip_evsub *sub, goto on_return; - /* Create message body to reflect the presence status. */ - status = pres_create_msg_body( pres, tdata ); - if (status != PJ_SUCCESS) - goto on_return; - + /* Create message body to reflect the presence status. + * Only do this if we have presence status info to send (see above). + */ + if (pres->status.info_cnt > 0) { + status = pres_create_msg_body( pres, tdata ); + if (status != PJ_SUCCESS) + goto on_return; + } /* Done. */ *p_tdata = tdata; @@ -507,8 +515,11 @@ PJ_DEF(pj_status_t) pjsip_pres_current_notify( pjsip_evsub *sub, pres = (pjsip_pres*) pjsip_evsub_get_mod_data(sub, mod_presence.id); PJ_ASSERT_RETURN(pres != NULL, PJSIP_SIMPLE_ENOPRESENCE); - /* Must have at least one presence info. */ - PJ_ASSERT_RETURN(pres->status.info_cnt > 0, PJSIP_SIMPLE_ENOPRESENCEINFO); + /* We may not have a presence info yet, e.g. when we receive SUBSCRIBE + * to refresh subscription while we're waiting for user authorization. + */ + //PJ_ASSERT_RETURN(pres->status.info_cnt > 0, + // PJSIP_SIMPLE_ENOPRESENCEINFO); /* Lock object. */ @@ -521,10 +532,11 @@ PJ_DEF(pj_status_t) pjsip_pres_current_notify( pjsip_evsub *sub, /* Create message body to reflect the presence status. */ - status = pres_create_msg_body( pres, tdata ); - if (status != PJ_SUCCESS) - goto on_return; - + if (pres->status.info_cnt > 0) { + status = pres_create_msg_body( pres, tdata ); + if (status != PJ_SUCCESS) + goto on_return; + } /* Done. */ *p_tdata = tdata; |