Ejemplo n.º 1
0
int sal_publish(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){
	belle_sip_request_t *req=NULL;
	if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) {
		if (from)
			sal_op_set_from(op,from);
		if (to)
			sal_op_set_to(op,to);

		sal_op_publish_fill_cbs(op);
		req=sal_op_build_request(op,"PUBLISH");
		if (sal_op_get_contact(op)){
			belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(sal_op_create_contact(op)));
		}
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event",eventname));
		sal_op_add_body(op,BELLE_SIP_MESSAGE(req),body);
		return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener);
	} else {
		/*update status*/
		const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher);
		belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans));
		/*update body*/
		sal_op_add_body(op,BELLE_SIP_MESSAGE(last_publish),expires!=0 ? body : NULL);
		return belle_sip_refresher_refresh(op->refresher,expires==-1 ? BELLE_SIP_REFRESHER_REUSE_EXPIRES : expires);
	}
}
Ejemplo n.º 2
0
int sal_subscribe(SalOp *op, const char *from, const char *to, const char *eventname, int expires, const SalBody *body){
	belle_sip_request_t *req=NULL;
	
	if (from)
		sal_op_set_from(op,from);
	if (to)
		sal_op_set_to(op,to);
	
	if (!op->dialog){
		sal_op_subscribe_fill_cbs(op);
		/*???sal_exosip_fix_route(op); make sure to ha ;lr*/
		req=sal_op_build_request(op,"SUBSCRIBE");
		if (eventname){
			if (op->event) belle_sip_object_unref(op->event);
			op->event=belle_sip_header_create("Event",eventname);
			belle_sip_object_ref(op->event);
		}
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),op->event);
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(expires)));
		sal_op_add_body(op,(belle_sip_message_t*)req,body);
		return sal_op_send_and_create_refresher(op,req,expires,subscribe_refresher_listener);
	}else if (op->refresher){
		const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher);
		belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr);
		/* modify last request to update body*/
		sal_op_add_body(op,(belle_sip_message_t*)last_req,body);
		return belle_sip_refresher_refresh(op->refresher,expires);
	}
	ms_warning("sal_subscribe(): no dialog and no refresher ?");
	return -1;
}
Ejemplo n.º 3
0
int sal_op_refresh(SalOp *op) {
	if (op->refresher) {
		belle_sip_refresher_refresh(op->refresher,belle_sip_refresher_get_expires(op->refresher));
		return 0;
	}
	ms_warning("sal_refresh on op [%p] of type [%s] no refresher",op,sal_op_type_to_string(op->type));
	return -1;
}
Ejemplo n.º 4
0
int sal_unsubscribe(SalOp *op){
	if (op->refresher){
		const belle_sip_transaction_t *tr=(const belle_sip_transaction_t*) belle_sip_refresher_get_transaction(op->refresher);
		belle_sip_request_t *last_req=belle_sip_transaction_get_request(tr);
		sal_op_add_body(op,(belle_sip_message_t*)last_req,NULL);
		belle_sip_refresher_refresh(op->refresher,0);
		return 0;
	}
	return -1;
}
Ejemplo n.º 5
0
static int timer_cb(void *user_data, unsigned int events) {
	belle_sip_refresher_t* refresher = (belle_sip_refresher_t*)user_data;

	if (refresher->timer_purpose==NORMAL_REFRESH && refresher->manual) {
		belle_sip_message("Refresher [%p] is in manual mode, skipping refresh.",refresher);
		/*call listener with special code 0 to indicate request is about to expire*/
		if (refresher->listener) refresher->listener(refresher,refresher->user_data,0, "about to expire");
		return BELLE_SIP_STOP;
	}

	if (belle_sip_refresher_refresh(refresher,refresher->target_expires)==-1){
		retry_later(refresher);
	}
	return BELLE_SIP_STOP;
}
Ejemplo n.º 6
0
static void process_transaction_terminated(belle_sip_listener_t *user_ctx, const belle_sip_transaction_terminated_event_t *event) {
	belle_sip_refresher_t* refresher=(belle_sip_refresher_t*)user_ctx;
	belle_sip_client_transaction_t*client_transaction = belle_sip_transaction_terminated_event_get_client_transaction(event);
	if (refresher && (client_transaction !=refresher->transaction))
		return; /*not for me*/

	if (refresher->publish_pending && refresher->state==started) {
		refresher->publish_pending = FALSE;
		belle_sip_message("Publish pending on refresher [%p], doing it",refresher);
		belle_sip_refresher_refresh(refresher,refresher->target_expires);
	} else {
		refresher->publish_pending = FALSE;
	}
	
}
Ejemplo n.º 7
0
static void publish_refresher_listener ( const belle_sip_refresher_t* refresher
		,void* user_pointer
		,unsigned int status_code
		,const char* reason_phrase) {
	SalOp* op = (SalOp*)user_pointer;
	/*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/
	ms_message("Publish refresher  [%i] reason [%s] for proxy [%s]",status_code,reason_phrase,sal_op_get_proxy(op));
	if (status_code==412){
		/*resubmit the request after removing the SIP-If-Match*/
		const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher);
		belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans));
		belle_sip_message_remove_header((belle_sip_message_t*)last_publish,"SIP-If-Match");
		belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES);
	}
}
Ejemplo n.º 8
0
/*presence publish */
int sal_publish_presence(SalOp *op, const char *from, const char *to, int expires, SalPresenceModel *presence){
	belle_sip_request_t *req=NULL;
	if(!op->refresher || !belle_sip_refresher_get_transaction(op->refresher)) {
		if (from)
			sal_op_set_from(op,from);
		if (to)
			sal_op_set_to(op,to);

		op->type=SalOpPublish;
		req=sal_op_build_request(op,"PUBLISH");
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create("Event","presence"));
		sal_add_presence_info(op,BELLE_SIP_MESSAGE(req),presence);
		return sal_op_send_and_create_refresher(op,req,expires,publish_refresher_listener);
	} else {
		/*update presence status*/
		const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher);
		belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans));
		sal_add_presence_info(op,BELLE_SIP_MESSAGE(last_publish),presence);
		return belle_sip_refresher_refresh(op->refresher,expires);
	}
}
Ejemplo n.º 9
0
int belle_sip_refresher_start(belle_sip_refresher_t* refresher) {
	if(refresher->state==started) {
		belle_sip_warning("Refresher [%p] already started",refresher);
	} else {
		if (refresher->target_expires>0) {
			belle_sip_request_t* request = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(refresher->transaction));
			refresher->state=started;
			if (is_contact_address_acurate(refresher,request)) {
				schedule_timer(refresher); /*re-arm timer*/
			} else {
				belle_sip_message("belle_sip_refresher_start(): refresher [%p] is resubmitting request because contact sent was not correct in original request.",refresher);
				belle_sip_refresher_refresh(refresher,refresher->target_expires);
				return 0;
			}
			belle_sip_message("Refresher [%p] started, next refresh in [%i] s",refresher,refresher->obtained_expires);
		}else{
			belle_sip_message("Refresher [%p] stopped, expires=%i",refresher,refresher->target_expires);
			refresher->state=stopped;
		}
	}
	return 0;
}
Ejemplo n.º 10
0
static void publish_refresher_listener (belle_sip_refresher_t* refresher
		,void* user_pointer
		,unsigned int status_code
		,const char* reason_phrase) {
	SalOp* op = (SalOp*)user_pointer;
	/*belle_sip_response_t* response=belle_sip_transaction_get_response(BELLE_SIP_TRANSACTION(belle_sip_refresher_get_transaction(refresher)));*/
	ms_message("Publish refresher  [%i] reason [%s] for proxy [%s]",status_code,reason_phrase?reason_phrase:"none",sal_op_get_proxy(op));
	if (status_code==412){
		/*resubmit the request after removing the SIP-If-Match*/
		const belle_sip_client_transaction_t* last_publish_trans=belle_sip_refresher_get_transaction(op->refresher);
		belle_sip_request_t* last_publish=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(last_publish_trans));
		belle_sip_message_remove_header((belle_sip_message_t*)last_publish,"SIP-If-Match");
		belle_sip_refresher_refresh(op->refresher,BELLE_SIP_REFRESHER_REUSE_EXPIRES);
	}else if (status_code==0){
		op->base.root->callbacks.on_expire(op);
	}else if (status_code>=200){
		SalError err;
		SalReason reason;
		sal_compute_sal_errors_from_code(status_code,&err,&reason);
		op->base.root->callbacks.on_publish_response(op,err,reason);
	}
}
Ejemplo n.º 11
0
int sal_register_refresh(SalOp *op, int expires){
	if (op->refresher)
		return belle_sip_refresher_refresh(op->refresher,expires);
	else
		return -1;
}
static void subscribe_test(void) {
	belle_sip_listener_callbacks_t client_callbacks;
	belle_sip_listener_callbacks_t server_callbacks;
	belle_sip_request_t* req;
	belle_sip_client_transaction_t* trans;
	belle_sip_header_route_t* destination_route;
	const char* identity = "sip:" USERNAME "@" SIPDOMAIN ;
	const char* domain="sip:" SIPDOMAIN ;
	endpoint_t* client,*server;
	belle_sip_uri_t *dest_uri;
	belle_sip_refresher_t* refresher;
	belle_sip_header_contact_t* contact=belle_sip_header_contact_new();
	uint64_t begin;
	uint64_t end;
	memset(&client_callbacks,0,sizeof(belle_sip_listener_callbacks_t));
	memset(&server_callbacks,0,sizeof(belle_sip_listener_callbacks_t));

	client_callbacks.process_response_event=client_process_response_event;
	client_callbacks.process_auth_requested=client_process_auth_requested;
	server_callbacks.process_request_event=server_process_request_event;

	client = create_udp_endpoint(3452,&client_callbacks);
	server = create_udp_endpoint(6788,&server_callbacks);
	server->expire_in_contact=0;
	server->auth=digest_auth;

	dest_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_listening_point_get_uri(server->lp));
	belle_sip_uri_set_host(dest_uri,"127.0.0.1");
	destination_route=belle_sip_header_route_create(belle_sip_header_address_create(NULL,dest_uri));


	req=belle_sip_request_create(
		                    belle_sip_uri_parse(domain),
		                    "SUBSCRIBE",
		                    belle_sip_provider_create_call_id(client->provider),
		                    belle_sip_header_cseq_create(20,"SUBSCRIBE"),
		                    belle_sip_header_from_create2(identity,BELLE_SIP_RANDOM_TAG),
		                    belle_sip_header_to_create2(identity,NULL),
		                    belle_sip_header_via_new(),
		                    70);
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact));
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(1)));
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_create("Event","Presence")));

	belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(destination_route));
	trans=belle_sip_provider_create_client_transaction(client->provider,req);
	belle_sip_object_ref(trans);/*to avoid trans from being deleted before refresher can use it*/
	belle_sip_client_transaction_send_request(trans);

	CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.fourHundredOne,1,1000));

	req=belle_sip_client_transaction_create_authenticated_request(trans,NULL,NULL);
	belle_sip_object_unref(trans);
	trans=belle_sip_provider_create_client_transaction(client->provider,req);
	belle_sip_object_ref(trans);
	belle_sip_client_transaction_send_request(trans);
	CU_ASSERT_TRUE_FATAL(wait_for(server->stack,client->stack,&client->stat.twoHundredOk,1,1000));
	 /*maybe dialog should be automatically created*/
	CU_ASSERT_PTR_NOT_NULL_FATAL(belle_sip_transaction_get_dialog(BELLE_SIP_TRANSACTION(trans)))

	refresher = belle_sip_client_transaction_create_refresher(trans);
	belle_sip_object_unref(trans);
	belle_sip_refresher_set_listener(refresher,belle_sip_refresher_listener,client);

	begin = belle_sip_time_ms();
	CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.refreshOk,3,4000));
	end = belle_sip_time_ms();
	CU_ASSERT_TRUE(end-begin>=3000);
	CU_ASSERT_TRUE(end-begin<5000);
	/*unsubscribe twice to make sure refresh operation can be safely cascaded*/
	belle_sip_refresher_refresh(refresher,0);
	belle_sip_refresher_refresh(refresher,0);

	belle_sip_refresher_stop(refresher);
	belle_sip_object_unref(refresher);
	destroy_endpoint(client);
	destroy_endpoint(server);
}
static void refresher_base_with_body(endpoint_t* client
										,endpoint_t *server
										, const char* method
										, belle_sip_header_content_type_t* content_type
										,const char* body) {
	belle_sip_request_t* req;
	belle_sip_client_transaction_t* trans;
	belle_sip_header_route_t* destination_route;
	belle_sip_refresher_t* refresher;
	const char* identity = "sip:" USERNAME "@" SIPDOMAIN ;
	const char* domain="sip:" SIPDOMAIN ;
	belle_sip_header_contact_t* contact=belle_sip_header_contact_new();
	belle_sip_uri_t *dest_uri;
	uint64_t begin;
	uint64_t end;
	if (client->expire_in_contact) belle_sip_header_contact_set_expires(contact,1);


	dest_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_listening_point_get_uri(server->lp));
	if (client->connection_family==AF_INET6)
		belle_sip_uri_set_host(dest_uri,"::1");
	else
		belle_sip_uri_set_host(dest_uri,"127.0.0.1");
	destination_route=belle_sip_header_route_create(belle_sip_header_address_create(NULL,dest_uri));


	req=belle_sip_request_create(
		                    belle_sip_uri_parse(domain),
		                    method,
		                    belle_sip_provider_create_call_id(client->provider),
		                    belle_sip_header_cseq_create(20,method),
		                    belle_sip_header_from_create2(identity,BELLE_SIP_RANDOM_TAG),
		                    belle_sip_header_to_create2(identity,NULL),
		                    belle_sip_header_via_new(),
		                    70);
	belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(contact));
	if (!client->expire_in_contact)
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_expires_create(1)));

	belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(destination_route));
	if (content_type && body) {
		size_t body_lenth=strlen(body);
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(content_type));
		belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_content_length_create(body_lenth)));
		belle_sip_message_set_body(BELLE_SIP_MESSAGE(req),body,body_lenth);
	}
	trans=belle_sip_provider_create_client_transaction(client->provider,req);
	belle_sip_object_ref(trans);/*to avoid trans from being deleted before refresher can use it*/
	belle_sip_client_transaction_send_request(trans);
	if (client->early_refresher) {
		client->refresher= refresher = belle_sip_client_transaction_create_refresher(trans);
	} else {
		if (server->auth == none) {
			CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.twoHundredOk,1,1000));
		} else {
			CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.fourHundredOne,1,1000));
			/*update cseq*/
			req=belle_sip_client_transaction_create_authenticated_request(trans,NULL,NULL);
			belle_sip_object_unref(trans);
			trans=belle_sip_provider_create_client_transaction(client->provider,req);
			belle_sip_object_ref(trans);
			belle_sip_client_transaction_send_request(trans);
			CU_ASSERT_TRUE_FATAL(wait_for(server->stack,client->stack,&client->stat.twoHundredOk,1,1000));
		}
		client->refresher= refresher = belle_sip_client_transaction_create_refresher(trans);
	}
	CU_ASSERT_TRUE_FATAL(refresher!=NULL);
	belle_sip_object_unref(trans);
	belle_sip_refresher_set_listener(refresher,belle_sip_refresher_listener,client);

	begin = belle_sip_time_ms();
	CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.refreshOk,client->register_count+(client->early_refresher?1:0),client->register_count*1000 + 1000));
	end = belle_sip_time_ms();
	CU_ASSERT_TRUE(end-begin>=client->register_count*1000*.9); /*because refresh is at 90% of expire*/
	CU_ASSERT_TRUE(end-begin<(client->register_count*1000 + 2000));
	/*unregister twice to make sure refresh operation can be safely cascaded*/
	belle_sip_refresher_refresh(refresher,0);
	belle_sip_refresher_refresh(refresher,0);
	CU_ASSERT_TRUE(wait_for(server->stack,client->stack,&client->stat.refreshOk,client->register_count+1,1000));
	CU_ASSERT_EQUAL(client->stat.refreshOk,client->register_count+1);
	belle_sip_refresher_stop(refresher);
	belle_sip_object_unref(refresher);
}
Ejemplo n.º 14
0
static void process_response_event(belle_sip_listener_t *user_ctx, const belle_sip_response_event_t *event){
	belle_sip_client_transaction_t* client_transaction = belle_sip_response_event_get_client_transaction(event);
	belle_sip_response_t* response = belle_sip_response_event_get_response(event);
	belle_sip_request_t* request=belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(client_transaction));
	int response_code = belle_sip_response_get_status_code(response);
	belle_sip_refresher_t* refresher=(belle_sip_refresher_t*)user_ctx;
	belle_sip_header_contact_t *contact;


	if (refresher && (client_transaction !=refresher->transaction))
		return; /*not for me*/

	set_or_update_dialog(refresher,belle_sip_response_event_get_dialog(event));
	/*success case:*/
	if (response_code>=200 && response_code<300){
		refresher->auth_failures=0;
		refresher->number_of_retry=0;
		/*great, success*/
		if (strcmp(belle_sip_request_get_method(request),"PUBLISH")==0) {
			/*search for etag*/
			belle_sip_header_t* etag=belle_sip_message_get_header(BELLE_SIP_MESSAGE(response),"SIP-ETag");
			if (etag) {
				belle_sip_header_t* sip_if_match = belle_sip_header_create("SIP-If-Match",belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(etag)));
				/*update request for next refresh*/
				belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),"SIP-If-Match");
				belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),sip_if_match);
			} else if (refresher->target_expires > 0){
				belle_sip_warning("Refresher [%p] received 200ok to a publish without etag",refresher);
			}
		}
		/*update expire if needed*/
		set_expires_from_trans(refresher);

		if (refresher->target_expires<=0) {
			belle_sip_refresher_stop(refresher); /*doesn't not make sense to refresh if expire =0;*/
		} else {
			/*remove all contact with expire = 0 from request if any, because no need to refresh them*/
			const belle_sip_list_t * contact_list= belle_sip_message_get_headers(BELLE_SIP_MESSAGE(request),BELLE_SIP_CONTACT);
			belle_sip_list_t *iterator, *head;
			if (contact_list) {
				for (iterator=head=belle_sip_list_copy(contact_list);iterator!=NULL;iterator=iterator->next) {
					belle_sip_header_contact_t *contact_for_expire = (belle_sip_header_contact_t *)(iterator->data);
					if (belle_sip_header_contact_get_expires(contact_for_expire) == 0) {
						belle_sip_message_remove_header_from_ptr(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact_for_expire));
					}
				}
				belle_sip_list_free(head);
			}
		}

		if (refresher->state==started) {
			if (!refresher->first_acknoleged_request)
				belle_sip_object_ref(refresher->first_acknoleged_request = request);
			if (is_contact_address_acurate(refresher,request)) {
				schedule_timer(refresher); /*re-arm timer*/
			} else {
				belle_sip_message("belle_sip_refresher_start(): refresher [%p] is resubmitting request because contact sent was not correct in original request.",refresher);
				belle_sip_refresher_refresh(refresher,refresher->target_expires);
				return;
			}
		}
		else belle_sip_message("Refresher [%p] not scheduling next refresh, because it was stopped",refresher);
	}else{/*special error cases*/
		switch (response_code) {
		case 301:
		case 302:
			contact=belle_sip_message_get_header_by_type(response,belle_sip_header_contact_t);
			if (contact){
				belle_sip_uri_t *uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(contact));
				if (uri && belle_sip_refresher_refresh_internal(refresher,refresher->target_expires,TRUE,&refresher->auth_events,uri)==0)
					return;
			}
			break;
		case 401:
		case 407:
			refresher->auth_failures++;
			if (refresher->auth_failures>1){
				/*avoid looping with 407 or 401 */
				belle_sip_warning("Authentication is failing constantly, %s",(refresher->target_expires>0)? "will retry later":"giving up.");
				if (refresher->target_expires>0) retry_later(refresher);
				refresher->auth_failures=0; /*reset auth failure*/
				break;
			}
			if (refresher->auth_events) {
				refresher->auth_events=belle_sip_list_free_with_data(refresher->auth_events,(void (*)(void*))belle_sip_auth_event_destroy);
			}
			if (belle_sip_refresher_refresh_internal(refresher,refresher->target_expires,TRUE,&refresher->auth_events,NULL)==0)
				return; /*ok, keep 401 internal*/
			break; /*Else notify user of registration failure*/
		case 403:
			/*In case of 403, we will retry later, just in case*/
			if (refresher->target_expires>0) retry_later(refresher);
			break;
		case 412:
			if (strcmp(belle_sip_request_get_method(request),"PUBLISH")==0) {
				belle_sip_message_remove_header(BELLE_SIP_MESSAGE(request),"SIP-If-Match");
				if (refresher->target_expires>0) {
					retry_later_on_io_error(refresher);
					return; /*do not notify this kind of error*/
				}
			} else {
				if (refresher->target_expires>0) retry_later(refresher);
			}
			break;
		case 423:{
			belle_sip_header_extension_t *min_expires=BELLE_SIP_HEADER_EXTENSION(belle_sip_message_get_header((belle_sip_message_t*)response,"Min-Expires"));
			if (min_expires){
				const char *value=belle_sip_header_extension_get_value(min_expires);
				if (value){
					int new_expires=atoi(value);
					if (new_expires>0 && refresher->state==started){
						refresher->target_expires=new_expires;
						belle_sip_refresher_refresh(refresher,refresher->target_expires);
						return;
					}
				}
			}else belle_sip_warning("Receiving 423 but no min-expires header.");
			break;
		}
		case 491: {
			if (refresher->target_expires>0) {
				retry_later_on_io_error(refresher);
				return; /*do not notify this kind of error*/
			}
		}
		case 505:
		case 501:
			/*irrecoverable errors, probably no need to retry later*/
			break;
		
		default:
			/*for all other errors, retry later*/
			if (refresher->target_expires>0) retry_later(refresher);
			break;
		}
	}
	if (refresher->listener) refresher->listener(refresher,refresher->user_data,response_code, belle_sip_response_get_reason_phrase(response));

}