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 ...@@ -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); 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 * Dialogs
*/ */
struct belle_sip_dialog{ struct belle_sip_dialog{
belle_sip_object_t base; belle_sip_object_t base;
void *appdata; void *appdata;
belle_sip_dialog_type_t type;
belle_sip_provider_t *provider; belle_sip_provider_t *provider;
belle_sip_request_t *last_out_invite; belle_sip_request_t *last_out_invite;
belle_sip_request_t *last_out_ack; /*so that it can be retransmitted when needed*/ 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){ ...@@ -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 * 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 ...@@ -394,6 +421,7 @@ int belle_sip_dialog_update(belle_sip_dialog_t *obj, belle_sip_transaction_t* tr
int ret = 0; int ret = 0;
int is_invite = strcmp(belle_sip_request_get_method(req),"INVITE")==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_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); belle_sip_message("Dialog [%p]: now updated by transaction [%p].",obj, transaction);
...@@ -525,7 +553,14 @@ int belle_sip_dialog_update(belle_sip_dialog_t *obj, belle_sip_transaction_t* tr ...@@ -525,7 +553,14 @@ 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 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))){ && (code>=200 || (code==0 && belle_sip_transaction_get_state(transaction)==BELLE_SIP_TRANSACTION_TERMINATED))){
delete_dialog = TRUE; 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; break;
case BELLE_SIP_DIALOG_TERMINATED: case BELLE_SIP_DIALOG_TERMINATED:
...@@ -590,6 +625,14 @@ belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t){ ...@@ -590,6 +625,14 @@ belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t){
obj->pending_trans_checking_enabled=1; obj->pending_trans_checking_enabled=1;
obj->call_id=(belle_sip_header_call_id_t*)belle_sip_object_ref(call_id); 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); belle_sip_object_ref(t);
obj->last_transaction=t; obj->last_transaction=t;
......
...@@ -103,12 +103,13 @@ static void process_dialog_terminated(belle_sip_listener_t *user_ctx, const bell ...@@ -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))) if (refresher && refresher->transaction && dialog != belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(refresher->transaction)))
return; /*not for me*/ return; /*not for me*/
/*
if (refresher->state == started) { if (refresher->state == started) {
belle_sip_warning("Refresher [%p] still started but receiving unexpected dialog deleted event on [%p], retrying",refresher,dialog); belle_sip_warning("Refresher [%p] still started but receiving unexpected dialog deleted event on [%p], retrying",refresher,dialog);
retry_later_on_io_error(refresher); retry_later_on_io_error(refresher);
if (refresher->listener) refresher->listener(refresher,refresher->user_data,481, "dialod terminated", TRUE); 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){ 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 ...@@ -324,10 +325,6 @@ static void process_response_event(belle_sip_listener_t *user_ctx, const belle_s
will_retry = FALSE; will_retry = FALSE;
break; break;
} }
case 481: {
/* will trigger dialog terminated, so nothing to do here*/
return;
}
case 491: { case 491: {
if (refresher->target_expires>0) { if (refresher->target_expires>0) {
retry_later_on_io_error(refresher); retry_later_on_io_error(refresher);
...@@ -340,7 +337,12 @@ static void process_response_event(belle_sip_listener_t *user_ctx, const belle_s ...@@ -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*/ /*irrecoverable errors, probably no need to retry later*/
will_retry = FALSE; will_retry = FALSE;
break; 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: default:
/*for all other errors <600, retry later*/ /*for all other errors <600, retry later*/
if (response_code < 600 && refresher->target_expires>0) retry_later(refresher); 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