Commit 7ddd3dda authored by jehan's avatar jehan

implements invite transaction cancelling

parent a6a62138
......@@ -41,15 +41,19 @@ BELLE_SIP_DECLARE_INTERFACE_END
#define BELLE_SIP_LISTENER(obj) BELLE_SIP_INTERFACE_CAST(obj,belle_sip_listener_t)
/*Response event*/
belle_sip_response_t* belle_sip_response_event_get_response(const belle_sip_response_event_t* event);
belle_sip_client_transaction_t *belle_sip_response_event_get_client_transaction(const belle_sip_response_event_t* event);
belle_sip_dialog_t *belle_sip_response_event_get_dialog(const belle_sip_response_event_t* event);
/*Request event*/
belle_sip_request_t* belle_sip_request_event_get_request(const belle_sip_request_event_t* event);
belle_sip_server_transaction_t *belle_sip_request_event_get_server_transaction(const belle_sip_request_event_t* event);
belle_sip_dialog_t *belle_sip_request_event_get_dialog(const belle_sip_request_event_t* event);
/*Dialog terminated event*/
belle_sip_dialog_t* belle_sip_dialog_terminated_get_dialog(const belle_sip_dialog_terminated_event_t *event);
/*auth event*/
const char* belle_sip_auth_event_get_username(const belle_sip_auth_event_t* event);
void belle_sip_auth_event_set_username(belle_sip_auth_event_t* event, const char* value);
......
......@@ -43,7 +43,7 @@ belle_sip_dialog_t* belle_sip_transaction_get_dialog(const belle_sip_transactio
void belle_sip_server_transaction_send_response(belle_sip_server_transaction_t *t, belle_sip_response_t *resp);
belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_client_transaction_t *t);
void belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t);
int belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t);
/**
* Create an authenticated request based on an existing terminated transaction
* */
......
......@@ -237,7 +237,7 @@ void belle_sip_fd_source_init(belle_sip_source_t *s, belle_sip_source_func_t fun
#ifdef __cplusplus
extern "C"{
extern "C" {
#endif
......@@ -563,7 +563,7 @@ static inline const belle_sip_timer_config_t * belle_sip_transaction_get_timer_c
static inline void belle_sip_transaction_start_timer(belle_sip_transaction_t *obj, belle_sip_source_t *timer){
belle_sip_main_loop_add_source(obj->provider->stack->ml,timer);
}
/** */
static inline void belle_sip_transaction_stop_timer(belle_sip_transaction_t *obj, belle_sip_source_t *timer){
belle_sip_main_loop_remove_source(obj->provider->stack->ml,timer);
}
......
......@@ -206,6 +206,13 @@ int belle_sip_dialog_establish(belle_sip_dialog_t *obj, belle_sip_request_t *req
obj->state=BELLE_SIP_DIALOG_CONFIRMED;
obj->needs_ack=TRUE;
}else return -1;
} else if (code>=300 && obj->state!=BELLE_SIP_DIALOG_CONFIRMED) {
/*12.3 Termination of a Dialog
Independent of the method, if a request outside of a dialog generates
a non-2xx final response, any early dialogs created through
provisional responses to that request are terminated. The mechanism
for terminating confirmed dialogs is method specific.*/
belle_sip_dialog_delete(obj);
}
return 0;
}
......
......@@ -28,21 +28,26 @@ static void ist_destroy(belle_sip_ist_t *obj){
static void ist_on_terminate(belle_sip_ist_t *obj){
belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;
/*timer pointers are set to NULL because they can be released later*/
if (obj->timer_G){
belle_sip_transaction_stop_timer(base,obj->timer_G);
belle_sip_object_unref(obj->timer_G);
obj->timer_G=NULL;
}
if (obj->timer_H){
belle_sip_transaction_stop_timer(base,obj->timer_H);
belle_sip_object_unref(obj->timer_H);
obj->timer_H=NULL;
}
if (obj->timer_I){
belle_sip_transaction_stop_timer(base,obj->timer_I);
belle_sip_object_unref(obj->timer_I);
obj->timer_I=NULL;
}
if (obj->timer_L){
belle_sip_transaction_stop_timer(base,obj->timer_L);
belle_sip_object_unref(obj->timer_L);
obj->timer_L=NULL;
}
}
......
......@@ -94,6 +94,7 @@ static void belle_sip_provider_dispatch_request(belle_sip_provider_t* prov, bell
ev.request=req;
BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov,process_request_event,&ev);
}
belle_sip_object_unref(req);
}
static void belle_sip_provider_dispatch_response(belle_sip_provider_t* prov, belle_sip_response_t *msg){
......@@ -117,6 +118,7 @@ static void belle_sip_provider_dispatch_response(belle_sip_provider_t* prov, bel
event.response=msg;
BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov,process_response_event,&event);
}
belle_sip_object_unref(msg);
}
static void belle_sip_provider_dispatch_message(belle_sip_provider_t *prov, belle_sip_message_t *msg){
......@@ -333,7 +335,11 @@ void belle_sip_provider_add_dialog(belle_sip_provider_t *prov, belle_sip_dialog_
}
void belle_sip_provider_remove_dialog(belle_sip_provider_t *prov, belle_sip_dialog_t *dialog){
belle_sip_dialog_terminated_event_t ev;
ev.source=prov;
ev.dialog=dialog;
prov->dialogs=belle_sip_list_remove(prov->dialogs,dialog);
BELLE_SIP_PROVIDER_INVOKE_LISTENERS(prov,process_dialog_terminated,&ev);
belle_sip_object_unref(dialog);
}
......@@ -493,7 +499,7 @@ struct server_transaction_matcher{
const char *branchid;
const char *method;
const char *sentby;
int is_ack;
int is_ack_or_cancel;
};
static int rfc3261_server_transaction_match(const void *p_tr, const void *p_matcher){
......@@ -502,7 +508,7 @@ static int rfc3261_server_transaction_match(const void *p_tr, const void *p_matc
const char *req_method=belle_sip_request_get_method(tr->base.request);
if (strcmp(matcher->branchid,tr->base.branch_id)==0){
if (strcmp(matcher->method,req_method)==0) return 0;
if (matcher->is_ack && strcmp(req_method,"INVITE")==0) return 0;
if (matcher->is_ack_or_cancel && strcmp(req_method,"INVITE")==0) return 0;
}
return -1;
}
......@@ -518,10 +524,10 @@ belle_sip_server_transaction_t * belle_sip_provider_find_matching_server_transac
}
matcher.branchid=belle_sip_header_via_get_branch(via);
matcher.method=belle_sip_request_get_method(req);
matcher.is_ack=(strcmp(matcher.method,"ACK")==0);
matcher.is_ack_or_cancel=(strcmp(matcher.method,"ACK")==0 || strcmp(matcher.method,"CANCEL")==0);
if (strncmp(matcher.branchid,BELLE_SIP_BRANCH_MAGIC_COOKIE,strlen(BELLE_SIP_BRANCH_MAGIC_COOKIE))==0){
/*compliant to RFC3261*/
elem=belle_sip_list_find_custom(prov->client_transactions,rfc3261_server_transaction_match,&matcher);
elem=belle_sip_list_find_custom(prov->server_transactions,rfc3261_server_transaction_match,&matcher);
}else{
//FIXME
}
......@@ -598,18 +604,24 @@ int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_requ
const char* ha1;
char computed_ha1[33];
int result=0;
const char* request_method;
/*check params*/
if (!p || !request) {
belle_sip_error("belle_sip_provider_add_authorization bad parameters");
return-1;
}
request_method=belle_sip_request_get_method(request);
if (strcmp("CANCEL",request_method)==0 || strcmp("ACK",request_method)==0) {
belle_sip_debug("no authorization header needed for method [%s]",request_method);
return 0;
}
/*get authenticates value from response*/
if (resp) {
call_id = belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(resp),belle_sip_header_call_id_t);
/*searching for authentication headers*/
head=authenticate_lst = belle_sip_list_copy(belle_sip_message_get_headers(BELLE_SIP_MESSAGE(resp),BELLE_SIP_WWW_AUTHENTICATE));
authenticate_lst = belle_sip_list_copy(belle_sip_message_get_headers(BELLE_SIP_MESSAGE(resp),BELLE_SIP_WWW_AUTHENTICATE));
/*search for proxy authenticate*/
authenticate_lst=belle_sip_list_append_link(authenticate_lst,belle_sip_list_copy(belle_sip_message_get_headers(BELLE_SIP_MESSAGE(resp),BELLE_SIP_PROXY_AUTHENTICATE)));
/*update auth contexts with authenticate headers from response*/
......@@ -617,7 +629,7 @@ int belle_sip_provider_add_authorization(belle_sip_provider_t *p, belle_sip_requ
authenticate=BELLE_SIP_HEADER_WWW_AUTHENTICATE(authenticate_lst->data);
belle_sip_provider_update_or_create_auth_context(p,call_id,authenticate);
}
belle_sip_list_free(head);
belle_sip_list_free(authenticate_lst);
}
/*put authorization header if passwd found*/
......
......@@ -42,7 +42,9 @@ belle_sip_dialog_t *belle_sip_request_event_get_dialog(const belle_sip_request_e
return event->dialog;
}
belle_sip_dialog_t* belle_sip_dialog_terminated_get_dialog(const belle_sip_dialog_terminated_event_t *event) {
return event->dialog;
}
typedef struct belle_sip_callbacks belle_sip_callbacks_t;
......
......@@ -121,6 +121,8 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR(belle_sip_server_transaction_t)={
};
void belle_sip_server_transaction_init(belle_sip_server_transaction_t *t, belle_sip_provider_t *prov,belle_sip_request_t *req){
belle_sip_header_via_t *via=BELLE_SIP_HEADER_VIA(belle_sip_message_get_header((belle_sip_message_t*)req,"via"));
t->base.branch_id=belle_sip_strdup(belle_sip_header_via_get_branch(via));
belle_sip_transaction_init((belle_sip_transaction_t*)t,prov,req);
belle_sip_random_token(t->to_tag,sizeof(t->to_tag));
}
......@@ -205,9 +207,10 @@ belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_clien
belle_sip_error("belle_sip_client_transaction_create_cancel() cannot be used for ACK or non-INVITE transactions.");
return NULL;
}
if (t->base.state==BELLE_SIP_TRANSACTION_PROCEEDING){
if (t->base.state!=BELLE_SIP_TRANSACTION_PROCEEDING){
belle_sip_error("belle_sip_client_transaction_create_cancel() can only be used in state BELLE_SIP_TRANSACTION_PROCEEDING"
" but current transaction state is %s",belle_sip_transaction_state_to_string(t->base.state));
return NULL;
}
req=belle_sip_request_new();
belle_sip_request_set_method(req,"CANCEL");
......@@ -225,14 +228,14 @@ belle_sip_request_t * belle_sip_client_transaction_create_cancel(belle_sip_clien
}
void belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t){
int belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t){
belle_sip_hop_t hop={0};
belle_sip_channel_t *chan;
belle_sip_provider_t *prov=t->base.provider;
if (t->base.state!=BELLE_SIP_TRANSACTION_INIT){
belle_sip_error("belle_sip_client_transaction_send_request: bad state.");
return;
return -1;
}
belle_sip_stack_get_next_hop(prov->stack,t->base.request,&hop);
chan=belle_sip_provider_get_channel(prov,hop.host, hop.port, hop.transport);
......@@ -250,19 +253,21 @@ void belle_sip_client_transaction_send_request(belle_sip_client_transaction_t *t
}
}else belle_sip_error("belle_sip_client_transaction_send_request(): no channel available");
belle_sip_hop_free(&hop);
return 0;
}
void belle_sip_client_transaction_notify_response(belle_sip_client_transaction_t *t, belle_sip_response_t *resp){
belle_sip_transaction_t *base=(belle_sip_transaction_t*)t;
belle_sip_response_event_t event;
belle_sip_dialog_t *dialog=base->dialog;
int status_code = belle_sip_response_get_status_code(resp);
if (base->last_response)
belle_sip_object_unref(base->last_response);
base->last_response=(belle_sip_response_t*)belle_sip_object_ref(resp);
if (dialog){
if (dialog->state==BELLE_SIP_DIALOG_EARLY || dialog->state==BELLE_SIP_DIALOG_CONFIRMED){
if (status_code>=200 && status_code<300
&& (dialog->state==BELLE_SIP_DIALOG_EARLY || dialog->state==BELLE_SIP_DIALOG_CONFIRMED)){
/*make sure this response matches the current dialog, or creates a new one*/
if (!belle_sip_dialog_match(dialog,(belle_sip_message_t*)resp,FALSE)){
dialog=belle_sip_dialog_new(base);
......
......@@ -321,6 +321,7 @@ static void simple_call(void) {
unregister_user(stack, prov, pauline_register_req ,1);
unregister_user(stack, prov, marie_register_req ,1);
}
int belle_sip_dialog_test_suite(){
CU_pSuite pSuite = CU_add_suite("Dialog", init, uninit);
......
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