Commit ca6c4f2f authored by Simon Morlat's avatar Simon Morlat
Browse files

Implement termination of dialogs upon receiving a NOTIFY with subscription-state terminated.

Improve refresher behavior (fixes crashes)
parent 223c8be6
......@@ -790,12 +790,17 @@ BELLE_SIP_DECLARE_CUSTOM_VPTR_END
belle_sip_nist_t * belle_sip_nist_new(belle_sip_provider_t *prov, belle_sip_request_t *req);
typedef enum belle_sip_dialog_type{
BELLE_SIP_DIALOG_INVITE,
BELLE_SIP_DIALOG_SUBSCRIBE_NOTIFY
}belle_sip_dialog_type_t;
/*
* Dialogs
*/
struct belle_sip_dialog{
belle_sip_object_t base;
void *appdata;
belle_sip_dialog_type_t type;
belle_sip_provider_t *provider;
belle_sip_request_t *last_out_invite;
belle_sip_request_t *last_out_ack; /*so that it can be retransmitted when needed*/
......
......@@ -382,6 +382,33 @@ static void belle_sip_dialog_stop_200Ok_retrans(belle_sip_dialog_t *obj){
}
}
/* returns true if the dialog is terminated by the NOTIFY request or response*/
static int belle_sip_dialog_should_terminate_by_notify(belle_sip_dialog_t *obj, belle_sip_transaction_t* transaction, int as_uas){
int should_terminate = FALSE;
if (obj->type == BELLE_SIP_DIALOG_SUBSCRIBE_NOTIFY) {
belle_sip_request_t *req=belle_sip_transaction_get_request(transaction);
belle_sip_response_t *resp=belle_sip_transaction_get_response(transaction);
belle_sip_header_subscription_state_t* subscription_state_header=belle_sip_message_get_header_by_type(req,belle_sip_header_subscription_state_t);
int code = resp ? belle_sip_response_get_status_code(resp) : 0;
if (!subscription_state_header || strcasecmp(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,belle_sip_header_subscription_state_get_state(subscription_state_header)) ==0) {
if (as_uas){
/*terminate the dialog when the application replies the 200 Ok*/
if (code == 200){
should_terminate = TRUE;
}
}else{
/*terminate the dialog when we receive the 200OK or the transaction terminates by timeout*/
if (code == 200 || belle_sip_transaction_get_state(transaction) == BELLE_SIP_TRANSACTION_TERMINATED){
should_terminate = TRUE;
}
}
}
}
return should_terminate;
}
/*
* return 0 if message should be delivered to the next listener, otherwise, its a retransmision, just keep it
* */
......@@ -394,6 +421,7 @@ int belle_sip_dialog_update(belle_sip_dialog_t *obj, belle_sip_transaction_t* tr
int ret = 0;
int is_invite = strcmp(belle_sip_request_get_method(req),"INVITE")==0;
int is_subscribe = strcmp(belle_sip_request_get_method(req),"SUBSCRIBE")==0;
int is_notify = strcmp(belle_sip_request_get_method(req),"NOTIFY")==0;
belle_sip_message("Dialog [%p]: now updated by transaction [%p].",obj, transaction);
......@@ -525,8 +553,15 @@ int belle_sip_dialog_update(belle_sip_dialog_t *obj, belle_sip_transaction_t* tr
if (belle_sip_dialog_schedule_expiration(obj, (belle_sip_message_t*)req) == BELLE_SIP_STOP
&& (code>=200 || (code==0 && belle_sip_transaction_get_state(transaction)==BELLE_SIP_TRANSACTION_TERMINATED))){
delete_dialog = TRUE;
}else if (!as_uas){
if (code >= 300 || (code==0 && belle_sip_transaction_get_state(transaction)==BELLE_SIP_TRANSACTION_TERMINATED)){
/*case of a SUBSCRIBE refresh that is rejected or unanswered*/
delete_dialog = TRUE;
}
}
}else if (is_notify){
delete_dialog = belle_sip_dialog_should_terminate_by_notify(obj, transaction, as_uas);
}
break;
case BELLE_SIP_DIALOG_TERMINATED:
/*ignore*/
......@@ -590,6 +625,14 @@ belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t){
obj->pending_trans_checking_enabled=1;
obj->call_id=(belle_sip_header_call_id_t*)belle_sip_object_ref(call_id);
if (strcmp(belle_sip_request_get_method(t->request),"INVITE") == 0){
obj->type = BELLE_SIP_DIALOG_INVITE;
}else if (strcmp(belle_sip_request_get_method(t->request),"SUBSCRIBE") == 0){
obj->type = BELLE_SIP_DIALOG_SUBSCRIBE_NOTIFY;
}else{
belle_sip_error("belle_sip_dialog_new(): unsupported request [%s] for creating a dialog.", belle_sip_request_get_method(t->request));
}
belle_sip_object_ref(t);
obj->last_transaction=t;
......
......@@ -103,12 +103,13 @@ static void process_dialog_terminated(belle_sip_listener_t *user_ctx, const bell
if (refresher && refresher->transaction && dialog != belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(refresher->transaction)))
return; /*not for me*/
/*
if (refresher->state == started) {
belle_sip_warning("Refresher [%p] still started but receiving unexpected dialog deleted event on [%p], retrying",refresher,dialog);
retry_later_on_io_error(refresher);
if (refresher->listener) refresher->listener(refresher,refresher->user_data,481, "dialod terminated", TRUE);
}
*/
}
static void process_io_error(belle_sip_listener_t *user_ctx, const belle_sip_io_error_event_t *event){
......@@ -324,10 +325,6 @@ static void process_response_event(belle_sip_listener_t *user_ctx, const belle_s
will_retry = FALSE;
break;
}
case 481: {
/* will trigger dialog terminated, so nothing to do here*/
return;
}
case 491: {
if (refresher->target_expires>0) {
retry_later_on_io_error(refresher);
......@@ -340,7 +337,12 @@ static void process_response_event(belle_sip_listener_t *user_ctx, const belle_s
/*irrecoverable errors, probably no need to retry later*/
will_retry = FALSE;
break;
case 503:
if (refresher->target_expires>0) {
if (refresher->dialog) retry_later_on_io_error(refresher);
else retry_later(refresher);
}else will_retry = FALSE;
break;
default:
/*for all other errors <600, retry later*/
if (response_code < 600 && refresher->target_expires>0) retry_later(refresher);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment